From: Michael Pratt Date: Fri, 6 Dec 2019 22:25:51 +0000 (-0500) Subject: cmd/link: generate relative relocs for PIE X-Git-Tag: go1.15beta1~1145 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=675a2e70780208dce18a0bc4b3e420de71fe0178;p=gostls13.git cmd/link: generate relative relocs for PIE Go's PIE binaries have tons of relocations, all R_X86_64_64 [1] when internally linked. R_X86_64_64 relocations require symbol lookup in the dynamic linker, which can be quite slow. The simple Go HTTP server in #36028 takes over 1s to complete dynamic linking! The external linker generates R_X86_64_RELATIVE [2] relocations, which are significantly more efficient. It turns out that generating these relocations internally is quite simple, so lets do it. Rather than referencing targ.Dynid in r_info and having the dynamic linker do a symbol lookup and then add (final targ address) + r.Add, use AddAddrPlus to generate another R_ADDR to have the linker compute (targ address + r.Add). The dynamic linker is then only left with base address + r_addend. Since we don't reference the symbol in the final relocation, Adddynsym is no longer necessary, saving ~1MB (of ~9MB) from the binary size of the example in #36028. [1] R_AARCH64_ABS64 on arm64. [2] R_AARCH64_RELATIVE on arm64. Fixes #36028 Change-Id: Ie0f4bb1d911f2e05ab46a0a0454c0f46ac01b43b Reviewed-on: https://go-review.googlesource.com/c/go/+/210181 Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot --- diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index 991f5523ed..74fa8dbb90 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -322,19 +322,31 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { } if ctxt.IsELF { - // TODO: We generate a R_X86_64_64 relocation for every R_ADDR, even - // though it would be more efficient (for the dynamic linker) if we - // generated R_X86_RELATIVE instead. - ld.Adddynsym(ctxt, targ) + // Generate R_X86_64_RELATIVE relocations for best + // efficiency in the dynamic linker. + // + // As noted above, symbol addresses have not been + // assigned yet, so we can't generate the final reloc + // entry yet. We ultimately want: + // + // r_offset = s + r.Off + // r_info = R_X86_64_RELATIVE + // r_addend = targ + r.Add + // + // The dynamic linker will set *offset = base address + + // addend. + // + // AddAddrPlus is used for r_offset and r_addend to + // generate new R_ADDR relocations that will update + // these fields in the 'reloc' phase. rela := ctxt.Syms.Lookup(".rela", 0) rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off)) if r.Siz == 8 { - rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_X86_64_64))) + rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE))) } else { - // TODO: never happens, remove. - rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_X86_64_32))) + ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) } - rela.AddUint64(ctxt.Arch, uint64(r.Add)) + rela.AddAddrPlus(ctxt.Arch, targ, int64(r.Add)) r.Type = objabi.ElfRelocOffset // ignore during relocsym return true } diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 9fccf73a59..690116de01 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -278,18 +278,31 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { } if ctxt.IsELF { - // TODO: We generate a R_AARCH64_ABS64 relocation for every R_ADDR, even - // though it would be more efficient (for the dynamic linker) if we - // generated R_AARCH64_RELATIVE instead. - ld.Adddynsym(ctxt, targ) + // Generate R_AARCH64_RELATIVE relocations for best + // efficiency in the dynamic linker. + // + // As noted above, symbol addresses have not been + // assigned yet, so we can't generate the final reloc + // entry yet. We ultimately want: + // + // r_offset = s + r.Off + // r_info = R_AARCH64_RELATIVE + // r_addend = targ + r.Add + // + // The dynamic linker will set *offset = base address + + // addend. + // + // AddAddrPlus is used for r_offset and r_addend to + // generate new R_ADDR relocations that will update + // these fields in the 'reloc' phase. rela := ctxt.Syms.Lookup(".rela", 0) rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off)) if r.Siz == 8 { - rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_AARCH64_ABS64))) + rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_AARCH64_RELATIVE))) } else { ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name) } - rela.AddUint64(ctxt.Arch, uint64(r.Add)) + rela.AddAddrPlus(ctxt.Arch, targ, int64(r.Add)) r.Type = objabi.ElfRelocOffset // ignore during relocsym return true }