]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: stream external relocations on ARM64 and on Darwin
authorCherry Zhang <cherryyz@google.com>
Fri, 17 Jul 2020 21:56:17 +0000 (17:56 -0400)
committerCherry Zhang <cherryyz@google.com>
Tue, 21 Jul 2020 21:15:02 +0000 (21:15 +0000)
Support streaming external relocations on ARM64. Support
architecture-specific relocations.

Also support streaming external relocations on Darwin. Do it in
the same CL so ARM64's archreloc doesn't need to support both
streaming and non-streaming.

Change-Id: Ia7fee9957892f98c065022c69a51f47402f4d6e2
Reviewed-on: https://go-review.googlesource.com/c/go/+/243644
Reviewed-by: Jeremy Faller <jeremy@golang.org>
src/cmd/link/internal/arm64/asm.go
src/cmd/link/internal/arm64/obj.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/macho.go
src/cmd/link/internal/ld/target.go

index 2d964e9cb64323a1d9534ef0223034d4f990545a..093aadb3435ba309de7cf1f8a0b36e479622a940 100644 (file)
@@ -456,15 +456,14 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
 
                        // set up addend for eventual relocation via outer symbol.
                        rs, off := ld.FoldSubSymbolOffset(ldr, rs)
-                       rr.Xadd = r.Add() + off
+                       xadd := r.Add() + off
                        rst := ldr.SymType(rs)
                        if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
                                ldr.Errorf(s, "missing section for %s", ldr.SymName(rs))
                        }
-                       rr.Xsym = rs
 
                        nExtReloc = 2 // need two ELF/Mach-O relocations. see elfreloc1/machoreloc1
-                       if target.IsDarwin() && rt == objabi.R_ADDRARM64 && rr.Xadd != 0 {
+                       if target.IsDarwin() && rt == objabi.R_ADDRARM64 && xadd != 0 {
                                nExtReloc = 4 // need another two relocations for non-zero addend
                        }
 
@@ -488,9 +487,8 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
                                // can only encode 24-bit of signed addend, but the instructions
                                // supports 33-bit of signed addend, so we always encode the
                                // addend in place.
-                               o0 |= (uint32((rr.Xadd>>12)&3) << 29) | (uint32((rr.Xadd>>12>>2)&0x7ffff) << 5)
-                               o1 |= uint32(rr.Xadd&0xfff) << 10
-                               rr.Xadd = 0
+                               o0 |= (uint32((xadd>>12)&3) << 29) | (uint32((xadd>>12>>2)&0x7ffff) << 5)
+                               o1 |= uint32(xadd&0xfff) << 10
 
                                // when laid out, the instruction order must always be o1, o2.
                                if target.IsBigEndian() {
@@ -508,8 +506,6 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
                        if rt == objabi.R_ARM64_TLS_IE {
                                nExtReloc = 2 // need two ELF relocations. see elfreloc1
                        }
-                       rr.Xsym = rs
-                       rr.Xadd = r.Add()
                        return val, nExtReloc, isOk
                }
        }
@@ -693,6 +689,42 @@ func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc2, sym.RelocVarian
        return -1
 }
 
