Skip to content

Commit fa42da1

Browse files
committed
[release-branch.go1.20] cmd/link: use label symbols for Duff's devices on darwin/arm64
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 <[email protected]> Run-TryBot: Cherry Mui <[email protected]> Reviewed-by: Than McIntosh <[email protected]> (cherry picked from commit 7dbd6de) Reviewed-on: https://go-review.googlesource.com/c/go/+/475175
1 parent 5c7cc46 commit fa42da1

File tree

1 file changed

+36
-30
lines changed
  • src/cmd/link/internal/arm64

1 file changed

+36
-30
lines changed

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

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,13 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
537537
ldr.Errorf(s, "internal error: relocation addend overflow: %s+0x%x", ldr.SymName(rs), xadd)
538538
}
539539
}
540+
if rt == objabi.R_CALLARM64 && xadd != 0 {
541+
label := ldr.Lookup(offsetLabelName(ldr, rs, xadd), ldr.SymVersion(rs))
542+
if label != 0 {
543+
xadd = ldr.SymValue(rs) + xadd - ldr.SymValue(label) // should always be 0 (checked below)
544+
rs = label
545+
}
546+
}
540547

541548
if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 ||
542549
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
564571
v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
565572
case objabi.R_CALLARM64:
566573
if xadd != 0 {
567-
out.Write32(uint32(sectoff))
568-
out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(xadd&0xffffff))
574+
// Addend should be handled above via label symbols.
575+
ldr.Errorf(s, "unexpected non-zero addend: %s+%d", ldr.SymName(rs), xadd)
569576
}
570-
571577
v |= 1 << 24 // pc-relative bit
572578
v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
573579
case objabi.R_ADDRARM64,
@@ -788,9 +794,6 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
788794

789795
case objabi.R_CALLARM64:
790796
nExtReloc = 1
791-
if target.IsDarwin() && r.Add() != 0 {
792-
nExtReloc = 2 // need another relocation for addend
793-
}
794797
return val, nExtReloc, isOk
795798

796799
case objabi.R_ARM64_TLS_LE:
@@ -1184,6 +1187,9 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
11841187
// addend. For large symbols, we generate "label" symbols in the middle, so
11851188
// that relocations can target them with smaller addends.
11861189
// On Windows, we only get 21 bits, again (presumably) signed.
1190+
// Also, on Windows (always) and Darwin (for very large binaries), the external
1191+
// linker does't support CALL relocations with addend, so we generate "label"
1192+
// symbols for functions of which we can target the middle (Duff's devices).
11871193
if !ctxt.IsDarwin() && !ctxt.IsWindows() || !ctxt.IsExternal() {
11881194
return
11891195
}
@@ -1193,19 +1199,6 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
11931199
limit = peRelocLimit
11941200
}
11951201

1196-
if ctxt.IsDarwin() {
1197-
big := false
1198-
for _, seg := range ld.Segments {
1199-
if seg.Length >= machoRelocLimit {
1200-
big = true
1201-
break
1202-
}
1203-
}
1204-
if !big {
1205-
return // skip work if nothing big
1206-
}
1207-
}
1208-
12091202
// addLabelSyms adds "label" symbols at s+limit, s+2*limit, etc.
12101203
addLabelSyms := func(s loader.Sym, limit, sz int64) {
12111204
v := ldr.SymValue(s)
@@ -1225,23 +1218,36 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) {
12251218
}
12261219
}
12271220

1221+
// Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each).
1222+
if s := ldr.Lookup("runtime.duffcopy", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
1223+
addLabelSyms(s, 8, 8*64)
1224+
}
1225+
if s := ldr.Lookup("runtime.duffzero", sym.SymVerABIInternal); s != 0 && ldr.AttrReachable(s) {
1226+
addLabelSyms(s, 4, 4*64)
1227+
}
1228+
1229+
if ctxt.IsDarwin() {
1230+
big := false
1231+
for _, seg := range ld.Segments {
1232+
if seg.Length >= machoRelocLimit {
1233+
big = true
1234+
break
1235+
}
1236+
}
1237+
if !big {
1238+
return // skip work if nothing big
1239+
}
1240+
}
1241+
12281242
for s, n := loader.Sym(1), loader.Sym(ldr.NSym()); s < n; s++ {
12291243
if !ldr.AttrReachable(s) {
12301244
continue
12311245
}
12321246
t := ldr.SymType(s)
12331247
if t == sym.STEXT {
1234-
if ctxt.IsDarwin() || ctxt.IsWindows() {
1235-
// Cannot relocate into middle of function.
1236-
// Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each).
1237-
switch ldr.SymName(s) {
1238-
case "runtime.duffcopy":
1239-
addLabelSyms(s, 8, 8*64)
1240-
case "runtime.duffzero":
1241-
addLabelSyms(s, 4, 4*64)
1242-
}
1243-
}
1244-
continue // we don't target the middle of other functions
1248+
// Except for Duff's devices (handled above), we don't
1249+
// target the middle of a function.
1250+
continue
12451251
}
12461252
if t >= sym.SDWARFSECT {
12471253
continue // no need to add label for DWARF symbols

0 commit comments

Comments
 (0)