mirror of
https://github.com/golang/go
synced 2024-10-03 06:21:21 -06:00
cmd/6l: support -linkshared
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>
This commit is contained in:
parent
ce469fadd8
commit
75c0566b55
@ -631,6 +631,10 @@ func deadcode() {
|
|||||||
mark(Linkrlookup(Ctxt, "main.init", 0))
|
mark(Linkrlookup(Ctxt, "main.init", 0))
|
||||||
} else {
|
} else {
|
||||||
mark(Linklookup(Ctxt, INITENTRY, 0))
|
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++ {
|
for i := 0; i < len(markextra); i++ {
|
||||||
mark(Linklookup(Ctxt, markextra[i], 0))
|
mark(Linklookup(Ctxt, markextra[i], 0))
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ package ld
|
|||||||
import (
|
import (
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -57,11 +58,19 @@ func addlib(ctxt *Link, src string, obj string, pathname string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pname string
|
var pname string
|
||||||
|
isshlib := false
|
||||||
if (ctxt.Windows == 0 && strings.HasPrefix(name, "/")) || (ctxt.Windows != 0 && len(name) >= 2 && name[1] == ':') {
|
if (ctxt.Windows == 0 && strings.HasPrefix(name, "/")) || (ctxt.Windows != 0 && len(name) >= 2 && name[1] == ':') {
|
||||||
pname = name
|
pname = name
|
||||||
} else {
|
} else {
|
||||||
// try dot, -L "libdir", and then goroot.
|
// try dot, -L "libdir", and then goroot.
|
||||||
for _, dir := range ctxt.Libdir {
|
for _, dir := range ctxt.Libdir {
|
||||||
|
if Linkshared {
|
||||||
|
pname = dir + "/" + pkg + ".shlibname"
|
||||||
|
if _, err := os.Stat(pname); err == nil {
|
||||||
|
isshlib = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
pname = dir + "/" + name
|
pname = dir + "/" + name
|
||||||
if _, err := os.Stat(pname); err == nil {
|
if _, err := os.Stat(pname); err == nil {
|
||||||
break
|
break
|
||||||
@ -72,10 +81,14 @@ func addlib(ctxt *Link, src string, obj string, pathname string) {
|
|||||||
pname = path.Clean(pname)
|
pname = path.Clean(pname)
|
||||||
|
|
||||||
if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
|
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
|
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
|
||||||
* pkg: package import path, e.g. container/vector
|
* 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++ {
|
for i := 0; i < len(ctxt.Library); i++ {
|
||||||
if file == ctxt.Library[i].File {
|
if pkg == ctxt.Library[i].Pkg {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
|
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{})
|
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.Srcref = srcref
|
||||||
l.File = file
|
l.File = file
|
||||||
l.Pkg = pkg
|
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 {
|
func atolwhex(s string) int64 {
|
||||||
|
@ -33,6 +33,7 @@ package ld
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
|
"debug/elf"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -40,6 +41,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -153,9 +155,7 @@ type Section struct {
|
|||||||
// DynlinkingGo returns whether we are producing Go code that can live
|
// DynlinkingGo returns whether we are producing Go code that can live
|
||||||
// in separate shared libraries linked together at runtime.
|
// in separate shared libraries linked together at runtime.
|
||||||
func DynlinkingGo() bool {
|
func DynlinkingGo() bool {
|
||||||
// TODO(mwhudson): This is a bit silly for now, but it will need to have
|
return Buildmode == BuildmodeShared || Linkshared
|
||||||
// "|| Linkshared" appended when a subsequent change adds that flag.
|
|
||||||
return Buildmode == BuildmodeShared
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -171,6 +171,7 @@ var (
|
|||||||
flag_installsuffix string
|
flag_installsuffix string
|
||||||
flag_race int
|
flag_race int
|
||||||
Buildmode BuildMode
|
Buildmode BuildMode
|
||||||
|
Linkshared bool
|
||||||
tracksym string
|
tracksym string
|
||||||
interpreter string
|
interpreter string
|
||||||
tmpdir string
|
tmpdir string
|
||||||
@ -371,16 +372,25 @@ func Errorexit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadinternal(name string) {
|
func loadinternal(name string) {
|
||||||
var pname string
|
|
||||||
|
|
||||||
found := 0
|
found := 0
|
||||||
for i := 0; i < len(Ctxt.Libdir); i++ {
|
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 {
|
if Debug['v'] != 0 {
|
||||||
fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, pname)
|
fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, pname)
|
||||||
}
|
}
|
||||||
if obj.Access(pname, obj.AEXIST) >= 0 {
|
if obj.Access(pname, obj.AEXIST) >= 0 {
|
||||||
addlibpath(Ctxt, "internal", "internal", pname, name)
|
addlibpath(Ctxt, "internal", "internal", pname, name, "")
|
||||||
found = 1
|
found = 1
|
||||||
break
|
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)
|
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"
|
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 {
|
if Linkmode == LinkAuto {
|
||||||
@ -451,7 +465,11 @@ func loadlib() {
|
|||||||
loadinternal("runtime/cgo")
|
loadinternal("runtime/cgo")
|
||||||
|
|
||||||
if i < len(Ctxt.Library) {
|
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
|
// TODO(crawshaw): android should require leaving the tlsg->type
|
||||||
// alone (as the runtime-provided SNOPTRBSS) just like darwin/arm.
|
// alone (as the runtime-provided SNOPTRBSS) just like darwin/arm.
|
||||||
// But some other part of the linker is expecting STLSBSS.
|
// 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.Type = STLSBSS
|
||||||
}
|
}
|
||||||
tlsg.Size = int64(Thearch.Ptrsize)
|
tlsg.Size = int64(Thearch.Ptrsize)
|
||||||
@ -827,6 +845,13 @@ func hostlink() {
|
|||||||
argv = append(argv, "-shared")
|
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, "-o")
|
||||||
argv = append(argv, outfile)
|
argv = append(argv, outfile)
|
||||||
|
|
||||||
@ -879,6 +904,18 @@ func hostlink() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
|
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...)
|
argv = append(argv, ldflag...)
|
||||||
|
|
||||||
for _, p := range strings.Fields(extldflags) {
|
for _, p := range strings.Fields(extldflags) {
|
||||||
@ -1029,6 +1066,91 @@ eof:
|
|||||||
Diag("truncated object file: %s", pn)
|
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() {
|
func mywhatsys() {
|
||||||
goroot = obj.Getgoroot()
|
goroot = obj.Getgoroot()
|
||||||
goos = obj.Getgoos()
|
goos = obj.Getgoos()
|
||||||
|
@ -114,6 +114,7 @@ type Link struct {
|
|||||||
Tlsg *LSym
|
Tlsg *LSym
|
||||||
Libdir []string
|
Libdir []string
|
||||||
Library []Library
|
Library []Library
|
||||||
|
Shlibs []string
|
||||||
Tlsoffset int
|
Tlsoffset int
|
||||||
Diag func(string, ...interface{})
|
Diag func(string, ...interface{})
|
||||||
Cursym *LSym
|
Cursym *LSym
|
||||||
@ -138,6 +139,7 @@ type Library struct {
|
|||||||
Srcref string
|
Srcref string
|
||||||
File string
|
File string
|
||||||
Pkg string
|
Pkg string
|
||||||
|
Shlib string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Pcln struct {
|
type Pcln struct {
|
||||||
|
@ -112,6 +112,7 @@ func Ldmain() {
|
|||||||
obj.Flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix)
|
obj.Flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix)
|
||||||
obj.Flagstr("k", "sym: set field tracking symbol", &tracksym)
|
obj.Flagstr("k", "sym: set field tracking symbol", &tracksym)
|
||||||
obj.Flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode)
|
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.Flagcount("n", "dump symbol table", &Debug['n'])
|
||||||
obj.Flagstr("o", "outfile: set output file", &outfile)
|
obj.Flagstr("o", "outfile: set output file", &outfile)
|
||||||
obj.Flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath)
|
obj.Flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath)
|
||||||
@ -176,6 +177,11 @@ func Ldmain() {
|
|||||||
|
|
||||||
Thearch.Archinit()
|
Thearch.Archinit()
|
||||||
|
|
||||||
|
if Linkshared && !Iself {
|
||||||
|
Diag("-linkshared can only be used on elf systems")
|
||||||
|
Errorexit()
|
||||||
|
}
|
||||||
|
|
||||||
if Debug['v'] != 0 {
|
if Debug['v'] != 0 {
|
||||||
fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
|
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 {
|
} else {
|
||||||
pkgpath, file = parts[0], parts[1]
|
pkgpath, file = parts[0], parts[1]
|
||||||
}
|
}
|
||||||
addlibpath(Ctxt, "command line", "command line", file, pkgpath)
|
addlibpath(Ctxt, "command line", "command line", file, pkgpath, "")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main")
|
addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main", "")
|
||||||
}
|
}
|
||||||
loadlib()
|
loadlib()
|
||||||
|
|
||||||
|
@ -104,6 +104,9 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
|
|||||||
|
|
||||||
case 'U':
|
case 'U':
|
||||||
type_ = STT_NOTYPE
|
type_ = STT_NOTYPE
|
||||||
|
if x == Ctxt.Tlsg {
|
||||||
|
type_ = STT_TLS
|
||||||
|
}
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
type_ = STT_TLS
|
type_ = STT_TLS
|
||||||
|
Loading…
Reference in New Issue
Block a user