aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/internal')
-rw-r--r--src/cmd/internal/archive/archive_test.go4
-rw-r--r--src/cmd/internal/buildid/buildid.go38
-rw-r--r--src/cmd/internal/buildid/buildid_test.go31
-rw-r--r--src/cmd/internal/buildid/note.go7
-rw-r--r--src/cmd/internal/buildid/rewrite.go71
-rw-r--r--src/cmd/internal/codesign/codesign.go268
-rw-r--r--src/cmd/internal/dwarf/dwarf.go33
-rw-r--r--src/cmd/internal/goobj/funcinfo.go82
-rw-r--r--src/cmd/internal/goobj/objfile.go12
-rw-r--r--src/cmd/internal/moddeps/moddeps_test.go3
-rw-r--r--src/cmd/internal/obj/arm/asm5.go8
-rw-r--r--src/cmd/internal/obj/arm/obj5.go36
-rw-r--r--src/cmd/internal/obj/arm64/a.out.go129
-rw-r--r--src/cmd/internal/obj/arm64/anames.go68
-rw-r--r--src/cmd/internal/obj/arm64/anames7.go11
-rw-r--r--src/cmd/internal/obj/arm64/asm7.go891
-rw-r--r--src/cmd/internal/obj/arm64/doc.go10
-rw-r--r--src/cmd/internal/obj/arm64/obj7.go38
-rw-r--r--src/cmd/internal/obj/dwarf.go34
-rw-r--r--src/cmd/internal/obj/ld.go2
-rw-r--r--src/cmd/internal/obj/link.go164
-rw-r--r--src/cmd/internal/obj/mips/asm0.go10
-rw-r--r--src/cmd/internal/obj/mips/obj0.go42
-rw-r--r--src/cmd/internal/obj/objfile.go220
-rw-r--r--src/cmd/internal/obj/objfile_test.go36
-rw-r--r--src/cmd/internal/obj/pass.go6
-rw-r--r--src/cmd/internal/obj/pcln.go83
-rw-r--r--src/cmd/internal/obj/plist.go36
-rw-r--r--src/cmd/internal/obj/ppc64/a.out.go6
-rw-r--r--src/cmd/internal/obj/ppc64/anames.go6
-rw-r--r--src/cmd/internal/obj/ppc64/asm9.go189
-rw-r--r--src/cmd/internal/obj/ppc64/obj9.go36
-rw-r--r--src/cmd/internal/obj/riscv/cpu.go12
-rw-r--r--src/cmd/internal/obj/riscv/obj.go168
-rw-r--r--src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go83
-rw-r--r--src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s44
-rw-r--r--src/cmd/internal/obj/s390x/asmz.go16
-rw-r--r--src/cmd/internal/obj/s390x/objz.go34
-rw-r--r--src/cmd/internal/obj/s390x/rotate.go82
-rw-r--r--src/cmd/internal/obj/s390x/rotate_test.go122
-rw-r--r--src/cmd/internal/obj/sizeof_test.go2
-rw-r--r--src/cmd/internal/obj/sym.go11
-rw-r--r--src/cmd/internal/obj/util.go54
-rw-r--r--src/cmd/internal/obj/wasm/wasmobj.go42
-rw-r--r--src/cmd/internal/obj/x86/asm6.go32
-rw-r--r--src/cmd/internal/obj/x86/obj6.go30
-rw-r--r--src/cmd/internal/objabi/flag.go39
-rw-r--r--src/cmd/internal/objabi/flag_test.go26
-rw-r--r--src/cmd/internal/objabi/funcdata.go15
-rw-r--r--src/cmd/internal/objabi/funcid.go6
-rw-r--r--src/cmd/internal/objabi/head.go2
-rw-r--r--src/cmd/internal/objabi/line.go33
-rw-r--r--src/cmd/internal/objabi/path.go22
-rw-r--r--src/cmd/internal/objabi/reloctype.go22
-rw-r--r--src/cmd/internal/objabi/reloctype_string.go70
-rw-r--r--src/cmd/internal/objabi/util.go18
-rw-r--r--src/cmd/internal/objfile/goobj.go20
-rw-r--r--src/cmd/internal/objfile/macho.go2
-rw-r--r--src/cmd/internal/pkgpath/pkgpath.go174
-rw-r--r--src/cmd/internal/pkgpath/pkgpath_test.go141
-rw-r--r--src/cmd/internal/sys/supported.go27
-rw-r--r--src/cmd/internal/sys/supported_test.go18
62 files changed, 3020 insertions, 957 deletions
diff --git a/src/cmd/internal/archive/archive_test.go b/src/cmd/internal/archive/archive_test.go
index 1468a58210..cb4eb842b4 100644
--- a/src/cmd/internal/archive/archive_test.go
+++ b/src/cmd/internal/archive/archive_test.go
@@ -243,7 +243,7 @@ func TestParseCGOArchive(t *testing.T) {
c1 := "c1"
c2 := "c2"
switch runtime.GOOS {
- case "darwin":
+ case "darwin", "ios":
c1 = "_" + c1
c2 = "_" + c2
case "windows":
@@ -275,7 +275,7 @@ func TestParseCGOArchive(t *testing.T) {
obj := io.NewSectionReader(f, e.Offset, e.Size)
switch runtime.GOOS {
- case "darwin":
+ case "darwin", "ios":
mf, err := macho.NewFile(obj)
if err != nil {
t.Fatal(err)
diff --git a/src/cmd/internal/buildid/buildid.go b/src/cmd/internal/buildid/buildid.go
index ac238d70ea..1e8855d3ac 100644
--- a/src/cmd/internal/buildid/buildid.go
+++ b/src/cmd/internal/buildid/buildid.go
@@ -10,18 +10,15 @@ import (
"fmt"
"internal/xcoff"
"io"
+ "io/fs"
"os"
"strconv"
"strings"
)
var (
- errBuildIDToolchain = fmt.Errorf("build ID only supported in gc toolchain")
errBuildIDMalformed = fmt.Errorf("malformed object file")
- errBuildIDUnknown = fmt.Errorf("lost build ID")
-)
-var (
bangArch = []byte("!<arch>")
pkgdef = []byte("__.PKGDEF")
goobject = []byte("go object ")
@@ -109,7 +106,7 @@ func ReadFile(name string) (id string, err error) {
// in cmd/go/internal/work/exec.go.
func readGccgoArchive(name string, f *os.File) (string, error) {
bad := func() (string, error) {
- return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
+ return "", &fs.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
}
off := int64(8)
@@ -167,7 +164,7 @@ func readGccgoArchive(name string, f *os.File) (string, error) {
// in cmd/go/internal/work/exec.go.
func readGccgoBigArchive(name string, f *os.File) (string, error) {
bad := func() (string, error) {
- return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
+ return "", &fs.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
}
// Read fixed-length header.
@@ -309,13 +306,38 @@ func readRaw(name string, data []byte) (id string, err error) {
j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd)
if j < 0 {
- return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
+ return "", &fs.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
}
quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1]
id, err = strconv.Unquote(string(quoted))
if err != nil {
- return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
+ return "", &fs.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
}
return id, nil
}
+
+// HashToString converts the hash h to a string to be recorded
+// in package archives and binaries as part of the build ID.
+// We use the first 120 bits of the hash (5 chunks of 24 bits each) and encode
+// it in base64, resulting in a 20-byte string. Because this is only used for
+// detecting the need to rebuild installed files (not for lookups
+// in the object file cache), 120 bits are sufficient to drive the
+// probability of a false "do not need to rebuild" decision to effectively zero.
+// We embed two different hashes in archives and four in binaries,
+// so cutting to 20 bytes is a significant savings when build IDs are displayed.
+// (20*4+3 = 83 bytes compared to 64*4+3 = 259 bytes for the
+// more straightforward option of printing the entire h in base64).
+func HashToString(h [32]byte) string {
+ const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
+ const chunks = 5
+ var dst [chunks * 4]byte
+ for i := 0; i < chunks; i++ {
+ v := uint32(h[3*i])<<16 | uint32(h[3*i+1])<<8 | uint32(h[3*i+2])
+ dst[4*i+0] = b64[(v>>18)&0x3F]
+ dst[4*i+1] = b64[(v>>12)&0x3F]
+ dst[4*i+2] = b64[(v>>6)&0x3F]
+ dst[4*i+3] = b64[v&0x3F]
+ }
+ return string(dst[:])
+}
diff --git a/src/cmd/internal/buildid/buildid_test.go b/src/cmd/internal/buildid/buildid_test.go
index 904c2c6f37..e832f9987e 100644
--- a/src/cmd/internal/buildid/buildid_test.go
+++ b/src/cmd/internal/buildid/buildid_test.go
@@ -11,6 +11,7 @@ import (
"io/ioutil"
"os"
"reflect"
+ "strings"
"testing"
)
@@ -146,3 +147,33 @@ func TestFindAndHash(t *testing.T) {
}
}
}
+
+func TestExcludedReader(t *testing.T) {
+ const s = "0123456789abcdefghijklmn"
+ tests := []struct {
+ start, end int64 // excluded range
+ results []string // expected results of reads
+ }{
+ {12, 15, []string{"0123456789", "ab\x00\x00\x00fghij", "klmn"}}, // within one read
+ {8, 21, []string{"01234567\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "\x00lmn"}}, // across multiple reads
+ {10, 20, []string{"0123456789", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "klmn"}}, // a whole read
+ {0, 5, []string{"\x00\x00\x00\x00\x0056789", "abcdefghij", "klmn"}}, // start
+ {12, 24, []string{"0123456789", "ab\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00"}}, // end
+ }
+ p := make([]byte, 10)
+ for _, test := range tests {
+ r := &excludedReader{strings.NewReader(s), 0, test.start, test.end}
+ for _, res := range test.results {
+ n, err := r.Read(p)
+ if err != nil {
+ t.Errorf("read failed: %v", err)
+ }
+ if n != len(res) {
+ t.Errorf("unexpected number of bytes read: want %d, got %d", len(res), n)
+ }
+ if string(p[:n]) != res {
+ t.Errorf("unexpected bytes: want %q, got %q", res, p[:n])
+ }
+ }
+ }
+}
diff --git a/src/cmd/internal/buildid/note.go b/src/cmd/internal/buildid/note.go
index 2d26ea9961..f5b6fc565f 100644
--- a/src/cmd/internal/buildid/note.go
+++ b/src/cmd/internal/buildid/note.go
@@ -11,6 +11,7 @@ import (
"encoding/binary"
"fmt"
"io"
+ "io/fs"
"os"
)
@@ -96,7 +97,7 @@ func readELF(name string, f *os.File, data []byte) (buildid string, err error) {
ef, err := elf.NewFile(bytes.NewReader(data))
if err != nil {
- return "", &os.PathError{Path: name, Op: "parse", Err: err}
+ return "", &fs.PathError{Path: name, Op: "parse", Err: err}
}
var gnu string
for _, p := range ef.Progs {
@@ -181,13 +182,13 @@ func readMacho(name string, f *os.File, data []byte) (buildid string, err error)
mf, err := macho.NewFile(f)
if err != nil {
- return "", &os.PathError{Path: name, Op: "parse", Err: err}
+ return "", &fs.PathError{Path: name, Op: "parse", Err: err}
}
sect := mf.Section("__text")
if sect == nil {
// Every binary has a __text section. Something is wrong.
- return "", &os.PathError{Path: name, Op: "parse", Err: fmt.Errorf("cannot find __text section")}
+ return "", &fs.PathError{Path: name, Op: "parse", Err: fmt.Errorf("cannot find __text section")}
}
// It should be in the first few bytes, but read a lot just in case,
diff --git a/src/cmd/internal/buildid/rewrite.go b/src/cmd/internal/buildid/rewrite.go
index 5be54552a6..a7928959c4 100644
--- a/src/cmd/internal/buildid/rewrite.go
+++ b/src/cmd/internal/buildid/rewrite.go
@@ -6,7 +6,9 @@ package buildid
import (
"bytes"
+ "cmd/internal/codesign"
"crypto/sha256"
+ "debug/macho"
"fmt"
"io"
)
@@ -26,6 +28,11 @@ func FindAndHash(r io.Reader, id string, bufSize int) (matches []int64, hash [32
zeros := make([]byte, len(id))
idBytes := []byte(id)
+ // For Mach-O files, we want to exclude the code signature.
+ // The code signature contains hashes of the whole file (except the signature
+ // itself), including the buildid. So the buildid cannot contain the signature.
+ r = excludeMachoCodeSignature(r)
+
// The strategy is to read the file through buf, looking for id,
// but we need to worry about what happens if id is broken up
// and returned in parts by two different reads.
@@ -87,5 +94,69 @@ func Rewrite(w io.WriterAt, pos []int64, id string) error {
return err
}
}
+
+ // Update Mach-O code signature, if any.
+ if f, cmd, ok := findMachoCodeSignature(w); ok {
+ if codesign.Size(int64(cmd.Dataoff), "a.out") == int64(cmd.Datasize) {
+ // Update the signature if the size matches, so we don't need to
+ // fix up headers. Binaries generated by the Go linker should have
+ // the expected size. Otherwise skip.
+ text := f.Segment("__TEXT")
+ cs := make([]byte, cmd.Datasize)
+ codesign.Sign(cs, w.(io.Reader), "a.out", int64(cmd.Dataoff), int64(text.Offset), int64(text.Filesz), f.Type == macho.TypeExec)
+ if _, err := w.WriteAt(cs, int64(cmd.Dataoff)); err != nil {
+ return err
+ }
+ }
+ }
+
return nil
}
+
+func excludeMachoCodeSignature(r io.Reader) io.Reader {
+ _, cmd, ok := findMachoCodeSignature(r)
+ if !ok {
+ return r
+ }
+ return &excludedReader{r, 0, int64(cmd.Dataoff), int64(cmd.Dataoff + cmd.Datasize)}
+}
+
+// excludedReader wraps an io.Reader. Reading from it returns the bytes from
+// the underlying reader, except that when the byte offset is within the
+// range between start and end, it returns zero bytes.
+type excludedReader struct {
+ r io.Reader
+ off int64 // current offset
+ start, end int64 // the range to be excluded (read as zero)
+}
+
+func (r *excludedReader) Read(p []byte) (int, error) {
+ n, err := r.r.Read(p)
+ if n > 0 && r.off+int64(n) > r.start && r.off < r.end {
+ cstart := r.start - r.off
+ if cstart < 0 {
+ cstart = 0
+ }
+ cend := r.end - r.off
+ if cend > int64(n) {
+ cend = int64(n)
+ }
+ zeros := make([]byte, cend-cstart)
+ copy(p[cstart:cend], zeros)
+ }
+ r.off += int64(n)
+ return n, err
+}
+
+func findMachoCodeSignature(r interface{}) (*macho.File, codesign.CodeSigCmd, bool) {
+ ra, ok := r.(io.ReaderAt)
+ if !ok {
+ return nil, codesign.CodeSigCmd{}, false
+ }
+ f, err := macho.NewFile(ra)
+ if err != nil {
+ return nil, codesign.CodeSigCmd{}, false
+ }
+ cmd, ok := codesign.FindCodeSigCmd(f)
+ return f, cmd, ok
+}
diff --git a/src/cmd/internal/codesign/codesign.go b/src/cmd/internal/codesign/codesign.go
new file mode 100644
index 0000000000..0517a10640
--- /dev/null
+++ b/src/cmd/internal/codesign/codesign.go
@@ -0,0 +1,268 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package codesign provides basic functionalities for
+// ad-hoc code signing of Mach-O files.
+//
+// This is not a general tool for code-signing. It is made
+// specifically for the Go toolchain. It uses the same
+// ad-hoc signing algorithm as the Darwin linker.
+package codesign
+
+import (
+ "crypto/sha256"
+ "debug/macho"
+ "encoding/binary"
+ "io"
+)
+
+// Code signature layout.
+//
+// The code signature is a block of bytes that contains
+// a SuperBlob, which contains one or more Blobs. For ad-hoc
+// signing, a single CodeDirectory Blob suffices.
+//
+// A SuperBlob starts with its header (the binary representation
+// of the SuperBlob struct), followed by a list of (in our case,
+// one) Blobs (offset and size). A CodeDirectory Blob starts
+// with its head (the binary representation of CodeDirectory struct),
+// followed by the identifier (as a C string) and the hashes, at
+// the corresponding offsets.
+//
+// The signature data must be included in the __LINKEDIT segment.
+// In the Mach-O file header, an LC_CODE_SIGNATURE load command
+// points to the data.
+
+const (
+ pageSizeBits = 12
+ pageSize = 1 << pageSizeBits
+)
+
+const LC_CODE_SIGNATURE = 0x1d
+
+// Constants and struct layouts are from
+// https://opensource.apple.com/source/xnu/xnu-4903.270.47/osfmk/kern/cs_blobs.h
+
+const (
+ CSMAGIC_REQUIREMENT = 0xfade0c00 // single Requirement blob
+ CSMAGIC_REQUIREMENTS = 0xfade0c01 // Requirements vector (internal requirements)
+ CSMAGIC_CODEDIRECTORY = 0xfade0c02 // CodeDirectory blob
+ CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 // embedded form of signature data
+ CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1 // multi-arch collection of embedded signatures
+
+ CSSLOT_CODEDIRECTORY = 0 // slot index for CodeDirectory
+)
+
+const (
+ CS_HASHTYPE_SHA1 = 1
+ CS_HASHTYPE_SHA256 = 2
+ CS_HASHTYPE_SHA256_TRUNCATED = 3
+ CS_HASHTYPE_SHA384 = 4
+)
+
+const (
+ CS_EXECSEG_MAIN_BINARY = 0x1 // executable segment denotes main binary
+ CS_EXECSEG_ALLOW_UNSIGNED = 0x10 // allow unsigned pages (for debugging)
+ CS_EXECSEG_DEBUGGER = 0x20 // main binary is debugger
+ CS_EXECSEG_JIT = 0x40 // JIT enabled
+ CS_EXECSEG_SKIP_LV = 0x80 // skip library validation
+ CS_EXECSEG_CAN_LOAD_CDHASH = 0x100 // can bless cdhash for execution
+ CS_EXECSEG_CAN_EXEC_CDHASH = 0x200 // can execute blessed cdhash
+)
+
+type Blob struct {
+ typ uint32 // type of entry
+ offset uint32 // offset of entry
+ // data follows
+}
+
+func (b *Blob) put(out []byte) []byte {
+ out = put32be(out, b.typ)
+ out = put32be(out, b.offset)
+ return out
+}
+
+const blobSize = 2 * 4
+
+type SuperBlob struct {
+ magic uint32 // magic number
+ length uint32 // total length of SuperBlob
+ count uint32 // number of index entries following
+ // blobs []Blob
+}
+
+func (s *SuperBlob) put(out []byte) []byte {
+ out = put32be(out, s.magic)
+ out = put32be(out, s.length)
+ out = put32be(out, s.count)
+ return out
+}
+
+const superBlobSize = 3 * 4
+
+type CodeDirectory struct {
+ magic uint32 // magic number (CSMAGIC_CODEDIRECTORY)
+ length uint32 // total length of CodeDirectory blob
+ version uint32 // compatibility version
+ flags uint32 // setup and mode flags
+ hashOffset uint32 // offset of hash slot element at index zero
+ identOffset uint32 // offset of identifier string
+ nSpecialSlots uint32 // number of special hash slots
+ nCodeSlots uint32 // number of ordinary (code) hash slots
+ codeLimit uint32 // limit to main image signature range
+ hashSize uint8 // size of each hash in bytes
+ hashType uint8 // type of hash (cdHashType* constants)
+ _pad1 uint8 // unused (must be zero)
+ pageSize uint8 // log2(page size in bytes); 0 => infinite
+ _pad2 uint32 // unused (must be zero)
+ scatterOffset uint32
+ teamOffset uint32
+ _pad3 uint32
+ codeLimit64 uint64
+ execSegBase uint64
+ execSegLimit uint64
+ execSegFlags uint64
+ // data follows
+}
+
+func (c *CodeDirectory) put(out []byte) []byte {
+ out = put32be(out, c.magic)
+ out = put32be(out, c.length)
+ out = put32be(out, c.version)
+ out = put32be(out, c.flags)
+ out = put32be(out, c.hashOffset)
+ out = put32be(out, c.identOffset)
+ out = put32be(out, c.nSpecialSlots)
+ out = put32be(out, c.nCodeSlots)
+ out = put32be(out, c.codeLimit)
+ out = put8(out, c.hashSize)
+ out = put8(out, c.hashType)
+ out = put8(out, c._pad1)
+ out = put8(out, c.pageSize)
+ out = put32be(out, c._pad2)
+ out = put32be(out, c.scatterOffset)
+ out = put32be(out, c.teamOffset)
+ out = put32be(out, c._pad3)
+ out = put64be(out, c.codeLimit64)
+ out = put64be(out, c.execSegBase)
+ out = put64be(out, c.execSegLimit)
+ out = put64be(out, c.execSegFlags)
+ return out
+}
+
+const codeDirectorySize = 13*4 + 4 + 4*8
+
+// CodeSigCmd is Mach-O LC_CODE_SIGNATURE load command.
+type CodeSigCmd struct {
+ Cmd uint32 // LC_CODE_SIGNATURE
+ Cmdsize uint32 // sizeof this command (16)
+ Dataoff uint32 // file offset of data in __LINKEDIT segment
+ Datasize uint32 // file size of data in __LINKEDIT segment
+}
+
+func FindCodeSigCmd(f *macho.File) (CodeSigCmd, bool) {
+ get32 := f.ByteOrder.Uint32
+ for _, l := range f.Loads {
+ data := l.Raw()
+ cmd := get32(data)
+ if cmd == LC_CODE_SIGNATURE {
+ return CodeSigCmd{
+ cmd,
+ get32(data[4:]),
+ get32(data[8:]),
+ get32(data[12:]),
+ }, true
+ }
+ }
+ return CodeSigCmd{}, false
+}
+
+func put32be(b []byte, x uint32) []byte { binary.BigEndian.PutUint32(b, x); return b[4:] }
+func put64be(b []byte, x uint64) []byte { binary.BigEndian.PutUint64(b, x); return b[8:] }
+func put8(b []byte, x uint8) []byte { b[0] = x; return b[1:] }
+func puts(b, s []byte) []byte { n := copy(b, s); return b[n:] }
+
+// Size computes the size of the code signature.
+// id is the identifier used for signing (a field in CodeDirectory blob, which
+// has no significance in ad-hoc signing).
+func Size(codeSize int64, id string) int64 {
+ nhashes := (codeSize + pageSize - 1) / pageSize
+ idOff := int64(codeDirectorySize)
+ hashOff := idOff + int64(len(id)+1)
+ cdirSz := hashOff + nhashes*sha256.Size
+ return int64(superBlobSize+blobSize) + cdirSz
+}
+
+// Sign generates an ad-hoc code signature and writes it to out.
+// out must have length at least Size(codeSize, id).
+// data is the file content without the signature, of size codeSize.
+// textOff and textSize is the file offset and size of the text segment.
+// isMain is true if this is a main executable.
+// id is the identifier used for signing (a field in CodeDirectory blob, which
+// has no significance in ad-hoc signing).
+func Sign(out []byte, data io.Reader, id string, codeSize, textOff, textSize int64, isMain bool) {
+ nhashes := (codeSize + pageSize - 1) / pageSize
+ idOff := int64(codeDirectorySize)
+ hashOff := idOff + int64(len(id)+1)
+ sz := Size(codeSize, id)
+
+ // emit blob headers
+ sb := SuperBlob{
+ magic: CSMAGIC_EMBEDDED_SIGNATURE,
+ length: uint32(sz),
+ count: 1,
+ }
+ blob := Blob{
+ typ: CSSLOT_CODEDIRECTORY,
+ offset: superBlobSize + blobSize,
+ }
+ cdir := CodeDirectory{
+ magic: CSMAGIC_CODEDIRECTORY,
+ length: uint32(sz) - (superBlobSize + blobSize),
+ version: 0x20400,
+ flags: 0x20002, // adhoc | linkerSigned
+ hashOffset: uint32(hashOff),
+ identOffset: uint32(idOff),
+ nCodeSlots: uint32(nhashes),
+ codeLimit: uint32(codeSize),
+ hashSize: sha256.Size,
+ hashType: CS_HASHTYPE_SHA256,
+ pageSize: uint8(pageSizeBits),
+ execSegBase: uint64(textOff),
+ execSegLimit: uint64(textSize),
+ }
+ if isMain {
+ cdir.execSegFlags = CS_EXECSEG_MAIN_BINARY
+ }
+
+ outp := out
+ outp = sb.put(outp)
+ outp = blob.put(outp)
+ outp = cdir.put(outp)
+
+ // emit the identifier
+ outp = puts(outp, []byte(id+"\000"))
+
+ // emit hashes
+ var buf [pageSize]byte
+ h := sha256.New()
+ p := 0
+ for p < int(codeSize) {
+ n, err := io.ReadFull(data, buf[:])
+ if err == io.EOF {
+ break
+ }
+ if err != nil && err != io.ErrUnexpectedEOF {
+ panic(err)
+ }
+ if p+n > int(codeSize) {
+ n = int(codeSize) - p
+ }
+ p += n
+ h.Reset()
+ h.Write(buf[:n])
+ b := h.Sum(nil)
+ outp = puts(outp, b[:])
+ }
+}
diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go
index 6ab83639ac..e1a70ef853 100644
--- a/src/cmd/internal/dwarf/dwarf.go
+++ b/src/cmd/internal/dwarf/dwarf.go
@@ -101,26 +101,26 @@ func EnableLogging(doit bool) {
logDwarf = doit
}
-// UnifyRanges merges the list of ranges of c into the list of ranges of s
-func (s *Scope) UnifyRanges(c *Scope) {
- out := make([]Range, 0, len(s.Ranges)+len(c.Ranges))
-
+// MergeRanges creates a new range list by merging the ranges from
+// its two arguments, then returns the new list.
+func MergeRanges(in1, in2 []Range) []Range {
+ out := make([]Range, 0, len(in1)+len(in2))
i, j := 0, 0
for {
var cur Range
- if i < len(s.Ranges) && j < len(c.Ranges) {
- if s.Ranges[i].Start < c.Ranges[j].Start {
- cur = s.Ranges[i]
+ if i < len(in2) && j < len(in1) {
+ if in2[i].Start < in1[j].Start {
+ cur = in2[i]
i++
} else {
- cur = c.Ranges[j]
+ cur = in1[j]
j++
}
- } else if i < len(s.Ranges) {
- cur = s.Ranges[i]
+ } else if i < len(in2) {
+ cur = in2[i]
i++
- } else if j < len(c.Ranges) {
- cur = c.Ranges[j]
+ } else if j < len(in1) {
+ cur = in1[j]
j++
} else {
break
@@ -133,7 +133,12 @@ func (s *Scope) UnifyRanges(c *Scope) {
}
}
- s.Ranges = out
+ return out
+}
+
+// UnifyRanges merges the ranges from 'c' into the list of ranges for 's'.
+func (s *Scope) UnifyRanges(c *Scope) {
+ s.Ranges = MergeRanges(s.Ranges, c.Ranges)
}
// AppendRange adds r to s, if r is non-empty.
@@ -378,7 +383,7 @@ func expandPseudoForm(form uint8) uint8 {
return form
}
expandedForm := DW_FORM_udata
- if objabi.GOOS == "darwin" {
+ if objabi.GOOS == "darwin" || objabi.GOOS == "ios" {
expandedForm = DW_FORM_data4
}
return uint8(expandedForm)
diff --git a/src/cmd/internal/goobj/funcinfo.go b/src/cmd/internal/goobj/funcinfo.go
index e0e6068b4b..2cca8f6c4e 100644
--- a/src/cmd/internal/goobj/funcinfo.go
+++ b/src/cmd/internal/goobj/funcinfo.go
@@ -23,12 +23,11 @@ type FuncInfo struct {
Locals uint32
FuncID objabi.FuncID
- Pcsp uint32
- Pcfile uint32
- Pcline uint32
- Pcinline uint32
- Pcdata []uint32
- PcdataEnd uint32
+ Pcsp SymRef
+ Pcfile SymRef
+ Pcline SymRef
+ Pcinline SymRef
+ Pcdata []SymRef
Funcdataoff []uint32
File []CUFileIndex
@@ -41,20 +40,24 @@ func (a *FuncInfo) Write(w *bytes.Buffer) {
binary.LittleEndian.PutUint32(b[:], x)
w.Write(b[:])
}
+ writeSymRef := func(s SymRef) {
+ writeUint32(s.PkgIdx)
+ writeUint32(s.SymIdx)
+ }
writeUint32(a.Args)
writeUint32(a.Locals)
writeUint32(uint32(a.FuncID))
- writeUint32(a.Pcsp)
- writeUint32(a.Pcfile)
- writeUint32(a.Pcline)
- writeUint32(a.Pcinline)
+ writeSymRef(a.Pcsp)
+ writeSymRef(a.Pcfile)
+ writeSymRef(a.Pcline)
+ writeSymRef(a.Pcinline)
writeUint32(uint32(len(a.Pcdata)))
- for _, x := range a.Pcdata {
- writeUint32(x)
+ for _, sym := range a.Pcdata {
+ writeSymRef(sym)
}
- writeUint32(a.PcdataEnd)
+
writeUint32(uint32(len(a.Funcdataoff)))
for _, x := range a.Funcdataoff {
writeUint32(x)
@@ -75,21 +78,23 @@ func (a *FuncInfo) Read(b []byte) {
b = b[4:]
return x
}
+ readSymIdx := func() SymRef {
+ return SymRef{readUint32(), readUint32()}
+ }
a.Args = readUint32()
a.Locals = readUint32()
a.FuncID = objabi.FuncID(readUint32())
- a.Pcsp = readUint32()
- a.Pcfile = readUint32()
- a.Pcline = readUint32()
- a.Pcinline = readUint32()
- pcdatalen := readUint32()
- a.Pcdata = make([]uint32, pcdatalen)
+ a.Pcsp = readSymIdx()
+ a.Pcfile = readSymIdx()
+ a.Pcline = readSymIdx()
+ a.Pcinline = readSymIdx()
+ a.Pcdata = make([]SymRef, readUint32())
for i := range a.Pcdata {
- a.Pcdata[i] = readUint32()
+ a.Pcdata[i] = readSymIdx()
}
- a.PcdataEnd = readUint32()
+
funcdataofflen := readUint32()
a.Funcdataoff = make([]uint32, funcdataofflen)
for i := range a.Funcdataoff {
@@ -127,11 +132,13 @@ type FuncInfoLengths struct {
func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
var result FuncInfoLengths
- const numpcdataOff = 28
+ // Offset to the number of pcdata values. This value is determined by counting
+ // the number of bytes until we write pcdata to the file.
+ const numpcdataOff = 44
result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:])
result.PcdataOff = numpcdataOff + 4
- numfuncdataoffOff := result.PcdataOff + 4*(result.NumPcdata+1)
+ numfuncdataoffOff := result.PcdataOff + 8*result.NumPcdata
result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
result.FuncdataoffOff = numfuncdataoffOff + 4
@@ -154,29 +161,28 @@ func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32
func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) }
-// return start and end offsets.
-func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) {
- return binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])
+func (*FuncInfo) ReadPcsp(b []byte) SymRef {
+ return SymRef{binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])}
}
-// return start and end offsets.
-func (*FuncInfo) ReadPcfile(b []byte) (uint32, uint32) {
- return binary.LittleEndian.Uint32(b[16:]), binary.LittleEndian.Uint32(b[20:])
+func (*FuncInfo) ReadPcfile(b []byte) SymRef {
+ return SymRef{binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])}
}
-// return start and end offsets.
-func (*FuncInfo) ReadPcline(b []byte) (uint32, uint32) {
- return binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])
+func (*FuncInfo) ReadPcline(b []byte) SymRef {
+ return SymRef{binary.LittleEndian.Uint32(b[28:]), binary.LittleEndian.Uint32(b[32:])}
}
-// return start and end offsets.
-func (*FuncInfo) ReadPcinline(b []byte, pcdataoffset uint32) (uint32, uint32) {
- return binary.LittleEndian.Uint32(b[24:]), binary.LittleEndian.Uint32(b[pcdataoffset:])
+func (*FuncInfo) ReadPcinline(b []byte) SymRef {
+ return SymRef{binary.LittleEndian.Uint32(b[36:]), binary.LittleEndian.Uint32(b[40:])}
}
-// return start and end offsets.
-func (*FuncInfo) ReadPcdata(b []byte, pcdataoffset uint32, k uint32) (uint32, uint32) {
- return binary.LittleEndian.Uint32(b[pcdataoffset+4*k:]), binary.LittleEndian.Uint32(b[pcdataoffset+4+4*k:])
+func (*FuncInfo) ReadPcdata(b []byte) []SymRef {
+ syms := make([]SymRef, binary.LittleEndian.Uint32(b[44:]))
+ for i := range syms {
+ syms[i] = SymRef{binary.LittleEndian.Uint32(b[48+i*8:]), binary.LittleEndian.Uint32(b[52+i*8:])}
+ }
+ return syms
}
func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 {
diff --git a/src/cmd/internal/goobj/objfile.go b/src/cmd/internal/goobj/objfile.go
index 8ec7c481d6..6e76bea111 100644
--- a/src/cmd/internal/goobj/objfile.go
+++ b/src/cmd/internal/goobj/objfile.go
@@ -433,8 +433,11 @@ const (
AuxDwarfLoc
AuxDwarfRanges
AuxDwarfLines
-
- // TODO: more. Pcdata?
+ AuxPcsp
+ AuxPcfile
+ AuxPcline
+ AuxPcinline
+ AuxPcdata
)
func (a *Aux) Type() uint8 { return a[0] }
@@ -839,11 +842,6 @@ func (r *Reader) Data(i uint32) []byte {
return r.BytesAt(base+off, int(end-off))
}
-// AuxDataBase returns the base offset of the aux data block.
-func (r *Reader) PcdataBase() uint32 {
- return r.h.Offsets[BlkPcdata]
-}
-
// NRefName returns the number of referenced symbol names.
func (r *Reader) NRefName() int {
return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go
index 2e6167322e..9ea21873c5 100644
--- a/src/cmd/internal/moddeps/moddeps_test.go
+++ b/src/cmd/internal/moddeps/moddeps_test.go
@@ -8,6 +8,7 @@ import (
"encoding/json"
"fmt"
"internal/testenv"
+ "io/fs"
"io/ioutil"
"os"
"os/exec"
@@ -32,7 +33,7 @@ func findGorootModules(t *testing.T) []gorootModule {
goBin := testenv.GoToolPath(t)
goroot.once.Do(func() {
- goroot.err = filepath.Walk(runtime.GOROOT(), func(path string, info os.FileInfo, err error) error {
+ goroot.err = filepath.WalkDir(runtime.GOROOT(), func(path string, info fs.DirEntry, err error) error {
if err != nil {
return err
}
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
index 269a4223d5..ebb98b4859 100644
--- a/src/cmd/internal/obj/arm/asm5.go
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -390,7 +390,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
var p *obj.Prog
var op *obj.Prog
- p = cursym.Func.Text
+ p = cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -482,8 +482,8 @@ func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
bflag = 0
pc = 0
times++
- c.cursym.Func.Text.Pc = 0 // force re-layout the code.
- for p = c.cursym.Func.Text; p != nil; p = p.Link {
+ c.cursym.Func().Text.Pc = 0 // force re-layout the code.
+ for p = c.cursym.Func().Text; p != nil; p = p.Link {
o = c.oplook(p)
if int64(pc) > p.Pc {
p.Pc = int64(pc)
@@ -558,7 +558,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
* perhaps we'd be able to parallelize the span loop above.
*/
- p = c.cursym.Func.Text
+ p = c.cursym.Func().Text
c.autosize = p.To.Offset + 4
c.cursym.Grow(c.cursym.Size)
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 4d9187b530..29d3a5867d 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -249,13 +249,13 @@ const (
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize := int32(0)
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
c := ctxt5{ctxt: ctxt, cursym: cursym, newprog: newprog}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
autoffset := int32(p.To.Offset)
if autoffset == -4 {
// Historical way to mark NOFRAME.
@@ -271,30 +271,30 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- cursym.Func.Locals = autoffset
- cursym.Func.Args = p.To.Val.(int32)
+ cursym.Func().Locals = autoffset
+ cursym.Func().Args = p.To.Val.(int32)
/*
* find leaf subroutines
*/
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case obj.ATEXT:
p.Mark |= LEAF
case ADIV, ADIVU, AMOD, AMODU:
- cursym.Func.Text.Mark &^= LEAF
+ cursym.Func().Text.Mark &^= LEAF
case ABL,
ABX,
obj.ADUFFZERO,
obj.ADUFFCOPY:
- cursym.Func.Text.Mark &^= LEAF
+ cursym.Func().Text.Mark &^= LEAF
}
}
var q2 *obj.Prog
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
@@ -311,20 +311,20 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize += 4
}
- if autosize == 0 && cursym.Func.Text.Mark&LEAF == 0 {
+ if autosize == 0 && cursym.Func().Text.Mark&LEAF == 0 {
// A very few functions that do not return to their caller
// are not identified as leaves but still have no frame.
if ctxt.Debugvlog {
ctxt.Logf("save suppressed in: %s\n", cursym.Name)
}
- cursym.Func.Text.Mark |= LEAF
+ cursym.Func().Text.Mark |= LEAF
}
// FP offsets need an updated p.To.Offset.
p.To.Offset = int64(autosize) - 4
- if cursym.Func.Text.Mark&LEAF != 0 {
+ if cursym.Func().Text.Mark&LEAF != 0 {
cursym.Set(obj.AttrLeaf, true)
if p.From.Sym.NoFrame() {
break
@@ -347,7 +347,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Reg = REGSP
p.Spadj = autosize
- if cursym.Func.Text.From.Sym.Wrapper() {
+ if cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVW g_panic(g), R1
@@ -460,7 +460,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case obj.ARET:
nocache(p)
- if cursym.Func.Text.Mark&LEAF != 0 {
+ if cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
p.As = AB
p.From = obj.Addr{}
@@ -487,6 +487,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// If there are instructions following
// this ARET, they come from a branch
// with the same stackframe, so no spadj.
+
if p.To.Sym != nil { // retjmp
p.To.Reg = REGLINK
q2 = obj.Appendp(p, newprog)
@@ -494,6 +495,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q2.To.Type = obj.TYPE_BRANCH
q2.To.Sym = p.To.Sym
p.To.Sym = nil
+ p.To.Name = obj.NAME_NONE
p = q2
}
@@ -508,7 +510,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
case ADIV, ADIVU, AMOD, AMODU:
- if cursym.Func.Text.From.Sym.NoSplit() {
+ if cursym.Func().Text.From.Sym.NoSplit() {
ctxt.Diag("cannot divide in NOSPLIT function")
}
const debugdivmod = false
@@ -720,7 +722,7 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
var last *obj.Prog
- for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
+ for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
}
// Now we are at the end of the function, but logically
@@ -751,7 +753,7 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
switch {
case c.cursym.CFunc():
morestack = "runtime.morestackc"
- case !c.cursym.Func.Text.From.Sym.NeedCtxt():
+ case !c.cursym.Func().Text.From.Sym.NeedCtxt():
morestack = "runtime.morestack_noctxt"
}
call.To.Sym = c.ctxt.Lookup(morestack)
@@ -762,7 +764,7 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
b := obj.Appendp(pcdata, c.newprog)
b.As = obj.AJMP
b.To.Type = obj.TYPE_BRANCH
- b.To.SetTarget(c.cursym.Func.Text.Link)
+ b.To.SetTarget(c.cursym.Func().Text.Link)
b.Spadj = +framesize
return end
diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go
index 03e0278a33..1d1bea505c 100644
--- a/src/cmd/internal/obj/arm64/a.out.go
+++ b/src/cmd/internal/obj/arm64/a.out.go
@@ -410,35 +410,42 @@ const (
C_FCON // floating-point constant
C_VCONADDR // 64-bit memory address
- C_AACON // ADDCON offset in auto constant $a(FP)
- C_LACON // 32-bit offset in auto constant $a(FP)
- C_AECON // ADDCON offset in extern constant $e(SB)
+ C_AACON // ADDCON offset in auto constant $a(FP)
+ C_AACON2 // 24-bit offset in auto constant $a(FP)
+ C_LACON // 32-bit offset in auto constant $a(FP)
+ C_AECON // ADDCON offset in extern constant $e(SB)
// TODO(aram): only one branch class should be enough
C_SBRA // for TYPE_BRANCH
C_LBRA
- C_ZAUTO // 0(RSP)
- C_NSAUTO_8 // -256 <= x < 0, 0 mod 8
- C_NSAUTO_4 // -256 <= x < 0, 0 mod 4
- C_NSAUTO // -256 <= x < 0
- C_NPAUTO // -512 <= x < 0, 0 mod 8
- C_NAUTO4K // -4095 <= x < 0
- C_PSAUTO_8 // 0 to 255, 0 mod 8
- C_PSAUTO_4 // 0 to 255, 0 mod 4
- C_PSAUTO // 0 to 255
- C_PPAUTO // 0 to 504, 0 mod 8
- C_UAUTO4K_8 // 0 to 4095, 0 mod 8
- C_UAUTO4K_4 // 0 to 4095, 0 mod 4
- C_UAUTO4K_2 // 0 to 4095, 0 mod 2
- C_UAUTO4K // 0 to 4095
- C_UAUTO8K_8 // 0 to 8190, 0 mod 8
- C_UAUTO8K_4 // 0 to 8190, 0 mod 4
- C_UAUTO8K // 0 to 8190, 0 mod 2
- C_UAUTO16K_8 // 0 to 16380, 0 mod 8
- C_UAUTO16K // 0 to 16380, 0 mod 4
- C_UAUTO32K // 0 to 32760, 0 mod 8
- C_LAUTO // any other 32-bit constant
+ C_ZAUTO // 0(RSP)
+ C_NSAUTO_8 // -256 <= x < 0, 0 mod 8
+ C_NSAUTO_4 // -256 <= x < 0, 0 mod 4
+ C_NSAUTO // -256 <= x < 0
+ C_NPAUTO // -512 <= x < 0, 0 mod 8
+ C_NAUTO4K // -4095 <= x < 0
+ C_PSAUTO_8 // 0 to 255, 0 mod 8
+ C_PSAUTO_4 // 0 to 255, 0 mod 4
+ C_PSAUTO // 0 to 255
+ C_PPAUTO_16 // 0 to 504, 0 mod 16
+ C_PPAUTO // 0 to 504, 0 mod 8
+ C_UAUTO4K_16 // 0 to 4095, 0 mod 16
+ C_UAUTO4K_8 // 0 to 4095, 0 mod 8
+ C_UAUTO4K_4 // 0 to 4095, 0 mod 4
+ C_UAUTO4K_2 // 0 to 4095, 0 mod 2
+ C_UAUTO4K // 0 to 4095
+ C_UAUTO8K_16 // 0 to 8190, 0 mod 16
+ C_UAUTO8K_8 // 0 to 8190, 0 mod 8
+ C_UAUTO8K_4 // 0 to 8190, 0 mod 4
+ C_UAUTO8K // 0 to 8190, 0 mod 2 + C_PSAUTO
+ C_UAUTO16K_16 // 0 to 16380, 0 mod 16
+ C_UAUTO16K_8 // 0 to 16380, 0 mod 8
+ C_UAUTO16K // 0 to 16380, 0 mod 4 + C_PSAUTO
+ C_UAUTO32K_16 // 0 to 32760, 0 mod 16 + C_PSAUTO
+ C_UAUTO32K // 0 to 32760, 0 mod 8 + C_PSAUTO
+ C_UAUTO64K // 0 to 65520, 0 mod 16 + C_PSAUTO
+ C_LAUTO // any other 32-bit constant
C_SEXT1 // 0 to 4095, direct
C_SEXT2 // 0 to 8190
@@ -456,17 +463,23 @@ const (
C_PSOREG_8
C_PSOREG_4
C_PSOREG
+ C_PPOREG_16
C_PPOREG
+ C_UOREG4K_16
C_UOREG4K_8
C_UOREG4K_4
C_UOREG4K_2
C_UOREG4K
+ C_UOREG8K_16
C_UOREG8K_8
C_UOREG8K_4
C_UOREG8K
+ C_UOREG16K_16
C_UOREG16K_8
C_UOREG16K
+ C_UOREG32K_16
C_UOREG32K
+ C_UOREG64K
C_LOREG
C_ADDR // TODO(aram): explain difference from C_VCONADDR
@@ -604,22 +617,6 @@ const (
ALDADDLD
ALDADDLH
ALDADDLW
- ALDANDAB
- ALDANDAD
- ALDANDAH
- ALDANDAW
- ALDANDALB
- ALDANDALD
- ALDANDALH
- ALDANDALW
- ALDANDB
- ALDANDD
- ALDANDH
- ALDANDW
- ALDANDLB
- ALDANDLD
- ALDANDLH
- ALDANDLW
ALDAR
ALDARB
ALDARH
@@ -630,6 +627,22 @@ const (
ALDAXRB
ALDAXRH
ALDAXRW
+ ALDCLRAB
+ ALDCLRAD
+ ALDCLRAH
+ ALDCLRAW
+ ALDCLRALB
+ ALDCLRALD
+ ALDCLRALH
+ ALDCLRALW
+ ALDCLRB
+ ALDCLRD
+ ALDCLRH
+ ALDCLRW
+ ALDCLRLB
+ ALDCLRLD
+ ALDCLRLH
+ ALDCLRLW
ALDEORAB
ALDEORAD
ALDEORAH
@@ -830,6 +843,20 @@ const (
ASWPLW
ASWPLH
ASWPLB
+ ACASD
+ ACASW
+ ACASH
+ ACASB
+ ACASAD
+ ACASAW
+ ACASLD
+ ACASLW
+ ACASALD
+ ACASALW
+ ACASALH
+ ACASALB
+ ACASPD
+ ACASPW
ABEQ
ABNE
ABCS
@@ -872,8 +899,12 @@ const (
AFDIVS
AFLDPD
AFLDPS
+ AFMOVQ
AFMOVD
AFMOVS
+ AVMOVQ
+ AVMOVD
+ AVMOVS
AFMULD
AFMULS
AFNEGD
@@ -953,9 +984,12 @@ const (
AVADD
AVADDP
AVAND
+ AVBIF
+ AVBCAX
AVCMEQ
AVCNT
AVEOR
+ AVEOR3
AVMOV
AVLD1
AVLD2
@@ -984,12 +1018,27 @@ const (
AVPMULL2
AVEXT
AVRBIT
+ AVRAX1
AVUSHR
+ AVUSHLL
+ AVUSHLL2
+ AVUXTL
+ AVUXTL2
+ AVUZP1
+ AVUZP2
AVSHL
AVSRI
+ AVSLI
+ AVBSL
+ AVBIT
AVTBL
+ AVXAR
AVZIP1
AVZIP2
+ AVCMTST
+ AVUADDW2
+ AVUADDW
+ AVUSRA
ALAST
AB = obj.AJMP
ABL = obj.ACALL
diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go
index 65ecd007ea..a98f8c7ed5 100644
--- a/src/cmd/internal/obj/arm64/anames.go
+++ b/src/cmd/internal/obj/arm64/anames.go
@@ -111,22 +111,6 @@ var Anames = []string{
"LDADDLD",
"LDADDLH",
"LDADDLW",
- "LDANDAB",
- "LDANDAD",
- "LDANDAH",
- "LDANDAW",
- "LDANDALB",
- "LDANDALD",
- "LDANDALH",
- "LDANDALW",
- "LDANDB",
- "LDANDD",
- "LDANDH",
- "LDANDW",
- "LDANDLB",
- "LDANDLD",
- "LDANDLH",
- "LDANDLW",
"LDAR",
"LDARB",
"LDARH",
@@ -137,6 +121,22 @@ var Anames = []string{
"LDAXRB",
"LDAXRH",
"LDAXRW",
+ "LDCLRAB",
+ "LDCLRAD",
+ "LDCLRAH",
+ "LDCLRAW",
+ "LDCLRALB",
+ "LDCLRALD",
+ "LDCLRALH",
+ "LDCLRALW",
+ "LDCLRB",
+ "LDCLRD",
+ "LDCLRH",
+ "LDCLRW",
+ "LDCLRLB",
+ "LDCLRLD",
+ "LDCLRLH",
+ "LDCLRLW",
"LDEORAB",
"LDEORAD",
"LDEORAH",
@@ -337,6 +337,20 @@ var Anames = []string{
"SWPLW",
"SWPLH",
"SWPLB",
+ "CASD",
+ "CASW",
+ "CASH",
+ "CASB",
+ "CASAD",
+ "CASAW",
+ "CASLD",
+ "CASLW",
+ "CASALD",
+ "CASALW",
+ "CASALH",
+ "CASALB",
+ "CASPD",
+ "CASPW",
"BEQ",
"BNE",
"BCS",
@@ -379,8 +393,12 @@ var Anames = []string{
"FDIVS",
"FLDPD",
"FLDPS",
+ "FMOVQ",
"FMOVD",
"FMOVS",
+ "VMOVQ",
+ "VMOVD",
+ "VMOVS",
"FMULD",
"FMULS",
"FNEGD",
@@ -460,9 +478,12 @@ var Anames = []string{
"VADD",
"VADDP",
"VAND",
+ "VBIF",
+ "VBCAX",
"VCMEQ",
"VCNT",
"VEOR",
+ "VEOR3",
"VMOV",
"VLD1",
"VLD2",
@@ -491,11 +512,26 @@ var Anames = []string{
"VPMULL2",
"VEXT",
"VRBIT",
+ "VRAX1",
"VUSHR",
+ "VUSHLL",
+ "VUSHLL2",
+ "VUXTL",
+ "VUXTL2",
+ "VUZP1",
+ "VUZP2",
"VSHL",
"VSRI",
+ "VSLI",
+ "VBSL",
+ "VBIT",
"VTBL",
+ "VXAR",
"VZIP1",
"VZIP2",
+ "VCMTST",
+ "VUADDW2",
+ "VUADDW",
+ "VUSRA",
"LAST",
}
diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go
index e1703fc4ab..f7e99517ce 100644
--- a/src/cmd/internal/obj/arm64/anames7.go
+++ b/src/cmd/internal/obj/arm64/anames7.go
@@ -36,6 +36,7 @@ var cnames7 = []string{
"FCON",
"VCONADDR",
"AACON",
+ "AACON2",
"LACON",
"AECON",
"SBRA",
@@ -50,16 +51,21 @@ var cnames7 = []string{
"PSAUTO_4",
"PSAUTO",
"PPAUTO",
+ "UAUTO4K_16",
"UAUTO4K_8",
"UAUTO4K_4",
"UAUTO4K_2",
"UAUTO4K",
+ "UAUTO8K_16",
"UAUTO8K_8",
"UAUTO8K_4",
"UAUTO8K",
+ "UAUTO16K_16",
"UAUTO16K_8",
"UAUTO16K",
+ "UAUTO32K_8",
"UAUTO32K",
+ "UAUTO64K",
"LAUTO",
"SEXT1",
"SEXT2",
@@ -77,16 +83,21 @@ var cnames7 = []string{
"PSOREG_4",
"PSOREG",
"PPOREG",
+ "UOREG4K_16",
"UOREG4K_8",
"UOREG4K_4",
"UOREG4K_2",
"UOREG4K",
+ "UOREG8K_16",
"UOREG8K_8",
"UOREG8K_4",
"UOREG8K",
+ "UOREG16K_16",
"UOREG16K_8",
"UOREG16K",
+ "UOREG32K_16",
"UOREG32K",
+ "UOREG64K",
"LOREG",
"ADDR",
"GOTADDR",
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 0b90e31392..1a359f1921 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -80,12 +80,17 @@ type Optab struct {
}
func IsAtomicInstruction(as obj.As) bool {
- _, ok := atomicInstructions[as]
- return ok
+ if _, ok := atomicLDADD[as]; ok {
+ return true
+ }
+ if _, ok := atomicSWP[as]; ok {
+ return true
+ }
+ return false
}
// known field values of an instruction.
-var atomicInstructions = map[obj.As]uint32{
+var atomicLDADD = map[obj.As]uint32{
ALDADDAD: 3<<30 | 0x1c5<<21 | 0x00<<10,
ALDADDAW: 2<<30 | 0x1c5<<21 | 0x00<<10,
ALDADDAH: 1<<30 | 0x1c5<<21 | 0x00<<10,
@@ -102,22 +107,22 @@ var atomicInstructions = map[obj.As]uint32{
ALDADDLW: 2<<30 | 0x1c3<<21 | 0x00<<10,
ALDADDLH: 1<<30 | 0x1c3<<21 | 0x00<<10,
ALDADDLB: 0<<30 | 0x1c3<<21 | 0x00<<10,
- ALDANDAD: 3<<30 | 0x1c5<<21 | 0x04<<10,
- ALDANDAW: 2<<30 | 0x1c5<<21 | 0x04<<10,
- ALDANDAH: 1<<30 | 0x1c5<<21 | 0x04<<10,
- ALDANDAB: 0<<30 | 0x1c5<<21 | 0x04<<10,
- ALDANDALD: 3<<30 | 0x1c7<<21 | 0x04<<10,
- ALDANDALW: 2<<30 | 0x1c7<<21 | 0x04<<10,
- ALDANDALH: 1<<30 | 0x1c7<<21 | 0x04<<10,
- ALDANDALB: 0<<30 | 0x1c7<<21 | 0x04<<10,
- ALDANDD: 3<<30 | 0x1c1<<21 | 0x04<<10,
- ALDANDW: 2<<30 | 0x1c1<<21 | 0x04<<10,
- ALDANDH: 1<<30 | 0x1c1<<21 | 0x04<<10,
- ALDANDB: 0<<30 | 0x1c1<<21 | 0x04<<10,
- ALDANDLD: 3<<30 | 0x1c3<<21 | 0x04<<10,
- ALDANDLW: 2<<30 | 0x1c3<<21 | 0x04<<10,
- ALDANDLH: 1<<30 | 0x1c3<<21 | 0x04<<10,
- ALDANDLB: 0<<30 | 0x1c3<<21 | 0x04<<10,
+ ALDCLRAD: 3<<30 | 0x1c5<<21 | 0x04<<10,
+ ALDCLRAW: 2<<30 | 0x1c5<<21 | 0x04<<10,
+ ALDCLRAH: 1<<30 | 0x1c5<<21 | 0x04<<10,
+ ALDCLRAB: 0<<30 | 0x1c5<<21 | 0x04<<10,
+ ALDCLRALD: 3<<30 | 0x1c7<<21 | 0x04<<10,
+ ALDCLRALW: 2<<30 | 0x1c7<<21 | 0x04<<10,
+ ALDCLRALH: 1<<30 | 0x1c7<<21 | 0x04<<10,
+ ALDCLRALB: 0<<30 | 0x1c7<<21 | 0x04<<10,
+ ALDCLRD: 3<<30 | 0x1c1<<21 | 0x04<<10,
+ ALDCLRW: 2<<30 | 0x1c1<<21 | 0x04<<10,
+ ALDCLRH: 1<<30 | 0x1c1<<21 | 0x04<<10,
+ ALDCLRB: 0<<30 | 0x1c1<<21 | 0x04<<10,
+ ALDCLRLD: 3<<30 | 0x1c3<<21 | 0x04<<10,
+ ALDCLRLW: 2<<30 | 0x1c3<<21 | 0x04<<10,
+ ALDCLRLH: 1<<30 | 0x1c3<<21 | 0x04<<10,
+ ALDCLRLB: 0<<30 | 0x1c3<<21 | 0x04<<10,
ALDEORAD: 3<<30 | 0x1c5<<21 | 0x08<<10,
ALDEORAW: 2<<30 | 0x1c5<<21 | 0x08<<10,
ALDEORAH: 1<<30 | 0x1c5<<21 | 0x08<<10,
@@ -150,22 +155,41 @@ var atomicInstructions = map[obj.As]uint32{
ALDORLW: 2<<30 | 0x1c3<<21 | 0x0c<<10,
ALDORLH: 1<<30 | 0x1c3<<21 | 0x0c<<10,
ALDORLB: 0<<30 | 0x1c3<<21 | 0x0c<<10,
- ASWPAD: 3<<30 | 0x1c5<<21 | 0x20<<10,
- ASWPAW: 2<<30 | 0x1c5<<21 | 0x20<<10,
- ASWPAH: 1<<30 | 0x1c5<<21 | 0x20<<10,
- ASWPAB: 0<<30 | 0x1c5<<21 | 0x20<<10,
- ASWPALD: 3<<30 | 0x1c7<<21 | 0x20<<10,
- ASWPALW: 2<<30 | 0x1c7<<21 | 0x20<<10,
- ASWPALH: 1<<30 | 0x1c7<<21 | 0x20<<10,
- ASWPALB: 0<<30 | 0x1c7<<21 | 0x20<<10,
- ASWPD: 3<<30 | 0x1c1<<21 | 0x20<<10,
- ASWPW: 2<<30 | 0x1c1<<21 | 0x20<<10,
- ASWPH: 1<<30 | 0x1c1<<21 | 0x20<<10,
- ASWPB: 0<<30 | 0x1c1<<21 | 0x20<<10,
- ASWPLD: 3<<30 | 0x1c3<<21 | 0x20<<10,
- ASWPLW: 2<<30 | 0x1c3<<21 | 0x20<<10,
- ASWPLH: 1<<30 | 0x1c3<<21 | 0x20<<10,
- ASWPLB: 0<<30 | 0x1c3<<21 | 0x20<<10,
+}
+
+var atomicSWP = map[obj.As]uint32{
+ ASWPAD: 3<<30 | 0x1c5<<21 | 0x20<<10,
+ ASWPAW: 2<<30 | 0x1c5<<21 | 0x20<<10,
+ ASWPAH: 1<<30 | 0x1c5<<21 | 0x20<<10,
+ ASWPAB: 0<<30 | 0x1c5<<21 | 0x20<<10,
+ ASWPALD: 3<<30 | 0x1c7<<21 | 0x20<<10,
+ ASWPALW: 2<<30 | 0x1c7<<21 | 0x20<<10,
+ ASWPALH: 1<<30 | 0x1c7<<21 | 0x20<<10,
+ ASWPALB: 0<<30 | 0x1c7<<21 | 0x20<<10,
+ ASWPD: 3<<30 | 0x1c1<<21 | 0x20<<10,
+ ASWPW: 2<<30 | 0x1c1<<21 | 0x20<<10,
+ ASWPH: 1<<30 | 0x1c1<<21 | 0x20<<10,
+ ASWPB: 0<<30 | 0x1c1<<21 | 0x20<<10,
+ ASWPLD: 3<<30 | 0x1c3<<21 | 0x20<<10,
+ ASWPLW: 2<<30 | 0x1c3<<21 | 0x20<<10,
+ ASWPLH: 1<<30 | 0x1c3<<21 | 0x20<<10,
+ ASWPLB: 0<<30 | 0x1c3<<21 | 0x20<<10,
+ ACASD: 3<<30 | 0x45<<21 | 0x1f<<10,
+ ACASW: 2<<30 | 0x45<<21 | 0x1f<<10,
+ ACASH: 1<<30 | 0x45<<21 | 0x1f<<10,
+ ACASB: 0<<30 | 0x45<<21 | 0x1f<<10,
+ ACASAD: 3<<30 | 0x47<<21 | 0x1f<<10,
+ ACASAW: 2<<30 | 0x47<<21 | 0x1f<<10,
+ ACASLD: 3<<30 | 0x45<<21 | 0x3f<<10,
+ ACASLW: 2<<30 | 0x45<<21 | 0x3f<<10,
+ ACASALD: 3<<30 | 0x47<<21 | 0x3f<<10,
+ ACASALW: 2<<30 | 0x47<<21 | 0x3f<<10,
+ ACASALH: 1<<30 | 0x47<<21 | 0x3f<<10,
+ ACASALB: 0<<30 | 0x47<<21 | 0x3f<<10,
+}
+var atomicCASP = map[obj.As]uint32{
+ ACASPD: 1<<30 | 0x41<<21 | 0x1f<<10,
+ ACASPW: 0<<30 | 0x41<<21 | 0x1f<<10,
}
var oprange [ALAST & obj.AMask][]Optab
@@ -205,12 +229,8 @@ func SYSHINT(x uint32) uint32 {
return SYSOP(0, 0, 3, 2, 0, x, 0x1F)
}
-func LDSTR12U(sz uint32, v uint32, opc uint32) uint32 {
- return sz<<30 | 7<<27 | v<<26 | 1<<24 | opc<<22
-}
-
-func LDSTR9S(sz uint32, v uint32, opc uint32) uint32 {
- return sz<<30 | 7<<27 | v<<26 | 0<<24 | opc<<22
+func LDSTR(sz uint32, v uint32, opc uint32) uint32 {
+ return sz<<30 | 7<<27 | v<<26 | opc<<22
}
func LD2STR(o uint32) uint32 {
@@ -260,8 +280,9 @@ func MOVCONST(d int64, s int, rt int) uint32 {
const (
// Optab.flag
LFROM = 1 << 0 // p.From uses constant pool
- LTO = 1 << 1 // p.To uses constant pool
- NOTUSETMP = 1 << 2 // p expands to multiple instructions, but does NOT use REGTMP
+ LFROM3 = 1 << 1 // p.From3 uses constant pool
+ LTO = 1 << 2 // p.To uses constant pool
+ NOTUSETMP = 1 << 3 // p expands to multiple instructions, but does NOT use REGTMP
)
var optab = []Optab{
@@ -391,7 +412,16 @@ var optab = []Optab{
{AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 16, 0, NOTUSETMP, 0},
{AMOVK, C_VCON, C_NONE, C_NONE, C_REG, 33, 4, 0, 0, 0},
- {AMOVD, C_AACON, C_NONE, C_NONE, C_REG, 4, 4, REGFROM, 0, 0},
+ {AMOVD, C_AACON, C_NONE, C_NONE, C_RSP, 4, 4, REGFROM, 0, 0},
+ {AMOVD, C_AACON2, C_NONE, C_NONE, C_RSP, 4, 8, REGFROM, 0, 0},
+
+ /* load long effective stack address (load int32 offset and add) */
+ {AMOVD, C_LACON, C_NONE, C_NONE, C_RSP, 34, 8, REGSP, LFROM, 0},
+
+ // Move a large constant to a vector register.
+ {AVMOVQ, C_VCON, C_NONE, C_VCON, C_VREG, 101, 4, 0, LFROM | LFROM3, 0},
+ {AVMOVD, C_VCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
+ {AVMOVS, C_LCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
/* jump operations */
{AB, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
@@ -403,12 +433,14 @@ var optab = []Optab{
{obj.ARET, C_NONE, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0},
{obj.ARET, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
{ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 7, 4, 0, 0, 0},
- {AADRP, C_SBRA, C_NONE, C_NONE, C_REG, 60, 4, 0, 0, 0},
- {AADR, C_SBRA, C_NONE, C_NONE, C_REG, 61, 4, 0, 0, 0},
{ACBZ, C_REG, C_NONE, C_NONE, C_SBRA, 39, 4, 0, 0, 0},
{ATBZ, C_VCON, C_REG, C_NONE, C_SBRA, 40, 4, 0, 0, 0},
{AERET, C_NONE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0},
+ // get a PC-relative address
+ {AADRP, C_SBRA, C_NONE, C_NONE, C_REG, 60, 4, 0, 0, 0},
+ {AADR, C_SBRA, C_NONE, C_NONE, C_REG, 61, 4, 0, 0, 0},
+
{ACLREX, C_NONE, C_NONE, C_NONE, C_VCON, 38, 4, 0, 0, 0},
{ACLREX, C_NONE, C_NONE, C_NONE, C_NONE, 38, 4, 0, 0, 0},
{ABFM, C_VCON, C_REG, C_VCON, C_REG, 42, 4, 0, 0, 0},
@@ -473,6 +505,9 @@ var optab = []Optab{
{AVTBL, C_ARNG, C_NONE, C_LIST, C_ARNG, 100, 4, 0, 0, 0},
{AVUSHR, C_VCON, C_ARNG, C_NONE, C_ARNG, 95, 4, 0, 0, 0},
{AVZIP1, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0},
+ {AVUSHLL, C_VCON, C_ARNG, C_NONE, C_ARNG, 102, 4, 0, 0, 0},
+ {AVUXTL, C_ARNG, C_NONE, C_NONE, C_ARNG, 102, 4, 0, 0, 0},
+ {AVUADDW, C_ARNG, C_ARNG, C_NONE, C_ARNG, 105, 4, 0, 0, 0},
/* conditional operations */
{ACSEL, C_COND, C_REG, C_REG, C_REG, 18, 4, 0, 0, 0},
@@ -499,6 +534,8 @@ var optab = []Optab{
{AFMOVS, C_FREG, C_NONE, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0},
+ {AFMOVQ, C_FREG, C_NONE, C_NONE, C_UAUTO64K, 20, 4, REGSP, 0, 0},
+ {AFMOVQ, C_FREG, C_NONE, C_NONE, C_UOREG64K, 20, 4, 0, 0, 0},
/* unscaled 9-bit signed displacement store */
{AMOVB, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
@@ -516,6 +553,8 @@ var optab = []Optab{
{AFMOVS, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
+ {AFMOVQ, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
+ {AFMOVQ, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
/* scaled 12-bit unsigned displacement load */
{AMOVB, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
@@ -533,6 +572,8 @@ var optab = []Optab{
{AFMOVS, C_UOREG16K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
{AFMOVD, C_UAUTO32K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
{AFMOVD, C_UOREG32K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
+ {AFMOVQ, C_UAUTO64K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
+ {AFMOVQ, C_UOREG64K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
/* unscaled 9-bit signed displacement load */
{AMOVB, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
@@ -550,6 +591,8 @@ var optab = []Optab{
{AFMOVS, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
{AFMOVD, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
{AFMOVD, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
+ {AFMOVQ, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
+ {AFMOVQ, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
/* long displacement store */
{AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
@@ -567,6 +610,8 @@ var optab = []Optab{
{AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+ {AFMOVQ, C_FREG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+ {AFMOVQ, C_FREG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
/* long displacement load */
{AMOVB, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
@@ -584,9 +629,8 @@ var optab = []Optab{
{AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
{AFMOVD, C_LAUTO, C_NONE, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0},
{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
-
- /* load long effective stack address (load int32 offset and add) */
- {AMOVD, C_LACON, C_NONE, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0},
+ {AFMOVQ, C_LAUTO, C_NONE, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0},
+ {AFMOVQ, C_LOREG, C_NONE, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
/* pre/post-indexed load (unscaled, signed 9-bit offset) */
{AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
@@ -596,6 +640,7 @@ var optab = []Optab{
{AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
{AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST},
{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST},
+ {AFMOVQ, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST},
{AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
{AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
@@ -604,6 +649,7 @@ var optab = []Optab{
{AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
{AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE},
{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE},
+ {AFMOVQ, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE},
/* pre/post-indexed store (unscaled, signed 9-bit offset) */
{AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
@@ -613,6 +659,7 @@ var optab = []Optab{
{AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
{AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
+ {AFMOVQ, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
{AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
{AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
@@ -621,6 +668,7 @@ var optab = []Optab{
{AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
{AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
+ {AFMOVQ, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
/* load with shifted or extended register offset */
{AMOVD, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
@@ -770,8 +818,10 @@ var optab = []Optab{
{ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST},
{ASTPW, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0},
- {ASWPD, C_REG, C_NONE, C_NONE, C_ZOREG, 47, 4, 0, 0, 0}, // RegTo2=C_REG
- {ASWPD, C_REG, C_NONE, C_NONE, C_ZAUTO, 47, 4, REGSP, 0, 0}, // RegTo2=C_REG
+ {ASWPD, C_REG, C_NONE, C_NONE, C_ZOREG, 47, 4, 0, 0, 0}, // RegTo2=C_REG
+ {ASWPD, C_REG, C_NONE, C_NONE, C_ZAUTO, 47, 4, REGSP, 0, 0}, // RegTo2=C_REG
+ {ACASPD, C_PAIR, C_NONE, C_NONE, C_ZOREG, 106, 4, 0, 0, 0}, // RegTo2=C_REGREG
+ {ACASPD, C_PAIR, C_NONE, C_NONE, C_ZAUTO, 106, 4, REGSP, 0, 0}, // RegTo2=C_REGREG
{ALDAR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0},
{ALDXR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0},
{ALDAXR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0},
@@ -832,6 +882,8 @@ var optab = []Optab{
{ASHA256H, C_ARNG, C_VREG, C_NONE, C_VREG, 1, 4, 0, 0, 0},
{AVREV32, C_ARNG, C_NONE, C_NONE, C_ARNG, 83, 4, 0, 0, 0},
{AVPMULL, C_ARNG, C_ARNG, C_NONE, C_ARNG, 93, 4, 0, 0, 0},
+ {AVEOR3, C_ARNG, C_ARNG, C_ARNG, C_ARNG, 103, 4, 0, 0, 0},
+ {AVXAR, C_VCON, C_ARNG, C_ARNG, C_ARNG, 104, 4, 0, 0, 0},
{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0},
{obj.APCDATA, C_VCON, C_NONE, C_NONE, C_VCON, 0, 0, 0, 0, 0},
@@ -900,7 +952,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Retpoline = false // don't keep printing
}
- p := cursym.Func.Text
+ p := cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -930,8 +982,8 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
alignedValue := p.From.Offset
m = pcAlignPadLength(pc, alignedValue, ctxt)
// Update the current text symbol alignment value.
- if int32(alignedValue) > cursym.Func.Align {
- cursym.Func.Align = int32(alignedValue)
+ if int32(alignedValue) > cursym.Func().Align {
+ cursym.Func().Align = int32(alignedValue)
}
break
case obj.ANOP, obj.AFUNCDATA, obj.APCDATA:
@@ -940,13 +992,14 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
c.ctxt.Diag("zero-width instruction\n%v", p)
}
}
- switch o.flag & (LFROM | LTO) {
- case LFROM:
+ if o.flag&LFROM != 0 {
c.addpool(p, &p.From)
-
- case LTO:
+ }
+ if o.flag&LFROM3 != 0 {
+ c.addpool(p, p.GetFrom3())
+ }
+ if o.flag&LTO != 0 {
c.addpool(p, &p.To)
- break
}
if p.As == AB || p.As == obj.ARET || p.As == AERET { /* TODO: other unconditional operations */
@@ -969,7 +1022,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
for bflag != 0 {
bflag = 0
pc = 0
- for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p = c.cursym.Func().Text.Link; p != nil; p = p.Link {
if p.As == ADWORD && (pc&7) != 0 {
pc += 4
}
@@ -1033,7 +1086,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
psz := int32(0)
var i int
var out [6]uint32
- for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text.Link; p != nil; p = p.Link {
c.pc = p.Pc
o = c.oplook(p)
@@ -1074,7 +1127,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// We use REGTMP as a scratch register during call injection,
// so instruction sequences that use REGTMP are unsafe to
// preempt asynchronously.
- obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint, c.isRestartable)
+ obj.MarkUnsafePoints(c.ctxt, c.cursym.Func().Text, c.newprog, c.isUnsafePoint, c.isRestartable)
}
// isUnsafePoint returns whether p is an unsafe point.
@@ -1164,8 +1217,8 @@ func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) {
sz := 4
if a.Type == obj.TYPE_CONST {
- if lit != int64(int32(lit)) && uint64(lit) != uint64(uint32(lit)) {
- // out of range -0x80000000 ~ 0xffffffff, must store 64-bit
+ if (lit != int64(int32(lit)) && uint64(lit) != uint64(uint32(lit))) || p.As == AVMOVQ || p.As == AVMOVD {
+ // out of range -0x80000000 ~ 0xffffffff or VMOVQ or VMOVD operand, must store 64-bit.
t.As = ADWORD
sz = 8
} // else store 32-bit
@@ -1197,37 +1250,49 @@ func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) {
C_PSAUTO,
C_PSAUTO_8,
C_PSAUTO_4,
+ C_PPAUTO_16,
C_PPAUTO,
+ C_UAUTO4K_16,
C_UAUTO4K_8,
C_UAUTO4K_4,
C_UAUTO4K_2,
C_UAUTO4K,
+ C_UAUTO8K_16,
C_UAUTO8K_8,
C_UAUTO8K_4,
C_UAUTO8K,
+ C_UAUTO16K_16,
C_UAUTO16K_8,
C_UAUTO16K,
+ C_UAUTO32K_16,
C_UAUTO32K,
+ C_UAUTO64K,
C_NSAUTO_8,
C_NSAUTO_4,
C_NSAUTO,
C_NPAUTO,
C_NAUTO4K,
C_LAUTO,
- C_PPOREG,
C_PSOREG,
- C_PSOREG_4,
C_PSOREG_8,
+ C_PSOREG_4,
+ C_PPOREG_16,
+ C_PPOREG,
+ C_UOREG4K_16,
C_UOREG4K_8,
C_UOREG4K_4,
C_UOREG4K_2,
C_UOREG4K,
+ C_UOREG8K_16,
C_UOREG8K_8,
C_UOREG8K_4,
C_UOREG8K,
+ C_UOREG16K_16,
C_UOREG16K_8,
C_UOREG16K,
+ C_UOREG32K_16,
C_UOREG32K,
+ C_UOREG64K,
C_NSOREG_8,
C_NSOREG_4,
C_NSOREG,
@@ -1352,6 +1417,10 @@ func isaddcon(v int64) bool {
return v <= 0xFFF
}
+func isaddcon2(v int64) bool {
+ return 0 <= v && v <= 0xFFFFFF
+}
+
// isbitcon reports whether a constant can be encoded into a logical instruction.
// bitcon has a binary form of repetition of a bit sequence of length 2, 4, 8, 16, 32, or 64,
// which itself is a rotate (w.r.t. the length of the unit) of a sequence of ones.
@@ -1518,10 +1587,18 @@ func autoclass(l int64) int {
}
return C_PSAUTO
}
- if l <= 504 && l&7 == 0 {
- return C_PPAUTO
+ if l <= 504 {
+ if l&15 == 0 {
+ return C_PPAUTO_16
+ }
+ if l&7 == 0 {
+ return C_PPAUTO
+ }
}
if l <= 4095 {
+ if l&15 == 0 {
+ return C_UAUTO4K_16
+ }
if l&7 == 0 {
return C_UAUTO4K_8
}
@@ -1534,6 +1611,9 @@ func autoclass(l int64) int {
return C_UAUTO4K
}
if l <= 8190 {
+ if l&15 == 0 {
+ return C_UAUTO8K_16
+ }
if l&7 == 0 {
return C_UAUTO8K_8
}
@@ -1545,6 +1625,9 @@ func autoclass(l int64) int {
}
}
if l <= 16380 {
+ if l&15 == 0 {
+ return C_UAUTO16K_16
+ }
if l&7 == 0 {
return C_UAUTO16K_8
}
@@ -1552,8 +1635,16 @@ func autoclass(l int64) int {
return C_UAUTO16K
}
}
- if l <= 32760 && (l&7) == 0 {
- return C_UAUTO32K
+ if l <= 32760 {
+ if l&15 == 0 {
+ return C_UAUTO32K_16
+ }
+ if l&7 == 0 {
+ return C_UAUTO32K
+ }
+ }
+ if l <= 65520 && (l&15) == 0 {
+ return C_UAUTO64K
}
return C_LAUTO
}
@@ -1581,6 +1672,8 @@ func (c *ctxt7) offsetshift(p *obj.Prog, v int64, cls int) int64 {
s = 2
case C_UAUTO32K, C_UOREG32K:
s = 3
+ case C_UAUTO64K, C_UOREG64K:
+ s = 4
default:
c.ctxt.Diag("bad class: %v\n%v", DRconv(cls), p)
}
@@ -1880,10 +1973,14 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
default:
return C_GOK
}
-
- if isaddcon(c.instoffset) {
+ cf := c.instoffset
+ if isaddcon(cf) || isaddcon(-cf) {
return C_AACON
}
+ if isaddcon2(cf) {
+ return C_AACON2
+ }
+
return C_LACON
case obj.TYPE_BRANCH:
@@ -1940,7 +2037,7 @@ func (c *ctxt7) oplook(p *obj.Prog) *Optab {
a1--
a3 := C_NONE + 1
- if p.GetFrom3() != nil {
+ if p.GetFrom3() != nil && p.RestArgs[0].Pos == 0 {
a3 = int(p.GetFrom3().Class)
if a3 == 0 {
a3 = c.aclass(p.GetFrom3()) + 1
@@ -2037,7 +2134,7 @@ func cmp(a int, b int) bool {
return cmp(C_LCON, b)
case C_LACON:
- if b == C_AACON {
+ if b == C_AACON || b == C_AACON2 {
return true
}
@@ -2108,46 +2205,66 @@ func cmp(a int, b int) bool {
case C_PPAUTO:
switch b {
- case C_ZAUTO, C_PSAUTO_8:
+ case C_ZAUTO, C_PSAUTO_8, C_PPAUTO_16:
return true
}
case C_UAUTO4K:
switch b {
case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
- C_PPAUTO, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8:
+ C_PPAUTO, C_PPAUTO_16,
+ C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO4K_16:
return true
}
case C_UAUTO8K:
switch b {
- case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
- C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8:
+ case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
+ C_PPAUTO, C_PPAUTO_16,
+ C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO4K_16,
+ C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO8K_16:
return true
}
case C_UAUTO16K:
switch b {
- case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
- C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO16K_8:
+ case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
+ C_PPAUTO, C_PPAUTO_16,
+ C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO4K_16,
+ C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO8K_16,
+ C_UAUTO16K_8, C_UAUTO16K_16:
return true
}
case C_UAUTO32K:
switch b {
case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
- C_PPAUTO, C_UAUTO4K_8, C_UAUTO8K_8, C_UAUTO16K_8:
+ C_PPAUTO, C_PPAUTO_16,
+ C_UAUTO4K_8, C_UAUTO4K_16,
+ C_UAUTO8K_8, C_UAUTO8K_16,
+ C_UAUTO16K_8, C_UAUTO16K_16,
+ C_UAUTO32K_16:
+ return true
+ }
+
+ case C_UAUTO64K:
+ switch b {
+ case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
+ C_PPAUTO_16, C_UAUTO4K_16, C_UAUTO8K_16, C_UAUTO16K_16,
+ C_UAUTO32K_16:
return true
}
case C_LAUTO:
switch b {
- case C_ZAUTO, C_NSAUTO, C_NSAUTO_4, C_NSAUTO_8, C_NPAUTO,
- C_NAUTO4K, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
- C_UAUTO4K, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8,
- C_UAUTO8K, C_UAUTO8K_4, C_UAUTO8K_8,
- C_UAUTO16K, C_UAUTO16K_8,
- C_UAUTO32K:
+ case C_ZAUTO, C_NSAUTO, C_NSAUTO_4, C_NSAUTO_8, C_NPAUTO, C_NAUTO4K,
+ C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
+ C_PPAUTO, C_PPAUTO_16,
+ C_UAUTO4K, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO4K_16,
+ C_UAUTO8K, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO8K_16,
+ C_UAUTO16K, C_UAUTO16K_8, C_UAUTO16K_16,
+ C_UAUTO32K, C_UAUTO32K_16,
+ C_UAUTO64K:
return true
}
@@ -2174,6 +2291,11 @@ func cmp(a int, b int) bool {
return true
}
+ case C_PSOREG_8:
+ if b == C_ZOREG {
+ return true
+ }
+
case C_PSOREG_4:
switch b {
case C_ZOREG, C_PSOREG_8:
@@ -2188,48 +2310,66 @@ func cmp(a int, b int) bool {
case C_PPOREG:
switch b {
- case C_ZOREG, C_PSOREG_8:
+ case C_ZOREG, C_PSOREG_8, C_PPOREG_16:
return true
}
case C_UOREG4K:
switch b {
- case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
- C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8:
+ case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8,
+ C_PPOREG, C_PPOREG_16,
+ C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, C_UOREG4K_16:
return true
}
case C_UOREG8K:
switch b {
- case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
- C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8,
- C_UOREG8K_4, C_UOREG8K_8:
+ case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8,
+ C_PPOREG, C_PPOREG_16,
+ C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, C_UOREG4K_16,
+ C_UOREG8K_4, C_UOREG8K_8, C_UOREG8K_16:
return true
}
case C_UOREG16K:
switch b {
- case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
- C_PPOREG, C_UOREG4K_4, C_UOREG4K_8, C_UOREG8K_4,
- C_UOREG8K_8, C_UOREG16K_8:
+ case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8,
+ C_PPOREG, C_PPOREG_16,
+ C_UOREG4K_4, C_UOREG4K_8, C_UOREG4K_16,
+ C_UOREG8K_4, C_UOREG8K_8, C_UOREG8K_16,
+ C_UOREG16K_8, C_UOREG16K_16:
return true
}
case C_UOREG32K:
switch b {
- case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
- C_PPOREG, C_UOREG4K_8, C_UOREG8K_8, C_UOREG16K_8:
+ case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8,
+ C_PPOREG, C_PPOREG_16,
+ C_UOREG4K_8, C_UOREG4K_16,
+ C_UOREG8K_8, C_UOREG8K_16,
+ C_UOREG16K_8, C_UOREG16K_16,
+ C_UOREG32K_16:
+ return true
+ }
+
+ case C_UOREG64K:
+ switch b {
+ case C_ZOREG, C_PSOREG, C_PSOREG_4, C_PSOREG_8,
+ C_PPOREG_16, C_UOREG4K_16, C_UOREG8K_16, C_UOREG16K_16,
+ C_UOREG32K_16:
return true
}
case C_LOREG:
switch b {
- case C_ZOREG, C_NSOREG, C_NSOREG_4, C_NSOREG_8, C_NPOREG,
- C_NOREG4K, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG,
- C_UOREG4K, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8,
- C_UOREG8K, C_UOREG8K_4, C_UOREG8K_8,
- C_UOREG16K, C_UOREG16K_8,
- C_UOREG32K:
+ case C_ZOREG, C_NSOREG, C_NSOREG_4, C_NSOREG_8, C_NPOREG, C_NOREG4K,
+ C_PSOREG, C_PSOREG_4, C_PSOREG_8,
+ C_PPOREG, C_PPOREG_16,
+ C_UOREG4K, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, C_UOREG4K_16,
+ C_UOREG8K, C_UOREG8K_4, C_UOREG8K_8, C_UOREG8K_16,
+ C_UOREG16K, C_UOREG16K_8, C_UOREG16K_16,
+ C_UOREG32K, C_UOREG32K_16,
+ C_UOREG64K:
return true
}
@@ -2382,10 +2522,18 @@ func buildop(ctxt *obj.Link) {
oprangeset(AMOVZW, t)
case ASWPD:
- for i := range atomicInstructions {
+ for i := range atomicLDADD {
+ oprangeset(i, t)
+ }
+ for i := range atomicSWP {
+ if i == ASWPD {
+ continue
+ }
oprangeset(i, t)
}
+ case ACASPD:
+ oprangeset(ACASPW, t)
case ABEQ:
oprangeset(ABNE, t)
oprangeset(ABCS, t)
@@ -2657,7 +2805,8 @@ func buildop(ctxt *obj.Link) {
case AFCSELD:
oprangeset(AFCSELS, t)
- case AFMOVS, AFMOVD:
+ case AFMOVQ, AFMOVD, AFMOVS,
+ AVMOVQ, AVMOVD, AVMOVS:
break
case AFCVTZSD:
@@ -2740,9 +2889,16 @@ func buildop(ctxt *obj.Link) {
oprangeset(AVCMEQ, t)
oprangeset(AVORR, t)
oprangeset(AVEOR, t)
+ oprangeset(AVBSL, t)
+ oprangeset(AVBIT, t)
+ oprangeset(AVCMTST, t)
+ oprangeset(AVUZP1, t)
+ oprangeset(AVUZP2, t)
+ oprangeset(AVBIF, t)
case AVADD:
oprangeset(AVSUB, t)
+ oprangeset(AVRAX1, t)
case AAESD:
oprangeset(AAESE, t)
@@ -2777,6 +2933,8 @@ func buildop(ctxt *obj.Link) {
case AVUSHR:
oprangeset(AVSHL, t)
oprangeset(AVSRI, t)
+ oprangeset(AVSLI, t)
+ oprangeset(AVUSRA, t)
case AVREV32:
oprangeset(AVCNT, t)
@@ -2787,6 +2945,12 @@ func buildop(ctxt *obj.Link) {
case AVZIP1:
oprangeset(AVZIP2, t)
+ case AVUXTL:
+ oprangeset(AVUXTL2, t)
+
+ case AVUSHLL:
+ oprangeset(AVUSHLL2, t)
+
case AVLD1R:
oprangeset(AVLD2, t)
oprangeset(AVLD2R, t)
@@ -2795,6 +2959,12 @@ func buildop(ctxt *obj.Link) {
oprangeset(AVLD4, t)
oprangeset(AVLD4R, t)
+ case AVEOR3:
+ oprangeset(AVBCAX, t)
+
+ case AVUADDW:
+ oprangeset(AVUADDW2, t)
+
case ASHA1H,
AVCNT,
AVMOV,
@@ -2807,7 +2977,8 @@ func buildop(ctxt *obj.Link) {
AVDUP,
AVMOVI,
APRFM,
- AVEXT:
+ AVEXT,
+ AVXAR:
break
case obj.ANOP,
@@ -3041,11 +3212,10 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
o1 |= (uint32(r&31) << 5) | uint32(rt&31)
- case 4: /* mov $addcon, R; mov $recon, R; mov $racon, R */
- o1 = c.opirr(p, p.As)
-
+ case 4: /* mov $addcon, R; mov $recon, R; mov $racon, R; mov $addcon2, R */
rt := int(p.To.Reg)
r := int(o.param)
+
if r == 0 {
r = REGZERO
} else if r == REGFROM {
@@ -3054,13 +3224,23 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
if r == 0 {
r = REGSP
}
+
v := int32(c.regoff(&p.From))
- if (v & 0xFFF000) != 0 {
- v >>= 12
- o1 |= 1 << 22 /* shift, by 12 */
+ var op int32
+ if v < 0 {
+ v = -v
+ op = int32(c.opirr(p, ASUB))
+ } else {
+ op = int32(c.opirr(p, AADD))
}
- o1 |= ((uint32(v) & 0xFFF) << 10) | (uint32(r&31) << 5) | uint32(rt&31)
+ if int(o.size) == 8 {
+ o1 = c.oaddi(p, op, v&0xfff000, r, REGTMP)
+ o2 = c.oaddi(p, op, v&0x000fff, REGTMP, rt)
+ break
+ }
+
+ o1 = c.oaddi(p, op, v, r, rt)
case 5: /* b s; bl s */
o1 = c.opbra(p, p.As)
@@ -3079,12 +3259,13 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 6: /* b ,O(R); bl ,O(R) */
o1 = c.opbrr(p, p.As)
-
o1 |= uint32(p.To.Reg&31) << 5
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 0
- rel.Type = objabi.R_CALLIND
+ if p.As == obj.ACALL {
+ rel := obj.Addrel(c.cursym)
+ rel.Off = int32(c.pc)
+ rel.Siz = 0
+ rel.Type = objabi.R_CALLIND
+ }
case 7: /* beq s */
o1 = c.opbra(p, p.As)
@@ -3343,10 +3524,10 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
r = int(o.param)
}
if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
- o1 = c.olsr9s(p, int32(c.opstr9(p, p.As)), v, r, int(p.From.Reg))
+ o1 = c.olsr9s(p, int32(c.opstr(p, p.As)), v, r, int(p.From.Reg))
} else {
v = int32(c.offsetshift(p, int64(v), int(o.a4)))
- o1 = c.olsr12u(p, int32(c.opstr12(p, p.As)), v, r, int(p.From.Reg))
+ o1 = c.olsr12u(p, int32(c.opstr(p, p.As)), v, r, int(p.From.Reg))
}
case 21: /* movT O(R),R -> ldrT */
@@ -3358,11 +3539,11 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
r = int(o.param)
}
if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
- o1 = c.olsr9s(p, int32(c.opldr9(p, p.As)), v, r, int(p.To.Reg))
+ o1 = c.olsr9s(p, int32(c.opldr(p, p.As)), v, r, int(p.To.Reg))
} else {
v = int32(c.offsetshift(p, int64(v), int(o.a1)))
//print("offset=%lld v=%ld a1=%d\n", instoffset, v, o->a1);
- o1 = c.olsr12u(p, int32(c.opldr12(p, p.As)), v, r, int(p.To.Reg))
+ o1 = c.olsr12u(p, int32(c.opldr(p, p.As)), v, r, int(p.To.Reg))
}
case 22: /* movT (R)O!,R; movT O(R)!, R -> ldrT */
@@ -3375,7 +3556,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
if v < -256 || v > 255 {
c.ctxt.Diag("offset out of range [-255,254]: %v", p)
}
- o1 = c.opldrpp(p, p.As)
+ o1 = c.opldr(p, p.As)
if o.scond == C_XPOST {
o1 |= 1 << 10
} else {
@@ -3393,7 +3574,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
if v < -256 || v > 255 {
c.ctxt.Diag("offset out of range [-255,254]: %v", p)
}
- o1 = LD2STR(c.opldrpp(p, p.As))
+ o1 = c.opstr(p, p.As)
if o.scond == C_XPOST {
o1 |= 1 << 10
} else {
@@ -3545,7 +3726,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
o1 = c.oaddi(p, int32(c.opirr(p, AADD)), hi, r, REGTMP)
- o2 = c.olsr12u(p, int32(c.opstr12(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.From.Reg))
+ o2 = c.olsr12u(p, int32(c.opstr(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.From.Reg))
break
storeusepool:
@@ -3589,7 +3770,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
o1 = c.oaddi(p, int32(c.opirr(p, AADD)), hi, r, REGTMP)
- o2 = c.olsr12u(p, int32(c.opldr12(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
+ o2 = c.olsr12u(p, int32(c.opldr(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
break
loadusepool:
@@ -3847,17 +4028,27 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 |= uint32(p.From.Reg&31) << 5
o1 |= uint32(p.To.Reg & 31)
- case 47: /* SWPx/LDADDx/LDANDx/LDEORx/LDORx Rs, (Rb), Rt */
+ case 47: // SWPx/LDADDx/LDCLRx/LDEORx/LDORx/CASx Rs, (Rb), Rt
rs := p.From.Reg
rt := p.RegTo2
rb := p.To.Reg
- fields := atomicInstructions[p.As]
- // rt can't be sp. rt can't be r31 when field A is 0, A bit is the 23rd bit.
- if rt == REG_RSP || (rt == REGZERO && (fields&(1<<23) == 0)) {
+ // rt can't be sp.
+ if rt == REG_RSP {
c.ctxt.Diag("illegal destination register: %v\n", p)
}
- o1 |= fields | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31)
+ if enc, ok := atomicLDADD[p.As]; ok {
+ // for LDADDx-like instructions, rt can't be r31 when field.enc A is 0, A bit is the 23rd bit.
+ if (rt == REGZERO) && (enc&(1<<23) == 0) {
+ c.ctxt.Diag("illegal destination register: %v\n", p)
+ }
+ o1 |= enc
+ } else if enc, ok := atomicSWP[p.As]; ok {
+ o1 |= enc
+ } else {
+ c.ctxt.Diag("invalid atomic instructions: %v\n", p)
+ }
+ o1 |= uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31)
case 48: /* ADD $C_ADDCON2, Rm, Rd */
// NOTE: this case does not use REGTMP. If it ever does,
@@ -4078,7 +4269,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
rel.Sym = p.To.Sym
rel.Add = p.To.Offset
rel.Type = objabi.R_ADDRARM64
- o3 = c.olsr12u(p, int32(c.opstr12(p, p.As)), 0, REGTMP, int(p.From.Reg))
+ o3 = c.olsr12u(p, int32(c.opstr(p, p.As)), 0, REGTMP, int(p.From.Reg))
case 65: /* movT addr,R -> adrp + add + movT (REGTMP), R */
o1 = ADR(1, 0, REGTMP)
@@ -4089,7 +4280,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
rel.Sym = p.From.Sym
rel.Add = p.From.Offset
rel.Type = objabi.R_ADDRARM64
- o3 = c.olsr12u(p, int32(c.opldr12(p, p.As)), 0, REGTMP, int(p.To.Reg))
+ o3 = c.olsr12u(p, int32(c.opldr(p, p.As)), 0, REGTMP, int(p.To.Reg))
case 66: /* ldp O(R)!, (r1, r2); ldp (R)O!, (r1, r2) */
v := int32(c.regoff(&p.From))
@@ -4142,7 +4333,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 70: /* IE model movd $tlsvar, reg -> adrp REGTMP, 0; ldr reg, [REGTMP, #0] + relocs */
o1 = ADR(1, 0, REGTMP)
- o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
+ o2 = c.olsr12u(p, int32(c.opldr(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
rel := obj.Addrel(c.cursym)
rel.Off = int32(c.pc)
rel.Siz = 8
@@ -4155,7 +4346,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 71: /* movd sym@GOT, reg -> adrp REGTMP, #0; ldr reg, [REGTMP, #0] + relocs */
o1 = ADR(1, 0, REGTMP)
- o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
+ o2 = c.olsr12u(p, int32(c.opldr(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
rel := obj.Addrel(c.cursym)
rel.Off = int32(c.pc)
rel.Siz = 8
@@ -4163,7 +4354,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
rel.Add = 0
rel.Type = objabi.R_ARM64_GOTPCREL
- case 72: /* vaddp/vand/vcmeq/vorr/vadd/veor/vfmla/vfmls Vm.<T>, Vn.<T>, Vd.<T> */
+ case 72: /* vaddp/vand/vcmeq/vorr/vadd/veor/vfmla/vfmls/vbit/vbsl/vcmtst/vsub/vbif/vuzip1/vuzip2/vrax1 Vm.<T>, Vn.<T>, Vd.<T> */
af := int((p.From.Reg >> 5) & 15)
af3 := int((p.Reg >> 5) & 15)
at := int((p.To.Reg >> 5) & 15)
@@ -4204,22 +4395,35 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
c.ctxt.Diag("invalid arrangement: %v", p)
}
- if (p.As == AVORR || p.As == AVAND || p.As == AVEOR) &&
- (af != ARNG_16B && af != ARNG_8B) {
- c.ctxt.Diag("invalid arrangement: %v", p)
- } else if (p.As == AVFMLA || p.As == AVFMLS) &&
- (af != ARNG_2D && af != ARNG_2S && af != ARNG_4S) {
- c.ctxt.Diag("invalid arrangement: %v", p)
- } else if p.As == AVORR {
- size = 2
- } else if p.As == AVAND || p.As == AVEOR {
+ switch p.As {
+ case AVORR, AVAND, AVEOR, AVBIT, AVBSL, AVBIF:
+ if af != ARNG_16B && af != ARNG_8B {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ }
+ case AVFMLA, AVFMLS:
+ if af != ARNG_2D && af != ARNG_2S && af != ARNG_4S {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ }
+ }
+ switch p.As {
+ case AVAND, AVEOR:
size = 0
- } else if p.As == AVFMLA || p.As == AVFMLS {
+ case AVBSL:
+ size = 1
+ case AVORR, AVBIT, AVBIF:
+ size = 2
+ case AVFMLA, AVFMLS:
if af == ARNG_2D {
size = 1
} else {
size = 0
}
+ case AVRAX1:
+ if af != ARNG_2D {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ }
+ size = 0
+ Q = 0
}
o1 |= (uint32(Q&1) << 30) | (uint32(size&3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
@@ -4703,7 +4907,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
}
- o1 = c.opldrpp(p, p.As)
+ o1 = c.opirr(p, p.As)
o1 |= (uint32(r&31) << 5) | (uint32((imm>>3)&0xfff) << 10) | (uint32(v & 31))
case 92: /* vmov Vn.<T>[index], Vd.<T>[index] */
@@ -4747,47 +4951,31 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
o1 |= (uint32(imm5&0x1f) << 16) | (uint32(imm4&0xf) << 11) | (uint32(rf&31) << 5) | uint32(rt&31)
- case 93: /* vpmull{2} Vm.<T>, Vn.<T>, Vd */
- af := int((p.From.Reg >> 5) & 15)
- at := int((p.To.Reg >> 5) & 15)
- a := int((p.Reg >> 5) & 15)
+ case 93: /* vpmull{2} Vm.<Tb>, Vn.<Tb>, Vd.<Ta> */
+ af := uint8((p.From.Reg >> 5) & 15)
+ at := uint8((p.To.Reg >> 5) & 15)
+ a := uint8((p.Reg >> 5) & 15)
+ if af != a {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ }
var Q, size uint32
- if p.As == AVPMULL {
- Q = 0
- } else {
+ if p.As == AVPMULL2 {
Q = 1
}
-
- var fArng int
- switch at {
- case ARNG_8H:
- if Q == 0 {
- fArng = ARNG_8B
- } else {
- fArng = ARNG_16B
- }
+ switch pack(Q, at, af) {
+ case pack(0, ARNG_8H, ARNG_8B), pack(1, ARNG_8H, ARNG_16B):
size = 0
- case ARNG_1Q:
- if Q == 0 {
- fArng = ARNG_1D
- } else {
- fArng = ARNG_2D
- }
+ case pack(0, ARNG_1Q, ARNG_1D), pack(1, ARNG_1Q, ARNG_2D):
size = 3
default:
- c.ctxt.Diag("invalid arrangement on Vd.<T>: %v", p)
- }
-
- if af != a || af != fArng {
- c.ctxt.Diag("invalid arrangement: %v", p)
+ c.ctxt.Diag("operand mismatch: %v\n", p)
}
o1 = c.oprrr(p, p.As)
rf := int((p.From.Reg) & 31)
rt := int((p.To.Reg) & 31)
r := int((p.Reg) & 31)
-
o1 |= ((Q & 1) << 30) | ((size & 3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
case 94: /* vext $imm4, Vm.<T>, Vn.<T>, Vd.<T> */
@@ -4825,7 +5013,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 |= ((Q & 1) << 30) | (uint32(r&31) << 16) | (uint32(index&15) << 11) | (uint32(rf&31) << 5) | uint32(rt&31)
- case 95: /* vushr $shift, Vn.<T>, Vd.<T> */
+ case 95: /* vushr/vshl/vsri/vsli/vusra $shift, Vn.<T>, Vd.<T> */
at := int((p.To.Reg >> 5) & 15)
af := int((p.Reg >> 5) & 15)
shift := int(p.From.Offset)
@@ -4862,14 +5050,13 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
imm := 0
-
switch p.As {
- case AVUSHR, AVSRI:
+ case AVUSHR, AVSRI, AVUSRA:
imm = esize*2 - shift
if imm < esize || imm > imax {
c.ctxt.Diag("shift out of range: %v", p)
}
- case AVSHL:
+ case AVSHL, AVSLI:
imm = esize + shift
if imm > imax {
c.ctxt.Diag("shift out of range: %v", p)
@@ -4882,7 +5069,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
rt := int((p.To.Reg) & 31)
rf := int((p.Reg) & 31)
- o1 |= ((Q & 1) << 30) | (uint32(imm&127) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
+ o1 |= ((Q & 1) << 30) | (uint32(imm&0x7f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
case 96: /* vst1 Vt1.<T>[index], offset(Rn) */
af := int((p.From.Reg >> 5) & 15)
@@ -5096,6 +5283,150 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 = q<<30 | 0xe<<24 | len<<13
o1 |= (uint32(rf&31) << 16) | uint32(offset&31)<<5 | uint32(rt&31)
+ case 101: // VMOVQ $vcon1, $vcon2, Vd or VMOVD|VMOVS $vcon, Vd -> FMOVQ/FMOVD/FMOVS pool(PC), Vd: load from constant pool.
+ o1 = c.omovlit(p.As, p, &p.From, int(p.To.Reg))
+
+ case 102: /* vushll, vushll2, vuxtl, vuxtl2 */
+ o1 = c.opirr(p, p.As)
+ rf := p.Reg
+ af := uint8((p.Reg >> 5) & 15)
+ at := uint8((p.To.Reg >> 5) & 15)
+ shift := int(p.From.Offset)
+ if p.As == AVUXTL || p.As == AVUXTL2 {
+ rf = p.From.Reg
+ af = uint8((p.From.Reg >> 5) & 15)
+ shift = 0
+ }
+
+ Q := (o1 >> 30) & 1
+ var immh, width uint8
+ switch pack(Q, af, at) {
+ case pack(0, ARNG_8B, ARNG_8H):
+ immh, width = 1, 8
+ case pack(1, ARNG_16B, ARNG_8H):
+ immh, width = 1, 8
+ case pack(0, ARNG_4H, ARNG_4S):
+ immh, width = 2, 16
+ case pack(1, ARNG_8H, ARNG_4S):
+ immh, width = 2, 16
+ case pack(0, ARNG_2S, ARNG_2D):
+ immh, width = 4, 32
+ case pack(1, ARNG_4S, ARNG_2D):
+ immh, width = 4, 32
+ default:
+ c.ctxt.Diag("operand mismatch: %v\n", p)
+ }
+ if !(0 <= shift && shift <= int(width-1)) {
+ c.ctxt.Diag("shift amount out of range: %v\n", p)
+ }
+ o1 |= uint32(immh)<<19 | uint32(shift)<<16 | uint32(rf&31)<<5 | uint32(p.To.Reg&31)
+
+ case 103: /* VEOR3/VBCAX Va.B16, Vm.B16, Vn.B16, Vd.B16 */
+ ta := (p.From.Reg >> 5) & 15
+ tm := (p.Reg >> 5) & 15
+ td := (p.To.Reg >> 5) & 15
+ tn := ((p.GetFrom3().Reg) >> 5) & 15
+
+ if ta != tm || ta != tn || ta != td || ta != ARNG_16B {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ break
+ }
+
+ o1 = c.oprrr(p, p.As)
+ ra := int(p.From.Reg)
+ rm := int(p.Reg)
+ rn := int(p.GetFrom3().Reg)
+ rd := int(p.To.Reg)
+ o1 |= uint32(rm&31)<<16 | uint32(ra&31)<<10 | uint32(rn&31)<<5 | uint32(rd)&31
+
+ case 104: /* vxar $imm4, Vm.<T>, Vn.<T>, Vd.<T> */
+ af := ((p.GetFrom3().Reg) >> 5) & 15
+ at := (p.To.Reg >> 5) & 15
+ a := (p.Reg >> 5) & 15
+ index := int(p.From.Offset)
+
+ if af != a || af != at {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ break
+ }
+
+ if af != ARNG_2D {
+ c.ctxt.Diag("invalid arrangement, should be D2: %v", p)
+ break
+ }
+
+ if index < 0 || index > 63 {
+ c.ctxt.Diag("illegal offset: %v", p)
+ }
+
+ o1 = c.opirr(p, p.As)
+ rf := (p.GetFrom3().Reg) & 31
+ rt := (p.To.Reg) & 31
+ r := (p.Reg) & 31
+
+ o1 |= (uint32(r&31) << 16) | (uint32(index&63) << 10) | (uint32(rf&31) << 5) | uint32(rt&31)
+
+ case 105: /* vuaddw{2} Vm.<Tb>, Vn.<Ta>, Vd.<Ta> */
+ af := uint8((p.From.Reg >> 5) & 15)
+ at := uint8((p.To.Reg >> 5) & 15)
+ a := uint8((p.Reg >> 5) & 15)
+ if at != a {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ break
+ }
+
+ var Q, size uint32
+ if p.As == AVUADDW2 {
+ Q = 1
+ }
+ switch pack(Q, at, af) {
+ case pack(0, ARNG_8H, ARNG_8B), pack(1, ARNG_8H, ARNG_16B):
+ size = 0
+ case pack(0, ARNG_4S, ARNG_4H), pack(1, ARNG_4S, ARNG_8H):
+ size = 1
+ case pack(0, ARNG_2D, ARNG_2S), pack(1, ARNG_2D, ARNG_4S):
+ size = 2
+ default:
+ c.ctxt.Diag("operand mismatch: %v\n", p)
+ }
+
+ o1 = c.oprrr(p, p.As)
+ rf := int((p.From.Reg) & 31)
+ rt := int((p.To.Reg) & 31)
+ r := int((p.Reg) & 31)
+ o1 |= ((Q & 1) << 30) | ((size & 3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
+
+ case 106: // CASPx (Rs, Rs+1), (Rb), (Rt, Rt+1)
+ rs := p.From.Reg
+ rt := p.GetTo2().Reg
+ rb := p.To.Reg
+ rs1 := int16(p.From.Offset)
+ rt1 := int16(p.GetTo2().Offset)
+
+ enc, ok := atomicCASP[p.As]
+ if !ok {
+ c.ctxt.Diag("invalid CASP-like atomic instructions: %v\n", p)
+ }
+ // for CASPx-like instructions, Rs<0> != 1 && Rt<0> != 1
+ switch {
+ case rs&1 != 0:
+ c.ctxt.Diag("source register pair must start from even register: %v\n", p)
+ break
+ case rt&1 != 0:
+ c.ctxt.Diag("destination register pair must start from even register: %v\n", p)
+ break
+ case rs != rs1-1:
+ c.ctxt.Diag("source register pair must be contiguous: %v\n", p)
+ break
+ case rt != rt1-1:
+ c.ctxt.Diag("destination register pair must be contiguous: %v\n", p)
+ break
+ }
+ // rt can't be sp.
+ if rt == REG_RSP {
+ c.ctxt.Diag("illegal destination register: %v\n", p)
+ }
+ o1 |= enc | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31)
}
out[0] = o1
out[1] = o2
@@ -5662,12 +5993,18 @@ func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 {
case AVADD:
return 7<<25 | 1<<21 | 1<<15 | 1<<10
+ case AVSUB:
+ return 0x17<<25 | 1<<21 | 1<<15 | 1<<10
+
case AVADDP:
return 7<<25 | 1<<21 | 1<<15 | 15<<10
case AVAND:
return 7<<25 | 1<<21 | 7<<10
+ case AVBCAX:
+ return 0xCE<<24 | 1<<21
+
case AVCMEQ:
return 1<<29 | 0x71<<21 | 0x23<<10
@@ -5683,12 +6020,18 @@ func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 {
case AVEOR:
return 1<<29 | 0x71<<21 | 7<<10
+ case AVEOR3:
+ return 0xCE << 24
+
case AVORR:
return 7<<25 | 5<<21 | 7<<10
case AVREV16:
return 3<<26 | 2<<24 | 1<<21 | 3<<11
+ case AVRAX1:
+ return 0xCE<<24 | 3<<21 | 1<<15 | 3<<10
+
case AVREV32:
return 11<<26 | 2<<24 | 1<<21 | 1<<11
@@ -5724,6 +6067,27 @@ func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 {
case AVLD2R, AVLD4R:
return 0xD<<24 | 3<<21
+
+ case AVBIF:
+ return 1<<29 | 7<<25 | 7<<21 | 7<<10
+
+ case AVBIT:
+ return 1<<29 | 0x75<<21 | 7<<10
+
+ case AVBSL:
+ return 1<<29 | 0x73<<21 | 7<<10
+
+ case AVCMTST:
+ return 0xE<<24 | 1<<21 | 0x23<<10
+
+ case AVUZP1:
+ return 7<<25 | 3<<11
+
+ case AVUZP2:
+ return 7<<25 | 1<<14 | 3<<11
+
+ case AVUADDW, AVUADDW2:
+ return 0x17<<25 | 1<<21 | 1<<12
}
c.ctxt.Diag("%v: bad rrr %d %v", p, a, a)
@@ -5922,6 +6286,24 @@ func (c *ctxt7) opirr(p *obj.Prog, a obj.As) uint32 {
case AVSRI:
return 0x5E<<23 | 17<<10
+
+ case AVSLI:
+ return 0x5E<<23 | 21<<10
+
+ case AVUSHLL, AVUXTL:
+ return 1<<29 | 15<<24 | 0x29<<10
+
+ case AVUSHLL2, AVUXTL2:
+ return 3<<29 | 15<<24 | 0x29<<10
+
+ case AVXAR:
+ return 0xCE<<24 | 1<<23
+
+ case AVUSRA:
+ return 1<<29 | 15<<24 | 5<<10
+
+ case APRFM:
+ return 0xf9<<24 | 2<<22
}
c.ctxt.Diag("%v: bad irr %v", p, a)
@@ -6316,7 +6698,7 @@ func (c *ctxt7) opstore(p *obj.Prog, a obj.As) uint32 {
}
/*
- * load/store register (unsigned immediate) C3.3.13
+ * load/store register (scaled 12-bit unsigned immediate) C3.3.13
* these produce 64-bit values (when there's an option)
*/
func (c *ctxt7) olsr12u(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
@@ -6326,49 +6708,12 @@ func (c *ctxt7) olsr12u(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
o |= (v & 0xFFF) << 10
o |= int32(b&31) << 5
o |= int32(r & 31)
+ o |= 1 << 24
return uint32(o)
}
-func (c *ctxt7) opldr12(p *obj.Prog, a obj.As) uint32 {
- switch a {
- case AMOVD:
- return LDSTR12U(3, 0, 1) /* imm12<<10 | Rn<<5 | Rt */
-
- case AMOVW:
- return LDSTR12U(2, 0, 2)
-
- case AMOVWU:
- return LDSTR12U(2, 0, 1)
-
- case AMOVH:
- return LDSTR12U(1, 0, 2)
-
- case AMOVHU:
- return LDSTR12U(1, 0, 1)
-
- case AMOVB:
- return LDSTR12U(0, 0, 2)
-
- case AMOVBU:
- return LDSTR12U(0, 0, 1)
-
- case AFMOVS:
- return LDSTR12U(2, 1, 1)
-
- case AFMOVD:
- return LDSTR12U(3, 1, 1)
- }
-
- c.ctxt.Diag("bad opldr12 %v\n%v", a, p)
- return 0
-}
-
-func (c *ctxt7) opstr12(p *obj.Prog, a obj.As) uint32 {
- return LD2STR(c.opldr12(p, a))
-}
-
/*
- * load/store register (unscaled immediate) C3.3.12
+ * load/store register (unscaled 9-bit signed immediate) C3.3.12
*/
func (c *ctxt7) olsr9s(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
if v < -256 || v > 255 {
@@ -6380,76 +6725,58 @@ func (c *ctxt7) olsr9s(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
return uint32(o)
}
-func (c *ctxt7) opldr9(p *obj.Prog, a obj.As) uint32 {
- switch a {
- case AMOVD:
- return LDSTR9S(3, 0, 1) /* simm9<<12 | Rn<<5 | Rt */
-
- case AMOVW:
- return LDSTR9S(2, 0, 2)
-
- case AMOVWU:
- return LDSTR9S(2, 0, 1)
-
- case AMOVH:
- return LDSTR9S(1, 0, 2)
-
- case AMOVHU:
- return LDSTR9S(1, 0, 1)
-
- case AMOVB:
- return LDSTR9S(0, 0, 2)
-
- case AMOVBU:
- return LDSTR9S(0, 0, 1)
-
- case AFMOVS:
- return LDSTR9S(2, 1, 1)
-
- case AFMOVD:
- return LDSTR9S(3, 1, 1)
+// store(immediate)
+// scaled 12-bit unsigned immediate offset.
+// unscaled 9-bit signed immediate offset.
+// pre/post-indexed store.
+// and the 12-bit and 9-bit are distinguished in olsr12u and oslr9s.
+func (c *ctxt7) opstr(p *obj.Prog, a obj.As) uint32 {
+ enc := c.opldr(p, a)
+ switch p.As {
+ case AFMOVQ:
+ enc = enc &^ (1 << 22)
+ default:
+ enc = LD2STR(enc)
}
-
- c.ctxt.Diag("bad opldr9 %v\n%v", a, p)
- return 0
-}
-
-func (c *ctxt7) opstr9(p *obj.Prog, a obj.As) uint32 {
- return LD2STR(c.opldr9(p, a))
+ return enc
}
-func (c *ctxt7) opldrpp(p *obj.Prog, a obj.As) uint32 {
+// load(immediate)
+// scaled 12-bit unsigned immediate offset.
+// unscaled 9-bit signed immediate offset.
+// pre/post-indexed load.
+// and the 12-bit and 9-bit are distinguished in olsr12u and oslr9s.
+func (c *ctxt7) opldr(p *obj.Prog, a obj.As) uint32 {
switch a {
case AMOVD:
- return 3<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 /* simm9<<12 | Rn<<5 | Rt */
+ return LDSTR(3, 0, 1) /* simm9<<12 | Rn<<5 | Rt */
case AMOVW:
- return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22
+ return LDSTR(2, 0, 2)
case AMOVWU:
- return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
+ return LDSTR(2, 0, 1)
case AMOVH:
- return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22
+ return LDSTR(1, 0, 2)
case AMOVHU:
- return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
+ return LDSTR(1, 0, 1)
case AMOVB:
- return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22
+ return LDSTR(0, 0, 2)
case AMOVBU:
- return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
+ return LDSTR(0, 0, 1)
case AFMOVS:
- return 2<<30 | 7<<27 | 1<<26 | 0<<24 | 1<<22
+ return LDSTR(2, 1, 1)
case AFMOVD:
- return 3<<30 | 7<<27 | 1<<26 | 0<<24 | 1<<22
-
- case APRFM:
- return 0xf9<<24 | 2<<22
+ return LDSTR(3, 1, 1)
+ case AFMOVQ:
+ return LDSTR(0, 1, 3)
}
c.ctxt.Diag("bad opldr %v\n%v", a, p)
@@ -6558,14 +6885,18 @@ func (c *ctxt7) omovlit(as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32 {
} else {
fp, w := 0, 0
switch as {
- case AFMOVS:
+ case AFMOVS, AVMOVS:
fp = 1
w = 0 /* 32-bit SIMD/FP */
- case AFMOVD:
+ case AFMOVD, AVMOVD:
fp = 1
w = 1 /* 64-bit SIMD/FP */
+ case AVMOVQ:
+ fp = 1
+ w = 2 /* 128-bit SIMD/FP */
+
case AMOVD:
if p.Pool.As == ADWORD {
w = 1 /* 64-bit */
@@ -6938,10 +7269,13 @@ func (c *ctxt7) maskOpvldvst(p *obj.Prog, o1 uint32) uint32 {
*/
func movesize(a obj.As) int {
switch a {
- case AMOVD:
+ case AFMOVQ:
+ return 4
+
+ case AMOVD, AFMOVD:
return 3
- case AMOVW, AMOVWU:
+ case AMOVW, AMOVWU, AFMOVS:
return 2
case AMOVH, AMOVHU:
@@ -6950,12 +7284,6 @@ func movesize(a obj.As) int {
case AMOVB, AMOVBU:
return 0
- case AFMOVS:
- return 2
-
- case AFMOVD:
- return 3
-
default:
return -1
}
@@ -7020,3 +7348,8 @@ func (c *ctxt7) encRegShiftOrExt(a *obj.Addr, r int16) uint32 {
return 0
}
+
+// pack returns the encoding of the "Q" field and two arrangement specifiers.
+func pack(q uint32, arngA, arngB uint8) uint32 {
+ return uint32(q)<<16 | uint32(arngA)<<8 | uint32(arngB)
+}
diff --git a/src/cmd/internal/obj/arm64/doc.go b/src/cmd/internal/obj/arm64/doc.go
index 7515217544..efd4577f56 100644
--- a/src/cmd/internal/obj/arm64/doc.go
+++ b/src/cmd/internal/obj/arm64/doc.go
@@ -86,6 +86,16 @@ In the following example, PCALIGN at the entry of the function Add will align it
MOVD $1, R1
RET
+7. Move large constants to vector registers.
+
+Go asm uses VMOVQ/VMOVD/VMOVS to move 128-bit, 64-bit and 32-bit constants into vector registers, respectively.
+And for a 128-bit interger, it take two 64-bit operands, for the high and low parts separately.
+
+ Examples:
+ VMOVS $0x11223344, V0
+ VMOVD $0x1122334455667788, V1
+ VMOVQ $0x1122334455667788, $8877665544332211, V2 // V2=0x11223344556677888877665544332211
+
Special Cases.
(1) umov is written as VMOV.
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 56da854f16..0baf51973a 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -166,7 +166,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
var last *obj.Prog
- for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
+ for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
}
// Now we are at the end of the function, but logically
@@ -209,7 +209,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
switch {
case c.cursym.CFunc():
morestack = "runtime.morestackc"
- case !c.cursym.Func.Text.From.Sym.NeedCtxt():
+ case !c.cursym.Func().Text.From.Sym.NeedCtxt():
morestack = "runtime.morestack_noctxt"
}
call.To.Sym = c.ctxt.Lookup(morestack)
@@ -220,7 +220,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
jmp := obj.Appendp(pcdata, c.newprog)
jmp.As = AB
jmp.To.Type = obj.TYPE_BRANCH
- jmp.To.SetTarget(c.cursym.Func.Text.Link)
+ jmp.To.SetTarget(c.cursym.Func().Text.Link)
jmp.Spadj = +framesize
return end
@@ -441,13 +441,13 @@ func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
}
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
textstksiz := p.To.Offset
if textstksiz == -8 {
// Historical way to mark NOFRAME.
@@ -463,13 +463,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- c.cursym.Func.Args = p.To.Val.(int32)
- c.cursym.Func.Locals = int32(textstksiz)
+ c.cursym.Func().Args = p.To.Val.(int32)
+ c.cursym.Func().Locals = int32(textstksiz)
/*
* find leaf subroutines
*/
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case obj.ATEXT:
p.Mark |= LEAF
@@ -477,18 +477,18 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case ABL,
obj.ADUFFZERO,
obj.ADUFFCOPY:
- c.cursym.Func.Text.Mark &^= LEAF
+ c.cursym.Func().Text.Mark &^= LEAF
}
}
var q *obj.Prog
var q1 *obj.Prog
var retjmp *obj.LSym
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
- c.cursym.Func.Text = p
+ c.cursym.Func().Text = p
c.autosize = int32(textstksiz)
if p.Mark&LEAF != 0 && c.autosize == 0 {
@@ -514,7 +514,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
c.ctxt.Diag("%v: unaligned frame size %d - must be 16 aligned", p, c.autosize-8)
}
c.autosize += extrasize
- c.cursym.Func.Locals += extrasize
+ c.cursym.Func().Locals += extrasize
// low 32 bits for autosize
// high 32 bits for extrasize
@@ -524,14 +524,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Offset = 0
}
- if c.autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 {
+ if c.autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
if c.ctxt.Debugvlog {
- c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func.Text.From.Sym.Name)
+ c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func().Text.From.Sym.Name)
}
- c.cursym.Func.Text.Mark |= LEAF
+ c.cursym.Func().Text.Mark |= LEAF
}
- if cursym.Func.Text.Mark&LEAF != 0 {
+ if cursym.Func().Text.Mark&LEAF != 0 {
cursym.Set(obj.AttrLeaf, true)
if p.From.Sym.NoFrame() {
break
@@ -589,7 +589,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.To.Reg = REGSP
q1.Spadj = c.autosize
- if c.ctxt.Headtype == objabi.Hdarwin {
+ if objabi.GOOS == "ios" {
// iOS does not support SA_ONSTACK. We will run the signal handler
// on the G stack. If we write below SP, it may be clobbered by
// the signal handler. So we save LR after decrementing SP.
@@ -641,7 +641,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.To.Reg = REGFP
}
- if c.cursym.Func.Text.From.Sym.Wrapper() {
+ if c.cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOV g_panic(g), R1
@@ -755,7 +755,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
retjmp = p.To.Sym
p.To = obj.Addr{}
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
if c.autosize != 0 {
p.As = AADD
p.From.Type = obj.TYPE_CONST
diff --git a/src/cmd/internal/obj/dwarf.go b/src/cmd/internal/obj/dwarf.go
index 9abb31b558..87c62e2981 100644
--- a/src/cmd/internal/obj/dwarf.go
+++ b/src/cmd/internal/obj/dwarf.go
@@ -46,12 +46,12 @@ func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
// we expect at the start of a new sequence.
stmt := true
line := int64(1)
- pc := s.Func.Text.Pc
+ pc := s.Func().Text.Pc
var lastpc int64 // last PC written to line table, not last PC in func
name := ""
prologue, wrotePrologue := false, false
// Walk the progs, generating the DWARF table.
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd)
// If we're not at a real instruction, keep looping!
if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == p.Pc) {
@@ -103,8 +103,9 @@ func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
// text address before the end sequence op. If this isn't done,
// GDB will assign a line number of zero the last row in the line
// table, which we don't want.
- lastlen := uint64(s.Size - (lastpc - s.Func.Text.Pc))
- putpclcdelta(ctxt, dctxt, lines, lastlen, 0)
+ lastlen := uint64(s.Size - (lastpc - s.Func().Text.Pc))
+ dctxt.AddUint8(lines, dwarf.DW_LNS_advance_pc)
+ dwarf.Uleb128put(dctxt, lines, int64(lastlen))
dctxt.AddUint8(lines, 0) // start extended opcode
dwarf.Uleb128put(dctxt, lines, 1)
dctxt.AddUint8(lines, dwarf.DW_LNE_end_sequence)
@@ -301,26 +302,27 @@ func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym,
if s.Type != objabi.STEXT {
ctxt.Diag("dwarfSym of non-TEXT %v", s)
}
- if s.Func.dwarfInfoSym == nil {
- s.Func.dwarfInfoSym = &LSym{
+ fn := s.Func()
+ if fn.dwarfInfoSym == nil {
+ fn.dwarfInfoSym = &LSym{
Type: objabi.SDWARFFCN,
}
if ctxt.Flag_locationlists {
- s.Func.dwarfLocSym = &LSym{
+ fn.dwarfLocSym = &LSym{
Type: objabi.SDWARFLOC,
}
}
- s.Func.dwarfRangesSym = &LSym{
+ fn.dwarfRangesSym = &LSym{
Type: objabi.SDWARFRANGE,
}
- s.Func.dwarfDebugLinesSym = &LSym{
+ fn.dwarfDebugLinesSym = &LSym{
Type: objabi.SDWARFLINES,
}
if s.WasInlined() {
- s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
+ fn.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
}
}
- return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
+ return fn.dwarfInfoSym, fn.dwarfLocSym, fn.dwarfRangesSym, fn.dwarfAbsFnSym, fn.dwarfDebugLinesSym
}
func (s *LSym) Length(dwarfContext interface{}) int64 {
@@ -331,7 +333,7 @@ func (s *LSym) Length(dwarfContext interface{}) int64 {
// first instruction (prog) of the specified function. This will
// presumably be the file in which the function is defined.
func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
- p := fn.Func.Text
+ p := fn.Func().Text
if p != nil {
f, _ := linkgetlineFromPos(ctxt, p.Pos)
fsym := ctxt.Lookup(f)
@@ -405,8 +407,8 @@ func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath str
if absfn.Size != 0 {
ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
}
- if s.Func == nil {
- s.Func = new(FuncInfo)
+ if s.Func() == nil {
+ s.NewFuncInfo()
}
scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
dwctxt := dwCtxt{ctxt}
@@ -527,8 +529,8 @@ func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
// wrapper generation as opposed to the main inlining phase) it's
// possible that we didn't cache the abstract function sym for the
// text symbol -- do so now if needed. See issue 38068.
- if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
- s.Func.dwarfAbsFnSym = absfn
+ if fn := s.Func(); fn != nil && fn.dwarfAbsFnSym == nil {
+ fn.dwarfAbsFnSym = absfn
}
ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
diff --git a/src/cmd/internal/obj/ld.go b/src/cmd/internal/obj/ld.go
index 4ba52c7785..5d6c000dc6 100644
--- a/src/cmd/internal/obj/ld.go
+++ b/src/cmd/internal/obj/ld.go
@@ -59,7 +59,7 @@ func mkfwd(sym *LSym) {
}
i := 0
- for p := sym.Func.Text; p != nil && p.Link != nil; p = p.Link {
+ for p := sym.Func().Text; p != nil && p.Link != nil; p = p.Link {
i--
if i < 0 {
i = LOG - 1
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 1d4217b5f5..8c8ff587ff 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -282,29 +282,42 @@ func (a *Addr) SetTarget(t *Prog) {
// The other fields not yet mentioned are for use by the back ends and should
// be left zeroed by creators of Prog lists.
type Prog struct {
- Ctxt *Link // linker context
- Link *Prog // next Prog in linked list
- From Addr // first source operand
- RestArgs []Addr // can pack any operands that not fit into {Prog.From, Prog.To}
- To Addr // destination operand (second is RegTo2 below)
- Pool *Prog // constant pool entry, for arm,arm64 back ends
- Forwd *Prog // for x86 back end
- Rel *Prog // for x86, arm back ends
- Pc int64 // for back ends or assembler: virtual or actual program counter, depending on phase
- Pos src.XPos // source position of this instruction
- Spadj int32 // effect of instruction on stack pointer (increment or decrement amount)
- As As // assembler opcode
- Reg int16 // 2nd source operand
- RegTo2 int16 // 2nd destination operand
- Mark uint16 // bitmask of arch-specific items
- Optab uint16 // arch-specific opcode index
- Scond uint8 // bits that describe instruction suffixes (e.g. ARM conditions)
- Back uint8 // for x86 back end: backwards branch state
- Ft uint8 // for x86 back end: type index of Prog.From
- Tt uint8 // for x86 back end: type index of Prog.To
- Isize uint8 // for x86 back end: size of the instruction in bytes
+ Ctxt *Link // linker context
+ Link *Prog // next Prog in linked list
+ From Addr // first source operand
+ RestArgs []AddrPos // can pack any operands that not fit into {Prog.From, Prog.To}
+ To Addr // destination operand (second is RegTo2 below)
+ Pool *Prog // constant pool entry, for arm,arm64 back ends
+ Forwd *Prog // for x86 back end
+ Rel *Prog // for x86, arm back ends
+ Pc int64 // for back ends or assembler: virtual or actual program counter, depending on phase
+ Pos src.XPos // source position of this instruction
+ Spadj int32 // effect of instruction on stack pointer (increment or decrement amount)
+ As As // assembler opcode
+ Reg int16 // 2nd source operand
+ RegTo2 int16 // 2nd destination operand
+ Mark uint16 // bitmask of arch-specific items
+ Optab uint16 // arch-specific opcode index
+ Scond uint8 // bits that describe instruction suffixes (e.g. ARM conditions)
+ Back uint8 // for x86 back end: backwards branch state
+ Ft uint8 // for x86 back end: type index of Prog.From
+ Tt uint8 // for x86 back end: type index of Prog.To
+ Isize uint8 // for x86 back end: size of the instruction in bytes
}
+// Pos indicates whether the oprand is the source or the destination.
+type AddrPos struct {
+ Addr
+ Pos OperandPos
+}
+
+type OperandPos int8
+
+const (
+ Source OperandPos = iota
+ Destination
+)
+
// From3Type returns p.GetFrom3().Type, or TYPE_NONE when
// p.GetFrom3() returns nil.
//
@@ -329,15 +342,36 @@ func (p *Prog) GetFrom3() *Addr {
if p.RestArgs == nil {
return nil
}
- return &p.RestArgs[0]
+ return &p.RestArgs[0].Addr
}
-// SetFrom3 assigns []Addr{a} to p.RestArgs.
+// SetFrom3 assigns []Args{{a, 0}} to p.RestArgs.
// In pair with Prog.GetFrom3 it can help in emulation of Prog.From3.
//
// Deprecated: for the same reasons as Prog.GetFrom3.
func (p *Prog) SetFrom3(a Addr) {
- p.RestArgs = []Addr{a}
+ p.RestArgs = []AddrPos{{a, Source}}
+}
+
+// SetTo2 assings []Args{{a, 1}} to p.RestArgs when the second destination
+// operand does not fit into prog.RegTo2.
+func (p *Prog) SetTo2(a Addr) {
+ p.RestArgs = []AddrPos{{a, Destination}}
+}
+
+// GetTo2 returns the second destination operand.
+func (p *Prog) GetTo2() *Addr {
+ if p.RestArgs == nil {
+ return nil
+ }
+ return &p.RestArgs[0].Addr
+}
+
+// SetRestArgs assigns more than one source operands to p.RestArgs.
+func (p *Prog) SetRestArgs(args []Addr) {
+ for i := range args {
+ p.RestArgs = append(p.RestArgs, AddrPos{args[i], Source})
+ }
}
// An As denotes an assembler opcode.
@@ -395,17 +429,16 @@ type LSym struct {
Type objabi.SymKind
Attribute
- RefIdx int // Index of this symbol in the symbol reference list.
Size int64
Gotype *LSym
P []byte
R []Reloc
- Func *FuncInfo
+ Extra *interface{} // *FuncInfo or *FileInfo, if present
Pkg string
PkgIdx int32
- SymIdx int32 // TODO: replace RefIdx
+ SymIdx int32
}
// A FuncInfo contains extra fields for STEXT symbols.
@@ -427,13 +460,59 @@ type FuncInfo struct {
GCArgs *LSym
GCLocals *LSym
- GCRegs *LSym // Only if !go115ReduceLiveness
StackObjects *LSym
OpenCodedDeferInfo *LSym
FuncInfoSym *LSym
}
+// NewFuncInfo allocates and returns a FuncInfo for LSym.
+func (s *LSym) NewFuncInfo() *FuncInfo {
+ if s.Extra != nil {
+ panic(fmt.Sprintf("invalid use of LSym - NewFuncInfo with Extra of type %T", *s.Extra))
+ }
+ f := new(FuncInfo)
+ s.Extra = new(interface{})
+ *s.Extra = f
+ return f
+}
+
+// Func returns the *FuncInfo associated with s, or else nil.
+func (s *LSym) Func() *FuncInfo {
+ if s.Extra == nil {
+ return nil
+ }
+ f, _ := (*s.Extra).(*FuncInfo)
+ return f
+}
+
+// A FileInfo contains extra fields for SDATA symbols backed by files.
+// (If LSym.Extra is a *FileInfo, LSym.P == nil.)
+type FileInfo struct {
+ Name string // name of file to read into object file
+ Size int64 // length of file
+}
+
+// NewFileInfo allocates and returns a FileInfo for LSym.
+func (s *LSym) NewFileInfo() *FileInfo {
+ if s.Extra != nil {
+ panic(fmt.Sprintf("invalid use of LSym - NewFileInfo with Extra of type %T", *s.Extra))
+ }
+ f := new(FileInfo)
+ s.Extra = new(interface{})
+ *s.Extra = f
+ return f
+}
+
+// File returns the *FileInfo associated with s, or else nil.
+func (s *LSym) File() *FileInfo {
+ if s.Extra == nil {
+ return nil
+ }
+ f, _ := (*s.Extra).(*FileInfo)
+ return f
+}
+
type InlMark struct {
// When unwinding from an instruction in an inlined body, mark
// where we should unwind to.
@@ -482,6 +561,20 @@ const (
ABICount
)
+// ParseABI converts from a string representation in 'abistr' to the
+// corresponding ABI value. Second return value is TRUE if the
+// abi string is recognized, FALSE otherwise.
+func ParseABI(abistr string) (ABI, bool) {
+ switch abistr {
+ default:
+ return ABI0, false
+ case "ABI0":
+ return ABI0, true
+ case "ABIInternal":
+ return ABIInternal, true
+ }
+}
+
// Attribute is a set of symbol attributes.
type Attribute uint32
@@ -634,11 +727,12 @@ func (s *LSym) CanBeAnSSASym() {
}
type Pcln struct {
- Pcsp Pcdata
- Pcfile Pcdata
- Pcline Pcdata
- Pcinline Pcdata
- Pcdata []Pcdata
+ // Aux symbols for pcln
+ Pcsp *LSym
+ Pcfile *LSym
+ Pcline *LSym
+ Pcinline *LSym
+ Pcdata []*LSym
Funcdata []*LSym
Funcdataoff []int64
UsedFiles map[goobj.CUFileIndex]struct{} // file indices used while generating pcfile
@@ -660,10 +754,6 @@ type Auto struct {
Gotype *LSym
}
-type Pcdata struct {
- P []byte
-}
-
// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.
type Link struct {
diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go
index 6107974745..fd29f9fa21 100644
--- a/src/cmd/internal/obj/mips/asm0.go
+++ b/src/cmd/internal/obj/mips/asm0.go
@@ -410,7 +410,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Retpoline = false // don't keep printing
}
- p := cursym.Func.Text
+ p := cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -455,7 +455,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
for bflag != 0 {
bflag = 0
pc = 0
- for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p = c.cursym.Func().Text.Link; p != nil; p = p.Link {
p.Pc = pc
o = c.oplook(p)
@@ -512,7 +512,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
bp := c.cursym.P
var i int32
var out [4]uint32
- for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text.Link; p != nil; p = p.Link {
c.pc = p.Pc
o = c.oplook(p)
if int(o.size) > 4*len(out) {
@@ -529,7 +529,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// We use REGTMP as a scratch register during call injection,
// so instruction sequences that use REGTMP are unsafe to
// preempt asynchronously.
- obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint, c.isRestartable)
+ obj.MarkUnsafePoints(c.ctxt, c.cursym.Func().Text, c.newprog, c.isUnsafePoint, c.isRestartable)
}
// isUnsafePoint returns whether p is an unsafe point.
@@ -1302,7 +1302,7 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
o1 = OP_JMP(c.opirr(p.As), uint32(v))
if p.To.Sym == nil {
- p.To.Sym = c.cursym.Func.Text.From.Sym
+ p.To.Sym = c.cursym.Func().Text.From.Sym
p.To.Offset = p.To.Target().Pc
}
rel := obj.Addrel(c.cursym)
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
index f19facc00c..135a8df3aa 100644
--- a/src/cmd/internal/obj/mips/obj0.go
+++ b/src/cmd/internal/obj/mips/obj0.go
@@ -133,11 +133,11 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// a switch for enabling/disabling instruction scheduling
nosched := true
- if c.cursym.Func.Text == nil || c.cursym.Func.Text.Link == nil {
+ if c.cursym.Func().Text == nil || c.cursym.Func().Text.Link == nil {
return
}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
textstksiz := p.To.Offset
if textstksiz == -ctxt.FixedFrameSize() {
// Historical way to mark NOFRAME.
@@ -153,8 +153,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- c.cursym.Func.Args = p.To.Val.(int32)
- c.cursym.Func.Locals = int32(textstksiz)
+ c.cursym.Func().Args = p.To.Val.(int32)
+ c.cursym.Func().Locals = int32(textstksiz)
/*
* find leaf subroutines
@@ -162,7 +162,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
* expand BECOME pseudo
*/
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
/* too hard, just leave alone */
case obj.ATEXT:
@@ -203,7 +203,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
AJAL,
obj.ADUFFZERO,
obj.ADUFFCOPY:
- c.cursym.Func.Text.Mark &^= LEAF
+ c.cursym.Func().Text.Mark &^= LEAF
fallthrough
case AJMP,
@@ -267,7 +267,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize := int32(0)
var p1 *obj.Prog
var p2 *obj.Prog
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
@@ -288,19 +288,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize += 4
}
- if autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 {
- if c.cursym.Func.Text.From.Sym.NoSplit() {
+ if autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
+ if c.cursym.Func().Text.From.Sym.NoSplit() {
if ctxt.Debugvlog {
ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
}
- c.cursym.Func.Text.Mark |= LEAF
+ c.cursym.Func().Text.Mark |= LEAF
}
}
p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
c.cursym.Set(obj.AttrLeaf, true)
if p.From.Sym.NoFrame() {
break
@@ -344,7 +344,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
}
- if c.cursym.Func.Text.From.Sym.Wrapper() && c.cursym.Func.Text.Mark&LEAF == 0 {
+ if c.cursym.Func().Text.From.Sym.Wrapper() && c.cursym.Func().Text.Mark&LEAF == 0 {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOV g_panic(g), R1
@@ -438,7 +438,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
p.To.Sym = nil
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
p.As = AJMP
p.From = obj.Addr{}
@@ -540,7 +540,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
if c.ctxt.Arch.Family == sys.MIPS {
// rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access
- for p = c.cursym.Func.Text; p != nil; p = p1 {
+ for p = c.cursym.Func().Text; p != nil; p = p1 {
p1 = p.Link
if p.As != AMOVD {
@@ -580,7 +580,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
if nosched {
// if we don't do instruction scheduling, simply add
// NOP after each branch instruction.
- for p = c.cursym.Func.Text; p != nil; p = p.Link {
+ for p = c.cursym.Func().Text; p != nil; p = p.Link {
if p.Mark&BRANCH != 0 {
c.addnop(p)
}
@@ -589,10 +589,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// instruction scheduling
- q = nil // p - 1
- q1 = c.cursym.Func.Text // top of block
- o := 0 // count of instructions
- for p = c.cursym.Func.Text; p != nil; p = p1 {
+ q = nil // p - 1
+ q1 = c.cursym.Func().Text // top of block
+ o := 0 // count of instructions
+ for p = c.cursym.Func().Text; p != nil; p = p1 {
p1 = p.Link
o++
if p.Mark&NOSCHED != 0 {
@@ -791,7 +791,7 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.To.Type = obj.TYPE_BRANCH
if c.cursym.CFunc() {
p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
- } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
+ } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
} else {
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
@@ -805,7 +805,7 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.As = AJMP
p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(c.cursym.Func.Text.Link)
+ p.To.SetTarget(c.cursym.Func().Text.Link)
p.Mark |= BRANCH
// placeholder for q1's jump target
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 7bc4f4992e..bb58b4f0c2 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -16,6 +16,8 @@ import (
"encoding/binary"
"fmt"
"io"
+ "log"
+ "os"
"path/filepath"
"sort"
"strings"
@@ -147,14 +149,20 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
// Data indexes
h.Offsets[goobj.BlkDataIdx] = w.Offset()
- dataOff := uint32(0)
+ dataOff := int64(0)
for _, list := range lists {
for _, s := range list {
- w.Uint32(dataOff)
- dataOff += uint32(len(s.P))
+ w.Uint32(uint32(dataOff))
+ dataOff += int64(len(s.P))
+ if file := s.File(); file != nil {
+ dataOff += int64(file.Size)
+ }
}
}
- w.Uint32(dataOff)
+ if int64(uint32(dataOff)) != dataOff {
+ log.Fatalf("data too large")
+ }
+ w.Uint32(uint32(dataOff))
// Relocs
h.Offsets[goobj.BlkReloc] = w.Offset()
@@ -179,14 +187,21 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
for _, list := range lists {
for _, s := range list {
w.Bytes(s.P)
+ if file := s.File(); file != nil {
+ w.writeFile(ctxt, file)
+ }
}
}
// Pcdata
h.Offsets[goobj.BlkPcdata] = w.Offset()
for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
- if s.Func != nil {
- pc := &s.Func.Pcln
+ // Because of the phase order, it's possible that we try to write an invalid
+ // object file, and the Pcln variables haven't been filled in. As such, we
+ // need to check that Pcsp exists, and assume the other pcln variables exist
+ // as well. Tests like test/fixedbugs/issue22200.go demonstrate this issue.
+ if fn := s.Func(); fn != nil && fn.Pcln.Pcsp != nil {
+ pc := &fn.Pcln
w.Bytes(pc.Pcsp.P)
w.Bytes(pc.Pcfile.P)
w.Bytes(pc.Pcline.P)
@@ -214,6 +229,7 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
type writer struct {
*goobj.Writer
+ filebuf []byte
ctxt *Link
pkgpath string // the package import path (escaped), "" if unknown
pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
@@ -228,6 +244,35 @@ func (w *writer) init() {
}
}
+func (w *writer) writeFile(ctxt *Link, file *FileInfo) {
+ f, err := os.Open(file.Name)
+ if err != nil {
+ ctxt.Diag("%v", err)
+ return
+ }
+ defer f.Close()
+ if w.filebuf == nil {
+ w.filebuf = make([]byte, 1024)
+ }
+ buf := w.filebuf
+ written := int64(0)
+ for {
+ n, err := f.Read(buf)
+ w.Bytes(buf[:n])
+ written += int64(n)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ ctxt.Diag("%v", err)
+ return
+ }
+ }
+ if written != file.Size {
+ ctxt.Diag("copy %s: unexpected length %d != %d", file.Name, written, file.Size)
+ }
+}
+
func (w *writer) StringTable() {
w.AddString("")
for _, p := range w.ctxt.Imports {
@@ -257,6 +302,10 @@ func (w *writer) StringTable() {
}
}
+// cutoff is the maximum data section size permitted by the linker
+// (see issue #9862).
+const cutoff = int64(2e9) // 2 GB (or so; looks better in errors than 2^31)
+
func (w *writer) Sym(s *LSym) {
abi := uint16(s.ABI())
if s.Static() {
@@ -299,8 +348,8 @@ func (w *writer) Sym(s *LSym) {
name = filepath.ToSlash(name)
}
var align uint32
- if s.Func != nil {
- align = uint32(s.Func.Align)
+ if fn := s.Func(); fn != nil {
+ align = uint32(fn.Align)
}
if s.ContentAddressable() {
// We generally assume data symbols are natually aligned,
@@ -321,6 +370,9 @@ func (w *writer) Sym(s *LSym) {
// don't bother setting align to 1.
}
}
+ if s.Size > cutoff {
+ w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
+ }
var o goobj.Sym
o.SetName(name, w.Writer)
o.SetABI(abi)
@@ -372,10 +424,29 @@ func contentHash64(s *LSym) goobj.Hash64Type {
// hashed symbols.
func (w *writer) contentHash(s *LSym) goobj.HashType {
h := sha1.New()
+ var tmp [14]byte
+
+ // Include the size of the symbol in the hash.
+ // This preserves the length of symbols, preventing the following two symbols
+ // from hashing the same:
+ //
+ // [2]int{1,2} ≠ [10]int{1,2,0,0,0...}
+ //
+ // In this case, if the smaller symbol is alive, the larger is not kept unless
+ // needed.
+ binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
+ h.Write(tmp[:8])
+
+ // Don't dedup type symbols with others, as they are in a different
+ // section.
+ if strings.HasPrefix(s.Name, "type.") {
+ h.Write([]byte{'T'})
+ } else {
+ h.Write([]byte{0})
+ }
// The compiler trims trailing zeros _sometimes_. We just do
// it always.
h.Write(bytes.TrimRight(s.P, "\x00"))
- var tmp [14]byte
for i := range s.R {
r := &s.R[i]
binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
@@ -447,25 +518,41 @@ func (w *writer) Aux(s *LSym) {
if s.Gotype != nil {
w.aux1(goobj.AuxGotype, s.Gotype)
}
- if s.Func != nil {
- w.aux1(goobj.AuxFuncInfo, s.Func.FuncInfoSym)
+ if fn := s.Func(); fn != nil {
+ w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
- for _, d := range s.Func.Pcln.Funcdata {
+ for _, d := range fn.Pcln.Funcdata {
w.aux1(goobj.AuxFuncdata, d)
}
- if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
- w.aux1(goobj.AuxDwarfInfo, s.Func.dwarfInfoSym)
+ if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
}
- if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
- w.aux1(goobj.AuxDwarfLoc, s.Func.dwarfLocSym)
+ if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
}
- if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
- w.aux1(goobj.AuxDwarfRanges, s.Func.dwarfRangesSym)
+ if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
}
- if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
- w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
+ if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
}
+ if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
+ w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
+ }
+ if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
+ w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
+ }
+ if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
+ w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
+ }
+ if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
+ w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
+ }
+ for _, pcSym := range fn.Pcln.Pcdata {
+ w.aux1(goobj.AuxPcdata, pcSym)
+ }
+
}
}
@@ -532,21 +619,34 @@ func nAuxSym(s *LSym) int {
if s.Gotype != nil {
n++
}
- if s.Func != nil {
+ if fn := s.Func(); fn != nil {
// FuncInfo is an aux symbol, each Funcdata is an aux symbol
- n += 1 + len(s.Func.Pcln.Funcdata)
- if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
+ n += 1 + len(fn.Pcln.Funcdata)
+ if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
+ n++
+ }
+ if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
+ n++
+ }
+ if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
n++
}
- if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
+ if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
n++
}
- if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
+ if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
n++
}
- if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
+ if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
n++
}
+ if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
+ n++
+ }
+ if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
+ n++
+ }
+ n += len(fn.Pcln.Pcdata)
}
return n
}
@@ -554,33 +654,38 @@ func nAuxSym(s *LSym) int {
// generate symbols for FuncInfo.
func genFuncInfoSyms(ctxt *Link) {
infosyms := make([]*LSym, 0, len(ctxt.Text))
- var pcdataoff uint32
+ hashedsyms := make([]*LSym, 0, 4*len(ctxt.Text))
+ preparePcSym := func(s *LSym) *LSym {
+ if s == nil {
+ return s
+ }
+ s.PkgIdx = goobj.PkgIdxHashed
+ s.SymIdx = int32(len(hashedsyms) + len(ctxt.hasheddefs))
+ s.Set(AttrIndexed, true)
+ hashedsyms = append(hashedsyms, s)
+ return s
+ }
var b bytes.Buffer
symidx := int32(len(ctxt.defs))
for _, s := range ctxt.Text {
- if s.Func == nil {
+ fn := s.Func()
+ if fn == nil {
continue
}
o := goobj.FuncInfo{
- Args: uint32(s.Func.Args),
- Locals: uint32(s.Func.Locals),
- FuncID: objabi.FuncID(s.Func.FuncID),
+ Args: uint32(fn.Args),
+ Locals: uint32(fn.Locals),
+ FuncID: objabi.FuncID(fn.FuncID),
}
- pc := &s.Func.Pcln
- o.Pcsp = pcdataoff
- pcdataoff += uint32(len(pc.Pcsp.P))
- o.Pcfile = pcdataoff
- pcdataoff += uint32(len(pc.Pcfile.P))
- o.Pcline = pcdataoff
- pcdataoff += uint32(len(pc.Pcline.P))
- o.Pcinline = pcdataoff
- pcdataoff += uint32(len(pc.Pcinline.P))
- o.Pcdata = make([]uint32, len(pc.Pcdata))
- for i, pcd := range pc.Pcdata {
- o.Pcdata[i] = pcdataoff
- pcdataoff += uint32(len(pcd.P))
+ pc := &fn.Pcln
+ o.Pcsp = makeSymRef(preparePcSym(pc.Pcsp))
+ o.Pcfile = makeSymRef(preparePcSym(pc.Pcfile))
+ o.Pcline = makeSymRef(preparePcSym(pc.Pcline))
+ o.Pcinline = makeSymRef(preparePcSym(pc.Pcinline))
+ o.Pcdata = make([]goobj.SymRef, len(pc.Pcdata))
+ for i, pcSym := range pc.Pcdata {
+ o.Pcdata[i] = makeSymRef(preparePcSym(pcSym))
}
- o.PcdataEnd = pcdataoff
o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
for i, x := range pc.Funcdataoff {
o.Funcdataoff[i] = uint32(x)
@@ -614,10 +719,10 @@ func genFuncInfoSyms(ctxt *Link) {
isym.Set(AttrIndexed, true)
symidx++
infosyms = append(infosyms, isym)
- s.Func.FuncInfoSym = isym
+ fn.FuncInfoSym = isym
b.Reset()
- dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym, s.Func.dwarfInfoSym}
+ dwsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym}
for _, s := range dwsyms {
if s == nil || s.Size == 0 {
continue
@@ -630,9 +735,9 @@ func genFuncInfoSyms(ctxt *Link) {
}
}
ctxt.defs = append(ctxt.defs, infosyms...)
+ ctxt.hasheddefs = append(ctxt.hasheddefs, hashedsyms...)
}
-// debugDumpAux is a dumper for selected aux symbols.
func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
// Most aux symbols (ex: funcdata) are not interesting--
// pick out just the DWARF ones for now.
@@ -663,7 +768,11 @@ func (ctxt *Link) writeSymDebug(s *LSym) {
}
func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
- fmt.Fprintf(ctxt.Bso, "%s ", name)
+ ver := ""
+ if ctxt.Debugasm > 1 {
+ ver = fmt.Sprintf("<%d>", s.ABI())
+ }
+ fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
if s.Type != 0 {
fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
}
@@ -684,14 +793,15 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
}
fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
if s.Type == objabi.STEXT {
- fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(s.Func.Args), uint64(s.Func.Locals), uint64(s.Func.FuncID))
+ fn := s.Func()
+ fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID))
if s.Leaf() {
fmt.Fprintf(ctxt.Bso, " leaf")
}
}
fmt.Fprintf(ctxt.Bso, "\n")
if s.Type == objabi.STEXT {
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
if ctxt.Debugasm > 1 {
io.WriteString(ctxt.Bso, p.String())
@@ -726,15 +836,19 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
sort.Sort(relocByOff(s.R)) // generate stable output
for _, r := range s.R {
name := ""
+ ver := ""
if r.Sym != nil {
name = r.Sym.Name
+ if ctxt.Debugasm > 1 {
+ ver = fmt.Sprintf("<%d>", r.Sym.ABI())
+ }
} else if r.Type == objabi.R_TLS_LE {
name = "TLS"
}
if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
- fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
+ fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%x\n", int(r.Off), r.Siz, r.Type, name, ver, uint64(r.Add))
} else {
- fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
+ fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
}
}
}
diff --git a/src/cmd/internal/obj/objfile_test.go b/src/cmd/internal/obj/objfile_test.go
index 155701fa4e..146627b62b 100644
--- a/src/cmd/internal/obj/objfile_test.go
+++ b/src/cmd/internal/obj/objfile_test.go
@@ -5,9 +5,16 @@
package obj
import (
+ "bytes"
"cmd/internal/goobj"
"cmd/internal/sys"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
"testing"
+ "unsafe"
)
var dummyArch = LinkArch{Arch: sys.ArchAMD64}
@@ -85,3 +92,32 @@ func TestContentHash(t *testing.T) {
}
}
}
+
+func TestSymbolTooLarge(t *testing.T) { // Issue 42054
+ testenv.MustHaveGoBuild(t)
+ if unsafe.Sizeof(uintptr(0)) < 8 {
+ t.Skip("skip on 32-bit architectures")
+ }
+
+ tmpdir, err := ioutil.TempDir("", "TestSymbolTooLarge")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ src := filepath.Join(tmpdir, "p.go")
+ err = ioutil.WriteFile(src, []byte("package p; var x [1<<32]byte"), 0666)
+ if err != nil {
+ t.Fatalf("failed to write source file: %v\n", err)
+ }
+ obj := filepath.Join(tmpdir, "p.o")
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", obj, src)
+ out, err := cmd.CombinedOutput()
+ if err == nil {
+ t.Fatalf("did not fail\noutput: %s", out)
+ }
+ const want = "symbol too large"
+ if !bytes.Contains(out, []byte(want)) {
+ t.Errorf("unexpected error message: want: %q, got: %s", want, out)
+ }
+}
diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go
index 09d520b4e9..01657dd4f6 100644
--- a/src/cmd/internal/obj/pass.go
+++ b/src/cmd/internal/obj/pass.go
@@ -118,7 +118,7 @@ func checkaddr(ctxt *Link, p *Prog, a *Addr) {
}
func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
- for p := sym.Func.Text; p != nil; p = p.Link {
+ for p := sym.Func().Text; p != nil; p = p.Link {
checkaddr(ctxt, p, &p.From)
if p.GetFrom3() != nil {
checkaddr(ctxt, p, p.GetFrom3())
@@ -138,7 +138,7 @@ func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
if p.To.Sym != nil {
continue
}
- q := sym.Func.Text
+ q := sym.Func().Text
for q != nil && p.To.Offset != q.Pc {
if q.Forwd != nil && p.To.Offset >= q.Forwd.Pc {
q = q.Forwd
@@ -164,7 +164,7 @@ func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
}
// Collapse series of jumps to jumps.
- for p := sym.Func.Text; p != nil; p = p.Link {
+ for p := sym.Func().Text; p != nil; p = p.Link {
if p.To.Target() == nil {
continue
}
diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go
index bffeda041d..67c4f9a62b 100644
--- a/src/cmd/internal/obj/pcln.go
+++ b/src/cmd/internal/obj/pcln.go
@@ -6,6 +6,7 @@ package obj
import (
"cmd/internal/goobj"
+ "cmd/internal/objabi"
"encoding/binary"
"log"
)
@@ -14,16 +15,19 @@ import (
// returned by valfunc parameterized by arg. The invocation of valfunc to update the
// current value is, for each p,
//
-// val = valfunc(func, val, p, 0, arg);
-// record val as value at p->pc;
-// val = valfunc(func, val, p, 1, arg);
+// sym = valfunc(func, p, 0, arg);
+// record sym.P as value at p->pc;
+// sym = valfunc(func, p, 1, arg);
//
// where func is the function, val is the current value, p is the instruction being
// considered, and arg can be used to further parameterize valfunc.
-func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) {
+func funcpctab(ctxt *Link, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) *LSym {
dbg := desc == ctxt.Debugpcln
-
- dst.P = dst.P[:0]
+ dst := []byte{}
+ sym := &LSym{
+ Type: objabi.SRODATA,
+ Attribute: AttrContentAddressable,
+ }
if dbg {
ctxt.Logf("funcpctab %s [valfunc=%s]\n", func_.Name, desc)
@@ -31,19 +35,21 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
val := int32(-1)
oldval := val
- if func_.Func.Text == nil {
- return
+ fn := func_.Func()
+ if fn.Text == nil {
+ // Return the emtpy symbol we've built so far.
+ return sym
}
- pc := func_.Func.Text.Pc
+ pc := fn.Text.Pc
if dbg {
- ctxt.Logf("%6x %6d %v\n", uint64(pc), val, func_.Func.Text)
+ ctxt.Logf("%6x %6d %v\n", uint64(pc), val, fn.Text)
}
buf := make([]byte, binary.MaxVarintLen32)
started := false
- for p := func_.Func.Text; p != nil; p = p.Link {
+ for p := fn.Text; p != nil; p = p.Link {
// Update val. If it's not changing, keep going.
val = valfunc(ctxt, func_, val, p, 0, arg)
@@ -88,13 +94,13 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
if started {
pcdelta := (p.Pc - pc) / int64(ctxt.Arch.MinLC)
n := binary.PutUvarint(buf, uint64(pcdelta))
- dst.P = append(dst.P, buf[:n]...)
+ dst = append(dst, buf[:n]...)
pc = p.Pc
}
delta := val - oldval
n := binary.PutVarint(buf, int64(delta))
- dst.P = append(dst.P, buf[:n]...)
+ dst = append(dst, buf[:n]...)
oldval = val
started = true
val = valfunc(ctxt, func_, val, p, 1, arg)
@@ -102,25 +108,29 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
if started {
if dbg {
- ctxt.Logf("%6x done\n", uint64(func_.Func.Text.Pc+func_.Size))
+ ctxt.Logf("%6x done\n", uint64(fn.Text.Pc+func_.Size))
}
v := (func_.Size - pc) / int64(ctxt.Arch.MinLC)
if v < 0 {
ctxt.Diag("negative pc offset: %v", v)
}
n := binary.PutUvarint(buf, uint64(v))
- dst.P = append(dst.P, buf[:n]...)
+ dst = append(dst, buf[:n]...)
// add terminating varint-encoded 0, which is just 0
- dst.P = append(dst.P, 0)
+ dst = append(dst, 0)
}
if dbg {
- ctxt.Logf("wrote %d bytes to %p\n", len(dst.P), dst)
- for _, p := range dst.P {
+ ctxt.Logf("wrote %d bytes to %p\n", len(dst), dst)
+ for _, p := range dst {
ctxt.Logf(" %02x", p)
}
ctxt.Logf("\n")
}
+
+ sym.Size = int64(len(dst))
+ sym.P = dst
+ return sym
}
// pctofileline computes either the file number (arg == 0)
@@ -248,12 +258,12 @@ func pctopcdata(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg i
}
func linkpcln(ctxt *Link, cursym *LSym) {
- pcln := &cursym.Func.Pcln
+ pcln := &cursym.Func().Pcln
pcln.UsedFiles = make(map[goobj.CUFileIndex]struct{})
npcdata := 0
nfuncdata := 0
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
// Find the highest ID of any used PCDATA table. This ignores PCDATA table
// that consist entirely of "-1", since that's the assumed default value.
// From.Offset is table ID
@@ -268,23 +278,23 @@ func linkpcln(ctxt *Link, cursym *LSym) {
}
}
- pcln.Pcdata = make([]Pcdata, npcdata)
- pcln.Pcdata = pcln.Pcdata[:npcdata]
+ pcln.Pcdata = make([]*LSym, npcdata)
pcln.Funcdata = make([]*LSym, nfuncdata)
pcln.Funcdataoff = make([]int64, nfuncdata)
pcln.Funcdataoff = pcln.Funcdataoff[:nfuncdata]
- funcpctab(ctxt, &pcln.Pcsp, cursym, "pctospadj", pctospadj, nil)
- funcpctab(ctxt, &pcln.Pcfile, cursym, "pctofile", pctofileline, pcln)
- funcpctab(ctxt, &pcln.Pcline, cursym, "pctoline", pctofileline, nil)
+ pcln.Pcsp = funcpctab(ctxt, cursym, "pctospadj", pctospadj, nil)
+ pcln.Pcfile = funcpctab(ctxt, cursym, "pctofile", pctofileline, pcln)
+ pcln.Pcline = funcpctab(ctxt, cursym, "pctoline", pctofileline, nil)
// Check that all the Progs used as inline markers are still reachable.
// See issue #40473.
- inlMarkProgs := make(map[*Prog]struct{}, len(cursym.Func.InlMarks))
- for _, inlMark := range cursym.Func.InlMarks {
+ fn := cursym.Func()
+ inlMarkProgs := make(map[*Prog]struct{}, len(fn.InlMarks))
+ for _, inlMark := range fn.InlMarks {
inlMarkProgs[inlMark.p] = struct{}{}
}
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := fn.Text; p != nil; p = p.Link {
if _, ok := inlMarkProgs[p]; ok {
delete(inlMarkProgs, p)
}
@@ -294,8 +304,8 @@ func linkpcln(ctxt *Link, cursym *LSym) {
}
pcinlineState := new(pcinlineState)
- funcpctab(ctxt, &pcln.Pcinline, cursym, "pctoinline", pcinlineState.pctoinline, nil)
- for _, inlMark := range cursym.Func.InlMarks {
+ pcln.Pcinline = funcpctab(ctxt, cursym, "pctoinline", pcinlineState.pctoinline, nil)
+ for _, inlMark := range fn.InlMarks {
pcinlineState.setParentPC(ctxt, int(inlMark.id), int32(inlMark.p.Pc))
}
pcln.InlTree = pcinlineState.localTree
@@ -308,7 +318,7 @@ func linkpcln(ctxt *Link, cursym *LSym) {
// tabulate which pc and func data we have.
havepc := make([]uint32, (npcdata+31)/32)
havefunc := make([]uint32, (nfuncdata+31)/32)
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := fn.Text; p != nil; p = p.Link {
if p.As == AFUNCDATA {
if (havefunc[p.From.Offset/32]>>uint64(p.From.Offset%32))&1 != 0 {
ctxt.Diag("multiple definitions for FUNCDATA $%d", p.From.Offset)
@@ -324,14 +334,19 @@ func linkpcln(ctxt *Link, cursym *LSym) {
// pcdata.
for i := 0; i < npcdata; i++ {
if (havepc[i/32]>>uint(i%32))&1 == 0 {
- continue
+ // use an empty symbol.
+ pcln.Pcdata[i] = &LSym{
+ Type: objabi.SRODATA,
+ Attribute: AttrContentAddressable,
+ }
+ } else {
+ pcln.Pcdata[i] = funcpctab(ctxt, cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
}
- funcpctab(ctxt, &pcln.Pcdata[i], cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
}
// funcdata
if nfuncdata > 0 {
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := fn.Text; p != nil; p = p.Link {
if p.As != AFUNCDATA {
continue
}
diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go
index 6e33f29959..2b096996f7 100644
--- a/src/cmd/internal/obj/plist.go
+++ b/src/cmd/internal/obj/plist.go
@@ -81,7 +81,7 @@ func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc, myimportpath string
continue
}
found := false
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == objabi.FUNCDATA_ArgsPointerMaps {
found = true
break
@@ -89,7 +89,7 @@ func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc, myimportpath string
}
if !found {
- p := Appendp(s.Func.Text, newprog)
+ p := Appendp(s.Func().Text, newprog)
p.As = AFUNCDATA
p.From.Type = TYPE_CONST
p.From.Offset = objabi.FUNCDATA_ArgsPointerMaps
@@ -120,15 +120,15 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
// func _() { }
return
}
- if s.Func != nil {
+ if s.Func() != nil {
ctxt.Diag("InitTextSym double init for %s", s.Name)
}
- s.Func = new(FuncInfo)
+ s.NewFuncInfo()
if s.OnList() {
ctxt.Diag("symbol %s listed multiple times", s.Name)
}
name := strings.Replace(s.Name, "\"\"", ctxt.Pkgpath, -1)
- s.Func.FuncID = objabi.GetFuncID(name, flag&WRAPPER != 0)
+ s.Func().FuncID = objabi.GetFuncID(name, flag&WRAPPER != 0)
s.Set(AttrOnList, true)
s.Set(AttrDuplicateOK, flag&DUPOK != 0)
s.Set(AttrNoSplit, flag&NOSPLIT != 0)
@@ -178,14 +178,14 @@ func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
// Prog generated.
func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := ctxt.EmitEntryStackMap(s, p, newprog)
- pcdata = ctxt.EmitEntryRegMap(s, pcdata, newprog)
+ pcdata = ctxt.EmitEntryUnsafePoint(s, pcdata, newprog)
return pcdata
}
// Similar to EmitEntryLiveness, but just emit stack map.
func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
- pcdata.Pos = s.Func.Text.Pos
+ pcdata.Pos = s.Func().Text.Pos
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_StackMapIndex
@@ -195,13 +195,13 @@ func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
return pcdata
}
-// Similar to EmitEntryLiveness, but just emit register map.
-func (ctxt *Link) EmitEntryRegMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
+// Similar to EmitEntryLiveness, but just emit unsafe point map.
+func (ctxt *Link) EmitEntryUnsafePoint(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
- pcdata.Pos = s.Func.Text.Pos
+ pcdata.Pos = s.Func().Text.Pos
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
- pcdata.From.Offset = objabi.PCDATA_RegMapIndex
+ pcdata.From.Offset = objabi.PCDATA_UnsafePoint
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = -1
@@ -216,9 +216,9 @@ func (ctxt *Link) StartUnsafePoint(p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
- pcdata.From.Offset = objabi.PCDATA_RegMapIndex
+ pcdata.From.Offset = objabi.PCDATA_UnsafePoint
pcdata.To.Type = TYPE_CONST
- pcdata.To.Offset = objabi.PCDATA_RegMapUnsafe
+ pcdata.To.Offset = objabi.PCDATA_UnsafePointUnsafe
return pcdata
}
@@ -231,7 +231,7 @@ func (ctxt *Link) EndUnsafePoint(p *Prog, newprog ProgAlloc, oldval int64) *Prog
pcdata := Appendp(p, newprog)
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
- pcdata.From.Offset = objabi.PCDATA_RegMapIndex
+ pcdata.From.Offset = objabi.PCDATA_UnsafePoint
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = oldval
@@ -257,11 +257,11 @@ func MarkUnsafePoints(ctxt *Link, p0 *Prog, newprog ProgAlloc, isUnsafePoint, is
prevPcdata := int64(-1) // entry PC data value
prevRestart := int64(0)
for p := prev.Link; p != nil; p, prev = p.Link, p {
- if p.As == APCDATA && p.From.Offset == objabi.PCDATA_RegMapIndex {
+ if p.As == APCDATA && p.From.Offset == objabi.PCDATA_UnsafePoint {
prevPcdata = p.To.Offset
continue
}
- if prevPcdata == objabi.PCDATA_RegMapUnsafe {
+ if prevPcdata == objabi.PCDATA_UnsafePointUnsafe {
continue // already unsafe
}
if isUnsafePoint(p) {
@@ -288,7 +288,7 @@ func MarkUnsafePoints(ctxt *Link, p0 *Prog, newprog ProgAlloc, isUnsafePoint, is
q := Appendp(prev, newprog)
q.As = APCDATA
q.From.Type = TYPE_CONST
- q.From.Offset = objabi.PCDATA_RegMapIndex
+ q.From.Offset = objabi.PCDATA_UnsafePoint
q.To.Type = TYPE_CONST
q.To.Offset = val
q.Pc = p.Pc
@@ -305,7 +305,7 @@ func MarkUnsafePoints(ctxt *Link, p0 *Prog, newprog ProgAlloc, isUnsafePoint, is
p = Appendp(p, newprog)
p.As = APCDATA
p.From.Type = TYPE_CONST
- p.From.Offset = objabi.PCDATA_RegMapIndex
+ p.From.Offset = objabi.PCDATA_UnsafePoint
p.To.Type = TYPE_CONST
p.To.Offset = prevPcdata
p.Pc = p.Link.Pc
diff --git a/src/cmd/internal/obj/ppc64/a.out.go b/src/cmd/internal/obj/ppc64/a.out.go
index 8b32692778..4c97302f83 100644
--- a/src/cmd/internal/obj/ppc64/a.out.go
+++ b/src/cmd/internal/obj/ppc64/a.out.go
@@ -575,6 +575,7 @@ const (
ARLWMICC
ARLWNM
ARLWNMCC
+ ACLRLSLWI
ASLW
ASLWCC
ASRW
@@ -716,6 +717,9 @@ const (
ARLDCLCC
ARLDICL
ARLDICLCC
+ ARLDIC
+ ARLDICCC
+ ACLRLSLDI
AROTL
AROTLW
ASLBIA
@@ -729,6 +733,8 @@ const (
ASRAD
ASRADCC
ASRDCC
+ AEXTSWSLI
+ AEXTSWSLICC
ASTDCCC
ATD
diff --git a/src/cmd/internal/obj/ppc64/anames.go b/src/cmd/internal/obj/ppc64/anames.go
index 287011877c..fca4b3e355 100644
--- a/src/cmd/internal/obj/ppc64/anames.go
+++ b/src/cmd/internal/obj/ppc64/anames.go
@@ -180,6 +180,7 @@ var Anames = []string{
"RLWMICC",
"RLWNM",
"RLWNMCC",
+ "CLRLSLWI",
"SLW",
"SLWCC",
"SRW",
@@ -312,6 +313,9 @@ var Anames = []string{
"RLDCLCC",
"RLDICL",
"RLDICLCC",
+ "RLDIC",
+ "RLDICCC",
+ "CLRLSLDI",
"ROTL",
"ROTLW",
"SLBIA",
@@ -325,6 +329,8 @@ var Anames = []string{
"SRAD",
"SRADCC",
"SRDCC",
+ "EXTSWSLI",
+ "EXTSWSLICC",
"STDCCC",
"TD",
"DWORD",
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 98b453de6c..41e263b2c0 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -160,6 +160,8 @@ var optab = []Optab{
{ASLD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
{ASLD, C_SCON, C_REG, C_NONE, C_REG, 25, 4, 0},
{ASLD, C_SCON, C_NONE, C_NONE, C_REG, 25, 4, 0},
+ {AEXTSWSLI, C_SCON, C_NONE, C_NONE, C_REG, 25, 4, 0},
+ {AEXTSWSLI, C_SCON, C_REG, C_NONE, C_REG, 25, 4, 0},
{ASLW, C_SCON, C_REG, C_NONE, C_REG, 57, 4, 0},
{ASLW, C_SCON, C_NONE, C_NONE, C_REG, 57, 4, 0},
{ASRAW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
@@ -172,6 +174,7 @@ var optab = []Optab{
{ASRAD, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0},
{ARLWMI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0},
{ARLWMI, C_REG, C_REG, C_LCON, C_REG, 63, 4, 0},
+ {ACLRLSLWI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0},
{ARLDMI, C_SCON, C_REG, C_LCON, C_REG, 30, 4, 0},
{ARLDC, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0},
{ARLDCL, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0},
@@ -331,6 +334,7 @@ var optab = []Optab{
{ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0},
{ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0},
{ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0},
+ {ABR, C_NONE, C_NONE, C_SCON, C_LR, 18, 4, 0},
{ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0},
{ABR, C_REG, C_NONE, C_NONE, C_CTR, 18, 4, 0},
{ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0},
@@ -661,8 +665,8 @@ func addpad(pc, a int64, ctxt *obj.Link, cursym *obj.LSym) int {
// the function alignment is not changed which might
// result in 16 byte alignment but that is still fine.
// TODO: alignment on AIX
- if ctxt.Headtype != objabi.Haix && cursym.Func.Align < 32 {
- cursym.Func.Align = 32
+ if ctxt.Headtype != objabi.Haix && cursym.Func().Align < 32 {
+ cursym.Func().Align = 32
}
default:
ctxt.Diag("Unexpected alignment: %d for PCALIGN directive\n", a)
@@ -671,7 +675,7 @@ func addpad(pc, a int64, ctxt *obj.Link, cursym *obj.LSym) int {
}
func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- p := cursym.Func.Text
+ p := cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -720,7 +724,7 @@ func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
for bflag != 0 {
bflag = 0
pc = 0
- for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p = c.cursym.Func().Text.Link; p != nil; p = p.Link {
p.Pc = pc
o = c.oplook(p)
@@ -782,7 +786,7 @@ func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
bp := c.cursym.P
var i int32
var out [6]uint32
- for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text.Link; p != nil; p = p.Link {
c.pc = p.Pc
o = c.oplook(p)
if int(o.size) > 4*len(out) {
@@ -1277,6 +1281,9 @@ func buildop(ctxt *obj.Link) {
case AREMD:
opset(AREMDU, r0)
+ case AMULLW:
+ opset(AMULLD, r0)
+
case ADIVW: /* op Rb[,Ra],Rd */
opset(AMULHW, r0)
@@ -1310,7 +1317,6 @@ func buildop(ctxt *obj.Link) {
opset(AMULHDCC, r0)
opset(AMULHDU, r0)
opset(AMULHDUCC, r0)
- opset(AMULLD, r0)
opset(AMULLDCC, r0)
opset(AMULLDVCC, r0)
opset(AMULLDV, r0)
@@ -1877,6 +1883,9 @@ func buildop(ctxt *obj.Link) {
case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
opset(ASRAWCC, r0)
+ case AEXTSWSLI:
+ opset(AEXTSWSLICC, r0)
+
case ASRAD: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
opset(ASRADCC, r0)
@@ -1922,6 +1931,9 @@ func buildop(ctxt *obj.Link) {
opset(ARLDICLCC, r0)
opset(ARLDICR, r0)
opset(ARLDICRCC, r0)
+ opset(ARLDIC, r0)
+ opset(ARLDICCC, r0)
+ opset(ACLRLSLDI, r0)
case AFMOVD:
opset(AFMOVDCC, r0)
@@ -1987,7 +1999,6 @@ func buildop(ctxt *obj.Link) {
AMOVB, /* macro: move byte with sign extension */
AMOVBU, /* macro: move byte with sign extension & update */
AMOVFL,
- AMULLW,
/* op $s[,r2],r3; op r1[,r2],r3; no cc/v */
ASUBC, /* op r1,$s,r3; op r1[,r2],r3 */
ASTSW,
@@ -2000,6 +2011,7 @@ func buildop(ctxt *obj.Link) {
AADDEX,
ACMPEQB,
AECIWX,
+ ACLRLSLWI,
obj.ANOP,
obj.ATEXT,
obj.AUNDEF,
@@ -2149,7 +2161,7 @@ func AOP_DQ(op uint32, d uint32, a uint32, b uint32) uint32 {
/* Z23-form, 3-register operands + CY field */
func AOP_Z23I(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
- return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (c&3)<<7
+ return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (c&3)<<9
}
/* X-form, 3-register operands + EH field */
@@ -2185,49 +2197,54 @@ func AOP_RLDIC(op uint32, a uint32, s uint32, sh uint32, m uint32) uint32 {
return op | (s&31)<<21 | (a&31)<<16 | (sh&31)<<11 | ((sh&32)>>5)<<1 | (m&31)<<6 | ((m&32)>>5)<<5
}
+func AOP_EXTSWSLI(op uint32, a uint32, s uint32, sh uint32) uint32 {
+ return op | (a&31)<<21 | (s&31)<<16 | (sh&31)<<11 | ((sh&32)>>5)<<1
+}
+
func AOP_ISEL(op uint32, t uint32, a uint32, b uint32, bc uint32) uint32 {
return op | (t&31)<<21 | (a&31)<<16 | (b&31)<<11 | (bc&0x1F)<<6
}
const (
/* each rhs is OPVCC(_, _, _, _) */
- OP_ADD = 31<<26 | 266<<1 | 0<<10 | 0
- OP_ADDI = 14<<26 | 0<<1 | 0<<10 | 0
- OP_ADDIS = 15<<26 | 0<<1 | 0<<10 | 0
- OP_ANDI = 28<<26 | 0<<1 | 0<<10 | 0
- OP_EXTSB = 31<<26 | 954<<1 | 0<<10 | 0
- OP_EXTSH = 31<<26 | 922<<1 | 0<<10 | 0
- OP_EXTSW = 31<<26 | 986<<1 | 0<<10 | 0
- OP_ISEL = 31<<26 | 15<<1 | 0<<10 | 0
- OP_MCRF = 19<<26 | 0<<1 | 0<<10 | 0
- OP_MCRFS = 63<<26 | 64<<1 | 0<<10 | 0
- OP_MCRXR = 31<<26 | 512<<1 | 0<<10 | 0
- OP_MFCR = 31<<26 | 19<<1 | 0<<10 | 0
- OP_MFFS = 63<<26 | 583<<1 | 0<<10 | 0
- OP_MFMSR = 31<<26 | 83<<1 | 0<<10 | 0
- OP_MFSPR = 31<<26 | 339<<1 | 0<<10 | 0
- OP_MFSR = 31<<26 | 595<<1 | 0<<10 | 0
- OP_MFSRIN = 31<<26 | 659<<1 | 0<<10 | 0
- OP_MTCRF = 31<<26 | 144<<1 | 0<<10 | 0
- OP_MTFSF = 63<<26 | 711<<1 | 0<<10 | 0
- OP_MTFSFI = 63<<26 | 134<<1 | 0<<10 | 0
- OP_MTMSR = 31<<26 | 146<<1 | 0<<10 | 0
- OP_MTMSRD = 31<<26 | 178<<1 | 0<<10 | 0
- OP_MTSPR = 31<<26 | 467<<1 | 0<<10 | 0
- OP_MTSR = 31<<26 | 210<<1 | 0<<10 | 0
- OP_MTSRIN = 31<<26 | 242<<1 | 0<<10 | 0
- OP_MULLW = 31<<26 | 235<<1 | 0<<10 | 0
- OP_MULLD = 31<<26 | 233<<1 | 0<<10 | 0
- OP_OR = 31<<26 | 444<<1 | 0<<10 | 0
- OP_ORI = 24<<26 | 0<<1 | 0<<10 | 0
- OP_ORIS = 25<<26 | 0<<1 | 0<<10 | 0
- OP_RLWINM = 21<<26 | 0<<1 | 0<<10 | 0
- OP_RLWNM = 23<<26 | 0<<1 | 0<<10 | 0
- OP_SUBF = 31<<26 | 40<<1 | 0<<10 | 0
- OP_RLDIC = 30<<26 | 4<<1 | 0<<10 | 0
- OP_RLDICR = 30<<26 | 2<<1 | 0<<10 | 0
- OP_RLDICL = 30<<26 | 0<<1 | 0<<10 | 0
- OP_RLDCL = 30<<26 | 8<<1 | 0<<10 | 0
+ OP_ADD = 31<<26 | 266<<1 | 0<<10 | 0
+ OP_ADDI = 14<<26 | 0<<1 | 0<<10 | 0
+ OP_ADDIS = 15<<26 | 0<<1 | 0<<10 | 0
+ OP_ANDI = 28<<26 | 0<<1 | 0<<10 | 0
+ OP_EXTSB = 31<<26 | 954<<1 | 0<<10 | 0
+ OP_EXTSH = 31<<26 | 922<<1 | 0<<10 | 0
+ OP_EXTSW = 31<<26 | 986<<1 | 0<<10 | 0
+ OP_ISEL = 31<<26 | 15<<1 | 0<<10 | 0
+ OP_MCRF = 19<<26 | 0<<1 | 0<<10 | 0
+ OP_MCRFS = 63<<26 | 64<<1 | 0<<10 | 0
+ OP_MCRXR = 31<<26 | 512<<1 | 0<<10 | 0
+ OP_MFCR = 31<<26 | 19<<1 | 0<<10 | 0
+ OP_MFFS = 63<<26 | 583<<1 | 0<<10 | 0
+ OP_MFMSR = 31<<26 | 83<<1 | 0<<10 | 0
+ OP_MFSPR = 31<<26 | 339<<1 | 0<<10 | 0
+ OP_MFSR = 31<<26 | 595<<1 | 0<<10 | 0
+ OP_MFSRIN = 31<<26 | 659<<1 | 0<<10 | 0
+ OP_MTCRF = 31<<26 | 144<<1 | 0<<10 | 0
+ OP_MTFSF = 63<<26 | 711<<1 | 0<<10 | 0
+ OP_MTFSFI = 63<<26 | 134<<1 | 0<<10 | 0
+ OP_MTMSR = 31<<26 | 146<<1 | 0<<10 | 0
+ OP_MTMSRD = 31<<26 | 178<<1 | 0<<10 | 0
+ OP_MTSPR = 31<<26 | 467<<1 | 0<<10 | 0
+ OP_MTSR = 31<<26 | 210<<1 | 0<<10 | 0
+ OP_MTSRIN = 31<<26 | 242<<1 | 0<<10 | 0
+ OP_MULLW = 31<<26 | 235<<1 | 0<<10 | 0
+ OP_MULLD = 31<<26 | 233<<1 | 0<<10 | 0
+ OP_OR = 31<<26 | 444<<1 | 0<<10 | 0
+ OP_ORI = 24<<26 | 0<<1 | 0<<10 | 0
+ OP_ORIS = 25<<26 | 0<<1 | 0<<10 | 0
+ OP_RLWINM = 21<<26 | 0<<1 | 0<<10 | 0
+ OP_RLWNM = 23<<26 | 0<<1 | 0<<10 | 0
+ OP_SUBF = 31<<26 | 40<<1 | 0<<10 | 0
+ OP_RLDIC = 30<<26 | 4<<1 | 0<<10 | 0
+ OP_RLDICR = 30<<26 | 2<<1 | 0<<10 | 0
+ OP_RLDICL = 30<<26 | 0<<1 | 0<<10 | 0
+ OP_RLDCL = 30<<26 | 8<<1 | 0<<10 | 0
+ OP_EXTSWSLI = 31<<26 | 445<<2
)
func oclass(a *obj.Addr) int {
@@ -2734,13 +2751,31 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
case ARLDICR, ARLDICRCC:
me := int(d)
sh := c.regoff(&p.From)
+ if me < 0 || me > 63 || sh > 63 {
+ c.ctxt.Diag("Invalid me or sh for RLDICR: %x %x\n%v", int(d), sh, p)
+ }
o1 = AOP_RLDIC(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(sh), uint32(me))
- case ARLDICL, ARLDICLCC:
+ case ARLDICL, ARLDICLCC, ARLDIC, ARLDICCC:
mb := int(d)
sh := c.regoff(&p.From)
+ if mb < 0 || mb > 63 || sh > 63 {
+ c.ctxt.Diag("Invalid mb or sh for RLDIC, RLDICL: %x %x\n%v", mb, sh, p)
+ }
o1 = AOP_RLDIC(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(sh), uint32(mb))
+ case ACLRLSLDI:
+ // This is an extended mnemonic defined in the ISA section C.8.1
+ // clrlsldi ra,rs,b,n --> rldic ra,rs,n,b-n
+ // It maps onto RLDIC so is directly generated here based on the operands from
+ // the clrlsldi.
+ n := int32(d)
+ b := c.regoff(&p.From)
+ if n > b || b > 63 {
+ c.ctxt.Diag("Invalid n or b for CLRLSLDI: %x %x\n%v", n, b, p)
+ }
+ o1 = AOP_RLDIC(OP_RLDIC, uint32(p.To.Reg), uint32(r), uint32(n), uint32(b)-uint32(n))
+
default:
c.ctxt.Diag("unexpected op in rldc case\n%v", p)
a = 0
@@ -2810,6 +2845,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
var v int32
+ var bh uint32 = 0
if p.As == ABC || p.As == ABCL {
v = c.regoff(&p.From) & 31
} else {
@@ -2831,6 +2867,15 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
v = 0
}
+ // Insert optional branch hint for bclr[l]/bcctr[l]
+ if p.From3Type() != obj.TYPE_NONE {
+ bh = uint32(p.GetFrom3().Offset)
+ if bh == 2 || bh > 3 {
+ log.Fatalf("BH must be 0,1,3 for %v", p)
+ }
+ o1 |= bh << 11
+ }
+
if p.As == ABL || p.As == ABCL {
o1 |= 1
}
@@ -2943,14 +2988,21 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
case AROTL:
a = int(0)
op = OP_RLDICL
+ case AEXTSWSLI:
+ a = int(v)
default:
c.ctxt.Diag("unexpected op in sldi case\n%v", p)
a = 0
o1 = 0
}
- o1 = AOP_RLDIC(op, uint32(p.To.Reg), uint32(r), uint32(v), uint32(a))
- if p.As == ASLDCC || p.As == ASRDCC {
+ if p.As == AEXTSWSLI || p.As == AEXTSWSLICC {
+ o1 = AOP_EXTSWSLI(OP_EXTSWSLI, uint32(r), uint32(p.To.Reg), uint32(v))
+
+ } else {
+ o1 = AOP_RLDIC(op, uint32(p.To.Reg), uint32(r), uint32(v), uint32(a))
+ }
+ if p.As == ASLDCC || p.As == ASRDCC || p.As == AEXTSWSLICC {
o1 |= 1 // Set the condition code bit
}
@@ -3354,17 +3406,28 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 62: /* rlwmi $sh,s,$mask,a */
v := c.regoff(&p.From)
+ switch p.As {
+ case ACLRLSLWI:
+ n := c.regoff(p.GetFrom3())
+ // This is an extended mnemonic described in the ISA C.8.2
+ // clrlslwi ra,rs,b,n -> rlwinm ra,rs,n,b-n,31-n
+ // It maps onto rlwinm which is directly generated here.
+ if n > v || v >= 32 {
+ c.ctxt.Diag("Invalid n or b for CLRLSLWI: %x %x\n%v", v, n, p)
+ }
- var mask [2]uint8
- c.maskgen(p, mask[:], uint32(c.regoff(p.GetFrom3())))
- o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(v))
- o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
+ o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.Reg), uint32(n), uint32(v-n), uint32(31-n))
+ default:
+ var mask [2]uint8
+ c.maskgen(p, mask[:], uint32(c.regoff(p.GetFrom3())))
+ o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(v))
+ o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
+ }
case 63: /* rlwmi b,s,$mask,a */
var mask [2]uint8
c.maskgen(p, mask[:], uint32(c.regoff(p.GetFrom3())))
-
- o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(p.From.Reg))
+ o1 = AOP_RRR(c.oprrr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(p.From.Reg))
o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
case 64: /* mtfsf fr[, $m] {,fpcsr} */
@@ -4277,6 +4340,11 @@ func (c *ctxt9) oprrr(a obj.As) uint32 {
case ARLDICRCC:
return OPVCC(30, 0, 0, 1) | 2<<1 // rldicr.
+ case ARLDIC:
+ return OPVCC(30, 0, 0, 0) | 4<<1 // rldic
+ case ARLDICCC:
+ return OPVCC(30, 0, 0, 1) | 4<<1 // rldic.
+
case ASYSCALL:
return OPVCC(17, 1, 0, 0)
@@ -4298,6 +4366,11 @@ func (c *ctxt9) oprrr(a obj.As) uint32 {
case ASRADCC:
return OPVCC(31, 794, 0, 1)
+ case AEXTSWSLI:
+ return OPVCC(31, 445, 0, 0)
+ case AEXTSWSLICC:
+ return OPVCC(31, 445, 0, 1)
+
case ASRW:
return OPVCC(31, 536, 0, 0)
case ASRWCC:
@@ -4915,8 +4988,8 @@ func (c *ctxt9) opirr(a obj.As) uint32 {
case ADARN:
return OPVCC(31, 755, 0, 0) /* darn - v3.00 */
- case AMULLW:
- return OPVCC(7, 0, 0, 0)
+ case AMULLW, AMULLD:
+ return OPVCC(7, 0, 0, 0) /* mulli works with MULLW or MULLD */
case AOR:
return OPVCC(24, 0, 0, 0)
@@ -4961,6 +5034,10 @@ func (c *ctxt9) opirr(a obj.As) uint32 {
return OPVCC(31, (413 << 1), 0, 0)
case ASRADCC:
return OPVCC(31, (413 << 1), 0, 1)
+ case AEXTSWSLI:
+ return OPVCC(31, 445, 0, 0)
+ case AEXTSWSLICC:
+ return OPVCC(31, 445, 0, 1)
case ASTSW:
return OPVCC(31, 725, 0, 0)
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index c012762a18..fddf552156 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -32,6 +32,7 @@ package ppc64
import (
"cmd/internal/obj"
"cmd/internal/objabi"
+ "cmd/internal/src"
"cmd/internal/sys"
)
@@ -402,13 +403,13 @@ func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// TODO(minux): add morestack short-cuts with small fixed frame-size.
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
textstksiz := p.To.Offset
if textstksiz == -8 {
// Compatibility hack.
@@ -424,8 +425,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- c.cursym.Func.Args = p.To.Val.(int32)
- c.cursym.Func.Locals = int32(textstksiz)
+ c.cursym.Func().Args = p.To.Val.(int32)
+ c.cursym.Func().Locals = int32(textstksiz)
/*
* find leaf subroutines
@@ -435,7 +436,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
var q *obj.Prog
var q1 *obj.Prog
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
/* too hard, just leave alone */
case obj.ATEXT:
@@ -541,7 +542,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ABCL,
obj.ADUFFZERO,
obj.ADUFFCOPY:
- c.cursym.Func.Text.Mark &^= LEAF
+ c.cursym.Func().Text.Mark &^= LEAF
fallthrough
case ABC,
@@ -598,7 +599,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize := int32(0)
var p1 *obj.Prog
var p2 *obj.Prog
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
@@ -664,7 +665,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
rel.Type = objabi.R_ADDRPOWER_PCREL
}
- if !c.cursym.Func.Text.From.Sym.NoSplit() {
+ if !c.cursym.Func().Text.From.Sym.NoSplit() {
q = c.stacksplit(q, autosize) // emit split check
}
@@ -672,6 +673,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// save the link register and update the stack, since that code is
// called directly from C/C++ and can't clobber REGTMP (R31).
if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
+ var prologueEnd *obj.Prog
// Save the link register and update the SP. MOVDU is used unless
// the frame size is too large. The link register must be saved
// even for non-empty leaf functions so that traceback works.
@@ -685,6 +687,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.To.Type = obj.TYPE_REG
q.To.Reg = REGTMP
+ prologueEnd = q
+
q = obj.Appendp(q, c.newprog)
q.As = AMOVDU
q.Pos = p.Pos
@@ -720,6 +724,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.To.Offset = int64(-autosize)
q.To.Reg = REGSP
+ prologueEnd = q
+
q = obj.Appendp(q, c.newprog)
q.As = AADD
q.Pos = p.Pos
@@ -730,16 +736,16 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Spadj = +autosize
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
-
}
- } else if c.cursym.Func.Text.Mark&LEAF == 0 {
+ prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
+ } else if c.cursym.Func().Text.Mark&LEAF == 0 {
// A very few functions that do not return to their caller
// (e.g. gogo) are not identified as leaves but still have
// no frame.
- c.cursym.Func.Text.Mark |= LEAF
+ c.cursym.Func().Text.Mark |= LEAF
}
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
c.cursym.Set(obj.AttrLeaf, true)
break
}
@@ -755,7 +761,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.To.Offset = 24
}
- if c.cursym.Func.Text.From.Sym.Wrapper() {
+ if c.cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVD g_panic(g), R3
@@ -853,7 +859,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
retTarget := p.To.Sym
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" {
p.As = ABR
p.From = obj.Addr{}
@@ -1161,7 +1167,7 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
var morestacksym *obj.LSym
if c.cursym.CFunc() {
morestacksym = c.ctxt.Lookup("runtime.morestackc")
- } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
+ } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
} else {
morestacksym = c.ctxt.Lookup("runtime.morestack")
diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go
index 482f9e0b6d..b1324b62a0 100644
--- a/src/cmd/internal/obj/riscv/cpu.go
+++ b/src/cmd/internal/obj/riscv/cpu.go
@@ -109,7 +109,7 @@ const (
REG_RA = REG_X1 // aka REG_LR
REG_SP = REG_X2
REG_GP = REG_X3 // aka REG_SB
- REG_TP = REG_X4 // aka REG_G
+ REG_TP = REG_X4
REG_T0 = REG_X5
REG_T1 = REG_X6
REG_T2 = REG_X7
@@ -132,17 +132,17 @@ const (
REG_S8 = REG_X24
REG_S9 = REG_X25
REG_S10 = REG_X26
- REG_S11 = REG_X27
+ REG_S11 = REG_X27 // aka REG_G
REG_T3 = REG_X28
REG_T4 = REG_X29
REG_T5 = REG_X30
REG_T6 = REG_X31 // aka REG_TMP
// Go runtime register names.
- REG_G = REG_TP // G pointer.
- REG_CTXT = REG_S4 // Context for closures.
- REG_LR = REG_RA // Link register.
- REG_TMP = REG_T6 // Reserved for assembler use.
+ REG_G = REG_S11 // G pointer.
+ REG_CTXT = REG_S4 // Context for closures.
+ REG_LR = REG_RA // Link register.
+ REG_TMP = REG_T6 // Reserved for assembler use.
// ABI names for floating point registers.
REG_FT0 = REG_F0
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 77d383b290..9257a6453a 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -33,7 +33,7 @@ func buildop(ctxt *obj.Link) {}
// lr is the link register to use for the JALR.
// p must be a CALL, JMP or RET.
func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *obj.Prog {
- if p.As != obj.ACALL && p.As != obj.AJMP && p.As != obj.ARET {
+ if p.As != obj.ACALL && p.As != obj.AJMP && p.As != obj.ARET && p.As != obj.ADUFFZERO && p.As != obj.ADUFFCOPY {
ctxt.Diag("unexpected Prog in jalrToSym: %v", p)
return p
}
@@ -48,7 +48,7 @@ func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *ob
p.As = AAUIPC
p.Mark |= NEED_PCREL_ITYPE_RELOC
- p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: to.Offset, Sym: to.Sym}}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: to.Offset, Sym: to.Sym})
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
p.Reg = 0
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
@@ -58,30 +58,14 @@ func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *ob
p.As = AJALR
p.From.Type = obj.TYPE_REG
p.From.Reg = lr
- p.From.Sym = to.Sym
p.Reg = 0
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_TMP
- lowerJALR(p)
+ p.To.Sym = to.Sym
return p
}
-// lowerJALR normalizes a JALR instruction.
-func lowerJALR(p *obj.Prog) {
- if p.As != AJALR {
- panic("lowerJALR: not a JALR")
- }
-
- // JALR gets parsed like JAL - the linkage pointer goes in From,
- // and the target is in To. However, we need to assemble it as an
- // I-type instruction, so place the linkage pointer in To, the
- // target register in Reg, and the offset in From.
- p.Reg = p.To.Reg
- p.From, p.To = p.To, p.From
- p.From.Type, p.From.Reg = obj.TYPE_CONST, obj.REG_NONE
-}
-
// progedit is called individually for each *obj.Prog. It normalizes instruction
// formats and eliminates as many pseudo-instructions as possible.
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
@@ -125,7 +109,6 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
switch p.As {
case obj.AJMP:
// Turn JMP into JAL ZERO or JALR ZERO.
- // p.From is actually an _output_ for this instruction.
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_ZERO
@@ -136,7 +119,6 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
switch p.To.Name {
case obj.NAME_NONE:
p.As = AJALR
- lowerJALR(p)
case obj.NAME_EXTERN:
// Handled in preprocess.
default:
@@ -154,14 +136,10 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.As = AJALR
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_LR
- lowerJALR(p)
default:
ctxt.Diag("unknown destination type %+v in CALL: %v", p.To.Type, p)
}
- case AJALR:
- lowerJALR(p)
-
case obj.AUNDEF:
p.As = AEBREAK
@@ -256,7 +234,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
p.As = AAUIPC
p.Mark |= NEED_PCREL_ITYPE_RELOC
- p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym}}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym})
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
p.Reg = 0
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: to.Reg}
@@ -274,19 +252,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
switch p.To.Type {
case obj.TYPE_REG:
switch p.As {
- case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb
- p.As = AADDI
- p.Reg = p.From.Reg
- p.From = obj.Addr{Type: obj.TYPE_CONST}
-
- case AMOVF: // MOVF Ra, Rb -> FSGNJS Ra, Ra, Rb
- p.As = AFSGNJS
- p.Reg = p.From.Reg
-
- case AMOVD: // MOVD Ra, Rb -> FSGNJD Ra, Ra, Rb
- p.As = AFSGNJD
- p.Reg = p.From.Reg
-
+ case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
default:
ctxt.Diag("unsupported register-register move at %v", p)
}
@@ -309,7 +275,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
p.As = AAUIPC
p.Mark |= NEED_PCREL_STYPE_RELOC
- p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym}}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym})
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
p.Reg = 0
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
@@ -374,7 +340,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
p.As = AAUIPC
p.Mark |= NEED_PCREL_ITYPE_RELOC
- p.RestArgs = []obj.Addr{obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym}}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: p.From.Offset, Sym: p.From.Sym})
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
p.Reg = 0
p.To = to
@@ -449,12 +415,12 @@ func InvertBranch(as obj.As) obj.As {
// instruction. Must be called after progedit.
func containsCall(sym *obj.LSym) bool {
// CALLs are CALL or JAL(R) with link register LR.
- for p := sym.Func.Text; p != nil; p = p.Link {
+ for p := sym.Func().Text; p != nil; p = p.Link {
switch p.As {
- case obj.ACALL:
+ case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
return true
case AJAL, AJALR:
- if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_LR {
+ if p.From.Type == obj.TYPE_REG && p.From.Reg == REG_LR {
return true
}
}
@@ -521,12 +487,12 @@ func stackOffset(a *obj.Addr, stacksize int64) {
// concrete, real RISC-V instructions or directive pseudo-ops like TEXT,
// PCDATA, and FUNCDATA.
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
// Generate the prologue.
- text := cursym.Func.Text
+ text := cursym.Func().Text
if text.As != obj.ATEXT {
ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
return
@@ -560,12 +526,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
stacksize += ctxt.FixedFrameSize()
}
- cursym.Func.Args = text.To.Val.(int32)
- cursym.Func.Locals = int32(stacksize)
+ cursym.Func().Args = text.To.Val.(int32)
+ cursym.Func().Locals = int32(stacksize)
prologue := text
- if !cursym.Func.Text.From.Sym.NoSplit() {
+ if !cursym.Func().Text.From.Sym.NoSplit() {
prologue = stacksplit(ctxt, prologue, cursym, newprog, stacksize) // emit split check
}
@@ -589,7 +555,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
prologue = ctxt.EndUnsafePoint(prologue, newprog, -1)
}
- if cursym.Func.Text.From.Sym.Wrapper() {
+ if cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOV g_panic(g), X11
@@ -669,13 +635,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// Update stack-based offsets.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
stackOffset(&p.From, stacksize)
stackOffset(&p.To, stacksize)
}
// Additional instruction rewriting.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case obj.AGETCALLERPC:
if cursym.Leaf() {
@@ -690,7 +656,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From.Reg = REG_SP
}
- case obj.ACALL:
+ case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
switch p.To.Type {
case obj.TYPE_MEM:
jalrToSym(ctxt, p, newprog, REG_LR)
@@ -731,11 +697,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p = jalrToSym(ctxt, p, newprog, REG_ZERO)
} else {
p.As = AJALR
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 0
- p.Reg = REG_LR
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_ZERO
+ p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
+ p.Reg = 0
+ p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
}
// "Add back" the stack removed in the previous instruction.
@@ -757,7 +721,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// Rewrite MOV pseudo-instructions. This cannot be done in
// progedit, as SP offsets need to be applied before we split
// up some of the Addrs.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
rewriteMOV(ctxt, newprog, p)
@@ -765,7 +729,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// Split immediates larger than 12-bits.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
// <opi> $imm, REG, TO
case AADDI, AANDI, AORI, AXORI:
@@ -882,9 +846,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// a fixed point will be reached). No attempt to handle functions > 2GiB.
for {
rescan := false
- setPCs(cursym.Func.Text, 0)
+ setPCs(cursym.Func().Text, 0)
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
if p.To.Type != obj.TYPE_BRANCH {
@@ -917,9 +881,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// it is reserved by SSA.
jmp := obj.Appendp(p, newprog)
jmp.As = AJALR
- jmp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0}
- jmp.To = p.From
- jmp.Reg = REG_TMP
+ jmp.From = p.From
+ jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP}
// p.From is not generally valid, however will be
// fixed up in the next loop.
@@ -942,7 +905,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// Now that there are no long branches, resolve branch and jump targets.
// At this point, instruction rewriting which changes the number of
// instructions will break everything--don't do it!
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ, AJAL:
switch p.To.Type {
@@ -965,7 +928,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// Validate all instructions - this provides nice error messages.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
for _, ins := range instructionsForProg(p) {
ins.validate(ctxt)
}
@@ -1093,7 +1056,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgA
p.To.Type = obj.TYPE_BRANCH
if cursym.CFunc() {
p.To.Sym = ctxt.Lookup("runtime.morestackc")
- } else if !cursym.Func.Text.From.Sym.NeedCtxt() {
+ } else if !cursym.Func().Text.From.Sym.NeedCtxt() {
p.To.Sym = ctxt.Lookup("runtime.morestack_noctxt")
} else {
p.To.Sym = ctxt.Lookup("runtime.morestack")
@@ -1108,7 +1071,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgA
p.As = AJAL
p.To = obj.Addr{Type: obj.TYPE_BRANCH}
p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
- p.To.SetTarget(cursym.Func.Text.Link)
+ p.To.SetTarget(cursym.Func().Text.Link)
// placeholder for to_done's jump target
p = obj.Appendp(p, newprog)
@@ -1733,6 +1696,8 @@ var encodings = [ALAST & obj.AMask]encoding{
obj.APCDATA: pseudoOpEncoding,
obj.ATEXT: pseudoOpEncoding,
obj.ANOP: pseudoOpEncoding,
+ obj.ADUFFZERO: pseudoOpEncoding,
+ obj.ADUFFCOPY: pseudoOpEncoding,
}
// encodingForAs returns the encoding for an obj.As.
@@ -1801,8 +1766,8 @@ func instructionsForProg(p *obj.Prog) []*instruction {
inss := []*instruction{ins}
switch ins.as {
- case AJAL:
- ins.rd, ins.rs2 = uint32(p.From.Reg), obj.REG_NONE
+ case AJAL, AJALR:
+ ins.rd, ins.rs1, ins.rs2 = uint32(p.From.Reg), uint32(p.To.Reg), obj.REG_NONE
ins.imm = p.To.Offset
case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
@@ -1812,15 +1777,15 @@ func instructionsForProg(p *obj.Prog) []*instruction {
case ABGEZ:
ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg)
case ABGT:
- ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.Reg), uint32(p.From.Reg)
+ ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg)
case ABGTU:
- ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.Reg), uint32(p.From.Reg)
+ ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg)
case ABGTZ:
ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO
case ABLE:
- ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.Reg), uint32(p.From.Reg)
+ ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg)
case ABLEU:
- ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.Reg), uint32(p.From.Reg)
+ ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg)
case ABLEZ:
ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO
case ABLTZ:
@@ -1830,6 +1795,44 @@ func instructionsForProg(p *obj.Prog) []*instruction {
}
ins.imm = p.To.Offset
+ case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
+ // Handle register to register moves.
+ if p.From.Type != obj.TYPE_REG || p.To.Type != obj.TYPE_REG {
+ break
+ }
+ switch p.As {
+ case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb
+ ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, uint32(p.From.Reg), obj.REG_NONE, 0
+ case AMOVW: // MOVW Ra, Rb -> ADDIW $0, Ra, Rb
+ ins.as, ins.rs1, ins.rs2, ins.imm = AADDIW, uint32(p.From.Reg), obj.REG_NONE, 0
+ case AMOVBU: // MOVBU Ra, Rb -> ANDI $255, Ra, Rb
+ ins.as, ins.rs1, ins.rs2, ins.imm = AANDI, uint32(p.From.Reg), obj.REG_NONE, 255
+ case AMOVF: // MOVF Ra, Rb -> FSGNJS Ra, Ra, Rb
+ ins.as, ins.rs1 = AFSGNJS, uint32(p.From.Reg)
+ case AMOVD: // MOVD Ra, Rb -> FSGNJD Ra, Ra, Rb
+ ins.as, ins.rs1 = AFSGNJD, uint32(p.From.Reg)
+ case AMOVB, AMOVH:
+ // Use SLLI/SRAI to extend.
+ ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
+ if p.As == AMOVB {
+ ins.imm = 56
+ } else if p.As == AMOVH {
+ ins.imm = 48
+ }
+ ins2 := &instruction{as: ASRAI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
+ inss = append(inss, ins2)
+ case AMOVHU, AMOVWU:
+ // Use SLLI/SRLI to extend.
+ ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
+ if p.As == AMOVHU {
+ ins.imm = 48
+ } else if p.As == AMOVWU {
+ ins.imm = 32
+ }
+ ins2 := &instruction{as: ASRLI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
+ inss = append(inss, ins2)
+ }
+
case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
if p.From.Type != obj.TYPE_MEM {
p.Ctxt.Diag("%v requires memory for source", p)
@@ -1884,13 +1887,13 @@ func instructionsForProg(p *obj.Prog) []*instruction {
} else {
ins.as = AFEQD
}
- ins = &instruction{
+ ins2 := &instruction{
as: AXORI, // [bit] xor 1 = not [bit]
rd: ins.rd,
rs1: ins.rd,
imm: 1,
}
- inss = append(inss, ins)
+ inss = append(inss, ins2)
case AFSQRTS, AFSQRTD:
// These instructions expect a zero (i.e. float register 0)
@@ -1951,7 +1954,7 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
var symcode []uint32
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case AJALR:
if p.To.Sym != nil {
@@ -1983,6 +1986,13 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Diag("AUIPC needing PC-relative reloc missing symbol")
break
}
+ if addr.Sym.Type == objabi.STLSBSS {
+ if rt == objabi.R_RISCV_PCREL_ITYPE {
+ rt = objabi.R_RISCV_TLS_IE_ITYPE
+ } else if rt == objabi.R_RISCV_PCREL_STYPE {
+ rt = objabi.R_RISCV_TLS_IE_STYPE
+ }
+ }
rel := obj.Addrel(cursym)
rel.Off = int32(p.Pc)
@@ -2006,7 +2016,7 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Arch.ByteOrder.PutUint32(p, symcode[i])
}
- obj.MarkUnsafePoints(ctxt, cursym.Func.Text, newprog, isUnsafePoint, nil)
+ obj.MarkUnsafePoints(ctxt, cursym.Func().Text, newprog, isUnsafePoint, nil)
}
func isUnsafePoint(p *obj.Prog) bool {
diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go
index 803ba8c77c..279aeb2c32 100644
--- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go
+++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go
@@ -11,6 +11,8 @@ import (
)
func testBEQZ(a int64) (r bool)
+func testBGE(a, b int64) (r bool)
+func testBGEU(a, b int64) (r bool)
func testBGEZ(a int64) (r bool)
func testBGT(a, b int64) (r bool)
func testBGTU(a, b int64) (r bool)
@@ -18,6 +20,8 @@ func testBGTZ(a int64) (r bool)
func testBLE(a, b int64) (r bool)
func testBLEU(a, b int64) (r bool)
func testBLEZ(a int64) (r bool)
+func testBLT(a, b int64) (r bool)
+func testBLTU(a, b int64) (r bool)
func testBLTZ(a int64) (r bool)
func testBNEZ(a int64) (r bool)
@@ -29,30 +33,75 @@ func TestBranchCondition(t *testing.T) {
fn func(a, b int64) bool
want bool
}{
- {"BGT", 0, 1, testBGT, true},
+ {"BGE", 0, 1, testBGE, false},
+ {"BGE", 0, 0, testBGE, true},
+ {"BGE", 0, -1, testBGE, true},
+ {"BGE", -1, 0, testBGE, false},
+ {"BGE", 1, 0, testBGE, true},
+ {"BGEU", 0, 1, testBGEU, false},
+ {"BGEU", 0, 0, testBGEU, true},
+ {"BGEU", 0, -1, testBGEU, false},
+ {"BGEU", -1, 0, testBGEU, true},
+ {"BGEU", 1, 0, testBGEU, true},
+ {"BGT", 0, 1, testBGT, false},
{"BGT", 0, 0, testBGT, false},
- {"BGT", 0, -1, testBGT, false},
- {"BGT", -1, 0, testBGT, true},
- {"BGT", 1, 0, testBGT, false},
- {"BGTU", 0, 1, testBGTU, true},
- {"BGTU", 0, -1, testBGTU, true},
- {"BGTU", -1, 0, testBGTU, false},
- {"BGTU", 1, 0, testBGTU, false},
- {"BLE", 0, 1, testBLE, false},
- {"BLE", 0, -1, testBLE, true},
+ {"BGT", 0, -1, testBGT, true},
+ {"BGT", -1, 0, testBGT, false},
+ {"BGT", 1, 0, testBGT, true},
+ {"BGTU", 0, 1, testBGTU, false},
+ {"BGTU", 0, 0, testBGTU, false},
+ {"BGTU", 0, -1, testBGTU, false},
+ {"BGTU", -1, 0, testBGTU, true},
+ {"BGTU", 1, 0, testBGTU, true},
+ {"BLE", 0, 1, testBLE, true},
{"BLE", 0, 0, testBLE, true},
- {"BLE", -1, 0, testBLE, false},
- {"BLE", 1, 0, testBLE, true},
- {"BLEU", 0, 1, testBLEU, false},
- {"BLEU", 0, -1, testBLEU, false},
+ {"BLE", 0, -1, testBLE, false},
+ {"BLE", -1, 0, testBLE, true},
+ {"BLE", 1, 0, testBLE, false},
+ {"BLEU", 0, 1, testBLEU, true},
{"BLEU", 0, 0, testBLEU, true},
- {"BLEU", -1, 0, testBLEU, true},
- {"BLEU", 1, 0, testBLEU, true},
+ {"BLEU", 0, -1, testBLEU, true},
+ {"BLEU", -1, 0, testBLEU, false},
+ {"BLEU", 1, 0, testBLEU, false},
+ {"BLT", 0, 1, testBLT, true},
+ {"BLT", 0, 0, testBLT, false},
+ {"BLT", 0, -1, testBLT, false},
+ {"BLT", -1, 0, testBLT, true},
+ {"BLT", 1, 0, testBLT, false},
+ {"BLTU", 0, 1, testBLTU, true},
+ {"BLTU", 0, 0, testBLTU, false},
+ {"BLTU", 0, -1, testBLTU, true},
+ {"BLTU", -1, 0, testBLTU, false},
+ {"BLTU", 1, 0, testBLTU, false},
}
for _, test := range tests {
t.Run(test.ins, func(t *testing.T) {
+ var fn func(a, b int64) bool
+ switch test.ins {
+ case "BGE":
+ fn = func(a, b int64) bool { return a >= b }
+ case "BGEU":
+ fn = func(a, b int64) bool { return uint64(a) >= uint64(b) }
+ case "BGT":
+ fn = func(a, b int64) bool { return a > b }
+ case "BGTU":
+ fn = func(a, b int64) bool { return uint64(a) > uint64(b) }
+ case "BLE":
+ fn = func(a, b int64) bool { return a <= b }
+ case "BLEU":
+ fn = func(a, b int64) bool { return uint64(a) <= uint64(b) }
+ case "BLT":
+ fn = func(a, b int64) bool { return a < b }
+ case "BLTU":
+ fn = func(a, b int64) bool { return uint64(a) < uint64(b) }
+ default:
+ t.Fatalf("Unknown instruction %q", test.ins)
+ }
+ if got := fn(test.a, test.b); got != test.want {
+ t.Errorf("Go %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want)
+ }
if got := test.fn(test.a, test.b); got != test.want {
- t.Errorf("%v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want)
+ t.Errorf("Assembly %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want)
}
})
}
diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s
index 6cff235848..8dd6f563af 100644
--- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s
+++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s
@@ -16,6 +16,28 @@ b:
MOV X6, r+8(FP)
RET
+// func testBGE(a, b int64) (r bool)
+TEXT ·testBGE(SB),NOSPLIT,$0-0
+ MOV a+0(FP), X5
+ MOV b+8(FP), X6
+ MOV $1, X7
+ BGE X5, X6, b
+ MOV $0, X7
+b:
+ MOV X7, r+16(FP)
+ RET
+
+// func testBGEU(a, b int64) (r bool)
+TEXT ·testBGEU(SB),NOSPLIT,$0-0
+ MOV a+0(FP), X5
+ MOV b+8(FP), X6
+ MOV $1, X7
+ BGEU X5, X6, b
+ MOV $0, X7
+b:
+ MOV X7, r+16(FP)
+ RET
+
// func testBGEZ(a int64) (r bool)
TEXT ·testBGEZ(SB),NOSPLIT,$0-0
MOV a+0(FP), X5
@@ -90,6 +112,28 @@ b:
MOV X6, r+8(FP)
RET
+// func testBLT(a, b int64) (r bool)
+TEXT ·testBLT(SB),NOSPLIT,$0-0
+ MOV a+0(FP), X5
+ MOV b+8(FP), X6
+ MOV $1, X7
+ BLT X5, X6, b
+ MOV $0, X7
+b:
+ MOV X7, r+16(FP)
+ RET
+
+// func testBLTU(a, b int64) (r bool)
+TEXT ·testBLTU(SB),NOSPLIT,$0-0
+ MOV a+0(FP), X5
+ MOV b+8(FP), X6
+ MOV $1, X7
+ BLTU X5, X6, b
+ MOV $0, X7
+b:
+ MOV X7, r+16(FP)
+ RET
+
// func testBLTZ(a int64) (r bool)
TEXT ·testBLTZ(SB),NOSPLIT,$0-0
MOV a+0(FP), X5
diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go
index 68f01f1c5d..06921085c9 100644
--- a/src/cmd/internal/obj/s390x/asmz.go
+++ b/src/cmd/internal/obj/s390x/asmz.go
@@ -447,7 +447,7 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Retpoline = false // don't keep printing
}
- p := cursym.Func.Text
+ p := cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -461,6 +461,7 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
buffer := make([]byte, 0)
changed := true
loop := 0
+ nrelocs0 := len(c.cursym.R)
for changed {
if loop > 100 {
c.ctxt.Diag("stuck in spanz loop")
@@ -468,8 +469,11 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
changed = false
buffer = buffer[:0]
- c.cursym.R = make([]obj.Reloc, 0)
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for i := range c.cursym.R[nrelocs0:] {
+ c.cursym.R[nrelocs0+i] = obj.Reloc{}
+ }
+ c.cursym.R = c.cursym.R[:nrelocs0] // preserve marker relocations generated by the compiler
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
pc := int64(len(buffer))
if pc != p.Pc {
changed = true
@@ -500,7 +504,7 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// We use REGTMP as a scratch register during call injection,
// so instruction sequences that use REGTMP are unsafe to
// preempt asynchronously.
- obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint, nil)
+ obj.MarkUnsafePoints(c.ctxt, c.cursym.Func().Text, c.newprog, c.isUnsafePoint, nil)
}
// Return whether p is an unsafe point.
@@ -714,7 +718,7 @@ func (c *ctxtz) oplook(p *obj.Prog) *Optab {
p.From.Class = int8(c.aclass(&p.From) + 1)
p.To.Class = int8(c.aclass(&p.To) + 1)
for i := range p.RestArgs {
- p.RestArgs[i].Class = int8(c.aclass(&p.RestArgs[i]) + 1)
+ p.RestArgs[i].Addr.Class = int8(c.aclass(&p.RestArgs[i].Addr) + 1)
}
// Mirrors the argument list in Optab.
@@ -3696,7 +3700,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
}
case 80: // sync
- zRR(op_BCR, uint32(NotEqual), 0, asm)
+ zRR(op_BCR, 14, 0, asm) // fast-BCR-serialization
case 81: // float to fixed and fixed to float moves (no conversion)
switch p.As {
diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go
index 625bb0f7b4..970cf827d6 100644
--- a/src/cmd/internal/obj/s390x/objz.go
+++ b/src/cmd/internal/obj/s390x/objz.go
@@ -205,13 +205,13 @@ func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// TODO(minux): add morestack short-cuts with small fixed frame-size.
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
c := ctxtz{ctxt: ctxt, cursym: cursym, newprog: newprog}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
textstksiz := p.To.Offset
if textstksiz == -8 {
// Compatibility hack.
@@ -227,8 +227,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- c.cursym.Func.Args = p.To.Val.(int32)
- c.cursym.Func.Locals = int32(textstksiz)
+ c.cursym.Func().Args = p.To.Val.(int32)
+ c.cursym.Func().Locals = int32(textstksiz)
/*
* find leaf subroutines
@@ -237,7 +237,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
*/
var q *obj.Prog
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case obj.ATEXT:
q = p
@@ -245,7 +245,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case ABL, ABCL:
q = p
- c.cursym.Func.Text.Mark &^= LEAF
+ c.cursym.Func().Text.Mark &^= LEAF
fallthrough
case ABC,
@@ -294,7 +294,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
var pPre *obj.Prog
var pPreempt *obj.Prog
wasSplit := false
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
pLast = p
switch p.As {
case obj.ATEXT:
@@ -356,19 +356,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Spadj = autosize
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
- } else if c.cursym.Func.Text.Mark&LEAF == 0 {
+ } else if c.cursym.Func().Text.Mark&LEAF == 0 {
// A very few functions that do not return to their caller
// (e.g. gogo) are not identified as leaves but still have
// no frame.
- c.cursym.Func.Text.Mark |= LEAF
+ c.cursym.Func().Text.Mark |= LEAF
}
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
c.cursym.Set(obj.AttrLeaf, true)
break
}
- if c.cursym.Func.Text.From.Sym.Wrapper() {
+ if c.cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVD g_panic(g), R3
@@ -461,7 +461,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case obj.ARET:
retTarget := p.To.Sym
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
p.As = ABR
p.From = obj.Addr{}
@@ -497,8 +497,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGSP
p.From.Offset = 0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_LR
+ p.To = obj.Addr{
+ Type: obj.TYPE_REG,
+ Reg: REG_LR,
+ }
q = p
@@ -696,7 +698,7 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog,
p.To.Type = obj.TYPE_BRANCH
if c.cursym.CFunc() {
p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
- } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
+ } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
} else {
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
@@ -709,7 +711,7 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog,
p.As = ABR
p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(c.cursym.Func.Text.Link)
+ p.To.SetTarget(c.cursym.Func().Text.Link)
return p
}
diff --git a/src/cmd/internal/obj/s390x/rotate.go b/src/cmd/internal/obj/s390x/rotate.go
index fd2d5482db..7dbc45e648 100644
--- a/src/cmd/internal/obj/s390x/rotate.go
+++ b/src/cmd/internal/obj/s390x/rotate.go
@@ -4,6 +4,10 @@
package s390x
+import (
+ "math/bits"
+)
+
// RotateParams represents the immediates required for a "rotate
// then ... selected bits instruction".
//
@@ -24,12 +28,18 @@ package s390x
// input left by. Note that this rotation is performed
// before the masked region is used.
type RotateParams struct {
- Start uint8 // big-endian start bit index [0..63]
- End uint8 // big-endian end bit index [0..63]
- Amount uint8 // amount to rotate left
+ Start int8 // big-endian start bit index [0..63]
+ End int8 // big-endian end bit index [0..63]
+ Amount int8 // amount to rotate left
}
-func NewRotateParams(start, end, amount int64) RotateParams {
+// NewRotateParams creates a set of parameters representing a
+// rotation left by the amount provided and a selection of the bits
+// between the provided start and end indexes (inclusive).
+//
+// The start and end indexes and the rotation amount must all
+// be in the range 0-63 inclusive or this function will panic.
+func NewRotateParams(start, end, amount int8) RotateParams {
if start&^63 != 0 {
panic("start out of bounds")
}
@@ -40,8 +50,66 @@ func NewRotateParams(start, end, amount int64) RotateParams {
panic("amount out of bounds")
}
return RotateParams{
- Start: uint8(start),
- End: uint8(end),
- Amount: uint8(amount),
+ Start: start,
+ End: end,
+ Amount: amount,
}
}
+
+// RotateLeft generates a new set of parameters with the rotation amount
+// increased by the given value. The selected bits are left unchanged.
+func (r RotateParams) RotateLeft(amount int8) RotateParams {
+ r.Amount += amount
+ r.Amount &= 63
+ return r
+}
+
+// OutMask provides a mask representing the selected bits.
+func (r RotateParams) OutMask() uint64 {
+ // Note: z must be unsigned for bootstrap compiler
+ z := uint8(63-r.End+r.Start) & 63 // number of zero bits in mask
+ return bits.RotateLeft64(^uint64(0)<<z, -int(r.Start))
+}
+
+// InMask provides a mask representing the selected bits relative
+// to the source value (i.e. pre-rotation).
+func (r RotateParams) InMask() uint64 {
+ return bits.RotateLeft64(r.OutMask(), -int(r.Amount))
+}
+
+// OutMerge tries to generate a new set of parameters representing
+// the intersection between the selected bits and the provided mask.
+// If the intersection is unrepresentable (0 or not contiguous) nil
+// will be returned.
+func (r RotateParams) OutMerge(mask uint64) *RotateParams {
+ mask &= r.OutMask()
+ if mask == 0 {
+ return nil
+ }
+
+ // normalize the mask so that the set bits are left aligned
+ o := bits.LeadingZeros64(^mask)
+ mask = bits.RotateLeft64(mask, o)
+ z := bits.LeadingZeros64(mask)
+ mask = bits.RotateLeft64(mask, z)
+
+ // check that the normalized mask is contiguous
+ l := bits.LeadingZeros64(^mask)
+ if l+bits.TrailingZeros64(mask) != 64 {
+ return nil
+ }
+
+ // update start and end positions (rotation amount remains the same)
+ r.Start = int8(o+z) & 63
+ r.End = (r.Start + int8(l) - 1) & 63
+ return &r
+}
+
+// InMerge tries to generate a new set of parameters representing
+// the intersection between the selected bits and the provided mask
+// as applied to the source value (i.e. pre-rotation).
+// If the intersection is unrepresentable (0 or not contiguous) nil
+// will be returned.
+func (r RotateParams) InMerge(mask uint64) *RotateParams {
+ return r.OutMerge(bits.RotateLeft64(mask, int(r.Amount)))
+}
diff --git a/src/cmd/internal/obj/s390x/rotate_test.go b/src/cmd/internal/obj/s390x/rotate_test.go
new file mode 100644
index 0000000000..fa5b5bdecd
--- /dev/null
+++ b/src/cmd/internal/obj/s390x/rotate_test.go
@@ -0,0 +1,122 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s390x
+
+import (
+ "testing"
+)
+
+func TestRotateParamsMask(t *testing.T) {
+ tests := []struct {
+ start, end, amount int8
+ inMask, outMask uint64
+ }{
+ // start before end, no rotation
+ {start: 0, end: 63, amount: 0, inMask: ^uint64(0), outMask: ^uint64(0)},
+ {start: 1, end: 63, amount: 0, inMask: ^uint64(0) >> 1, outMask: ^uint64(0) >> 1},
+ {start: 0, end: 62, amount: 0, inMask: ^uint64(1), outMask: ^uint64(1)},
+ {start: 1, end: 62, amount: 0, inMask: ^uint64(3) >> 1, outMask: ^uint64(3) >> 1},
+
+ // end before start, no rotation
+ {start: 63, end: 0, amount: 0, inMask: 1<<63 | 1, outMask: 1<<63 | 1},
+ {start: 62, end: 0, amount: 0, inMask: 1<<63 | 3, outMask: 1<<63 | 3},
+ {start: 63, end: 1, amount: 0, inMask: 3<<62 | 1, outMask: 3<<62 | 1},
+ {start: 62, end: 1, amount: 0, inMask: 3<<62 | 3, outMask: 3<<62 | 3},
+
+ // rotation
+ {start: 32, end: 63, amount: 32, inMask: 0xffffffff00000000, outMask: 0x00000000ffffffff},
+ {start: 48, end: 15, amount: 16, inMask: 0xffffffff00000000, outMask: 0xffff00000000ffff},
+ {start: 0, end: 7, amount: -8 & 63, inMask: 0xff, outMask: 0xff << 56},
+ }
+ for i, test := range tests {
+ r := NewRotateParams(test.start, test.end, test.amount)
+ if m := r.OutMask(); m != test.outMask {
+ t.Errorf("out mask %v: want %#x, got %#x", i, test.outMask, m)
+ }
+ if m := r.InMask(); m != test.inMask {
+ t.Errorf("in mask %v: want %#x, got %#x", i, test.inMask, m)
+ }
+ }
+}
+
+func TestRotateParamsMerge(t *testing.T) {
+ tests := []struct {
+ // inputs
+ src RotateParams
+ mask uint64
+
+ // results
+ in *RotateParams
+ out *RotateParams
+ }{
+ {
+ src: RotateParams{Start: 48, End: 15, Amount: 16},
+ mask: 0xffffffffffffffff,
+ in: &RotateParams{Start: 48, End: 15, Amount: 16},
+ out: &RotateParams{Start: 48, End: 15, Amount: 16},
+ },
+ {
+ src: RotateParams{Start: 16, End: 47, Amount: 0},
+ mask: 0x00000000ffffffff,
+ in: &RotateParams{Start: 32, End: 47, Amount: 0},
+ out: &RotateParams{Start: 32, End: 47, Amount: 0},
+ },
+ {
+ src: RotateParams{Start: 16, End: 47, Amount: 0},
+ mask: 0xffff00000000ffff,
+ in: nil,
+ out: nil,
+ },
+ {
+ src: RotateParams{Start: 0, End: 63, Amount: 0},
+ mask: 0xf7f0000000000000,
+ in: nil,
+ out: nil,
+ },
+ {
+ src: RotateParams{Start: 0, End: 63, Amount: 1},
+ mask: 0x000000000000ff00,
+ in: &RotateParams{Start: 47, End: 54, Amount: 1},
+ out: &RotateParams{Start: 48, End: 55, Amount: 1},
+ },
+ {
+ src: RotateParams{Start: 32, End: 63, Amount: 32},
+ mask: 0xffff00000000ffff,
+ in: &RotateParams{Start: 32, End: 47, Amount: 32},
+ out: &RotateParams{Start: 48, End: 63, Amount: 32},
+ },
+ {
+ src: RotateParams{Start: 0, End: 31, Amount: 32},
+ mask: 0x8000000000000000,
+ in: nil,
+ out: &RotateParams{Start: 0, End: 0, Amount: 32},
+ },
+ {
+ src: RotateParams{Start: 0, End: 31, Amount: 32},
+ mask: 0x0000000080000000,
+ in: &RotateParams{Start: 0, End: 0, Amount: 32},
+ out: nil,
+ },
+ }
+
+ eq := func(x, y *RotateParams) bool {
+ if x == nil && y == nil {
+ return true
+ }
+ if x == nil || y == nil {
+ return false
+ }
+ return *x == *y
+ }
+
+ for _, test := range tests {
+ if r := test.src.InMerge(test.mask); !eq(r, test.in) {
+ t.Errorf("%v merged with %#x (input): want %v, got %v", test.src, test.mask, test.in, r)
+ }
+ if r := test.src.OutMerge(test.mask); !eq(r, test.out) {
+ t.Errorf("%v merged with %#x (output): want %v, got %v", test.src, test.mask, test.out, r)
+ }
+ }
+}
diff --git a/src/cmd/internal/obj/sizeof_test.go b/src/cmd/internal/obj/sizeof_test.go
index b5e170c694..69e60473f5 100644
--- a/src/cmd/internal/obj/sizeof_test.go
+++ b/src/cmd/internal/obj/sizeof_test.go
@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
_64bit uintptr // size on 64bit platforms
}{
{Addr{}, 32, 48},
- {LSym{}, 76, 128},
+ {LSym{}, 72, 120},
{Prog{}, 132, 200},
}
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index d58877ee15..4515bdd0d3 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -38,6 +38,7 @@ import (
"log"
"math"
"sort"
+ "strings"
)
func Linknew(arch *LinkArch) *Link {
@@ -204,7 +205,9 @@ func (ctxt *Link) NumberSyms() {
// if Pkgpath is unknown, cannot hash symbols with relocations, as it
// may reference named symbols whose names are not fully expanded.
if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
- if len(s.P) <= 8 && len(s.R) == 0 { // we can use short hash only for symbols without relocations
+ if s.Size <= 8 && len(s.R) == 0 && !strings.HasPrefix(s.Name, "type.") {
+ // We can use short hash only for symbols without relocations.
+ // Don't use short hash for type symbols, as they need special handling.
s.PkgIdx = goobj.PkgIdxHashed64
s.SymIdx = hashed64idx
if hashed64idx != int32(len(ctxt.hashed64defs)) {
@@ -355,7 +358,8 @@ func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
}
func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym)) {
- pc := &fsym.Func.Pcln
+ fninfo := fsym.Func()
+ pc := &fninfo.Pcln
if flag&traverseAux == 0 {
// NB: should it become necessary to walk aux sym reloc references
// without walking the aux syms themselves, this can be changed.
@@ -386,7 +390,8 @@ func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent
fn(fsym, filesym)
}
}
- dwsyms := []*LSym{fsym.Func.dwarfRangesSym, fsym.Func.dwarfLocSym, fsym.Func.dwarfDebugLinesSym, fsym.Func.dwarfInfoSym}
+
+ dwsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym}
for _, dws := range dwsyms {
if dws == nil || dws.Size == 0 {
continue
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
index a30ccf0564..b9bacb7a22 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -175,9 +175,11 @@ func (p *Prog) WriteInstructionString(w io.Writer) {
sep = ", "
}
for i := range p.RestArgs {
- io.WriteString(w, sep)
- WriteDconv(w, p, &p.RestArgs[i])
- sep = ", "
+ if p.RestArgs[i].Pos == Source {
+ io.WriteString(w, sep)
+ WriteDconv(w, p, &p.RestArgs[i].Addr)
+ sep = ", "
+ }
}
if p.As == ATEXT {
@@ -198,6 +200,13 @@ func (p *Prog) WriteInstructionString(w io.Writer) {
if p.RegTo2 != REG_NONE {
fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2)))
}
+ for i := range p.RestArgs {
+ if p.RestArgs[i].Pos == Destination {
+ io.WriteString(w, sep)
+ WriteDconv(w, p, &p.RestArgs[i].Addr)
+ sep = ", "
+ }
+ }
}
func (ctxt *Link) NewProg() *Prog {
@@ -210,13 +219,30 @@ func (ctxt *Link) CanReuseProgs() bool {
return ctxt.Debugasm == 0
}
+// Dconv accepts an argument 'a' within a prog 'p' and returns a string
+// with a formatted version of the argument.
func Dconv(p *Prog, a *Addr) string {
buf := new(bytes.Buffer)
- WriteDconv(buf, p, a)
+ writeDconv(buf, p, a, false)
+ return buf.String()
+}
+
+// DconvDconvWithABIDetail accepts an argument 'a' within a prog 'p'
+// and returns a string with a formatted version of the argument, in
+// which text symbols are rendered with explicit ABI selectors.
+func DconvWithABIDetail(p *Prog, a *Addr) string {
+ buf := new(bytes.Buffer)
+ writeDconv(buf, p, a, true)
return buf.String()
}
+// WriteDconv accepts an argument 'a' within a prog 'p'
+// and writes a formatted version of the arg to the writer.
func WriteDconv(w io.Writer, p *Prog, a *Addr) {
+ writeDconv(w, p, a, false)
+}
+
+func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
switch a.Type {
default:
fmt.Fprintf(w, "type=%d", a.Type)
@@ -250,7 +276,7 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
case TYPE_BRANCH:
if a.Sym != nil {
- fmt.Fprintf(w, "%s(SB)", a.Sym.Name)
+ fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail))
} else if a.Target() != nil {
fmt.Fprint(w, a.Target().Pc)
} else {
@@ -259,7 +285,7 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
case TYPE_INDIR:
io.WriteString(w, "*")
- a.WriteNameTo(w)
+ a.writeNameTo(w, abiDetail)
case TYPE_MEM:
a.WriteNameTo(w)
@@ -299,7 +325,7 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
case TYPE_ADDR:
io.WriteString(w, "$")
- a.WriteNameTo(w)
+ a.writeNameTo(w, abiDetail)
case TYPE_SHIFT:
v := int(a.Offset)
@@ -335,6 +361,11 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
}
func (a *Addr) WriteNameTo(w io.Writer) {
+ a.writeNameTo(w, false)
+}
+
+func (a *Addr) writeNameTo(w io.Writer, abiDetail bool) {
+
switch a.Name {
default:
fmt.Fprintf(w, "name=%d", a.Name)
@@ -356,7 +387,7 @@ func (a *Addr) WriteNameTo(w io.Writer) {
reg = Rconv(int(a.Reg))
}
if a.Sym != nil {
- fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
+ fmt.Fprintf(w, "%s%s%s(%s)", a.Sym.Name, abiDecorate(a, abiDetail), offConv(a.Offset), reg)
} else {
fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
}
@@ -596,3 +627,10 @@ func Bool2int(b bool) int {
}
return i
}
+
+func abiDecorate(a *Addr, abiDetail bool) string {
+ if !abiDetail || a.Sym == nil {
+ return ""
+ }
+ return fmt.Sprintf("<%s>", a.Sym.ABI())
+}
diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go
index 70e8e51e65..2e9890d86c 100644
--- a/src/cmd/internal/obj/wasm/wasmobj.go
+++ b/src/cmd/internal/obj/wasm/wasmobj.go
@@ -129,7 +129,6 @@ var (
morestackNoCtxt *obj.LSym
gcWriteBarrier *obj.LSym
sigpanic *obj.LSym
- sigpanic0 *obj.LSym
deferreturn *obj.LSym
jmpdefer *obj.LSym
)
@@ -142,9 +141,8 @@ const (
func instinit(ctxt *obj.Link) {
morestack = ctxt.Lookup("runtime.morestack")
morestackNoCtxt = ctxt.Lookup("runtime.morestack_noctxt")
- gcWriteBarrier = ctxt.Lookup("runtime.gcWriteBarrier")
+ gcWriteBarrier = ctxt.LookupABI("runtime.gcWriteBarrier", obj.ABIInternal)
sigpanic = ctxt.LookupABI("runtime.sigpanic", obj.ABIInternal)
- sigpanic0 = ctxt.LookupABI("runtime.sigpanic", 0) // sigpanic called from assembly, which has ABI0
deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal)
// jmpdefer is defined in assembly as ABI0, but what we're
// looking for is the *call* to jmpdefer from the Go function
@@ -182,14 +180,14 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
return p
}
- framesize := s.Func.Text.To.Offset
+ framesize := s.Func().Text.To.Offset
if framesize < 0 {
panic("bad framesize")
}
- s.Func.Args = s.Func.Text.To.Val.(int32)
- s.Func.Locals = int32(framesize)
+ s.Func().Args = s.Func().Text.To.Val.(int32)
+ s.Func().Locals = int32(framesize)
- if s.Func.Text.From.Sym.Wrapper() {
+ if s.Func().Text.From.Sym.Wrapper() {
// if g._panic != nil && g._panic.argp == FP {
// g._panic.argp = bottom-of-frame
// }
@@ -222,7 +220,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
Offset: 0, // panic.argp
}
- p := s.Func.Text
+ p := s.Func().Text
p = appendp(p, AMOVD, gpanic, regAddr(REG_R0))
p = appendp(p, AGet, regAddr(REG_R0))
@@ -245,7 +243,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
if framesize > 0 {
- p := s.Func.Text
+ p := s.Func().Text
p = appendp(p, AGet, regAddr(REG_SP))
p = appendp(p, AI32Const, constAddr(framesize))
p = appendp(p, AI32Sub)
@@ -260,8 +258,8 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
pc := int64(0) // pc is only incremented when necessary, this avoids bloat of the BrTable instruction
var tableIdxs []uint64
tablePC := int64(0)
- base := ctxt.PosTable.Pos(s.Func.Text.Pos).Base()
- for p := s.Func.Text; p != nil; p = p.Link {
+ base := ctxt.PosTable.Pos(s.Func().Text.Pos).Base()
+ for p := s.Func().Text; p != nil; p = p.Link {
prevBase := base
base = ctxt.PosTable.Pos(p.Pos).Base()
switch p.As {
@@ -313,8 +311,8 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
tableIdxs = append(tableIdxs, uint64(numResumePoints))
s.Size = pc + 1
- if !s.Func.Text.From.Sym.NoSplit() {
- p := s.Func.Text
+ if !s.Func().Text.From.Sym.NoSplit() {
+ p := s.Func().Text
if framesize <= objabi.StackSmall {
// small stack: SP <= stackguard
@@ -352,7 +350,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
p = appendp(p, AIf)
p = appendp(p, obj.ACALL, constAddr(0))
- if s.Func.Text.From.Sym.NeedCtxt() {
+ if s.Func().Text.From.Sym.NeedCtxt() {
p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: morestack}
} else {
p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: morestackNoCtxt}
@@ -365,7 +363,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
var entryPointLoopBranches []*obj.Prog
var unwindExitBranches []*obj.Prog
currentDepth := 0
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABlock, ALoop, AIf:
currentDepth++
@@ -493,7 +491,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
// return value of call is on the top of the stack, indicating whether to unwind the WebAssembly stack
- if call.As == ACALLNORESUME && call.To.Sym != sigpanic && call.To.Sym != sigpanic0 { // sigpanic unwinds the stack, but it never resumes
+ if call.As == ACALLNORESUME && call.To.Sym != sigpanic { // sigpanic unwinds the stack, but it never resumes
// trying to unwind WebAssembly stack but call has no resume point, terminate with error
p = appendp(p, AIf)
p = appendp(p, obj.AUNDEF)
@@ -562,7 +560,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
}
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
switch p.From.Name {
case obj.NAME_AUTO:
p.From.Offset += int64(framesize)
@@ -712,7 +710,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
{
- p := s.Func.Text
+ p := s.Func().Text
if len(unwindExitBranches) > 0 {
p = appendp(p, ABlock) // unwindExit, used to return 1 when unwinding the stack
for _, b := range unwindExitBranches {
@@ -749,7 +747,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
currentDepth = 0
blockDepths := make(map[*obj.Prog]int)
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABlock, ALoop, AIf:
currentDepth++
@@ -850,7 +848,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
hasLocalSP = true
var regUsed [MAXREG - MINREG]bool
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
if p.From.Reg != 0 {
regUsed[p.From.Reg-MINREG] = true
}
@@ -896,7 +894,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
updateLocalSP(w)
}
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
switch p.As {
case AGet:
if p.From.Type != obj.TYPE_REG {
@@ -1007,6 +1005,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
panic("bad name for Call")
}
r := obj.Addrel(s)
+ r.Siz = 1 // actually variable sized
r.Off = int32(w.Len())
r.Type = objabi.R_CALL
if p.Mark&WasmImport != 0 {
@@ -1033,6 +1032,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
case AI32Const, AI64Const:
if p.From.Name == obj.NAME_EXTERN {
r := obj.Addrel(s)
+ r.Siz = 1 // actually variable sized
r.Off = int32(w.Len())
r.Type = objabi.R_ADDR
r.Sym = p.From.Sym
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index fb99c620ad..a6b85ac4a0 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -1851,9 +1851,9 @@ func spadjop(ctxt *obj.Link, l, q obj.As) obj.As {
return q
}
-// If the environment variable GOAMD64=alignedjumps the assembler will ensure that
-// no standalone or macro-fused jump will straddle or end on a 32 byte boundary
-// by inserting NOPs before the jumps
+// isJump returns whether p is a jump instruction.
+// It is used to ensure that no standalone or macro-fused jump will straddle
+// or end on a 32 byte boundary by inserting NOPs before the jumps.
func isJump(p *obj.Prog) bool {
return p.To.Target() != nil || p.As == obj.AJMP || p.As == obj.ACALL ||
p.As == obj.ARET || p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO
@@ -1987,11 +1987,6 @@ func makePjcCtx(ctxt *obj.Link) padJumpsCtx {
return padJumpsCtx(0)
}
- if objabi.GOAMD64 != "alignedjumps" {
- return padJumpsCtx(0)
-
- }
-
return padJumpsCtx(32)
}
@@ -2050,7 +2045,7 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Diag("x86 tables not initialized, call x86.instinit first")
}
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
if p.To.Type == obj.TYPE_BRANCH && p.To.Target() == nil {
p.To.SetTarget(p)
}
@@ -2085,7 +2080,7 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
var count int64 // rough count of number of instructions
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
count++
p.Back = branchShort // use short branches first time through
if q := p.To.Target(); q != nil && (q.Back&branchShort != 0) {
@@ -2100,19 +2095,20 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
var c int32
errors := ctxt.Errors
var nops []nopPad // Padding for a particular assembly (reuse slice storage if multiple assemblies)
+ nrelocs0 := len(s.R)
for {
// This loop continues while there are reasons to re-assemble
// whole block, like the presence of long forward jumps.
reAssemble := false
- for i := range s.R {
- s.R[i] = obj.Reloc{}
+ for i := range s.R[nrelocs0:] {
+ s.R[nrelocs0+i] = obj.Reloc{}
}
- s.R = s.R[:0]
+ s.R = s.R[:nrelocs0] // preserve marker relocations generated by the compiler
s.P = s.P[:0]
c = 0
var pPrev *obj.Prog
nops = nops[:0]
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
c0 := c
c = pjc.padJump(ctxt, s, p, c)
@@ -2226,7 +2222,7 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
// the first instruction.)
return p.From.Index == REG_TLS
}
- obj.MarkUnsafePoints(ctxt, s.Func.Text, newprog, useTLS, nil)
+ obj.MarkUnsafePoints(ctxt, s.Func().Text, newprog, useTLS, nil)
}
}
@@ -4269,7 +4265,7 @@ func (ab *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
args = append(args, ft)
}
for i := range p.RestArgs {
- args = append(args, oclass(ctxt, p, &p.RestArgs[i])*Ymax)
+ args = append(args, oclass(ctxt, p, &p.RestArgs[i].Addr)*Ymax)
}
if tt != Ynone*Ymax {
args = append(args, tt)
@@ -5437,10 +5433,10 @@ func (ab *AsmBuf) asmins(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
// unpackOps4 extracts 4 operands from p.
func unpackOps4(p *obj.Prog) (arg0, arg1, arg2, dst *obj.Addr) {
- return &p.From, &p.RestArgs[0], &p.RestArgs[1], &p.To
+ return &p.From, &p.RestArgs[0].Addr, &p.RestArgs[1].Addr, &p.To
}
// unpackOps5 extracts 5 operands from p.
func unpackOps5(p *obj.Prog) (arg0, arg1, arg2, arg3, dst *obj.Addr) {
- return &p.From, &p.RestArgs[0], &p.RestArgs[1], &p.RestArgs[2], &p.To
+ return &p.From, &p.RestArgs[0].Addr, &p.RestArgs[1].Addr, &p.RestArgs[2].Addr, &p.To
}
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 18a6afcd77..184fb4308b 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -324,9 +324,9 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
// flags and duffzero on 386 does not otherwise do so).
var sym *obj.LSym
if p.As == obj.ADUFFZERO {
- sym = ctxt.Lookup("runtime.duffzero")
+ sym = ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
} else {
- sym = ctxt.Lookup("runtime.duffcopy")
+ sym = ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
}
offset := p.To.Offset
p.As = mov
@@ -563,11 +563,11 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
}
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
- p := cursym.Func.Text
+ p := cursym.Func().Text
autoffset := int32(p.To.Offset)
if autoffset < 0 {
autoffset = 0
@@ -602,12 +602,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
textarg := int64(p.To.Val.(int32))
- cursym.Func.Args = int32(textarg)
- cursym.Func.Locals = int32(p.To.Offset)
+ cursym.Func().Args = int32(textarg)
+ cursym.Func().Locals = int32(p.To.Offset)
// TODO(rsc): Remove.
- if ctxt.Arch.Family == sys.I386 && cursym.Func.Locals < 0 {
- cursym.Func.Locals = 0
+ if ctxt.Arch.Family == sys.I386 && cursym.Func().Locals < 0 {
+ cursym.Func().Locals = 0
}
// TODO(rsc): Remove 'ctxt.Arch.Family == sys.AMD64 &&'.
@@ -642,7 +642,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p = load_g_cx(ctxt, p, newprog) // load g into CX
}
- if !cursym.Func.Text.From.Sym.NoSplit() {
+ if !cursym.Func().Text.From.Sym.NoSplit() {
p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg)) // emit split check
}
@@ -690,7 +690,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Reg = REG_BP
}
- if cursym.Func.Text.From.Sym.Wrapper() {
+ if cursym.Func().Text.From.Sym.Wrapper() {
// if g._panic != nil && g._panic.argp == FP {
// g._panic.argp = bottom-of-frame
// }
@@ -808,7 +808,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
var deltasp int32
- for p = cursym.Func.Text; p != nil; p = p.Link {
+ for p = cursym.Func().Text; p != nil; p = p.Link {
pcsize := ctxt.Arch.RegSize
switch p.From.Name {
case obj.NAME_AUTO:
@@ -1103,7 +1103,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
end := ctxt.EndUnsafePoint(jls, newprog, -1)
var last *obj.Prog
- for last = cursym.Func.Text; last.Link != nil; last = last.Link {
+ for last = cursym.Func().Text; last.Link != nil; last = last.Link {
}
// Now we are at the end of the function, but logically
@@ -1117,7 +1117,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
pcdata = ctxt.StartUnsafePoint(pcdata, newprog)
call := obj.Appendp(pcdata, newprog)
- call.Pos = cursym.Func.Text.Pos
+ call.Pos = cursym.Func().Text.Pos
call.As = obj.ACALL
call.To.Type = obj.TYPE_BRANCH
call.To.Name = obj.NAME_EXTERN
@@ -1125,7 +1125,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
switch {
case cursym.CFunc():
morestack = "runtime.morestackc"
- case !cursym.Func.Text.From.Sym.NeedCtxt():
+ case !cursym.Func().Text.From.Sym.NeedCtxt():
morestack = "runtime.morestack_noctxt"
}
call.To.Sym = ctxt.Lookup(morestack)
@@ -1144,7 +1144,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
jmp := obj.Appendp(pcdata, newprog)
jmp.As = obj.AJMP
jmp.To.Type = obj.TYPE_BRANCH
- jmp.To.SetTarget(cursym.Func.Text.Link)
+ jmp.To.SetTarget(cursym.Func().Text.Link)
jmp.Spadj = +framesize
jls.To.SetTarget(call)
diff --git a/src/cmd/internal/objabi/flag.go b/src/cmd/internal/objabi/flag.go
index 79ad2ccf74..3fd73f3c57 100644
--- a/src/cmd/internal/objabi/flag.go
+++ b/src/cmd/internal/objabi/flag.go
@@ -5,6 +5,7 @@
package objabi
import (
+ "bytes"
"flag"
"fmt"
"io"
@@ -59,6 +60,9 @@ func expandArgs(in []string) (out []string) {
log.Fatal(err)
}
args := strings.Split(strings.TrimSpace(strings.Replace(string(slurp), "\r", "", -1)), "\n")
+ for i, arg := range args {
+ args[i] = DecodeArg(arg)
+ }
out = append(out, expandArgs(args)...)
} else if out != nil {
out = append(out, s)
@@ -160,3 +164,38 @@ func (f fn1) Set(s string) error {
}
func (f fn1) String() string { return "" }
+
+// DecodeArg decodes an argument.
+//
+// This function is public for testing with the parallel encoder.
+func DecodeArg(arg string) string {
+ // If no encoding, fastpath out.
+ if !strings.ContainsAny(arg, "\\\n") {
+ return arg
+ }
+
+ // We can't use strings.Builder as this must work at bootstrap.
+ var b bytes.Buffer
+ var wasBS bool
+ for _, r := range arg {
+ if wasBS {
+ switch r {
+ case '\\':
+ b.WriteByte('\\')
+ case 'n':
+ b.WriteByte('\n')
+ default:
+ // This shouldn't happen. The only backslashes that reach here
+ // should encode '\n' and '\\' exclusively.
+ panic("badly formatted input")
+ }
+ } else if r == '\\' {
+ wasBS = true
+ continue
+ } else {
+ b.WriteRune(r)
+ }
+ wasBS = false
+ }
+ return b.String()
+}
diff --git a/src/cmd/internal/objabi/flag_test.go b/src/cmd/internal/objabi/flag_test.go
new file mode 100644
index 0000000000..935b9c2193
--- /dev/null
+++ b/src/cmd/internal/objabi/flag_test.go
@@ -0,0 +1,26 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objabi
+
+import "testing"
+
+func TestDecodeArg(t *testing.T) {
+ t.Parallel()
+ tests := []struct {
+ arg, want string
+ }{
+ {"", ""},
+ {"hello", "hello"},
+ {"hello\\n", "hello\n"},
+ {"hello\\nthere", "hello\nthere"},
+ {"hello\\\\there", "hello\\there"},
+ {"\\\\\\n", "\\\n"},
+ }
+ for _, test := range tests {
+ if got := DecodeArg(test.arg); got != test.want {
+ t.Errorf("decodoeArg(%q) = %q, want %q", test.arg, got, test.want)
+ }
+ }
+}
diff --git a/src/cmd/internal/objabi/funcdata.go b/src/cmd/internal/objabi/funcdata.go
index c9480bf2f0..faa2863325 100644
--- a/src/cmd/internal/objabi/funcdata.go
+++ b/src/cmd/internal/objabi/funcdata.go
@@ -11,17 +11,15 @@ package objabi
// ../../../runtime/symtab.go.
const (
- PCDATA_RegMapIndex = 0 // if !go115ReduceLiveness
- PCDATA_UnsafePoint = 0 // if go115ReduceLiveness
+ PCDATA_UnsafePoint = 0
PCDATA_StackMapIndex = 1
PCDATA_InlTreeIndex = 2
FUNCDATA_ArgsPointerMaps = 0
FUNCDATA_LocalsPointerMaps = 1
- FUNCDATA_RegPointerMaps = 2 // if !go115ReduceLiveness
- FUNCDATA_StackObjects = 3
- FUNCDATA_InlTree = 4
- FUNCDATA_OpenCodedDeferInfo = 5
+ FUNCDATA_StackObjects = 2
+ FUNCDATA_InlTree = 3
+ FUNCDATA_OpenCodedDeferInfo = 4
// ArgsSizeUnknown is set in Func.argsize to mark all functions
// whose argument size is unknown (C vararg functions, and
@@ -32,11 +30,6 @@ const (
// Special PCDATA values.
const (
- // PCDATA_RegMapIndex values.
- //
- // Only if !go115ReduceLiveness.
- PCDATA_RegMapUnsafe = PCDATA_UnsafePointUnsafe // Unsafe for async preemption
-
// PCDATA_UnsafePoint values.
PCDATA_UnsafePointSafe = -1 // Safe for async preemption
PCDATA_UnsafePointUnsafe = -2 // Unsafe for async preemption
diff --git a/src/cmd/internal/objabi/funcid.go b/src/cmd/internal/objabi/funcid.go
index 6c9336f31c..1d098ee172 100644
--- a/src/cmd/internal/objabi/funcid.go
+++ b/src/cmd/internal/objabi/funcid.go
@@ -26,7 +26,7 @@ const (
FuncID_gcBgMarkWorker
FuncID_systemstack_switch
FuncID_systemstack
- FuncID_cgocallback_gofunc
+ FuncID_cgocallback
FuncID_gogo
FuncID_externalthreadhandler
FuncID_debugCallV1
@@ -70,8 +70,8 @@ func GetFuncID(name string, isWrapper bool) FuncID {
return FuncID_systemstack_switch
case "runtime.systemstack":
return FuncID_systemstack
- case "runtime.cgocallback_gofunc":
- return FuncID_cgocallback_gofunc
+ case "runtime.cgocallback":
+ return FuncID_cgocallback
case "runtime.gogo":
return FuncID_gogo
case "runtime.externalthreadhandler":
diff --git a/src/cmd/internal/objabi/head.go b/src/cmd/internal/objabi/head.go
index 95b8db3809..48ff292307 100644
--- a/src/cmd/internal/objabi/head.go
+++ b/src/cmd/internal/objabi/head.go
@@ -54,7 +54,7 @@ func (h *HeadType) Set(s string) error {
switch s {
case "aix":
*h = Haix
- case "darwin":
+ case "darwin", "ios":
*h = Hdarwin
case "dragonfly":
*h = Hdragonfly
diff --git a/src/cmd/internal/objabi/line.go b/src/cmd/internal/objabi/line.go
index 178c8363d9..0733b65138 100644
--- a/src/cmd/internal/objabi/line.go
+++ b/src/cmd/internal/objabi/line.go
@@ -37,25 +37,36 @@ func AbsFile(dir, file, rewrites string) string {
abs = filepath.Join(dir, file)
}
+ abs, rewritten := ApplyRewrites(abs, rewrites)
+ if !rewritten && hasPathPrefix(abs, GOROOT) {
+ abs = "$GOROOT" + abs[len(GOROOT):]
+ }
+
+ if abs == "" {
+ abs = "??"
+ }
+ return abs
+}
+
+// ApplyRewrites returns the filename for file in the given directory,
+// as rewritten by the rewrites argument.
+//
+// The rewrites argument is a ;-separated list of rewrites.
+// Each rewrite is of the form "prefix" or "prefix=>replace",
+// where prefix must match a leading sequence of path elements
+// and is either removed entirely or replaced by the replacement.
+func ApplyRewrites(file, rewrites string) (string, bool) {
start := 0
for i := 0; i <= len(rewrites); i++ {
if i == len(rewrites) || rewrites[i] == ';' {
- if new, ok := applyRewrite(abs, rewrites[start:i]); ok {
- abs = new
- goto Rewritten
+ if new, ok := applyRewrite(file, rewrites[start:i]); ok {
+ return new, true
}
start = i + 1
}
}
- if hasPathPrefix(abs, GOROOT) {
- abs = "$GOROOT" + abs[len(GOROOT):]
- }
-Rewritten:
- if abs == "" {
- abs = "??"
- }
- return abs
+ return file, false
}
// applyRewrite applies the rewrite to the path,
diff --git a/src/cmd/internal/objabi/path.go b/src/cmd/internal/objabi/path.go
index 2a42179a36..fd1c9981c6 100644
--- a/src/cmd/internal/objabi/path.go
+++ b/src/cmd/internal/objabi/path.go
@@ -39,3 +39,25 @@ func PathToPrefix(s string) string {
return string(p)
}
+
+// IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it
+// belongs to the collection of "runtime-related" packages, including
+// "runtime" itself, "reflect", "syscall", and the
+// "runtime/internal/*" packages. The compiler and/or assembler in
+// some cases need to be aware of when they are building such a
+// package, for example to enable features such as ABI selectors in
+// assembly sources.
+func IsRuntimePackagePath(pkgpath string) bool {
+ rval := false
+ switch pkgpath {
+ case "runtime":
+ rval = true
+ case "reflect":
+ rval = true
+ case "syscall":
+ rval = true
+ default:
+ rval = strings.HasPrefix(pkgpath, "runtime/internal")
+ }
+ return rval
+}
diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go
index f029a3c396..649f690194 100644
--- a/src/cmd/internal/objabi/reloctype.go
+++ b/src/cmd/internal/objabi/reloctype.go
@@ -89,6 +89,17 @@ const (
// should be linked into the final binary, even if there are no other
// direct references. (This is used for types reachable by reflection.)
R_USETYPE
+ // R_USEIFACE marks a type is converted to an interface in the function this
+ // relocation is applied to. The target is a type descriptor.
+ // This is a marker relocation (0-sized), for the linker's reachabililty
+ // analysis.
+ R_USEIFACE
+ // R_USEIFACEMETHOD marks an interface method that is used in the function
+ // this relocation is applied to. The target is an interface type descriptor.
+ // The addend is the offset of the method in the type descriptor.
+ // This is a marker relocation (0-sized), for the linker's reachabililty
+ // analysis.
+ R_USEIFACEMETHOD
// R_METHODOFF resolves to a 32-bit offset from the beginning of the section
// holding the data being relocated to the referenced symbol.
// It is a variant of R_ADDROFF used when linking from the uncommonType of a
@@ -145,6 +156,9 @@ const (
// R_ARM64_LDST8 sets a LD/ST immediate value to bits [11:0] of a local address.
R_ARM64_LDST8
+ // R_ARM64_LDST16 sets a LD/ST immediate value to bits [11:1] of a local address.
+ R_ARM64_LDST16
+
// R_ARM64_LDST32 sets a LD/ST immediate value to bits [11:2] of a local address.
R_ARM64_LDST32
@@ -212,6 +226,14 @@ const (
// AUIPC + S-type instruction pair.
R_RISCV_PCREL_STYPE
+ // R_RISCV_TLS_IE_ITYPE resolves a 32-bit TLS initial-exec TOC offset
+ // address using an AUIPC + I-type instruction pair.
+ R_RISCV_TLS_IE_ITYPE
+
+ // R_RISCV_TLS_IE_STYPE resolves a 32-bit TLS initial-exec TOC offset
+ // address using an AUIPC + S-type instruction pair.
+ R_RISCV_TLS_IE_STYPE
+
// R_PCRELDBL relocates s390x 2-byte aligned PC-relative addresses.
// TODO(mundaym): remove once variants can be serialized - see issue 14218.
R_PCRELDBL
diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go
index 83dfe71e07..658a44f8b8 100644
--- a/src/cmd/internal/objabi/reloctype_string.go
+++ b/src/cmd/internal/objabi/reloctype_string.go
@@ -4,9 +4,75 @@ package objabi
import "strconv"
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[R_ADDR-1]
+ _ = x[R_ADDRPOWER-2]
+ _ = x[R_ADDRARM64-3]
+ _ = x[R_ADDRMIPS-4]
+ _ = x[R_ADDROFF-5]
+ _ = x[R_WEAKADDROFF-6]
+ _ = x[R_SIZE-7]
+ _ = x[R_CALL-8]
+ _ = x[R_CALLARM-9]
+ _ = x[R_CALLARM64-10]
+ _ = x[R_CALLIND-11]
+ _ = x[R_CALLPOWER-12]
+ _ = x[R_CALLMIPS-13]
+ _ = x[R_CALLRISCV-14]
+ _ = x[R_CONST-15]
+ _ = x[R_PCREL-16]
+ _ = x[R_TLS_LE-17]
+ _ = x[R_TLS_IE-18]
+ _ = x[R_GOTOFF-19]
+ _ = x[R_PLT0-20]
+ _ = x[R_PLT1-21]
+ _ = x[R_PLT2-22]
+ _ = x[R_USEFIELD-23]
+ _ = x[R_USETYPE-24]
+ _ = x[R_USEIFACE-25]
+ _ = x[R_USEIFACEMETHOD-26]
+ _ = x[R_METHODOFF-27]
+ _ = x[R_POWER_TOC-28]
+ _ = x[R_GOTPCREL-29]
+ _ = x[R_JMPMIPS-30]
+ _ = x[R_DWARFSECREF-31]
+ _ = x[R_DWARFFILEREF-32]
+ _ = x[R_ARM64_TLS_LE-33]
+ _ = x[R_ARM64_TLS_IE-34]
+ _ = x[R_ARM64_GOTPCREL-35]
+ _ = x[R_ARM64_GOT-36]
+ _ = x[R_ARM64_PCREL-37]
+ _ = x[R_ARM64_LDST8-38]
+ _ = x[R_ARM64_LDST16-39]
+ _ = x[R_ARM64_LDST32-40]
+ _ = x[R_ARM64_LDST64-41]
+ _ = x[R_ARM64_LDST128-42]
+ _ = x[R_POWER_TLS_LE-43]
+ _ = x[R_POWER_TLS_IE-44]
+ _ = x[R_POWER_TLS-45]
+ _ = x[R_ADDRPOWER_DS-46]
+ _ = x[R_ADDRPOWER_GOT-47]
+ _ = x[R_ADDRPOWER_PCREL-48]
+ _ = x[R_ADDRPOWER_TOCREL-49]
+ _ = x[R_ADDRPOWER_TOCREL_DS-50]
+ _ = x[R_RISCV_PCREL_ITYPE-51]
+ _ = x[R_RISCV_PCREL_STYPE-52]
+ _ = x[R_RISCV_TLS_IE_ITYPE-53]
+ _ = x[R_RISCV_TLS_IE_STYPE-54]
+ _ = x[R_PCRELDBL-55]
+ _ = x[R_ADDRMIPSU-56]
+ _ = x[R_ADDRMIPSTLS-57]
+ _ = x[R_ADDRCUOFF-58]
+ _ = x[R_WASMIMPORT-59]
+ _ = x[R_XCOFFREF-60]
+}
+
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 219, 230, 240, 249, 262, 276, 290, 304, 320, 331, 344, 357, 371, 385, 400, 414, 428, 439, 453, 468, 485, 503, 524, 543, 562, 572, 583, 596, 607, 619, 629}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 234, 245, 256, 266, 275, 288, 302, 316, 330, 346, 357, 370, 383, 397, 411, 425, 440, 454, 468, 479, 493, 508, 525, 543, 564, 583, 602, 622, 642, 652, 663, 676, 687, 699, 709}
func (i RelocType) String() string {
i -= 1
diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go
index d2d6fdbda8..a73ab479a1 100644
--- a/src/cmd/internal/objabi/util.go
+++ b/src/cmd/internal/objabi/util.go
@@ -25,7 +25,6 @@ var (
GOARCH = envOr("GOARCH", defaultGOARCH)
GOOS = envOr("GOOS", defaultGOOS)
GO386 = envOr("GO386", defaultGO386)
- GOAMD64 = goamd64()
GOARM = goarm()
GOMIPS = gomips()
GOMIPS64 = gomips64()
@@ -37,17 +36,16 @@ var (
const (
ElfRelocOffset = 256
- MachoRelocOffset = 2048 // reserve enough space for ELF relocations
- Go115AMD64 = "alignedjumps" // Should be "alignedjumps" or "normaljumps"; this replaces environment variable introduced in CL 219357.
+ MachoRelocOffset = 2048 // reserve enough space for ELF relocations
)
-// TODO(1.16): assuming no issues in 1.15 release, remove this and related constant.
-func goamd64() string {
- return Go115AMD64
-}
-
func goarm() int {
- switch v := envOr("GOARM", defaultGOARM); v {
+ def := defaultGOARM
+ if GOOS == "android" && GOARCH == "arm" {
+ // Android arm devices always support GOARM=7.
+ def = "7"
+ }
+ switch v := envOr("GOARM", def); v {
case "5":
return 5
case "6":
@@ -139,7 +137,7 @@ func init() {
}
// Note: must agree with runtime.framepointer_enabled.
-var Framepointer_enabled = GOARCH == "amd64" || GOARCH == "arm64" && (GOOS == "linux" || GOOS == "darwin")
+var Framepointer_enabled = GOARCH == "amd64" || GOARCH == "arm64" && (GOOS == "linux" || GOOS == "darwin" || GOOS == "ios")
func addexp(s string) {
// Could do general integer parsing here, but the runtime copy doesn't yet.
diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go
index af9ada3324..f19bec5dcb 100644
--- a/src/cmd/internal/objfile/goobj.go
+++ b/src/cmd/internal/objfile/goobj.go
@@ -234,7 +234,15 @@ func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
if f.arch == nil {
return "", 0, nil
}
- pcdataBase := r.PcdataBase()
+ getSymData := func(s goobj.SymRef) []byte {
+ if s.PkgIdx != goobj.PkgIdxHashed {
+ // We don't need the data for non-hashed symbols, yet.
+ panic("not supported")
+ }
+ i := uint32(s.SymIdx + uint32(r.NSym()+r.NHashed64def()))
+ return r.BytesAt(r.DataOff(i), r.DataSize(i))
+ }
+
ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef())
for i := uint32(0); i < ndef; i++ {
osym := r.Sym(i)
@@ -259,15 +267,11 @@ func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
}
b := r.BytesAt(r.DataOff(isym), r.DataSize(isym))
var info *goobj.FuncInfo
- lengths := info.ReadFuncInfoLengths(b)
- off, end := info.ReadPcline(b)
- pcline := r.BytesAt(pcdataBase+off, int(end-off))
+ pcline := getSymData(info.ReadPcline(b))
line := int(pcValue(pcline, pc-addr, f.arch))
- off, end = info.ReadPcfile(b)
- pcfile := r.BytesAt(pcdataBase+off, int(end-off))
+ pcfile := getSymData(info.ReadPcfile(b))
fileID := pcValue(pcfile, pc-addr, f.arch)
- globalFileID := info.ReadFile(b, lengths.FileOff, uint32(fileID))
- fileName := r.File(int(globalFileID))
+ fileName := r.File(int(fileID))
// Note: we provide only the name in the Func structure.
// We could provide more if needed.
return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: osym.Name(r)}}
diff --git a/src/cmd/internal/objfile/macho.go b/src/cmd/internal/objfile/macho.go
index fdb7e76dfc..1d6963f7c4 100644
--- a/src/cmd/internal/objfile/macho.go
+++ b/src/cmd/internal/objfile/macho.go
@@ -60,7 +60,7 @@ func (f *machoFile) symbols() ([]Sym, error) {
} else if int(s.Sect) <= len(f.macho.Sections) {
sect := f.macho.Sections[s.Sect-1]
switch sect.Seg {
- case "__TEXT":
+ case "__TEXT", "__DATA_CONST":
sym.Code = 'R'
case "__DATA":
sym.Code = 'D'
diff --git a/src/cmd/internal/pkgpath/pkgpath.go b/src/cmd/internal/pkgpath/pkgpath.go
new file mode 100644
index 0000000000..40a040a81a
--- /dev/null
+++ b/src/cmd/internal/pkgpath/pkgpath.go
@@ -0,0 +1,174 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkgpath determines the package path used by gccgo/GoLLVM symbols.
+// This package is not used for the gc compiler.
+package pkgpath
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strings"
+)
+
+// ToSymbolFunc returns a function that may be used to convert a
+// package path into a string suitable for use as a symbol.
+// cmd is the gccgo/GoLLVM compiler in use, and tmpdir is a temporary
+// directory to pass to ioutil.TempFile.
+// For example, this returns a function that converts "net/http"
+// into a string like "net..z2fhttp". The actual string varies for
+// different gccgo/GoLLVM versions, which is why this returns a function
+// that does the conversion appropriate for the compiler in use.
+func ToSymbolFunc(cmd, tmpdir string) (func(string) string, error) {
+ // To determine the scheme used by cmd, we compile a small
+ // file and examine the assembly code. Older versions of gccgo
+ // use a simple mangling scheme where there can be collisions
+ // between packages whose paths are different but mangle to
+ // the same string. More recent versions use a new mangler
+ // that avoids these collisions.
+ const filepat = "*_gccgo_manglechck.go"
+ f, err := ioutil.TempFile(tmpdir, filepat)
+ if err != nil {
+ return nil, err
+ }
+ gofilename := f.Name()
+ f.Close()
+ defer os.Remove(gofilename)
+
+ if err := ioutil.WriteFile(gofilename, []byte(mangleCheckCode), 0644); err != nil {
+ return nil, err
+ }
+
+ command := exec.Command(cmd, "-S", "-o", "-", gofilename)
+ buf, err := command.Output()
+ if err != nil {
+ return nil, err
+ }
+
+ // Original mangling: go.l__ufer.Run
+ // Mangling v2: go.l..u00e4ufer.Run
+ // Mangling v3: go_0l_u00e4ufer.Run
+ if bytes.Contains(buf, []byte("go_0l_u00e4ufer.Run")) {
+ return toSymbolV3, nil
+ } else if bytes.Contains(buf, []byte("go.l..u00e4ufer.Run")) {
+ return toSymbolV2, nil
+ } else if bytes.Contains(buf, []byte("go.l__ufer.Run")) {
+ return toSymbolV1, nil
+ } else {
+ return nil, errors.New(cmd + ": unrecognized mangling scheme")
+ }
+}
+
+// mangleCheckCode is the package we compile to determine the mangling scheme.
+const mangleCheckCode = `
+package läufer
+func Run(x int) int {
+ return 1
+}
+`
+
+// toSymbolV1 converts a package path using the original mangling scheme.
+func toSymbolV1(ppath string) string {
+ clean := func(r rune) rune {
+ switch {
+ case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+ '0' <= r && r <= '9':
+ return r
+ }
+ return '_'
+ }
+ return strings.Map(clean, ppath)
+}
+
+// toSymbolV2 converts a package path using the second mangling scheme.
+func toSymbolV2(ppath string) string {
+ // This has to build at boostrap time, so it has to build
+ // with Go 1.4, so we don't use strings.Builder.
+ bsl := make([]byte, 0, len(ppath))
+ changed := false
+ for _, c := range ppath {
+ if ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_' {
+ bsl = append(bsl, byte(c))
+ continue
+ }
+ var enc string
+ switch {
+ case c == '.':
+ enc = ".x2e"
+ case c < 0x80:
+ enc = fmt.Sprintf("..z%02x", c)
+ case c < 0x10000:
+ enc = fmt.Sprintf("..u%04x", c)
+ default:
+ enc = fmt.Sprintf("..U%08x", c)
+ }
+ bsl = append(bsl, enc...)
+ changed = true
+ }
+ if !changed {
+ return ppath
+ }
+ return string(bsl)
+}
+
+// v3UnderscoreCodes maps from a character that supports an underscore
+// encoding to the underscore encoding character.
+var v3UnderscoreCodes = map[byte]byte{
+ '_': '_',
+ '.': '0',
+ '/': '1',
+ '*': '2',
+ ',': '3',
+ '{': '4',
+ '}': '5',
+ '[': '6',
+ ']': '7',
+ '(': '8',
+ ')': '9',
+ '"': 'a',
+ ' ': 'b',
+ ';': 'c',
+}
+
+// toSymbolV3 converts a package path using the third mangling scheme.
+func toSymbolV3(ppath string) string {
+ // This has to build at boostrap time, so it has to build
+ // with Go 1.4, so we don't use strings.Builder.
+ bsl := make([]byte, 0, len(ppath))
+ changed := false
+ for _, c := range ppath {
+ if ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') {
+ bsl = append(bsl, byte(c))
+ continue
+ }
+
+ if c < 0x80 {
+ if u, ok := v3UnderscoreCodes[byte(c)]; ok {
+ bsl = append(bsl, '_', u)
+ changed = true
+ continue
+ }
+ }
+
+ var enc string
+ switch {
+ case c < 0x80:
+ enc = fmt.Sprintf("_x%02x", c)
+ case c < 0x10000:
+ enc = fmt.Sprintf("_u%04x", c)
+ default:
+ enc = fmt.Sprintf("_U%08x", c)
+ }
+ bsl = append(bsl, enc...)
+ changed = true
+ }
+ if !changed {
+ return ppath
+ }
+ return string(bsl)
+}
diff --git a/src/cmd/internal/pkgpath/pkgpath_test.go b/src/cmd/internal/pkgpath/pkgpath_test.go
new file mode 100644
index 0000000000..232e803a60
--- /dev/null
+++ b/src/cmd/internal/pkgpath/pkgpath_test.go
@@ -0,0 +1,141 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkgpath
+
+import (
+ "os"
+ "testing"
+)
+
+const testEnvName = "GO_PKGPATH_TEST_COMPILER"
+
+// This init function supports TestToSymbolFunc. For simplicity,
+// we use the test binary itself as a sample gccgo driver.
+// We set an environment variable to specify how it should behave.
+func init() {
+ switch os.Getenv(testEnvName) {
+ case "":
+ return
+ case "v1":
+ os.Stdout.WriteString(`.string "go.l__ufer.Run"`)
+ os.Exit(0)
+ case "v2":
+ os.Stdout.WriteString(`.string "go.l..u00e4ufer.Run"`)
+ os.Exit(0)
+ case "v3":
+ os.Stdout.WriteString(`.string "go_0l_u00e4ufer.Run"`)
+ os.Exit(0)
+ case "error":
+ os.Stdout.WriteString(`unknown string`)
+ os.Exit(0)
+ }
+}
+
+func TestToSymbolFunc(t *testing.T) {
+ const input = "pä世🜃"
+ tests := []struct {
+ env string
+ fail bool
+ mangled string
+ }{
+ {
+ env: "v1",
+ mangled: "p___",
+ },
+ {
+ env: "v2",
+ mangled: "p..u00e4..u4e16..U0001f703",
+ },
+ {
+ env: "v3",
+ mangled: "p_u00e4_u4e16_U0001f703",
+ },
+ {
+ env: "error",
+ fail: true,
+ },
+ }
+
+ cmd := os.Args[0]
+ tmpdir := t.TempDir()
+
+ defer os.Unsetenv(testEnvName)
+
+ for _, test := range tests {
+ t.Run(test.env, func(t *testing.T) {
+ os.Setenv(testEnvName, test.env)
+
+ fn, err := ToSymbolFunc(cmd, tmpdir)
+ if err != nil {
+ if !test.fail {
+ t.Errorf("ToSymbolFunc(%q, %q): unexpected error %v", cmd, tmpdir, err)
+ }
+ } else if test.fail {
+ t.Errorf("ToSymbolFunc(%q, %q) succeeded but expected to fail", cmd, tmpdir)
+ } else if got, want := fn(input), test.mangled; got != want {
+ t.Errorf("ToSymbolFunc(%q, %q)(%q) = %q, want %q", cmd, tmpdir, input, got, want)
+ }
+ })
+ }
+}
+
+var symbolTests = []struct {
+ input, v1, v2, v3 string
+}{
+ {
+ "",
+ "",
+ "",
+ "",
+ },
+ {
+ "bytes",
+ "bytes",
+ "bytes",
+ "bytes",
+ },
+ {
+ "net/http",
+ "net_http",
+ "net..z2fhttp",
+ "net_1http",
+ },
+ {
+ "golang.org/x/net/http",
+ "golang_org_x_net_http",
+ "golang.x2eorg..z2fx..z2fnet..z2fhttp",
+ "golang_0org_1x_1net_1http",
+ },
+ {
+ "pä世.🜃",
+ "p____",
+ "p..u00e4..u4e16.x2e..U0001f703",
+ "p_u00e4_u4e16_0_U0001f703",
+ },
+}
+
+func TestV1(t *testing.T) {
+ for _, test := range symbolTests {
+ if got, want := toSymbolV1(test.input), test.v1; got != want {
+ t.Errorf("toSymbolV1(%q) = %q, want %q", test.input, got, want)
+ }
+ }
+}
+
+func TestV2(t *testing.T) {
+ for _, test := range symbolTests {
+ if got, want := toSymbolV2(test.input), test.v2; got != want {
+ t.Errorf("toSymbolV2(%q) = %q, want %q", test.input, got, want)
+ }
+ }
+}
+
+func TestV3(t *testing.T) {
+ for _, test := range symbolTests {
+ if got, want := toSymbolV3(test.input), test.v3; got != want {
+ t.Errorf("toSymbolV3(%q) = %q, want %q", test.input, got, want)
+ }
+ }
+}
diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go
index c27b3b986d..ef7c017bd4 100644
--- a/src/cmd/internal/sys/supported.go
+++ b/src/cmd/internal/sys/supported.go
@@ -13,7 +13,9 @@ func RaceDetectorSupported(goos, goarch string) bool {
switch goos {
case "linux":
return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64"
- case "darwin", "freebsd", "netbsd", "windows":
+ case "darwin":
+ return goarch == "amd64" || goarch == "arm64"
+ case "freebsd", "netbsd", "windows":
return goarch == "amd64"
default:
return false
@@ -32,13 +34,14 @@ func MSanSupported(goos, goarch string) bool {
}
// MustLinkExternal reports whether goos/goarch requires external linking.
+// (This is the opposite of internal/testenv.CanInternalLink. Keep them in sync.)
func MustLinkExternal(goos, goarch string) bool {
switch goos {
case "android":
if goarch != "arm64" {
return true
}
- case "darwin":
+ case "ios":
if goarch == "arm64" {
return true
}
@@ -69,7 +72,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
"freebsd/amd64",
- "darwin/amd64",
+ "darwin/amd64", "darwin/arm64",
"windows/amd64", "windows/386":
return true
}
@@ -83,10 +86,11 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
case "pie":
switch platform {
- case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
+ case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
"freebsd/amd64",
- "darwin/amd64",
+ "darwin/amd64", "darwin/arm64",
+ "ios/amd64", "ios/arm64",
"aix/ppc64",
"windows/386", "windows/amd64", "windows/arm":
return true
@@ -104,7 +108,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
switch platform {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le",
"android/amd64", "android/arm", "android/arm64", "android/386",
- "darwin/amd64",
+ "darwin/amd64", "darwin/arm64",
"freebsd/amd64":
return true
}
@@ -114,3 +118,14 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
return false
}
}
+
+func InternalLinkPIESupported(goos, goarch string) bool {
+ switch goos + "/" + goarch {
+ case "darwin/amd64", "darwin/arm64",
+ "linux/amd64", "linux/arm64",
+ "android/arm64",
+ "windows-amd64", "windows-386", "windows-arm":
+ return true
+ }
+ return false
+}
diff --git a/src/cmd/internal/sys/supported_test.go b/src/cmd/internal/sys/supported_test.go
new file mode 100644
index 0000000000..1217814af5
--- /dev/null
+++ b/src/cmd/internal/sys/supported_test.go
@@ -0,0 +1,18 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+import (
+ "internal/testenv"
+ "runtime"
+ "testing"
+)
+
+func TestMustLinkExternalMatchesTestenv(t *testing.T) {
+ // MustLinkExternal and testenv.CanInternalLink are the exact opposite.
+ if b := MustLinkExternal(runtime.GOOS, runtime.GOARCH); b != !testenv.CanInternalLink() {
+ t.Fatalf("MustLinkExternal() == %v, testenv.CanInternalLink() == %v, don't match", b, testenv.CanInternalLink())
+ }
+}