Commit cd9fc3eb authored by Michael Hudson-Doyle's avatar Michael Hudson-Doyle

cmd/link: allow symbols from .a files to override those from .so files

https://golang.org/s/execmodes defines rules for how multiple codes of a go
package work when they end up in the address space of a single process, but
currently the linker blows up in this situation. Fix that by loading all .a
files before any .so files and ignoring duplicate symbols found when loading
shared libraries.

I know this is very very late for 1.6 but at least it should clearly not have
any effect when shared libraries are not in use.

Change-Id: I512ac912937e7502ff58eb5628b658ecce3c38e5
Reviewed-on: https://go-review.googlesource.com/18714Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
parent 97266969
......@@ -749,3 +749,15 @@ func TestABIChecking(t *testing.T) {
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
run(t, "after non-ABI breaking change", "./bin/exe")
}
// If a package 'explicit' imports a package 'implicit', building
// 'explicit' into a shared library implicitly includes implicit in
// the shared library. Building an executable that imports both
// explicit and implicit builds the code from implicit into the
// executable rather than fetching it from the shared library. The
// link still succeeds and the executable still runs though.
func TestImplicitInclusion(t *testing.T) {
goCmd(t, "install", "-buildmode=shared", "-linkshared", "explicit")
goCmd(t, "install", "-linkshared", "implicitcmd")
run(t, "running executable linked against library that contains same package as it", "./bin/implicitcmd")
}
package explicit
import (
"implicit"
)
func E() int {
return implicit.I()
}
package implicit
func I() int {
return 42
}
package main
import (
"explicit"
"implicit"
)
func main() {
println(implicit.I() + explicit.E())
}
......@@ -504,14 +504,21 @@ func loadlib() {
var i int
for i = 0; i < len(Ctxt.Library); i++ {
if Debug['v'] > 1 {
fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
}
iscgo = iscgo || Ctxt.Library[i].Pkg == "runtime/cgo"
if Ctxt.Library[i].Shlib == "" {
if Debug['v'] > 1 {
fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
}
objfile(Ctxt.Library[i])
}
}
for i = 0; i < len(Ctxt.Library); i++ {
if Ctxt.Library[i].Shlib != "" {
if Debug['v'] > 1 {
fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].Shlib, Ctxt.Library[i].Objref)
}
ldshlibsyms(Ctxt.Library[i].Shlib)
} else {
objfile(Ctxt.Library[i])
}
}
......@@ -1458,18 +1465,11 @@ func ldshlibsyms(shlib string) {
continue
}
lsym := Linklookup(Ctxt, elfsym.Name, 0)
if lsym.Type != 0 && lsym.Type != obj.SDYNIMPORT && lsym.Dupok == 0 {
if (lsym.Type != obj.SBSS && lsym.Type != obj.SNOPTRBSS) || len(lsym.R) != 0 || len(lsym.P) != 0 || f.Sections[elfsym.Section].Type != elf.SHT_NOBITS {
Diag("Found duplicate symbol %s reading from %s, first found in %s", elfsym.Name, shlib, lsym.File)
}
if lsym.Size > int64(elfsym.Size) {
// If the existing symbol is a BSS value that is
// larger than the one read from the shared library,
// keep references to that. Conversely, if the
// version from the shared libray is larger, we want
// to make all references be to that.
continue
}
// Because loadlib above loads all .a files before loading any shared
// libraries, any symbols we find that duplicate symbols already
// loaded should be ignored (the symbols from the .a files "win").
if lsym.Type != 0 {
continue
}
lsym.Type = obj.SDYNIMPORT
lsym.ElfType = elf.ST_TYPE(elfsym.Info)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment