diff options
-rw-r--r-- | src/cmd/link/internal/arm/asm.go | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index 9eaa7b9eea..1e4b36df48 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -396,9 +396,26 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) { // laid out. Conservatively use a trampoline. This should be rare, as we lay out packages // in dependency order. if ldr.SymValue(rs) != 0 { - // r.Add is the instruction - // low 24-bit encodes the target address - t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4 + // Workaround for issue #58425: it appears that the + // external linker doesn't always take into account the + // relocation addend when doing reachability checks. This + // means that if you have a call from function XYZ at + // offset 8 to runtime.duffzero with addend 800 (for + // example), where the distance between the start of XYZ + // and the start of runtime.duffzero is just over the + // limit (by 100 bytes, say), you can get "relocation + // doesn't fit" errors from the external linker. To deal + // with this, ignore the addend when performing the + // distance calculation (this assumes that we're only + // handling backward jumps; ideally we might want to check + // both with and without the addend). + if ctxt.IsExternal() { + t = (ldr.SymValue(rs) - (ldr.SymValue(s) + int64(r.Off()))) / 4 + } else { + // r.Add is the instruction + // low 24-bit encodes the target address + t = (ldr.SymValue(rs) + int64(signext24(r.Add()&0xffffff)*4) - (ldr.SymValue(s) + int64(r.Off()))) / 4 + } } if t > 0x7fffff || t < -0x800000 || ldr.SymValue(rs) == 0 || (*ld.FlagDebugTramp > 1 && ldr.SymPkg(s) != ldr.SymPkg(rs)) { // direct call too far, need to insert trampoline. |