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 <iant@golang.org>
This commit is contained in:
Michael Hudson-Doyle 2015-10-29 12:17:43 +13:00
parent ab7e82ef3b
commit c34fb3cfc6
8 changed files with 34 additions and 19 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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")
}

View File

@ -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

View File

@ -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++
}

View File

@ -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