From a5f57d795010bba4b391944dac545adef017ed85 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Tue, 16 Jun 2015 13:41:11 +1200 Subject: [PATCH] cmd/link: when reading symbols from a shared library, allow duplicates when they are both in bss This makes the behaviour match what happens when duplicate symbols are read from regular object files and fixes errors about cgoAlwaysFalse when linking an executable that uses cgo against a shared library. Change-Id: Ibb8cd8fe3f7813cde504b7483f1e857868d7e063 Reviewed-on: https://go-review.googlesource.com/11117 Reviewed-by: Ian Lance Taylor --- misc/cgo/testshared/shared_test.go | 7 +++++++ misc/cgo/testshared/src/execgo/exe.go | 8 ++++++++ src/cmd/link/internal/ld/lib.go | 27 ++++++++++++++++++--------- 3 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 misc/cgo/testshared/src/execgo/exe.go diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go index ae977c00637..c73abbf0f42 100644 --- a/misc/cgo/testshared/shared_test.go +++ b/misc/cgo/testshared/shared_test.go @@ -309,6 +309,13 @@ func TestTrivialExecutable(t *testing.T) { AssertHasRPath(t, "./bin/trivial", gorootInstallDir) } +// Build an executable that uses cgo linked against the shared runtime and check it +// runs. +func TestCgoExecutable(t *testing.T) { + goCmd(t, "install", "-linkshared", "execgo") + run(t, "cgo executable", "./bin/execgo") +} + // Build a GOPATH package into a shared library that links against the goroot runtime // and an executable that links against both. func TestGopathShlib(t *testing.T) { diff --git a/misc/cgo/testshared/src/execgo/exe.go b/misc/cgo/testshared/src/execgo/exe.go new file mode 100644 index 00000000000..0427be8bdfd --- /dev/null +++ b/misc/cgo/testshared/src/execgo/exe.go @@ -0,0 +1,8 @@ +package main + +/* + */ +import "C" + +func main() { +} diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index ba906fbde3b..faa5fc9fd68 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1290,25 +1290,34 @@ func ldshlibsyms(shlib string) { Diag("cannot read symbols from shared library: %s", libpath) return } - for _, s := range syms { - if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION { + for _, elfsym := range syms { + if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION { continue } - lsym := Linklookup(Ctxt, s.Name, 0) + lsym := Linklookup(Ctxt, elfsym.Name, 0) if lsym.Type != 0 && lsym.Type != obj.SDYNIMPORT && lsym.Dupok == 0 { - Diag( - "Found duplicate symbol %s reading from %s, first found in %s", - s.Name, shlib, lsym.File) + 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 + } } lsym.Type = obj.SDYNIMPORT - lsym.ElfType = elf.ST_TYPE(s.Info) - if s.Section != elf.SHN_UNDEF { + lsym.ElfType = elf.ST_TYPE(elfsym.Info) + lsym.Size = int64(elfsym.Size) + if elfsym.Section != elf.SHN_UNDEF { // Set .File for the library that actually defines the symbol. lsym.File = libpath // The decodetype_* functions in decodetype.go need access to // the type data. if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") { - lsym.P = readelfsymboldata(f, &s) + lsym.P = readelfsymboldata(f, &elfsym) } } }