]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.20] cmd/link: use label symbols for Duff's devices on darwin...
authorCherry Mui <cherryyz@google.com>
Wed, 8 Mar 2023 21:38:32 +0000 (16:38 -0500)
committerCherry Mui <cherryyz@google.com>
Wed, 15 Mar 2023 20:12:19 +0000 (20:12 +0000)
On darwin, the external linker generally supports CALL relocations
with addend. One exception is that for a very large binary when it
decides to insert a trampoline, instead of applying the addend to
the call target (in the trampoline), it applies the addend to the
CALL instruction in the caller, i.e. generating a call to
trampoline+addend, which is not the correct address and usually
points to unreloated functions.

To work around this, we use label symbols so the CALL is targeting
a label symbol without addend. To make things simple we always use
label symbols for CALLs with addend (in external linking mode on
darwin/arm64), even for small binaries.

Updates #58935.
Fixes #58954.

Change-Id: I38aed6b62a0496c277c589b5accbbef6aace8dd5
Reviewed-on: https://go-review.googlesource.com/c/go/+/474620
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Cherry Mui <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
(cherry picked from commit 7dbd6de7d45da622e532e149de616e159286e1d4)
Reviewed-on: https://go-review.googlesource.com/c/go/+/475175

src/cmd/link/internal/arm64/asm.go

index fc0ad3fb4e4d2438cbf4ecd95fc11978f2d1fd02..7109d84fa32b81148f1b52cf24e02b65ee1b591d 100644 (file)
@@ -537,6 +537,13 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
                        ldr.Errorf(s, "internal error: relocation addend overflow: %s+0x%x", ldr.SymName(rs), xadd)
                }
        }
+       if rt == objabi.R_CALLARM64 && xadd != 0 {
+               label := ldr.Lookup(offsetLabelName(ldr, rs, xadd), ldr.SymVersion(rs))
+               if label != 0 {
+                       xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label) // should always be 0 (checked below)
+                       rs = label
+               }
+       }
 
        if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 ||
                rt == objabi.R_ARM64_PCREL_LDST8 || rt == objabi.R_ARM64_PCREL_LDST16 ||
@@ -564,10 +571,9 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
                v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
        case objabi.R_CALLARM64:
                if xadd != 0 {
-                       out.Write32(uint32(sectoff))
-                       out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
+                       // Addend should be handled above via label symbols.
+                       ldr.Errorf(s, "unexpected non-zero addend: %s+%d", ldr.SymName(rs), xadd)
                }
-
                v |= 1 << 24 // pc-relative bit
                v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
        case objabi.R_ADDRARM64,
@@ -788,9 +794,6 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
 
                case objabi.R_CALLARM64:
                        nExtReloc = 1
-                       if target.IsDarwin() && r.Add() != 0 {
-                               nExtReloc = 2 // need another relocation for addend
-                       }
                        return val, nExtReloc, isOk
 
                case objabi.R_ARM64_TLS_LE:
@@ -1184,6 +1187,9 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
        // addend. For large symbols, we generate "label" symbols in the middle, so
        // that relocations can target them with smaller addends.
        // On Windows, we only get 21 bits, again (presumably) signed.
+       // Also, on Windows (always) and Darwin (for very large binaries), the external
+       // linker does't support CALL relocations with addend, so we generate "label"
+       // symbols for functions of which we can target the middle (Duff's devices).
        if !ctxt.IsDarwin() && !ctxt.IsWindows() || !ctxt.IsExternal() {
                return
        }
@@ -1193,19 +1199,6 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
                limit = peRelocLimit
        }
 
-       if ctxt.IsDarwin() {
-               big := false
-               for _, seg := range ld.Segments {
-                       if seg.Length >= machoRelocLimit {
-                               big = true
-                               break
-                       }
-               }
-               if !big {
-                       return // skip work if nothing big
-               }
-       }
-
        // addLabelSyms adds "label" symbols at s+limit, s+2*limit, etc.
        addLabelSyms := func(s loader.Sym, limit, sz int64) {
                v := ldr.SymValue(s)
@@ -1225,23 +1218,36 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
                }
        }
 
+       // Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each).
+       if s := ldr.Lookup("runtime.duffcopy", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
+               addLabelSyms(s, 8, 8*64)
+       }
+       if s := ldr.Lookup("runtime.duffzero", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
+               addLabelSyms(s, 4, 4*64)
+       }
+
+       if ctxt.IsDarwin() {
+               big := false
+               for _, seg := range ld.Segments {
+                       if seg.Length >= machoRelocLimit {
+                               big = true
+                               break
+                       }
+               }
+               if !big {
+                       return // skip work if nothing big
+               }
+       }
+
        for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ {
                if !ldr.AttrReachable(s) {
                        continue
                }
                t := ldr.SymType(s)
                if t == sym.STEXT {
-                       if ctxt.IsDarwin() || ctxt.IsWindows() {
-                               // Cannot relocate into middle of function.
-                               // Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each).
-                               switch ldr.SymName(s) {
-                               case "runtime.duffcopy":
-                                       addLabelSyms(s, 8, 8*64)
-                               case "runtime.duffzero":
-                                       addLabelSyms(s, 4, 4*64)
-                               }
-                       }
-                       continue // we don't target the middle of other functions
+                       // Except for Duff's devices (handled above), we don't
+                       // target the middle of a function.
+                       continue
                }
                if t >= sym.SDWARFSECT {
                        continue // no need to add label for DWARF symbols