]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: allow symbols from .a files to override those from .so files
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Wed, 20 Jan 2016 02:31:26 +0000 (15:31 +1300)
committerMichael Hudson-Doyle <michael.hudson@canonical.com>
Wed, 20 Jan 2016 19:53:53 +0000 (19:53 +0000)
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/18714
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>

misc/cgo/testshared/shared_test.go
misc/cgo/testshared/src/explicit/explicit.go [new file with mode: 0644]
misc/cgo/testshared/src/implicit/implicit.go [new file with mode: 0644]
misc/cgo/testshared/src/implicitcmd/implicitcmd.go [new file with mode: 0644]
src/cmd/link/internal/ld/lib.go

index 592a91715e7114dab7ed9a6aca08a71f50150aab..86fb530167de0a88339fed2cc816383bef36f186 100644 (file)
@@ -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")
+}
diff --git a/misc/cgo/testshared/src/explicit/explicit.go b/misc/cgo/testshared/src/explicit/explicit.go
new file mode 100644 (file)
index 0000000..6a4453f
--- /dev/null
@@ -0,0 +1,9 @@
+package explicit
+
+import (
+       "implicit"
+)
+
+func E() int {
+       return implicit.I()
+}
diff --git a/misc/cgo/testshared/src/implicit/implicit.go b/misc/cgo/testshared/src/implicit/implicit.go
new file mode 100644 (file)
index 0000000..5360188
--- /dev/null
@@ -0,0 +1,5 @@
+package implicit
+
+func I() int {
+       return 42
+}
diff --git a/misc/cgo/testshared/src/implicitcmd/implicitcmd.go b/misc/cgo/testshared/src/implicitcmd/implicitcmd.go
new file mode 100644 (file)
index 0000000..f611293
--- /dev/null
@@ -0,0 +1,10 @@
+package main
+
+import (
+       "explicit"
+       "implicit"
+)
+
+func main() {
+       println(implicit.I() + explicit.E())
+}
index 75612503b1e31126eeab11cc7c12905c4e6f8d5d..a23a437e3d0023001ec5dc1c866839c770e0752b 100644 (file)
@@ -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)