]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: generate relative relocs for PIE
authorMichael Pratt <mpratt@google.com>
Fri, 6 Dec 2019 22:25:51 +0000 (17:25 -0500)
committerCherry Zhang <cherryyz@google.com>
Fri, 21 Feb 2020 20:28:45 +0000 (20:28 +0000)
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 <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

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

index 991f5523edc94746078c3056912ef936c4684f44..74fa8dbb90489ee438897e3d8c14e3bd0c6c86dc 100644 (file)
@@ -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
                }
index 9fccf73a5902d1173bd37b3a43f3e2382c571a29..690116de0101988ac32bee8955d1c07b3ad31383 100644 (file)
@@ -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
                }