]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/6l: support -linkshared
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Wed, 1 Apr 2015 01:57:34 +0000 (14:57 +1300)
committerIan Lance Taylor <iant@golang.org>
Sat, 11 Apr 2015 19:36:19 +0000 (19:36 +0000)
Change-Id: Id469165b1acd383837b1f4e1e6f961e10dfa5d61
Reviewed-on: https://go-review.googlesource.com/8332
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>

src/cmd/internal/ld/go.go
src/cmd/internal/ld/ld.go
src/cmd/internal/ld/lib.go
src/cmd/internal/ld/link.go
src/cmd/internal/ld/pobj.go
src/cmd/internal/ld/symtab.go

index 55c9bb20a93627ec773873264c8d7f3e51a4c3ba..1d83081025fbba8eaef4bc95aa0f1a843cc04a88 100644 (file)
@@ -631,6 +631,10 @@ func deadcode() {
                mark(Linkrlookup(Ctxt, "main.init", 0))
        } else {
                mark(Linklookup(Ctxt, INITENTRY, 0))
+               if Linkshared && Buildmode == BuildmodeExe {
+                       mark(Linkrlookup(Ctxt, "main.main", 0))
+                       mark(Linkrlookup(Ctxt, "main.init", 0))
+               }
                for i := 0; i < len(markextra); i++ {
                        mark(Linklookup(Ctxt, markextra[i], 0))
                }
index a0f1f325bd87d2dda6b2d58959bcb6bfa6d6a2e8..7242301d0f6f4bd37b7f312caabf1125fbc7cdfc 100644 (file)
@@ -34,6 +34,7 @@ package ld
 import (
        "cmd/internal/obj"
        "fmt"
+       "io/ioutil"
        "os"
        "path"
        "strconv"
@@ -57,11 +58,19 @@ func addlib(ctxt *Link, src string, obj string, pathname string) {
        }
 
        var pname string
+       isshlib := false
        if (ctxt.Windows == 0 && strings.HasPrefix(name, "/")) || (ctxt.Windows != 0 && len(name) >= 2 && name[1] == ':') {
                pname = name
        } else {
                // try dot, -L "libdir", and then goroot.
                for _, dir := range ctxt.Libdir {
+                       if Linkshared {
+                               pname = dir + "/" + pkg + ".shlibname"
+                               if _, err := os.Stat(pname); err == nil {
+                                       isshlib = true
+                                       break
+                               }
+                       }
                        pname = dir + "/" + name
                        if _, err := os.Stat(pname); err == nil {
                                break
@@ -72,10 +81,14 @@ func addlib(ctxt *Link, src string, obj string, pathname string) {
        pname = path.Clean(pname)
 
        if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
-               fmt.Fprintf(ctxt.Bso, "%5.2f addlib: %s %s pulls in %s\n", elapsed(), obj, src, pname)
+               fmt.Fprintf(ctxt.Bso, "%5.2f addlib: %s %s pulls in %s isshlib %v\n", elapsed(), obj, src, pname, isshlib)
        }
 
-       addlibpath(ctxt, src, obj, pname, pkg)
+       if isshlib {
+               addlibpath(ctxt, src, obj, "", pkg, pname)
+       } else {
+               addlibpath(ctxt, src, obj, pname, pkg, "")
+       }
 }
 
 /*
@@ -85,15 +98,15 @@ func addlib(ctxt *Link, src string, obj string, pathname string) {
  *     file: object file, e.g., /home/rsc/go/pkg/container/vector.a
  *     pkg: package import path, e.g. container/vector
  */
-func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string) {
+func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlibnamefile string) {
        for i := 0; i < len(ctxt.Library); i++ {
-               if file == ctxt.Library[i].File {
+               if pkg == ctxt.Library[i].Pkg {
                        return
                }
        }
 
        if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
-               fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", obj.Cputime(), srcref, objref, file, pkg)
+               fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlibnamefile: %s\n", obj.Cputime(), srcref, objref, file, pkg, shlibnamefile)
        }
 
        ctxt.Library = append(ctxt.Library, Library{})
@@ -102,6 +115,13 @@ func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg strin
        l.Srcref = srcref
        l.File = file
        l.Pkg = pkg
+       if shlibnamefile != "" {
+               shlibbytes, err := ioutil.ReadFile(shlibnamefile)
+               if err != nil {
+                       Diag("cannot read %s: %v", shlibnamefile, err)
+               }
+               l.Shlib = strings.TrimSpace(string(shlibbytes))
+       }
 }
 
 func atolwhex(s string) int64 {
index ed54ce87aee7b3ca2d52d8807181bc2c85a2d64e..02d93af6d6d42f03d86e407572791b08b67359ec 100644 (file)
@@ -33,6 +33,7 @@ package ld
 import (
        "bytes"
        "cmd/internal/obj"
+       "debug/elf"
        "errors"
        "fmt"
        "io"
@@ -40,6 +41,7 @@ import (
        "log"
        "os"
        "os/exec"
+       "path/filepath"
        "strings"
 )
 
@@ -153,9 +155,7 @@ type Section struct {
 // DynlinkingGo returns whether we are producing Go code that can live
 // in separate shared libraries linked together at runtime.
 func DynlinkingGo() bool {
-       // TODO(mwhudson): This is a bit silly for now, but it will need to have
-       // "|| Linkshared" appended when a subsequent change adds that flag.
-       return Buildmode == BuildmodeShared
+       return Buildmode == BuildmodeShared || Linkshared
 }
 
 var (
@@ -171,6 +171,7 @@ var (
        flag_installsuffix string
        flag_race          int
        Buildmode          BuildMode
+       Linkshared         bool
        tracksym           string
        interpreter        string
        tmpdir             string
@@ -371,16 +372,25 @@ func Errorexit() {
 }
 
 func loadinternal(name string) {
-       var pname string
-
        found := 0
        for i := 0; i < len(Ctxt.Libdir); i++ {
-               pname = fmt.Sprintf("%s/%s.a", Ctxt.Libdir[i], name)
+               if Linkshared {
+                       shlibname := fmt.Sprintf("%s/%s.shlibname", Ctxt.Libdir[i], name)
+                       if Debug['v'] != 0 {
+                               fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, shlibname)
+                       }
+                       if obj.Access(shlibname, obj.AEXIST) >= 0 {
+                               addlibpath(Ctxt, "internal", "internal", "", name, shlibname)
+                               found = 1
+                               break
+                       }
+               }
+               pname := fmt.Sprintf("%s/%s.a", Ctxt.Libdir[i], name)
                if Debug['v'] != 0 {
                        fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, pname)
                }
                if obj.Access(pname, obj.AEXIST) >= 0 {
-                       addlibpath(Ctxt, "internal", "internal", pname, name)
+                       addlibpath(Ctxt, "internal", "internal", pname, name, "")
                        found = 1
                        break
                }
@@ -412,7 +422,11 @@ func loadlib() {
                        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"
-               objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+               if Ctxt.Library[i].Shlib != "" {
+                       ldshlibsyms(Ctxt.Library[i].Shlib)
+               } else {
+                       objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+               }
        }
 
        if Linkmode == LinkAuto {
@@ -451,7 +465,11 @@ func loadlib() {
                loadinternal("runtime/cgo")
 
                if i < len(Ctxt.Library) {
-                       objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+                       if Ctxt.Library[i].Shlib != "" {
+                               ldshlibsyms(Ctxt.Library[i].Shlib)
+                       } else {
+                               objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
+                       }
                }
        }
 
@@ -482,7 +500,7 @@ func loadlib() {
        // TODO(crawshaw): android should require leaving the tlsg->type
        // alone (as the runtime-provided SNOPTRBSS) just like darwin/arm.
        // But some other part of the linker is expecting STLSBSS.
-       if goos != "darwin" || Thearch.Thechar != '5' {
+       if tlsg.Type != SDYNIMPORT && (goos != "darwin" || Thearch.Thechar != '5') {
                tlsg.Type = STLSBSS
        }
        tlsg.Size = int64(Thearch.Ptrsize)
@@ -827,6 +845,13 @@ func hostlink() {
                argv = append(argv, "-shared")
        }
 
+       if Linkshared && Iself {
+               // We force all symbol resolution to be done at program startup
+               // because lazy PLT resolution can use large amounts of stack at
+               // times we cannot allow it to do so.
+               argv = append(argv, "-znow")
+       }
+
        argv = append(argv, "-o")
        argv = append(argv, outfile)
 
@@ -879,6 +904,18 @@ func hostlink() {
        }
 
        argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
+
+       if Linkshared {
+               for _, shlib := range Ctxt.Shlibs {
+                       dir, base := filepath.Split(shlib)
+                       argv = append(argv, "-L"+dir)
+                       argv = append(argv, "-Wl,-rpath="+dir)
+                       base = strings.TrimSuffix(base, ".so")
+                       base = strings.TrimPrefix(base, "lib")
+                       argv = append(argv, "-l"+base)
+               }
+       }
+
        argv = append(argv, ldflag...)
 
        for _, p := range strings.Fields(extldflags) {
@@ -1029,6 +1066,91 @@ eof:
        Diag("truncated object file: %s", pn)
 }
 
+func ldshlibsyms(shlib string) {
+       found := false
+       libpath := ""
+       for _, libdir := range Ctxt.Libdir {
+               libpath = filepath.Join(libdir, shlib)
+               if _, err := os.Stat(libpath); err == nil {
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               Diag("cannot find shared library: %s", shlib)
+               return
+       }
+       for _, processedname := range Ctxt.Shlibs {
+               if processedname == libpath {
+                       return
+               }
+       }
+       if Ctxt.Debugvlog > 1 && Ctxt.Bso != nil {
+               fmt.Fprintf(Ctxt.Bso, "%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath)
+               Bflush(Ctxt.Bso)
+       }
+
+       f, err := elf.Open(libpath)
+       if err != nil {
+               Diag("cannot open shared library: %s", libpath)
+               return
+       }
+       defer f.Close()
+       syms, err := f.DynamicSymbols()
+       if err != nil {
+               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 {
+                       continue
+               }
+               if s.Section == elf.SHN_UNDEF {
+                       continue
+               }
+               if strings.HasPrefix(s.Name, "_") {
+                       continue
+               }
+               lsym := Linklookup(Ctxt, s.Name, 0)
+               if lsym.Type != 0 && lsym.Dupok == 0 {
+                       Diag(
+                               "Found duplicate symbol %s reading from %s, first found in %s",
+                               s.Name, shlib, lsym.File)
+               }
+               lsym.Type = SDYNIMPORT
+               lsym.File = libpath
+       }
+
+       // We might have overwritten some functions above (this tends to happen for the
+       // autogenerated type equality/hashing functions) and we don't want to generated
+       // pcln table entries for these any more so unstitch them from the Textp linked
+       // list.
+       var last *LSym
+
+       for s := Ctxt.Textp; s != nil; s = s.Next {
+               if s.Type == SDYNIMPORT {
+                       continue
+               }
+
+               if last == nil {
+                       Ctxt.Textp = s
+               } else {
+                       last.Next = s
+               }
+               last = s
+       }
+
+       if last == nil {
+               Ctxt.Textp = nil
+               Ctxt.Etextp = nil
+       } else {
+               last.Next = nil
+               Ctxt.Etextp = last
+       }
+
+       Ctxt.Shlibs = append(Ctxt.Shlibs, libpath)
+}
+
 func mywhatsys() {
        goroot = obj.Getgoroot()
        goos = obj.Getgoos()
index 83cfe283f4fe08f6674b35520b9f97fac5aafa24..0eca045f7dbf324a127c2638a752427b3c8e9f6f 100644 (file)
@@ -114,6 +114,7 @@ type Link struct {
        Tlsg      *LSym
        Libdir    []string
        Library   []Library
+       Shlibs    []string
        Tlsoffset int
        Diag      func(string, ...interface{})
        Cursym    *LSym
@@ -138,6 +139,7 @@ type Library struct {
        Srcref string
        File   string
        Pkg    string
+       Shlib  string
 }
 
 type Pcln struct {
index 539e3d353aedab73428bb6537c12d482d56cf9a9..c4e779df7a9c10dc96e5fa2baabfa8cdcfa09785 100644 (file)
@@ -112,6 +112,7 @@ func Ldmain() {
        obj.Flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix)
        obj.Flagstr("k", "sym: set field tracking symbol", &tracksym)
        obj.Flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode)
+       flag.BoolVar(&Linkshared, "linkshared", false, "link against installed Go shared libraries")
        obj.Flagcount("n", "dump symbol table", &Debug['n'])
        obj.Flagstr("o", "outfile: set output file", &outfile)
        obj.Flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath)
@@ -176,6 +177,11 @@ func Ldmain() {
 
        Thearch.Archinit()
 
+       if Linkshared && !Iself {
+               Diag("-linkshared can only be used on elf systems")
+               Errorexit()
+       }
+
        if Debug['v'] != 0 {
                fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
        }
@@ -191,10 +197,10 @@ func Ldmain() {
                        } else {
                                pkgpath, file = parts[0], parts[1]
                        }
-                       addlibpath(Ctxt, "command line", "command line", file, pkgpath)
+                       addlibpath(Ctxt, "command line", "command line", file, pkgpath, "")
                }
        } else {
-               addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main")
+               addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main", "")
        }
        loadlib()
 
index c31f70abd12aff21ee0f253f7907703115aa254b..1898a9b818b3ff4da3167a4cbdc08b73b04411f3 100644 (file)
@@ -104,6 +104,9 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
 
        case 'U':
                type_ = STT_NOTYPE
+               if x == Ctxt.Tlsg {
+                       type_ = STT_TLS
+               }
 
        case 't':
                type_ = STT_TLS