]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/link: support cgo internal/linking on darwin/arm64
authorCherry Zhang <cherryyz@google.com>
Thu, 15 Oct 2020 01:15:37 +0000 (21:15 -0400)
committerCherry Zhang <cherryyz@google.com>
Tue, 20 Oct 2020 02:25:52 +0000 (02:25 +0000)
Cgo programs work as well. Still not enabled by default for now.

Enable internal linking tests.

Updates #38485.

Change-Id: I8324a5c263fba221eb4e67d71207ca84fa241e6c
Reviewed-on: https://go-review.googlesource.com/c/go/+/263637
Trust: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
misc/cgo/test/issue4029.c
misc/cgo/test/issue4029.go
misc/cgo/test/issue4029w.go
src/cmd/dist/test.go
src/cmd/link/internal/arm64/asm.go
src/cmd/link/internal/ld/config.go
src/cmd/link/internal/loader/loader.go
src/cmd/link/internal/loadmacho/ldmacho.go

index e6a777fe6465efa0c59959e3e185502a5a1d5ca7..e79c5a709c87eb3e6ece6e16682cad1e52e14678 100644 (file)
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build !windows,!static
-// +build !darwin !internal_pie
+// +build !darwin !internal_pie,!arm64
 
 #include <stdint.h>
 #include <dlfcn.h>
index 8602ce19e2dc68ec2312e7d130a82fd211d26714..b2d131833a9377ac3643893b5aaa92cff4a179db 100644 (file)
@@ -3,10 +3,11 @@
 // license that can be found in the LICENSE file.
 
 // +build !windows,!static
-// +build !darwin !internal_pie
+// +build !darwin !internal_pie,!arm64
 
 // Excluded in darwin internal linking PIE mode, as dynamic export is not
 // supported.
+// Excluded in internal linking mode on darwin/arm64, as it is always PIE.
 
 package cgotest
 
index de0cf2138ae531168ecca79a8527acb168c94d5d..b969bdd0fe8702a74ddfdf8bd72dfde97abe46ca 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build windows static darwin,internal_pie
+// +build windows static darwin,internal_pie darwin,arm64
 
 package cgotest
 
