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:
Michael Hudson-Doyle 2015-04-01 14:57:34 +13:00 committed by Ian Lance Taylor
parent ce469fadd8
commit 75c0566b55
6 changed files with 174 additions and 17 deletions

View 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()