From: Michael Hudson-Doyle Date: Wed, 28 Oct 2015 23:17:43 +0000 (+1300) Subject: cmd/link: always resolve functions locally when linking dynamically X-Git-Tag: go1.6beta1~686 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c34fb3cfc69c81c9671c097b599e9e642a9d1fed;p=gostls13.git cmd/link: always resolve functions locally when linking dynamically When dynamically linking, we want references to functions defined in this module to always be to the function object, not to the PLT. We force this by writing an additional local symbol for every global function symbol and making all relocations against the global symbol refer to this local symbol instead. This is approximately equivalent to the ELF linker -Bsymbolic-functions option, but that is buggy on several platforms. Change-Id: Ie6983eb4d1947f8543736fd349f9a90df3cce91a Reviewed-on: https://go-review.googlesource.com/16436 Reviewed-by: Ian Lance Taylor --- diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index 51765a1847..1e50802bb3 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -323,7 +323,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { func elfreloc1(r *ld.Reloc, sectoff int64) int { ld.Thearch.Vput(uint64(sectoff)) - elfsym := r.Xsym.Elfsym + elfsym := r.Xsym.ElfsymForReloc() switch r.Type { default: return -1 diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index 01b2aaa3b4..5507312a1b 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -193,7 +193,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { func elfreloc1(r *ld.Reloc, sectoff int64) int { ld.Thearch.Lput(uint32(sectoff)) - elfsym := r.Xsym.Elfsym + elfsym := r.Xsym.ElfsymForReloc() switch r.Type { default: return -1 diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 58d5236398..7308d2fce1 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -51,7 +51,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { func elfreloc1(r *ld.Reloc, sectoff int64) int { ld.Thearch.Vput(uint64(sectoff)) - elfsym := r.Xsym.Elfsym + elfsym := r.Xsym.ElfsymForReloc() switch r.Type { default: return -1 diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 16c669e806..2cce02287d 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1615,7 +1615,7 @@ func elfrelocsect(sect *Section, first *LSym) { continue } - if r.Xsym.Elfsym == 0 { + if r.Xsym.ElfsymForReloc() == 0 { Diag("reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type) } if Thearch.Elfreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 { diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index ff9cabc214..a311c780ed 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1031,14 +1031,6 @@ func hostlink() { argv = append(argv, "-shared", "-Wl,-z,nodelete") } case BuildmodeShared: - // TODO(mwhudson): unless you do this, dynamic relocations fill - // out the findfunctab table and for some reason shared libraries - // and the executable both define a main function and putting the - // address of executable's main into the shared libraries - // findfunctab violates the assumptions of the runtime. TBH, I - // think we may well end up wanting to use -Bsymbolic here - // anyway. - argv = append(argv, "-Wl,-Bsymbolic-functions") if UseRelro() { argv = append(argv, "-Wl,-z,relro") } diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index 7102edfb4d..495d11ac7e 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -63,6 +63,7 @@ type LSym struct { Got int32 Align int32 Elfsym int32 + LocalElfsym int32 Args int32 Locals int32 Value int64 @@ -92,6 +93,16 @@ func (s *LSym) String() string { return fmt.Sprintf("%s<%d>", s.Name, s.Version) } +func (s *LSym) ElfsymForReloc() int32 { + // If putelfsym created a local version of this symbol, use that in all + // relocations. + if s.LocalElfsym != 0 { + return s.LocalElfsym + } else { + return s.Elfsym + } +} + type Reloc struct { Off int32 Siz uint8 diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index f71158663c..c53037168a 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -155,11 +155,6 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L bind = STB_LOCAL } - if bind != elfbind { - return - } - - off := putelfstr(s) if Linkmode == LinkExternal && elfshnum != SHN_UNDEF { addr -= int64(xo.Sect.Vaddr) } @@ -167,7 +162,24 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L if x.Type&obj.SHIDDEN != 0 { other = STV_HIDDEN } - putelfsyment(off, addr, size, bind<<4|type_&0xf, elfshnum, other) + + if DynlinkingGo() && bind == STB_GLOBAL && elfbind == STB_LOCAL && x.Type == obj.STEXT { + // When dynamically linking, we want references to functions defined + // in this module to always be to the function object, not to the + // PLT. We force this by writing an additional local symbol for every + // global function symbol and making all relocations against the + // global symbol refer to this local symbol instead (see + // (*LSym).ElfsymForReloc). This is approximately equivalent to the + // ELF linker -Bsymbolic-functions option, but that is buggy on + // several platforms. + putelfsyment(putelfstr("local."+s), addr, size, STB_LOCAL<<4|type_&0xf, elfshnum, other) + x.LocalElfsym = int32(numelfsym) + numelfsym++ + } else if bind != elfbind { + return + } + + putelfsyment(putelfstr(s), addr, size, bind<<4|type_&0xf, elfshnum, other) x.Elfsym = int32(numelfsym) numelfsym++ } diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index d30bd48b4e..8f9507168c 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -231,7 +231,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { func elfreloc1(r *ld.Reloc, sectoff int64) int { ld.Thearch.Lput(uint32(sectoff)) - elfsym := r.Xsym.Elfsym + elfsym := r.Xsym.ElfsymForReloc() switch r.Type { default: return -1