]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/ld: support for -buildmode=shared
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Mon, 30 Mar 2015 02:59:10 +0000 (02:59 +0000)
committerIan Lance Taylor <iant@golang.org>
Thu, 9 Apr 2015 00:51:02 +0000 (00:51 +0000)
Change-Id: Id4997d611ced29397133f14def6abc88aa9e811e
Reviewed-on: https://go-review.googlesource.com/8252
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/6l/asm.go
src/cmd/6l/obj.go
src/cmd/internal/ld/data.go
src/cmd/internal/ld/elf.go
src/cmd/internal/ld/go.go
src/cmd/internal/ld/lib.go
src/cmd/internal/ld/link.go
src/cmd/internal/ld/objfile.go
src/cmd/internal/ld/pcln.go
src/cmd/internal/ld/pobj.go
src/cmd/internal/ld/symtab.go

index c55dae462df4577de8fe9dc7c1725cb73d2ee802..07bb7c418f4f27e63997b8b42da145924f9f344b 100644 (file)
@@ -313,7 +313,11 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
        case ld.R_CALL:
                if r.Siz == 4 {
                        if r.Xsym.Type == ld.SDYNIMPORT {
-                               ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
+                               if ld.DynlinkingGo() {
+                                       ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
+                               } else {
+                                       ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
+                               }
                        } else {
                                ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
                        }
index ad1cf92bd542e0c0ee73b98e651652170b25ccc7..a1e012bec7a956da57ef68434d67f686592923fd 100644 (file)
@@ -91,7 +91,7 @@ func archinit() {
                ld.Linkmode = ld.LinkInternal
        }
 
-       if ld.Buildmode == ld.BuildmodeCShared {
+       if ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
                ld.Linkmode = ld.LinkExternal
        }
 
index 76446b1187d0c48275926f0256826a05a71b077b..39dfea910f08da05f1f8eac313af786762dabd3f 100644 (file)
@@ -333,8 +333,14 @@ func relocsym(s *LSym) {
                }
 
                if r.Sym != nil && (r.Sym.Type&(SMASK|SHIDDEN) == 0 || r.Sym.Type&SMASK == SXREF) {
-                       Diag("%s: not defined", r.Sym.Name)
-                       continue
+                       // When putting the runtime but not main into a shared library
+                       // these symbols are undefined and that's OK.
+                       if Buildmode == BuildmodeShared && (r.Sym.Name == "main.main" || r.Sym.Name == "main.init") {
+                               r.Sym.Type = SDYNIMPORT
+                       } else {
+                               Diag("%s: not defined", r.Sym.Name)
+                               continue
+                       }
                }
 
                if r.Type >= 256 {
@@ -344,8 +350,9 @@ func relocsym(s *LSym) {
                        continue
                }
 
-               // Solaris needs the ability to reference dynimport symbols.
-               if HEADTYPE != Hsolaris && r.Sym != nil && r.Sym.Type == SDYNIMPORT {
+               // We need to be able to reference dynimport symbols when linking against
+               // shared libraries, and Solaris needs it always
+               if HEADTYPE != Hsolaris && r.Sym != nil && r.Sym.Type == SDYNIMPORT && !DynlinkingGo() {
                        Diag("unhandled relocation for %s (type %d rtype %d)", r.Sym.Name, r.Sym.Type, r.Type)
                }
                if r.Sym != nil && r.Sym.Type != STLSBSS && !r.Sym.Reachable {
@@ -1322,7 +1329,7 @@ func dodata() {
        sect.Length = uint64(datsize) - sect.Vaddr
 
        /* shared library initializer */
-       if Buildmode == BuildmodeCShared {
+       if Buildmode == BuildmodeCShared || DynlinkingGo() {
                sect := addsection(&Segdata, ".init_array", 06)
                sect.Align = maxalign(s, SINITARR)
                datsize = Rnd(datsize, int64(sect.Align))
@@ -1728,10 +1735,12 @@ func address() {
        xdefine("runtime.etypelink", SRODATA, int64(typelink.Vaddr+typelink.Length))
 
        sym := Linklookup(Ctxt, "runtime.gcdata", 0)
+       sym.Local = true
        xdefine("runtime.egcdata", SRODATA, Symaddr(sym)+sym.Size)
        Linklookup(Ctxt, "runtime.egcdata", 0).Sect = sym.Sect
 
        sym = Linklookup(Ctxt, "runtime.gcbss", 0)
+       sym.Local = true
        xdefine("runtime.egcbss", SRODATA, Symaddr(sym)+sym.Size)
        Linklookup(Ctxt, "runtime.egcbss", 0).Sect = sym.Sect
 
index 3448fe6ce4fdd37ed38be1419bf8e6d1d3116564..a7674da3117d140e4cc04e3bac4398c7b2134155 100644 (file)
@@ -1658,7 +1658,7 @@ func doelf() {
                Addstring(shstrtab, ".note.GNU-stack")
        }
 
-       if Buildmode == BuildmodeCShared {
+       if Buildmode == BuildmodeCShared || DynlinkingGo() {
                Addstring(shstrtab, ".init_array")
                switch Thearch.Thechar {
                case '6', '7', '9':
index fac72f7d0523004377e678fea13720defdba8675..55c9bb20a93627ec773873264c8d7f3e51a4c3ba 100644 (file)
@@ -619,47 +619,58 @@ func deadcode() {
                fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime())
        }
 
-       mark(Linklookup(Ctxt, INITENTRY, 0))
-       for i := 0; i < len(markextra); i++ {
-               mark(Linklookup(Ctxt, markextra[i], 0))
-       }
-
-       for i := 0; i < len(dynexp); i++ {
-               mark(dynexp[i])
-       }
+       if Buildmode == BuildmodeShared {
+               // Mark all symbols as reachable when building a
+               // shared library.
+               for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+                       if s.Type != 0 {
+                               mark(s)
+                       }
+               }
+               mark(Linkrlookup(Ctxt, "main.main", 0))
+               mark(Linkrlookup(Ctxt, "main.init", 0))
+       } else {
+               mark(Linklookup(Ctxt, INITENTRY, 0))
+               for i := 0; i < len(markextra); i++ {
+                       mark(Linklookup(Ctxt, markextra[i], 0))
+               }
 
-       markflood()
+               for i := 0; i < len(dynexp); i++ {
+                       mark(dynexp[i])
+               }
+               markflood()
 
-       // keep each beginning with 'typelink.' if the symbol it points at is being kept.
-       for s := Ctxt.Allsym; s != nil; s = s.Allsym {
-               if strings.HasPrefix(s.Name, "go.typelink.") {
-                       s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable
+               // keep each beginning with 'typelink.' if the symbol it points at is being kept.
+               for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+                       if strings.HasPrefix(s.Name, "go.typelink.") {
+                               s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable
+                       }
                }
-       }
 
-       // remove dead text but keep file information (z symbols).
-       var last *LSym
+               // remove dead text but keep file information (z symbols).
+               var last *LSym
 
-       for s := Ctxt.Textp; s != nil; s = s.Next {
-               if !s.Reachable {
-                       continue
+               for s := Ctxt.Textp; s != nil; s = s.Next {
+                       if !s.Reachable {
+                               continue
+                       }
+
+                       // NOTE: Removing s from old textp and adding to new, shorter textp.
+                       if last == nil {
+                               Ctxt.Textp = s
+                       } else {
+                               last.Next = s
+                       }
+                       last = s
                }
 
-               // NOTE: Removing s from old textp and adding to new, shorter textp.
                if last == nil {
-                       Ctxt.Textp = s
+                       Ctxt.Textp = nil
+                       Ctxt.Etextp = nil
                } else {
-                       last.Next = s
+                       last.Next = nil
+                       Ctxt.Etextp = last
                }
-               last = s
-       }
-
-       if last == nil {
-               Ctxt.Textp = nil
-               Ctxt.Etextp = nil
-       } else {
-               last.Next = nil
-               Ctxt.Etextp = last
        }
 
        for s := Ctxt.Allsym; s != nil; s = s.Allsym {
index 2829b5b9f4f76d45df8d2511f95070755f32c4bf..ed54ce87aee7b3ca2d52d8807181bc2c85a2d64e 100644 (file)
@@ -150,6 +150,14 @@ type Section struct {
        Rellen  uint64
 }
 
+// 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
+}
+
 var (
        Thestring          string
        Thelinkarch        *LinkArch
@@ -241,11 +249,15 @@ func Lflag(arg string) {
 //   "c-shared": build a main package, plus all packages that it imports, into a
 //     single C shared library. The only callable symbols will be those functions
 //     marked as exported.
+//   "shared": combine all packages passed on the command line, and their
+//     dependencies, into a single shared library that will be used when
+//     building with the -linkshared option.
 type BuildMode uint8
 
 const (
        BuildmodeExe BuildMode = iota
        BuildmodeCShared
+       BuildmodeShared
 )
 
 func (mode *BuildMode) Set(s string) error {
@@ -260,6 +272,13 @@ func (mode *BuildMode) Set(s string) error {
                        return fmt.Errorf("not supported on %s", goarch)
                }
                *mode = BuildmodeCShared
+       case "shared":
+               goos := obj.Getgoos()
+               goarch := obj.Getgoarch()
+               if goos != "linux" || goarch != "amd64" {
+                       return fmt.Errorf("not supported on %s/%s", goos, goarch)
+               }
+               *mode = BuildmodeShared
        }
        return nil
 }
@@ -270,6 +289,8 @@ func (mode *BuildMode) String() string {
                return "exe"
        case BuildmodeCShared:
                return "c-shared"
+       case BuildmodeShared:
+               return "shared"
        }
        return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
 }
@@ -321,12 +342,16 @@ func libinit() {
                        INITENTRY = fmt.Sprintf("_rt0_%s_%s_lib", goarch, goos)
                case BuildmodeExe:
                        INITENTRY = fmt.Sprintf("_rt0_%s_%s", goarch, goos)
+               case BuildmodeShared:
+                       // No INITENTRY for -buildmode=shared
                default:
                        Diag("unknown INITENTRY for buildmode %v", Buildmode)
                }
        }
 
-       Linklookup(Ctxt, INITENTRY, 0).Type = SXREF
+       if !DynlinkingGo() {
+               Linklookup(Ctxt, INITENTRY, 0).Type = SXREF
+       }
 }
 
 func Errorexit() {
@@ -790,6 +815,16 @@ func hostlink() {
        if Buildmode == BuildmodeCShared {
                argv = append(argv, "-Wl,-Bsymbolic")
                argv = append(argv, "-shared")
+       } else if Buildmode == 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")
+               argv = append(argv, "-shared")
        }
 
        argv = append(argv, "-o")
@@ -1162,7 +1197,8 @@ func stkcheck(up *Chain, depth int) int {
                // external function.
                // should never be called directly.
                // only diagnose the direct caller.
-               if depth == 1 && s.Type != SXREF {
+               // TODO(mwhudson): actually think about this.
+               if depth == 1 && s.Type != SXREF && !DynlinkingGo() {
                        Diag("call to external function %s", s.Name)
                }
                return -1
@@ -1477,6 +1513,7 @@ func xdefine(p string, t int, v int64) {
        s.Value = v
        s.Reachable = true
        s.Special = 1
+       s.Local = true
 }
 
 func datoff(addr int64) int64 {
index 0a63567dd18310e80aaa75a72b1e5f7adfcfc20c..47af2ae77ff1a88aae98663b15aa0c4416a1c44d 100644 (file)
@@ -74,6 +74,7 @@ type LSym struct {
        Pcln        *Pcln
        P           []byte
        R           []Reloc
+       Local       bool
 }
 
 type Reloc struct {
index 34176bee6e9fe0779ce8dd47f9efc0be59c19607..ec846736ac4a6f807ec11853daf0891e3bf1002f 100644 (file)
@@ -327,12 +327,14 @@ func rdsym(ctxt *Link, f *Biobuf, pkg string) *LSym {
                        x, _ := strconv.ParseUint(s.Name[5:], 16, 32)
                        i32 := int32(x)
                        s.Type = SRODATA
+                       s.Local = true
                        Adduint32(ctxt, s, uint32(i32))
                        s.Reachable = false
                } else if strings.HasPrefix(s.Name, "$f64.") || strings.HasPrefix(s.Name, "$i64.") {
                        x, _ := strconv.ParseUint(s.Name[5:], 16, 64)
                        i64 := int64(x)
                        s.Type = SRODATA
+                       s.Local = true
                        Adduint64(ctxt, s, uint64(i64))
                        s.Reachable = false
                }
index 65ca0c32eab6b7e3cc5d6ac45d5294939cef782a..042be01d21b6819cd44005bbf1e9ab4ad9a50f4b 100644 (file)
@@ -380,6 +380,7 @@ func findfunctab() {
        t := Linklookup(Ctxt, "runtime.findfunctab", 0)
        t.Type = SRODATA
        t.Reachable = true
+       t.Local = true
 
        // find min and max address
        min := Ctxt.Textp.Value
index 32a89084402c92d4761d1bee91723e164f7602ee..539e3d353aedab73428bb6537c12d482d56cf9a9 100644 (file)
@@ -152,7 +152,7 @@ func Ldmain() {
                }
        }
 
-       if flag.NArg() != 1 {
+       if Buildmode != BuildmodeShared && flag.NArg() != 1 {
                usage()
        }
 
@@ -181,7 +181,21 @@ func Ldmain() {
        }
        Bflush(&Bso)
 
-       addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main")
+       if Buildmode == BuildmodeShared {
+               for i := 0; i < flag.NArg(); i++ {
+                       arg := flag.Arg(i)
+                       parts := strings.SplitN(arg, "=", 2)
+                       var pkgpath, file string
+                       if len(parts) == 1 {
+                               pkgpath, file = "main", arg
+                       } else {
+                               pkgpath, file = parts[0], parts[1]
+                       }
+                       addlibpath(Ctxt, "command line", "command line", file, pkgpath)
+               }
+       } else {
+               addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main")
+       }
        loadlib()
 
        if Thearch.Thechar == '5' {
index af818ce3aa9a3b076c6db024d2546689ef218ad0..7bcc1c667a4154b86be75f90fbe25f4f75c52271 100644 (file)
@@ -40,8 +40,13 @@ func putelfstr(s string) int {
                putelfstr("")
        }
 
-       // Rewrite · to . for ASCII-only tools like DTrace (sigh)
-       s = strings.Replace(s, "·", ".", -1)
+       // When dynamically linking, we create LSym's by reading the names from
+       // the symbol tables of the shared libraries and so the names need to
+       // match exactly.  Tools like DTrace will have to wait for now.
+       if !DynlinkingGo() {
+               // Rewrite · to . for ASCII-only tools like DTrace (sigh)
+               s = strings.Replace(s, "·", ".", -1)
+       }
 
        n := len(s) + 1
        for len(Elfstrdat)+n > cap(Elfstrdat) {
@@ -130,7 +135,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
        // maybe one day STB_WEAK.
        bind := STB_GLOBAL
 
-       if ver != 0 || (x.Type&SHIDDEN != 0) {
+       if ver != 0 || (x.Type&SHIDDEN != 0) || x.Local {
                bind = STB_LOCAL
        }
 
@@ -138,7 +143,8 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
        // to get the exported symbols put into the dynamic symbol table.
        // To avoid filling the dynamic table with lots of unnecessary symbols,
        // mark all Go symbols local (not global) in the final executable.
-       if Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 && elfshnum != SHN_UNDEF {
+       // But when we're dynamically linking, we need all those global symbols.
+       if !DynlinkingGo() && Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 && elfshnum != SHN_UNDEF {
                bind = STB_LOCAL
        }
 
@@ -322,21 +328,26 @@ func symtab() {
        xdefine("runtime.egcbss", SRODATA, 0)
 
        // pseudo-symbols to mark locations of type, string, and go string data.
-       s = Linklookup(Ctxt, "type.*", 0)
-
-       s.Type = STYPE
-       s.Size = 0
-       s.Reachable = true
-       symtype := s
+       var symtype *LSym
+       if !DynlinkingGo() {
+               s = Linklookup(Ctxt, "type.*", 0)
+
+               s.Type = STYPE
+               s.Size = 0
+               s.Reachable = true
+               symtype = s
+       }
 
        s = Linklookup(Ctxt, "go.string.*", 0)
        s.Type = SGOSTRING
+       s.Local = true
        s.Size = 0
        s.Reachable = true
        symgostring := s
 
        s = Linklookup(Ctxt, "go.func.*", 0)
        s.Type = SGOFUNC
+       s.Local = true
        s.Size = 0
        s.Reachable = true
        symgofunc := s
@@ -344,6 +355,7 @@ func symtab() {
        symtypelink := Linklookup(Ctxt, "runtime.typelink", 0)
 
        symt = Linklookup(Ctxt, "runtime.symtab", 0)
+       symt.Local = true
        symt.Type = SSYMTAB
        symt.Size = 0
        symt.Reachable = true
@@ -358,7 +370,7 @@ func symtab() {
                if !s.Reachable || s.Special != 0 || s.Type != SRODATA {
                        continue
                }
-               if strings.HasPrefix(s.Name, "type.") {
+               if strings.HasPrefix(s.Name, "type.") && !DynlinkingGo() {
                        s.Type = STYPE
                        s.Hide = 1
                        s.Outer = symtype
@@ -400,6 +412,7 @@ func symtab() {
        moduledata.Type = SNOPTRDATA
        moduledata.Size = 0 // truncate symbol back to 0 bytes to reinitialize
        moduledata.Reachable = true
+       moduledata.Local = true
        // The pclntab slice
        Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0))
        adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size))