+func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc2, s loader.Sym) (loader.ExtReloc, bool) {
+       rs := ldr.ResolveABIAlias(r.Sym())
+       var rr loader.ExtReloc
+       switch rt := r.Type(); rt {
+       case objabi.R_ARM64_GOTPCREL,
+               objabi.R_ADDRARM64:
+
+               // set up addend for eventual relocation via outer symbol.
+               rs, off := ld.FoldSubSymbolOffset(ldr, rs)
+               rr.Xadd = r.Add() + off
+               rr.Xsym = rs
+
+               // Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
+               // will make the linking fail because it thinks the code is not PIC even though
+               // the BR26 relocation should be fully resolved at link time.
+               // That is the reason why the next if block is disabled. When the bug in ld64
+               // is fixed, we can enable this block and also enable duff's device in cmd/7g.
+               if false && target.IsDarwin() {
+                       // Mach-O wants the addend to be encoded in the instruction
+                       // Note that although Mach-O supports ARM64_RELOC_ADDEND, it
+                       // can only encode 24-bit of signed addend, but the instructions
+                       // supports 33-bit of signed addend, so we always encode the
+                       // addend in place.
+                       rr.Xadd = 0
+               }
+               return rr, true
+       case objabi.R_CALLARM64,
+               objabi.R_ARM64_TLS_LE,
+               objabi.R_ARM64_TLS_IE:
+               rr.Xsym = rs
+               rr.Xadd = r.Add()
+               return rr, true
+       }
+       return rr, false
+}
+
 func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
        if plt.Size() == 0 {
                // stp     x16, x30, [sp, #-16]!
index e7c23978a6438afb0339e0fc85f157e50dfed8fb..37b72b6c377ce0821a45cc72838a33a7baf89fd0 100644 (file)
@@ -50,6 +50,7 @@ func Init() (*sys.Arch, ld.Arch) {
                Archinit:         archinit,
                Archreloc:        archreloc,
                Archrelocvariant: archrelocvariant,
+               Extreloc:         extreloc,
                Elfreloc1:        elfreloc1,
                ElfrelocSize:     24,
                Elfsetupplt:      elfsetupplt,
index d5034ae01cf8344d9817eb0ec6a9a18ddbb96196..26bad1b891f9ed19603b9b5cb044995f77caa07a 100644 (file)
@@ -264,7 +264,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
                                o = int64(target.Arch.ByteOrder.Uint64(P[off:]))
                        }
                        var rp *loader.ExtReloc
-                       if target.IsExternal() {
+                       if target.IsExternal() && !target.StreamExtRelocs() {
                                // Don't pass &rr directly to Archreloc, which will escape rr
                                // even if this case is not taken. Instead, as Archreloc will
                                // likely return true, we speculatively add rr to extRelocs
@@ -274,12 +274,16 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
                        }
                        out, nExtReloc, ok := thearch.Archreloc(target, ldr, syms, r, rp, s, o)
                        if target.IsExternal() {
-                               if nExtReloc == 0 {
-                                       // No external relocation needed. Speculation failed. Undo the append.
-                                       extRelocs = extRelocs[:len(extRelocs)-1]
+                               if target.StreamExtRelocs() {
+                                       extraExtReloc += nExtReloc
                                } else {
-                                       // Account for the difference between host relocations and Go relocations.
-                                       extraExtReloc += nExtReloc - 1
+                                       if nExtReloc == 0 {
+                                               // No external relocation needed. Speculation failed. Undo the append.
+                                               extRelocs = extRelocs[:len(extRelocs)-1]
+                                       } else {
+                                               // Account for the difference between host relocations and Go relocations.
+                                               extraExtReloc += nExtReloc - 1
+                                       }
                                }
                        }
                        needExtReloc = false // already appended
@@ -638,8 +642,7 @@ func extreloc(ctxt *Link, ldr *loader.Loader, s loader.Sym, r loader.Reloc2, ri
 
        switch rt {
        default:
-               // TODO: handle arch-specific relocations
-               panic("unsupported")
+               return thearch.Extreloc(&target, ldr, r, s)
 
        case objabi.R_TLS_LE, objabi.R_TLS_IE:
                if target.IsElf() {
index a489da02bc95a720f4bab673706614f7ed73419d..e45458d262761eb30a721869ad6426e74ec6e286 100644 (file)
@@ -239,6 +239,11 @@ type Arch struct {
        Asmb  func(*Link, *loader.Loader)
        Asmb2 func(*Link, *loader.Loader)
 
+       // Extreloc is an arch-specific hook that converts a Go relocation to an
+       // external relocation. Return the external relocation and whether it is
+       // needed.
+       Extreloc func(*Target, *loader.Loader, loader.Reloc2, loader.Sym) (loader.ExtReloc, bool)
+
        Elfreloc1      func(*Link, *OutBuf, *loader.Loader, loader.Sym, loader.ExtRelocView, int64) bool
        ElfrelocSize   uint32 // size of an ELF relocation record, must match Elfreloc1.
        Elfsetupplt    func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
index 4a0bb5d3812226474b504baab1ccf1d2b491afa9..1089d309a1dc1c63063fe7f0ff1d461426d9e383 100644 (file)
@@ -1045,17 +1045,25 @@ func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sy
                if ldr.SymValue(s) >= int64(eaddr) {
                        break
                }
-               relocs := ldr.ExtRelocs(s)
+
+               // Compute external relocations on the go, and pass to Machoreloc1
+               // to stream out.
+               relocs := ldr.Relocs(s)
                for ri := 0; ri < relocs.Count(); ri++ {
-                       r := relocs.At(ri)
-                       if r.Xsym == 0 {
+                       r := relocs.At2(ri)
+                       rr, ok := extreloc(ctxt, ldr, s, r, ri)
+                       if !ok {
+                               continue
+                       }
+                       if rr.Xsym == 0 {
                                ldr.Errorf(s, "missing xsym in relocation")
                                continue
                        }
-                       if !ldr.AttrReachable(r.Xsym) {
-                               ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(r.Xsym))
+                       if !ldr.AttrReachable(rr.Xsym) {
+                               ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
                        }
-                       if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, r, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
+                       rv := loader.ExtRelocView{Reloc2: r, ExtReloc: rr}
+                       if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rv, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
                                ldr.Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), r.Siz(), ldr.SymName(r.Sym()))
                        }
                }
index 8702db121e52ed2f4d19c7ea534d28100ae1ece3..d075bce17f9168e3b3366b916c6b4526aff1a29f 100644 (file)
@@ -184,5 +184,5 @@ func (t *Target) IsBigEndian() bool {
 
 // Temporary helper.
 func (t *Target) StreamExtRelocs() bool {
-       return t.IsELF && (t.IsAMD64() || t.Is386())
+       return (t.IsELF || t.IsDarwin()) && (t.IsAMD64() || t.Is386() || t.IsARM64())
 }