index bcb12f29fbdd4b1a15df2715079fe8eabd160b5f..09d69f72ed6cdfe17a4aac6a2c2370efb07a9ff4 100644 (file)
@@ -946,9 +946,6 @@ func (t *tester) internalLink() bool {
        if goos == "ios" {
                return false
        }
-       if goos == "darwin" && goarch == "arm64" {
-               return false
-       }
        // Internally linking cgo is incomplete on some architectures.
        // https://golang.org/issue/10373
        // https://golang.org/issue/14449
@@ -964,7 +961,7 @@ func (t *tester) internalLink() bool {
 
 func (t *tester) internalLinkPIE() bool {
        switch goos + "-" + goarch {
-       case "darwin-amd64",
+       case "darwin-amd64", "darwin-arm64",
                "linux-amd64", "linux-arm64",
                "android-arm64",
                "windows-amd64", "windows-386", "windows-arm":
@@ -1088,7 +1085,7 @@ func (t *tester) cgoTest(dt *distTest) error {
 
        pair := gohostos + "-" + goarch
        switch pair {
-       case "darwin-amd64",
+       case "darwin-amd64", "darwin-arm64",
                "openbsd-386", "openbsd-amd64",
                "windows-386", "windows-amd64":
                // test linkmode=external, but __thread not supported, so skip testtls.
index 585c96852f98a395608564bac022c29c2c94395e..e45641115587d8d24bc95a65d4c669277fa468f6 100644 (file)
@@ -71,13 +71,13 @@ func gentext(ctxt *ld.Link, ldr *loader.Loader) {
 }
 
 func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
-
        targ := r.Sym()
        var targType sym.SymKind
        if targ != 0 {
                targType = ldr.SymType(targ)
        }
 
+       const pcrel = 1
        switch r.Type() {
        default:
                if r.Type() >= objabi.ElfRelocOffset {
@@ -201,6 +201,75 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
                su := ldr.MakeSymbolUpdater(s)
                su.SetRelocType(rIdx, objabi.R_ARM64_LDST128)
                return true
+
+       // Handle relocations found in Mach-O object files.
+       case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_UNSIGNED*2:
+               if targType == sym.SDYNIMPORT {
+                       ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
+               }
+               su := ldr.MakeSymbolUpdater(s)
+               su.SetRelocType(rIdx, objabi.R_ADDR)
+               if target.IsPIE() && target.IsInternal() {
+                       // For internal linking PIE, this R_ADDR relocation cannot
+                       // be resolved statically. We need to generate a dynamic
+                       // relocation. Let the code below handle it.
+                       break
+               }
+               return true
+
+       case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_BRANCH26*2 + pcrel:
+               su := ldr.MakeSymbolUpdater(s)
+               su.SetRelocType(rIdx, objabi.R_CALLARM64)
+               if targType == sym.SDYNIMPORT {
+                       addpltsym(target, ldr, syms, targ)
+                       su.SetRelocSym(rIdx, syms.PLT)
+                       su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
+               }
+               return true
+
+       case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGE21*2 + pcrel,
+               objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGEOFF12*2:
+               if targType == sym.SDYNIMPORT {
+                       ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
+               }
+               su := ldr.MakeSymbolUpdater(s)
+               su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
+               return true
+
+       case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21*2 + pcrel,
+               objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12*2:
+               if targType != sym.SDYNIMPORT {
+                       // have symbol
+                       // turn MOVD sym@GOT (adrp+ldr) into MOVD $sym (adrp+add)
+                       data := ldr.Data(s)
+                       off := r.Off()
+                       if int(off+3) >= len(data) {
+                               ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
+                               return false
+                       }
+                       o := target.Arch.ByteOrder.Uint32(data[off:])
+                       su := ldr.MakeSymbolUpdater(s)
+                       switch {
+                       case (o>>24)&0x9f == 0x90: // adrp
+                               // keep instruction unchanged, change relocation type below
+                       case o>>24 == 0xf9: // ldr
+                               // rewrite to add
+                               o = (0x91 << 24) | (o & (1<<22 - 1))
+                               su.MakeWritable()
+                               su.SetUint32(target.Arch, int64(off), o)
+                       default:
+                               ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
+                               return false
+                       }
+                       su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
+                       return true
+               }
+               ld.AddGotSym(target, ldr, syms, targ, 0)
+               su := ldr.MakeSymbolUpdater(s)
+               su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
+               su.SetRelocSym(rIdx, syms.GOT)
+               su.SetRelocAdd(rIdx, int64(ldr.SymGot(targ)))
+               return true
        }
 
        // Reread the reloc to incorporate any changes in type above.
@@ -671,14 +740,28 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
                        }
                        o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
                        return val | int64(o0), noExtReloc, isOk
-               } else if (val>>24)&0x91 == 0x91 {
-                       // R_AARCH64_ADD_ABS_LO12_NC
+               } else if (val>>24)&0x9f == 0x91 {
+                       // ELF R_AARCH64_ADD_ABS_LO12_NC or Mach-O ARM64_RELOC_PAGEOFF12
                        // patch instruction: add
                        t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
                        o1 := uint32(t&0xfff) << 10
                        return val | int64(o1), noExtReloc, isOk
+               } else if (val>>24)&0x3b == 0x39 {
+                       // Mach-O ARM64_RELOC_PAGEOFF12
+                       // patch ldr/str(b/h/w/d/q) (integer or vector) instructions, which have different scaling factors.
+                       // Mach-O uses same relocation type for them.
+                       shift := uint32(val) >> 30
+                       if shift == 0 && (val>>20)&0x048 == 0x048 { // 128-bit vector load
+                               shift = 4
+                       }
+                       t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
+                       if t&(1<<shift-1) != 0 {
+                               ldr.Errorf(s, "invalid address: %x for relocation type: ARM64_RELOC_PAGEOFF12", t)
+                       }
+                       o1 := (uint32(t&0xfff) >> shift) << 10
+                       return val | int64(o1), noExtReloc, isOk
                } else {
-                       ldr.Errorf(s, "unsupported instruction for %x R_PCRELARM64", val)
+                       ldr.Errorf(s, "unsupported instruction for %x R_ARM64_PCREL", val)
                }
 
        case objabi.R_ARM64_LDST8:
index 834c87d06be8d9e830ebce1c03f2099a421a1ad0..a54b96dd5d76d523c929cf16a32ee7d8867f7536 100644 (file)
@@ -208,9 +208,6 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
        if iscgo && objabi.GOOS == "android" {
                return true, objabi.GOOS + " does not support internal cgo"
        }
-       if iscgo && objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" {
-               return true, objabi.GOOS + "/" + objabi.GOARCH + " does not support internal cgo"
-       }
 
        // When the race flag is set, the LLVM tsan relocatable file is linked
        // into the final binary, which means external linking is required because
index 47cac0441bc2f69a7450f621acb81568e017699c..d861efcb13a3b303b0bda1836a0ad86be7c7c122 100644 (file)
@@ -2622,11 +2622,15 @@ func (l *Loader) Dump() {
        fmt.Println("Nsyms:", len(l.objSyms))
        fmt.Println("syms")
        for i := Sym(1); i < Sym(len(l.objSyms)); i++ {
-               pi := interface{}("")
+               pi := ""
                if l.IsExternal(i) {
                        pi = fmt.Sprintf("<ext %d>", l.extIndex(i))
                }
-               fmt.Println(i, l.SymName(i), l.SymType(i), pi)
+               sect := ""
+               if l.SymSect(i) != nil {
+                       sect = l.SymSect(i).Name
+               }
+               fmt.Printf("%v %v %v %v %x %v\n", i, l.SymName(i), l.SymType(i), pi, l.SymValue(i), sect)
        }
        fmt.Println("symsByName")
        for name, i := range l.symsByName[0] {
index 864d80835b9f433230eb0b2e7f5e8e8ea82f48d4..d12f2bc2ac7ca2eed9c9dd97d0b33157a0911a37 100644 (file)
@@ -43,7 +43,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */
 
-// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld
+// TODO(crawshaw): de-duplicate these symbols with cmd/link/internal/ld
 const (
        MACHO_X86_64_RELOC_UNSIGNED = 0
        MACHO_X86_64_RELOC_SIGNED   = 1
@@ -172,11 +172,12 @@ const (
        LdMachoCpuVax         = 1
        LdMachoCpu68000       = 6
        LdMachoCpu386         = 7
-       LdMachoCpuAmd64       = 0x1000007
+       LdMachoCpuAmd64       = 1<<24 | 7
        LdMachoCpuMips        = 8
        LdMachoCpu98000       = 10
        LdMachoCpuHppa        = 11
        LdMachoCpuArm         = 12
+       LdMachoCpuArm64       = 1<<24 | 12
        LdMachoCpu88000       = 13
        LdMachoCpuSparc       = 14
        LdMachoCpu860         = 15
@@ -471,11 +472,14 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
        switch arch.Family {
        default:
                return errorf("mach-o %s unimplemented", arch.Name)
-
        case sys.AMD64:
                if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
                        return errorf("mach-o object but not amd64")
                }
+       case sys.ARM64:
+               if e != binary.LittleEndian || m.cputype != LdMachoCpuArm64 {
+                       return errorf("mach-o object but not arm64")
+               }
        }
 
        m.cmd = make([]ldMachoCmd, ncmd)
@@ -633,7 +637,9 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
                }
 
                bld.SetType(l.SymType(outer))
-               l.AddInteriorSym(outer, s)
+               if l.SymSize(outer) != 0 { // skip empty section (0-sized symbol)
+                       l.AddInteriorSym(outer, s)
+               }
 
                bld.SetValue(int64(machsym.value - sect.addr))
                if !l.AttrCgoExportDynamic(s) {
@@ -722,27 +728,28 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
 
                        // Handle X86_64_RELOC_SIGNED referencing a section (rel.extrn == 0).
                        p := l.Data(s)
-                       if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
-                               // Calculate the addend as the offset into the section.
-                               //
-                               // The rip-relative offset stored in the object file is encoded
-                               // as follows:
-                               //
-                               //    movsd     0x00000360(%rip),%xmm0
-                               //
-                               // To get the absolute address of the value this rip-relative address is pointing
-                               // to, we must add the address of the next instruction to it. This is done by
-                               // taking the address of the relocation and adding 4 to it (since the rip-relative
-                               // offset can at most be 32 bits long).  To calculate the offset into the section the
-                               // relocation is referencing, we subtract the vaddr of the start of the referenced
-                               // section found in the original object file.
-                               //
-                               // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
-                               secaddr := c.seg.sect[rel.symnum-1].addr
-
-                               rAdd = int64(uint64(int64(int32(e.Uint32(p[rOff:])))+int64(rOff)+4) - secaddr)
-                       } else {
-                               rAdd = int64(int32(e.Uint32(p[rOff:])))
+                       if arch.Family == sys.AMD64 {
+                               if rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
+                                       // Calculate the addend as the offset into the section.
+                                       //
+                                       // The rip-relative offset stored in the object file is encoded
+                                       // as follows:
+                                       //
+                                       //    movsd     0x00000360(%rip),%xmm0
+                                       //
+                                       // To get the absolute address of the value this rip-relative address is pointing
+                                       // to, we must add the address of the next instruction to it. This is done by
+                                       // taking the address of the relocation and adding 4 to it (since the rip-relative
+                                       // offset can at most be 32 bits long).  To calculate the offset into the section the
+                                       // relocation is referencing, we subtract the vaddr of the start of the referenced
+                                       // section found in the original object file.
+                                       //
+                                       // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
+                                       secaddr := c.seg.sect[rel.symnum-1].addr
+                                       rAdd = int64(uint64(int64(int32(e.Uint32(p[rOff:])))+int64(rOff)+4) - secaddr)
+                               } else {
+                                       rAdd = int64(int32(e.Uint32(p[rOff:])))
+                               }
                        }
 
                        // An unsigned internal relocation has a value offset