mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.link] cmd/link: convert ELF host object loading to new loader
This is a rewrite of the ELF host object loader to use just the Loader interfaces for symbol creation, without constructing sym.Symbols. At the moment this is gated under the temporary linker command line option "-newldelf". This version is able to get through all.bash on linux/amd64. Change-Id: I99f41368f75b0df9e35ef3c2cf2a702b732540c6 Reviewed-on: https://go-review.googlesource.com/c/go/+/210779 Run-TryBot: Than McIntosh <thanm@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
161e0a5497
commit
fa284af720
9 changed files with 1850 additions and 233 deletions
1
src/cmd/dist/buildtool.go
vendored
1
src/cmd/dist/buildtool.go
vendored
|
|
@ -74,6 +74,7 @@ var bootstrapDirs = []string{
|
|||
"cmd/link/internal/arm64",
|
||||
"cmd/link/internal/ld",
|
||||
"cmd/link/internal/loadelf",
|
||||
"cmd/link/internal/loadelfold",
|
||||
"cmd/link/internal/loader",
|
||||
"cmd/link/internal/loadmacho",
|
||||
"cmd/link/internal/loadpe",
|
||||
|
|
|
|||
|
|
@ -104,6 +104,17 @@ func hostArchive(ctxt *Link, name string) {
|
|||
any := true
|
||||
for any {
|
||||
var load []uint64
|
||||
if ctxt.IsELF && *FlagNewLdElf {
|
||||
returnAllUndefs := -1
|
||||
undefs := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
|
||||
for _, symIdx := range undefs {
|
||||
name := ctxt.loader.SymName(symIdx)
|
||||
if off := armap[name]; off != 0 && !loaded[off] {
|
||||
load = append(load, off)
|
||||
loaded[off] = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, s := range ctxt.loader.Syms {
|
||||
if s == nil {
|
||||
continue
|
||||
|
|
@ -118,6 +129,7 @@ func hostArchive(ctxt *Link, name string) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, off := range load {
|
||||
l := nextar(f, int64(off), &arhdr)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
|
@ -293,6 +294,166 @@ func setCgoAttr(ctxt *Link, lookup func(string, int) *sym.Symbol, file string, p
|
|||
}
|
||||
}
|
||||
|
||||
// Set symbol attributes or flags based on cgo directives.
|
||||
// This version works with loader.Sym and not sym.Symbol.
|
||||
// Any newly discovered HOSTOBJ syms are added to 'hostObjSyms'.
|
||||
func setCgoAttr2(ctxt *Link, lookup func(string, int) loader.Sym, file string, pkg string, directives [][]string, hostObjSyms map[loader.Sym]struct{}) {
|
||||
l := ctxt.loader
|
||||
for _, f := range directives {
|
||||
switch f[0] {
|
||||
case "cgo_import_dynamic":
|
||||
if len(f) < 2 || len(f) > 4 {
|
||||
break
|
||||
}
|
||||
|
||||
local := f[1]
|
||||
remote := local
|
||||
if len(f) > 2 {
|
||||
remote = f[2]
|
||||
}
|
||||
lib := ""
|
||||
if len(f) > 3 {
|
||||
lib = f[3]
|
||||
}
|
||||
|
||||
if *FlagD {
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
if local == "_" && remote == "_" {
|
||||
// allow #pragma dynimport _ _ "foo.so"
|
||||
// to force a link of foo.so.
|
||||
havedynamic = 1
|
||||
|
||||
if ctxt.HeadType == objabi.Hdarwin {
|
||||
machoadddynlib(lib, ctxt.LinkMode)
|
||||
} else {
|
||||
dynlib = append(dynlib, lib)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
local = expandpkg(local, pkg)
|
||||
q := ""
|
||||
if i := strings.Index(remote, "#"); i >= 0 {
|
||||
remote, q = remote[:i], remote[i+1:]
|
||||
}
|
||||
s := lookup(local, 0)
|
||||
st := l.SymType(s)
|
||||
if st == 0 || st == sym.SXREF || st == sym.SBSS || st == sym.SNOPTRBSS || st == sym.SHOSTOBJ {
|
||||
l.SetSymDynimplib(s, lib)
|
||||
l.SetSymExtname(s, remote)
|
||||
l.SetSymDynimpvers(s, q)
|
||||
if st != sym.SHOSTOBJ {
|
||||
su, _ := l.MakeSymbolUpdater(s)
|
||||
su.SetType(sym.SDYNIMPORT)
|
||||
} else {
|
||||
hostObjSyms[s] = struct{}{}
|
||||
}
|
||||
havedynamic = 1
|
||||
}
|
||||
|
||||
continue
|
||||
|
||||
case "cgo_import_static":
|
||||
if len(f) != 2 {
|
||||
break
|
||||
}
|
||||
local := f[1]
|
||||
|
||||
su, s := l.MakeSymbolUpdater(lookup(local, 0))
|
||||
su.SetType(sym.SHOSTOBJ)
|
||||
su.SetSize(0)
|
||||
hostObjSyms[s] = struct{}{}
|
||||
continue
|
||||
|
||||
case "cgo_export_static", "cgo_export_dynamic":
|
||||
if len(f) < 2 || len(f) > 3 {
|
||||
break
|
||||
}
|
||||
local := f[1]
|
||||
remote := local
|
||||
if len(f) > 2 {
|
||||
remote = f[2]
|
||||
}
|
||||
local = expandpkg(local, pkg)
|
||||
|
||||
// The compiler arranges for an ABI0 wrapper
|
||||
// to be available for all cgo-exported
|
||||
// functions. Link.loadlib will resolve any
|
||||
// ABI aliases we find here (since we may not
|
||||
// yet know it's an alias).
|
||||
s := lookup(local, 0)
|
||||
|
||||
if l.SymType(s) == sym.SHOSTOBJ {
|
||||
hostObjSyms[s] = struct{}{}
|
||||
}
|
||||
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
|
||||
if s == lookup("main", 0) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// export overrides import, for openbsd/cgo.
|
||||
// see issue 4878.
|
||||
if l.SymDynimplib(s) != "" {
|
||||
l.SetSymDynimplib(s, "")
|
||||
l.SetSymDynimpvers(s, "")
|
||||
l.SetSymExtname(s, "")
|
||||
var su *loader.SymbolBuilder
|
||||
su, s = l.MakeSymbolUpdater(s)
|
||||
su.SetType(0)
|
||||
}
|
||||
|
||||
if !(l.AttrCgoExportStatic(s) || l.AttrCgoExportDynamic(s)) {
|
||||
l.SetSymExtname(s, remote)
|
||||
} else if l.SymExtname(s) != remote {
|
||||
fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], l.SymName(s), l.SymExtname(s), remote)
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
if f[0] == "cgo_export_static" {
|
||||
l.SetAttrCgoExportStatic(s, true)
|
||||
} else {
|
||||
l.SetAttrCgoExportDynamic(s, true)
|
||||
}
|
||||
continue
|
||||
|
||||
case "cgo_dynamic_linker":
|
||||
if len(f) != 2 {
|
||||
break
|
||||
}
|
||||
|
||||
if *flagInterpreter == "" {
|
||||
if interpreter != "" && interpreter != f[1] {
|
||||
fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
|
||||
nerrors++
|
||||
return
|
||||
}
|
||||
|
||||
interpreter = f[1]
|
||||
}
|
||||
continue
|
||||
|
||||
case "cgo_ldflag":
|
||||
if len(f) != 2 {
|
||||
break
|
||||
}
|
||||
ldflag = append(ldflag, f[1])
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f)
|
||||
nerrors++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var seenlib = make(map[string]bool)
|
||||
|
||||
func adddynlib(ctxt *Link, lib string) {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import (
|
|||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loadelf"
|
||||
"cmd/link/internal/loadelfold"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/loadmacho"
|
||||
"cmd/link/internal/loadpe"
|
||||
|
|
@ -455,33 +456,8 @@ func (ctxt *Link) loadlib() {
|
|||
}
|
||||
}
|
||||
|
||||
if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
|
||||
// In newobj mode, we typically create sym.Symbols later therefore
|
||||
// also set cgo attributes later. However, for internal cgo linking,
|
||||
// the host object loaders still work with sym.Symbols (for now),
|
||||
// and they need cgo attributes set to work properly. So process
|
||||
// them now.
|
||||
for _, d := range ctxt.cgodata {
|
||||
setCgoAttr(ctxt, ctxt.loader.LookupOrCreate, d.file, d.pkg, d.directives)
|
||||
}
|
||||
ctxt.cgodata = nil
|
||||
|
||||
// Drop all the cgo_import_static declarations.
|
||||
// Turns out we won't be needing them.
|
||||
for _, s := range ctxt.loader.Syms {
|
||||
if s != nil && s.Type == sym.SHOSTOBJ {
|
||||
// If a symbol was marked both
|
||||
// cgo_import_static and cgo_import_dynamic,
|
||||
// then we want to make it cgo_import_dynamic
|
||||
// now.
|
||||
if s.Extname() != "" && s.Dynimplib() != "" && !s.Attr.CgoExport() {
|
||||
s.Type = sym.SDYNIMPORT
|
||||
} else {
|
||||
s.Type = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Process cgo directives (has to be done before host object loading).
|
||||
ctxt.loadcgodirectives(ctxt.IsELF && *FlagNewLdElf)
|
||||
|
||||
// Conditionally load host objects, or setup for external linking.
|
||||
hostobjs(ctxt)
|
||||
|
|
@ -494,6 +470,12 @@ func (ctxt *Link) loadlib() {
|
|||
// If we have any undefined symbols in external
|
||||
// objects, try to read them from the libgcc file.
|
||||
any := false
|
||||
if ctxt.IsELF && *FlagNewLdElf {
|
||||
undefs := ctxt.loader.UndefinedRelocTargets(1)
|
||||
if len(undefs) > 0 {
|
||||
any = true
|
||||
}
|
||||
} else {
|
||||
for _, s := range ctxt.loader.Syms {
|
||||
if s == nil {
|
||||
continue
|
||||
|
|
@ -506,6 +488,7 @@ func (ctxt *Link) loadlib() {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if any {
|
||||
if *flagLibGCC == "" {
|
||||
*flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
|
||||
|
|
@ -581,6 +564,67 @@ func setupdynexp(ctxt *Link) {
|
|||
ctxt.cgo_export_dynamic = nil
|
||||
}
|
||||
|
||||
// loadcgodirectives reads the previously discovered cgo directives,
|
||||
// creating symbols (either sym.Symbol or loader.Sym) in preparation
|
||||
// for host object loading or use later in the link.
|
||||
func (ctxt *Link) loadcgodirectives(useLoader bool) {
|
||||
if useLoader {
|
||||
l := ctxt.loader
|
||||
hostObjSyms := make(map[loader.Sym]struct{})
|
||||
for _, d := range ctxt.cgodata {
|
||||
setCgoAttr2(ctxt, ctxt.loader.LookupOrCreateSym, d.file, d.pkg, d.directives, hostObjSyms)
|
||||
}
|
||||
ctxt.cgodata = nil
|
||||
|
||||
if ctxt.LinkMode == LinkInternal {
|
||||
// Drop all the cgo_import_static declarations.
|
||||
// Turns out we won't be needing them.
|
||||
for symIdx := range hostObjSyms {
|
||||
if l.SymType(symIdx) == sym.SHOSTOBJ {
|
||||
// If a symbol was marked both
|
||||
// cgo_import_static and cgo_import_dynamic,
|
||||
// then we want to make it cgo_import_dynamic
|
||||
// now.
|
||||
su, _ := l.MakeSymbolUpdater(symIdx)
|
||||
if l.SymExtname(symIdx) != "" && l.SymDynimplib(symIdx) != "" && !(l.AttrCgoExportStatic(symIdx) || l.AttrCgoExportDynamic(symIdx)) {
|
||||
su.SetType(sym.SDYNIMPORT)
|
||||
} else {
|
||||
su.SetType(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// In newobj mode, we typically create sym.Symbols later therefore
|
||||
// also set cgo attributes later. However, for internal cgo linking,
|
||||
// the host object loaders still work with sym.Symbols (for now),
|
||||
// and they need cgo attributes set to work properly. So process
|
||||
// them now.
|
||||
for _, d := range ctxt.cgodata {
|
||||
setCgoAttr(ctxt, ctxt.loader.LookupOrCreate, d.file, d.pkg, d.directives)
|
||||
}
|
||||
ctxt.cgodata = nil
|
||||
|
||||
if ctxt.LinkMode == LinkInternal {
|
||||
// Drop all the cgo_import_static declarations.
|
||||
// Turns out we won't be needing them.
|
||||
for _, s := range ctxt.loader.Syms {
|
||||
if s != nil && s.Type == sym.SHOSTOBJ {
|
||||
// If a symbol was marked both
|
||||
// cgo_import_static and cgo_import_dynamic,
|
||||
// then we want to make it cgo_import_dynamic
|
||||
// now.
|
||||
if s.Extname() != "" && s.Dynimplib() != "" && !s.Attr.CgoExport() {
|
||||
s.Type = sym.SDYNIMPORT
|
||||
} else {
|
||||
s.Type = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up flags and special symbols depending on the platform build mode.
|
||||
func (ctxt *Link) linksetup() {
|
||||
switch ctxt.BuildMode {
|
||||
|
|
@ -1675,6 +1719,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
|
|||
|
||||
magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
|
||||
if magic == 0x7f454c46 { // \x7F E L F
|
||||
if *FlagNewLdElf {
|
||||
ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||
textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn, ehdr.flags)
|
||||
if err != nil {
|
||||
|
|
@ -1682,10 +1727,22 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
|
|||
return
|
||||
}
|
||||
ehdr.flags = flags
|
||||
ctxt.Textp2 = append(ctxt.Textp2, textp...)
|
||||
}
|
||||
return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
|
||||
} else {
|
||||
ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||
textp, flags, err := loadelfold.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn, ehdr.flags)
|
||||
if err != nil {
|
||||
Errorf(nil, "%v", err)
|
||||
return
|
||||
}
|
||||
ehdr.flags = flags
|
||||
ctxt.Textp = append(ctxt.Textp, textp...)
|
||||
}
|
||||
return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
|
||||
}
|
||||
}
|
||||
|
||||
if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
|
||||
ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||
|
|
@ -1950,6 +2007,7 @@ func ldshlibsyms(ctxt *Link, shlib string) {
|
|||
return
|
||||
}
|
||||
gcdataLocations := make(map[uint64]*sym.Symbol)
|
||||
gcdataLocations2 := make(map[uint64]loader.Sym)
|
||||
for _, elfsym := range syms {
|
||||
if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
|
||||
continue
|
||||
|
|
@ -1962,6 +2020,62 @@ func ldshlibsyms(ctxt *Link, shlib string) {
|
|||
ver = sym.SymVerABIInternal
|
||||
}
|
||||
|
||||
if *FlagNewLdElf {
|
||||
l := ctxt.loader
|
||||
symIdx := l.LookupOrCreateSym(elfsym.Name, ver)
|
||||
|
||||
// Because loadlib above loads all .a files before loading
|
||||
// any shared libraries, any non-dynimport symbols we find
|
||||
// that duplicate symbols already loaded should be ignored
|
||||
// (the symbols from the .a files "win").
|
||||
if l.SymType(symIdx) != 0 && l.SymType(symIdx) != sym.SDYNIMPORT {
|
||||
continue
|
||||
}
|
||||
su, s := l.MakeSymbolUpdater(symIdx)
|
||||
su.SetType(sym.SDYNIMPORT)
|
||||
l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
|
||||
su.SetSize(int64(elfsym.Size))
|
||||
if elfsym.Section != elf.SHN_UNDEF {
|
||||
// If it's not undefined, mark the symbol as reachable
|
||||
// so as to protect it from dead code elimination,
|
||||
// even if there aren't any explicit references to it.
|
||||
// Under the previous sym.Symbol based regime this
|
||||
// wasn't necessary, but for the loader-based deadcode
|
||||
// it is definitely needed.
|
||||
//
|
||||
// FIXME: have a more general/flexible mechanism for this?
|
||||
//
|
||||
l.SetAttrReachable(s, true)
|
||||
|
||||
// Set .File for the library that actually defines the symbol.
|
||||
l.SetSymFile(s, libpath)
|
||||
|
||||
// The decodetype_* functions in decodetype.go need access to
|
||||
// the type data.
|
||||
sname := l.SymName(s)
|
||||
if strings.HasPrefix(sname, "type.") && !strings.HasPrefix(sname, "type..") {
|
||||
su.SetData(readelfsymboldata(ctxt, f, &elfsym))
|
||||
gcdataLocations2[elfsym.Value+2*uint64(ctxt.Arch.PtrSize)+8+1*uint64(ctxt.Arch.PtrSize)] = s
|
||||
}
|
||||
}
|
||||
|
||||
// For function symbols, we don't know what ABI is
|
||||
// available, so alias it under both ABIs.
|
||||
//
|
||||
// TODO(austin): This is almost certainly wrong once
|
||||
// the ABIs are actually different. We might have to
|
||||
// mangle Go function names in the .so to include the
|
||||
// ABI.
|
||||
if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
|
||||
alias := ctxt.loader.LookupOrCreateSym(elfsym.Name, sym.SymVerABIInternal)
|
||||
if l.SymType(alias) != 0 {
|
||||
continue
|
||||
}
|
||||
su, _ := l.MakeSymbolUpdater(alias)
|
||||
su.SetType(sym.SABIALIAS)
|
||||
su.AddReloc(loader.Reloc{Sym: s})
|
||||
}
|
||||
} else {
|
||||
lsym := ctxt.loader.LookupOrCreate(elfsym.Name, ver)
|
||||
|
||||
// Because loadlib above loads all .a files before loading any shared
|
||||
|
|
@ -2000,7 +2114,9 @@ func ldshlibsyms(ctxt *Link, shlib string) {
|
|||
alias.R = []sym.Reloc{{Sym: lsym}}
|
||||
}
|
||||
}
|
||||
}
|
||||
gcdataAddresses := make(map[*sym.Symbol]uint64)
|
||||
gcdataAddresses2 := make(map[loader.Sym]uint64)
|
||||
if ctxt.Arch.Family == sys.ARM64 {
|
||||
for _, sect := range f.Sections {
|
||||
if sect.Type == elf.SHT_RELA {
|
||||
|
|
@ -2018,6 +2134,11 @@ func ldshlibsyms(ctxt *Link, shlib string) {
|
|||
if t != elf.R_AARCH64_RELATIVE {
|
||||
continue
|
||||
}
|
||||
if *FlagNewLdElf {
|
||||
if symIdx, ok := gcdataLocations2[rela.Off]; ok {
|
||||
gcdataAddresses2[symIdx] = uint64(rela.Addend)
|
||||
}
|
||||
} else {
|
||||
if lsym, ok := gcdataLocations[rela.Off]; ok {
|
||||
gcdataAddresses[lsym] = uint64(rela.Addend)
|
||||
}
|
||||
|
|
@ -2025,8 +2146,9 @@ func ldshlibsyms(ctxt *Link, shlib string) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdataAddresses: gcdataAddresses})
|
||||
ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdataAddresses: gcdataAddresses, gcdataAddresses2: gcdataAddresses2})
|
||||
}
|
||||
|
||||
func addsection(arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
|
||||
|
|
@ -2594,11 +2716,6 @@ func (ctxt *Link) loadlibfull() {
|
|||
// Pull the symbols out.
|
||||
ctxt.loader.ExtractSymbols(ctxt.Syms)
|
||||
|
||||
// Load cgo directives.
|
||||
for _, d := range ctxt.cgodata {
|
||||
setCgoAttr(ctxt, ctxt.Syms.Lookup, d.file, d.pkg, d.directives)
|
||||
}
|
||||
|
||||
setupdynexp(ctxt)
|
||||
|
||||
// Populate ctxt.Reachparent if appropriate.
|
||||
|
|
@ -2617,11 +2734,13 @@ func (ctxt *Link) loadlibfull() {
|
|||
}
|
||||
}
|
||||
|
||||
// Drop the reference.
|
||||
ctxt.loader = nil
|
||||
// Drop the cgodata reference.
|
||||
ctxt.cgodata = nil
|
||||
|
||||
addToTextp(ctxt)
|
||||
|
||||
// Drop the loader.
|
||||
ctxt.loader = nil
|
||||
}
|
||||
|
||||
func (ctxt *Link) dumpsyms() {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ type Shlib struct {
|
|||
Deps []string
|
||||
File *elf.File
|
||||
gcdataAddresses map[*sym.Symbol]uint64
|
||||
gcdataAddresses2 map[loader.Sym]uint64
|
||||
}
|
||||
|
||||
// Link holds the context for writing object code from a compiler
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ var (
|
|||
flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
|
||||
FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
|
||||
FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
|
||||
FlagNewLdElf = flag.Bool("newldelf", false, "ELF host obj load with new loader")
|
||||
|
||||
FlagRound = flag.Int("R", -1, "set address rounding `quantum`")
|
||||
FlagTextAddr = flag.Int64("T", -1, "set text segment `address`")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
|
@ -282,7 +282,7 @@ type ElfSect struct {
|
|||
align uint64
|
||||
entsize uint64
|
||||
base []byte
|
||||
sym *sym.Symbol
|
||||
sym loader.Sym
|
||||
}
|
||||
|
||||
type ElfObj struct {
|
||||
|
|
@ -320,7 +320,7 @@ type ElfSym struct {
|
|||
type_ uint8
|
||||
other uint8
|
||||
shndx uint16
|
||||
sym *sym.Symbol
|
||||
sym loader.Sym
|
||||
}
|
||||
|
||||
var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'}
|
||||
|
|
@ -453,21 +453,21 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags
|
|||
}
|
||||
|
||||
// Load loads the ELF file pn from f.
|
||||
// Symbols are written into syms, and a slice of the text symbols is returned.
|
||||
// Symbols are installed into the loader, and a slice of the text symbols is returned.
|
||||
//
|
||||
// On ARM systems, Load will attempt to determine what ELF header flags to
|
||||
// emit by scanning the attributes in the ELF file being loaded. The
|
||||
// parameter initEhdrFlags contains the current header flags for the output
|
||||
// object, and the returned ehdrFlags contains what this Load function computes.
|
||||
// TODO: find a better place for this logic.
|
||||
func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []*sym.Symbol, ehdrFlags uint32, err error) {
|
||||
newSym := func(name string, version int) *sym.Symbol {
|
||||
return l.Create(name)
|
||||
func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []loader.Sym, ehdrFlags uint32, err error) {
|
||||
newSym := func(name string, version int) loader.Sym {
|
||||
return l.CreateExtSym(name)
|
||||
}
|
||||
lookup := func(name string, version int) *sym.Symbol {
|
||||
return l.LookupOrCreate(name, version)
|
||||
lookup := func(name string, version int) loader.Sym {
|
||||
return l.LookupOrCreateSym(name, version)
|
||||
}
|
||||
errorf := func(str string, args ...interface{}) ([]*sym.Symbol, uint32, error) {
|
||||
errorf := func(str string, args ...interface{}) ([]loader.Sym, uint32, error) {
|
||||
return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...))
|
||||
}
|
||||
|
||||
|
|
@ -721,46 +721,46 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
|
|||
}
|
||||
sectsymNames[name] = true
|
||||
|
||||
s := lookup(name, localSymVersion)
|
||||
sb, _ := l.MakeSymbolUpdater(lookup(name, localSymVersion))
|
||||
|
||||
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
|
||||
default:
|
||||
return errorf("%s: unexpected flags for ELF section %s", pn, sect.name)
|
||||
|
||||
case ElfSectFlagAlloc:
|
||||
s.Type = sym.SRODATA
|
||||
sb.SetType(sym.SRODATA)
|
||||
|
||||
case ElfSectFlagAlloc + ElfSectFlagWrite:
|
||||
if sect.type_ == ElfSectNobits {
|
||||
s.Type = sym.SNOPTRBSS
|
||||
sb.SetType(sym.SNOPTRBSS)
|
||||
} else {
|
||||
s.Type = sym.SNOPTRDATA
|
||||
sb.SetType(sym.SNOPTRDATA)
|
||||
}
|
||||
|
||||
case ElfSectFlagAlloc + ElfSectFlagExec:
|
||||
s.Type = sym.STEXT
|
||||
sb.SetType(sym.STEXT)
|
||||
}
|
||||
|
||||
if sect.name == ".got" || sect.name == ".toc" {
|
||||
s.Type = sym.SELFGOT
|
||||
sb.SetType(sym.SELFGOT)
|
||||
}
|
||||
if sect.type_ == ElfSectProgbits {
|
||||
s.P = sect.base
|
||||
s.P = s.P[:sect.size]
|
||||
sb.SetData(sect.base[:sect.size])
|
||||
}
|
||||
|
||||
s.Size = int64(sect.size)
|
||||
s.Align = int32(sect.align)
|
||||
sect.sym = s
|
||||
sb.SetSize(int64(sect.size))
|
||||
sb.SetAlign(int32(sect.align))
|
||||
|
||||
sect.sym = sb.Sym()
|
||||
}
|
||||
|
||||
// enter sub-symbols into symbol table.
|
||||
// symbol 0 is the null symbol.
|
||||
symbols := make([]*sym.Symbol, elfobj.nsymtab)
|
||||
symbols := make([]loader.Sym, elfobj.nsymtab)
|
||||
|
||||
for i := 1; i < elfobj.nsymtab; i++ {
|
||||
var elfsym ElfSym
|
||||
if err := readelfsym(newSym, lookup, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
|
||||
if err := readelfsym(newSym, lookup, l, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
|
||||
return errorf("%s: malformed elf file: %v", pn, err)
|
||||
}
|
||||
symbols[i] = elfsym.sym
|
||||
|
|
@ -768,13 +768,15 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
|
|||
continue
|
||||
}
|
||||
if elfsym.shndx == ElfSymShnCommon || elfsym.type_ == ElfSymTypeCommon {
|
||||
s := elfsym.sym
|
||||
if uint64(s.Size) < elfsym.size {
|
||||
s.Size = int64(elfsym.size)
|
||||
sb, ns := l.MakeSymbolUpdater(elfsym.sym)
|
||||
if uint64(sb.Size()) < elfsym.size {
|
||||
sb.SetSize(int64(elfsym.size))
|
||||
}
|
||||
if s.Type == 0 || s.Type == sym.SXREF {
|
||||
s.Type = sym.SNOPTRBSS
|
||||
if sb.Type() == 0 || sb.Type() == sym.SXREF {
|
||||
sb.SetType(sym.SNOPTRBSS)
|
||||
}
|
||||
symbols[i] = ns
|
||||
elfsym.sym = ns
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -783,11 +785,11 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
|
|||
}
|
||||
|
||||
// even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols
|
||||
if elfsym.sym == nil {
|
||||
if elfsym.sym == 0 {
|
||||
continue
|
||||
}
|
||||
sect = &elfobj.sect[elfsym.shndx]
|
||||
if sect.sym == nil {
|
||||
if sect.sym == 0 {
|
||||
if strings.HasPrefix(elfsym.name, ".Linfo_string") { // clang does this
|
||||
continue
|
||||
}
|
||||
|
|
@ -812,36 +814,37 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
|
|||
}
|
||||
|
||||
s := elfsym.sym
|
||||
if s.Outer != nil {
|
||||
if s.Attr.DuplicateOK() {
|
||||
if l.OuterSym(s) != 0 {
|
||||
if l.AttrDuplicateOK(s) {
|
||||
continue
|
||||
}
|
||||
return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name)
|
||||
return errorf("duplicate symbol reference: %s in both %s and %s",
|
||||
l.SymName(s), l.SymName(l.OuterSym(s)), l.SymName(sect.sym))
|
||||
}
|
||||
|
||||
s.Sub = sect.sym.Sub
|
||||
sect.sym.Sub = s
|
||||
s.Type = sect.sym.Type
|
||||
s.Attr |= sym.AttrSubSymbol
|
||||
if !s.Attr.CgoExportDynamic() {
|
||||
s.SetDynimplib("") // satisfy dynimport
|
||||
sectsb, _ := l.MakeSymbolUpdater(sect.sym)
|
||||
sb, _ := l.MakeSymbolUpdater(s)
|
||||
|
||||
sb.SetType(sectsb.Type())
|
||||
sectsb.PrependSub(s)
|
||||
if !l.AttrCgoExportDynamic(s) {
|
||||
sb.SetDynimplib("") // satisfy dynimport
|
||||
}
|
||||
s.Value = int64(elfsym.value)
|
||||
s.Size = int64(elfsym.size)
|
||||
s.Outer = sect.sym
|
||||
if sect.sym.Type == sym.STEXT {
|
||||
if s.Attr.External() && !s.Attr.DuplicateOK() {
|
||||
return errorf("%v: duplicate symbol definition", s)
|
||||
sb.SetValue(int64(elfsym.value))
|
||||
sb.SetSize(int64(elfsym.size))
|
||||
if sectsb.Type() == sym.STEXT {
|
||||
if l.AttrExternal(s) && !l.AttrDuplicateOK(s) {
|
||||
return errorf("%s: duplicate symbol definition", sb.Name())
|
||||
}
|
||||
s.Attr |= sym.AttrExternal
|
||||
l.SetAttrExternal(s, true)
|
||||
}
|
||||
|
||||
if elfobj.machine == ElfMachPower64 {
|
||||
flag := int(elfsym.other) >> 5
|
||||
if 2 <= flag && flag <= 6 {
|
||||
s.SetLocalentry(1 << uint(flag-2))
|
||||
l.SetSymLocalentry(s, 1<<uint(flag-2))
|
||||
} else if flag == 7 {
|
||||
return errorf("%v: invalid sym.other 0x%x", s, elfsym.other)
|
||||
return errorf("%s: invalid sym.other 0x%x", sb.Name(), elfsym.other)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -850,24 +853,28 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
|
|||
// This keeps textp in increasing address order.
|
||||
for i := uint(0); i < elfobj.nsect; i++ {
|
||||
s := elfobj.sect[i].sym
|
||||
if s == nil {
|
||||
if s == 0 {
|
||||
continue
|
||||
}
|
||||
if s.Sub != nil {
|
||||
s.Sub = sym.SortSub(s.Sub)
|
||||
sb, _ := l.MakeSymbolUpdater(s)
|
||||
s = sb.Sym()
|
||||
if l.SubSym(s) != 0 {
|
||||
sb.SortSub()
|
||||
}
|
||||
if s.Type == sym.STEXT {
|
||||
if s.Attr.OnList() {
|
||||
return errorf("symbol %s listed multiple times", s.Name)
|
||||
if sb.Type() == sym.STEXT {
|
||||
if l.AttrOnList(s) {
|
||||
return errorf("symbol %s listed multiple times",
|
||||
l.SymName(s))
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
l.SetAttrOnList(s, true)
|
||||
textp = append(textp, s)
|
||||
for s = s.Sub; s != nil; s = s.Sub {
|
||||
if s.Attr.OnList() {
|
||||
return errorf("symbol %s listed multiple times", s.Name)
|
||||
for ss := l.SubSym(s); ss != 0; ss = l.SubSym(ss) {
|
||||
if l.AttrOnList(ss) {
|
||||
return errorf("symbol %s listed multiple times",
|
||||
l.SymName(ss))
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
textp = append(textp, s)
|
||||
l.SetAttrOnList(ss, true)
|
||||
textp = append(textp, ss)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -890,7 +897,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
|
|||
rela = 1
|
||||
}
|
||||
n := int(rsect.size / uint64(4+4*is64) / uint64(2+rela))
|
||||
r := make([]sym.Reloc, n)
|
||||
r := make([]loader.Reloc, n)
|
||||
p := rsect.base
|
||||
for j := 0; j < n; j++ {
|
||||
var add uint64
|
||||
|
|
@ -928,22 +935,22 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
|
|||
}
|
||||
|
||||
if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol
|
||||
rp.Sym = nil
|
||||
rp.Sym = 0
|
||||
} else {
|
||||
var elfsym ElfSym
|
||||
if err := readelfsym(newSym, lookup, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
|
||||
if err := readelfsym(newSym, lookup, l, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
|
||||
return errorf("malformed elf file: %v", err)
|
||||
}
|
||||
elfsym.sym = symbols[info>>32]
|
||||
if elfsym.sym == nil {
|
||||
return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), elfsym.name, elfsym.shndx, elfsym.type_)
|
||||
if elfsym.sym == 0 {
|
||||
return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", l.SymName(sect.sym), j, int(info>>32), elfsym.name, elfsym.shndx, elfsym.type_)
|
||||
}
|
||||
|
||||
rp.Sym = elfsym.sym
|
||||
}
|
||||
|
||||
rp.Type = objabi.ElfRelocOffset + objabi.RelocType(info)
|
||||
rp.Siz, err = relSize(arch, pn, uint32(info))
|
||||
rp.Size, err = relSize(arch, pn, uint32(info))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
|
@ -951,30 +958,30 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
|
|||
rp.Add = int64(add)
|
||||
} else {
|
||||
// load addend from image
|
||||
if rp.Siz == 4 {
|
||||
if rp.Size == 4 {
|
||||
rp.Add = int64(e.Uint32(sect.base[rp.Off:]))
|
||||
} else if rp.Siz == 8 {
|
||||
} else if rp.Size == 8 {
|
||||
rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
|
||||
} else {
|
||||
return errorf("invalid rela size %d", rp.Siz)
|
||||
return errorf("invalid rela size %d", rp.Size)
|
||||
}
|
||||
}
|
||||
|
||||
if rp.Siz == 2 {
|
||||
if rp.Size == 2 {
|
||||
rp.Add = int64(int16(rp.Add))
|
||||
}
|
||||
if rp.Siz == 4 {
|
||||
if rp.Size == 4 {
|
||||
rp.Add = int64(int32(rp.Add))
|
||||
}
|
||||
}
|
||||
|
||||
//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
|
||||
sort.Sort(sym.RelocByOff(r[:n]))
|
||||
sort.Sort(loader.RelocByOff(r[:n]))
|
||||
// just in case
|
||||
|
||||
s := sect.sym
|
||||
s.R = r
|
||||
s.R = s.R[:n]
|
||||
sb, _ := l.MakeSymbolUpdater(sect.sym)
|
||||
r = r[:n]
|
||||
sb.SetRelocs(r)
|
||||
}
|
||||
|
||||
return textp, ehdrFlags, nil
|
||||
|
|
@ -1008,7 +1015,7 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
|
||||
func readelfsym(newSym, lookup func(string, int) loader.Sym, l *loader.Loader, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
|
||||
if i >= elfobj.nsymtab || i < 0 {
|
||||
err = fmt.Errorf("invalid elf symbol index")
|
||||
return err
|
||||
|
|
@ -1040,7 +1047,8 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el
|
|||
elfsym.other = b.Other
|
||||
}
|
||||
|
||||
var s *sym.Symbol
|
||||
var s loader.Sym
|
||||
|
||||
if elfsym.name == "_GLOBAL_OFFSET_TABLE_" {
|
||||
elfsym.name = ".got"
|
||||
}
|
||||
|
|
@ -1067,8 +1075,12 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el
|
|||
// TODO(minux): correctly handle __i686.get_pc_thunk.bx without
|
||||
// set dupok generally. See https://golang.org/cl/5823055
|
||||
// comment #5 for details.
|
||||
if s != nil && elfsym.other == 2 {
|
||||
s.Attr |= sym.AttrDuplicateOK | sym.AttrVisibilityHidden
|
||||
if s != 0 && elfsym.other == 2 {
|
||||
if !l.IsExternal(s) {
|
||||
_, s = l.MakeSymbolUpdater(s)
|
||||
}
|
||||
l.SetAttrDuplicateOK(s, true)
|
||||
l.SetAttrVisibilityHidden(s, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1084,9 +1096,8 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el
|
|||
// so put it in the hash table.
|
||||
if needSym != 0 {
|
||||
s = lookup(elfsym.name, localSymVersion)
|
||||
s.Attr |= sym.AttrVisibilityHidden
|
||||
l.SetAttrVisibilityHidden(s, true)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
|
|
@ -1098,20 +1109,19 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el
|
|||
// reduce mem use, but also (possibly) make it harder
|
||||
// to debug problems.
|
||||
s = newSym(elfsym.name, localSymVersion)
|
||||
|
||||
s.Attr |= sym.AttrVisibilityHidden
|
||||
l.SetAttrVisibilityHidden(s, true)
|
||||
}
|
||||
|
||||
case ElfSymBindWeak:
|
||||
if needSym != 0 {
|
||||
s = lookup(elfsym.name, 0)
|
||||
if elfsym.other == 2 {
|
||||
s.Attr |= sym.AttrVisibilityHidden
|
||||
l.SetAttrVisibilityHidden(s, true)
|
||||
}
|
||||
|
||||
// Allow weak symbols to be duplicated when already defined.
|
||||
if s.Outer != nil {
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
if l.OuterSym(s) != 0 {
|
||||
l.SetAttrDuplicateOK(s, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1123,8 +1133,9 @@ func readelfsym(newSym, lookup func(string, int) *sym.Symbol, arch *sys.Arch, el
|
|||
|
||||
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
|
||||
// sense and should be removed when someone has thought about it properly.
|
||||
if s != nil && s.Type == 0 && !s.Attr.VisibilityHidden() && elfsym.type_ != ElfSymTypeSection {
|
||||
s.Type = sym.SXREF
|
||||
if s != 0 && l.SymType(s) == 0 && !l.AttrVisibilityHidden(s) && elfsym.type_ != ElfSymTypeSection {
|
||||
sb, _ := l.MakeSymbolUpdater(s)
|
||||
sb.SetType(sym.SXREF)
|
||||
}
|
||||
elfsym.sym = s
|
||||
|
||||
|
|
|
|||
1243
src/cmd/link/internal/loadelfold/ldelf.go
Normal file
1243
src/cmd/link/internal/loadelfold/ldelf.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1663,7 +1663,9 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
|||
nr += len(pp.relocs)
|
||||
// create and install the sym.Symbol here so that l.Syms will
|
||||
// be fully populated when we do relocation processing and
|
||||
// outer/sub processing below.
|
||||
// outer/sub processing below. Note that once we do this,
|
||||
// we'll need to get at the payload for a symbol with direct
|
||||
// reference to l.payloads[] as opposed to calling l.getPayload().
|
||||
s := l.allocSym(sname, 0)
|
||||
l.installSym(i, s)
|
||||
toConvert = append(toConvert, i)
|
||||
|
|
@ -1701,46 +1703,11 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
|
|||
// Copy data
|
||||
s.P = pp.data
|
||||
|
||||
// Convert outer/sub relationships
|
||||
if outer, ok := l.outer[i]; ok {
|
||||
s.Outer = l.Syms[outer]
|
||||
}
|
||||
if sub, ok := l.sub[i]; ok {
|
||||
s.Sub = l.Syms[sub]
|
||||
}
|
||||
// Transfer over attributes.
|
||||
l.migrateAttributes(i, s)
|
||||
|
||||
// Preprocess symbol.
|
||||
// Preprocess symbol. May set 'AttrLocal'.
|
||||
preprocess(arch, s)
|
||||
|
||||
// Convert attributes.
|
||||
// Note: this is an incomplete set; will be fixed up in
|
||||
// a subsequent patch.
|
||||
s.Attr.Set(sym.AttrReachable, l.attrReachable.has(i))
|
||||
s.Attr.Set(sym.AttrOnList, l.attrOnList.has(i))
|
||||
if l.attrLocal.has(i) {
|
||||
s.Attr.Set(sym.AttrLocal, true)
|
||||
}
|
||||
|
||||
// Set sub-symbol attribute. FIXME: would be better
|
||||
// to do away with this and just use l.OuterSymbol() != 0
|
||||
// elsewhere within the linker.
|
||||
s.Attr.Set(sym.AttrSubSymbol, s.Outer != nil)
|
||||
|
||||
// Copy over dynimplib, dynimpvers, extname.
|
||||
if l.SymExtname(i) != "" {
|
||||
s.SetExtname(l.SymExtname(i))
|
||||
}
|
||||
if l.SymDynimplib(i) != "" {
|
||||
s.SetDynimplib(l.SymDynimplib(i))
|
||||
}
|
||||
if l.SymDynimpvers(i) != "" {
|
||||
s.SetDynimpvers(l.SymDynimpvers(i))
|
||||
}
|
||||
|
||||
// Copy ELF type if set.
|
||||
if et, ok := l.elfType[i]; ok {
|
||||
s.SetElfType(et)
|
||||
}
|
||||
}
|
||||
|
||||
// load contents of defined symbols
|
||||
|
|
@ -1888,9 +1855,7 @@ func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
|
|||
}
|
||||
|
||||
s := l.addNewSym(istart+Sym(i), name, ver, r.unit, t)
|
||||
// NB: this is an incomplete set of attributes; a more complete
|
||||
// attribute migration appears in a subsequent patch.
|
||||
s.Attr.Set(sym.AttrReachable, l.attrReachable.has(istart+Sym(i)))
|
||||
l.migrateAttributes(istart+Sym(i), s)
|
||||
nr += r.NReloc(i)
|
||||
}
|
||||
return nr
|
||||
|
|
@ -2038,16 +2003,89 @@ func (l *Loader) cloneToExternal(symIdx Sym) Sym {
|
|||
l.symsByName[sver][sname] = ns
|
||||
}
|
||||
|
||||
// Copy over selected attributes / properties. This is
|
||||
// probably overkill for most of these attributes, but it's
|
||||
// simpler just to copy everything.
|
||||
l.copyAttributes(symIdx, ns)
|
||||
if l.SymExtname(symIdx) != "" {
|
||||
l.SetSymExtname(ns, l.SymExtname(symIdx))
|
||||
}
|
||||
if l.SymDynimplib(symIdx) != "" {
|
||||
l.SetSymDynimplib(ns, l.SymDynimplib(symIdx))
|
||||
}
|
||||
if l.SymDynimpvers(symIdx) != "" {
|
||||
l.SetSymDynimpvers(ns, l.SymDynimpvers(symIdx))
|
||||
}
|
||||
|
||||
// Add an overwrite entry (in case there are relocations against
|
||||
// the old symbol).
|
||||
l.overwrite[symIdx] = ns
|
||||
|
||||
// FIXME: copy other attributes? reachable is the main one, and we
|
||||
// don't expect it to be set at this point.
|
||||
|
||||
return ns
|
||||
}
|
||||
|
||||
// copyAttributes copies over all of the attributes of symbol 'src' to
|
||||
// symbol 'dst'. The assumption is that 'dst' is an external symbol.
|
||||
func (l *Loader) copyAttributes(src Sym, dst Sym) {
|
||||
l.SetAttrReachable(dst, l.AttrReachable(src))
|
||||
l.SetAttrOnList(dst, l.AttrOnList(src))
|
||||
l.SetAttrLocal(dst, l.AttrLocal(src))
|
||||
l.SetAttrVisibilityHidden(dst, l.AttrVisibilityHidden(src))
|
||||
l.SetAttrDuplicateOK(dst, l.AttrDuplicateOK(src))
|
||||
l.SetAttrShared(dst, l.AttrShared(src))
|
||||
l.SetAttrExternal(dst, l.AttrExternal(src))
|
||||
l.SetAttrTopFrame(dst, l.AttrTopFrame(src))
|
||||
l.SetAttrSpecial(dst, l.AttrSpecial(src))
|
||||
l.SetAttrCgoExportDynamic(dst, l.AttrCgoExportDynamic(src))
|
||||
l.SetAttrCgoExportStatic(dst, l.AttrCgoExportStatic(src))
|
||||
}
|
||||
|
||||
// migrateAttributes copies over all of the attributes of symbol 'src' to
|
||||
// sym.Symbol 'dst'.
|
||||
func (l *Loader) migrateAttributes(src Sym, dst *sym.Symbol) {
|
||||
src = l.getOverwrite(src)
|
||||
dst.Attr.Set(sym.AttrReachable, l.AttrReachable(src))
|
||||
dst.Attr.Set(sym.AttrOnList, l.AttrOnList(src))
|
||||
dst.Attr.Set(sym.AttrLocal, l.AttrLocal(src))
|
||||
dst.Attr.Set(sym.AttrVisibilityHidden, l.AttrVisibilityHidden(src))
|
||||
dst.Attr.Set(sym.AttrDuplicateOK, l.AttrDuplicateOK(src))
|
||||
dst.Attr.Set(sym.AttrShared, l.AttrShared(src))
|
||||
dst.Attr.Set(sym.AttrExternal, l.AttrExternal(src))
|
||||
dst.Attr.Set(sym.AttrTopFrame, l.AttrTopFrame(src))
|
||||
dst.Attr.Set(sym.AttrSpecial, l.AttrSpecial(src))
|
||||
dst.Attr.Set(sym.AttrCgoExportDynamic, l.AttrCgoExportDynamic(src))
|
||||
dst.Attr.Set(sym.AttrCgoExportStatic, l.AttrCgoExportStatic(src))
|
||||
|
||||
// Convert outer/sub relationships
|
||||
if outer, ok := l.outer[src]; ok {
|
||||
dst.Outer = l.Syms[outer]
|
||||
}
|
||||
if sub, ok := l.sub[src]; ok {
|
||||
dst.Sub = l.Syms[sub]
|
||||
}
|
||||
|
||||
// Set sub-symbol attribute. FIXME: would be better to do away
|
||||
// with this and just use l.OuterSymbol() != 0 elsewhere within
|
||||
// the linker.
|
||||
dst.Attr.Set(sym.AttrSubSymbol, dst.Outer != nil)
|
||||
|
||||
// Copy over dynimplib, dynimpvers, extname.
|
||||
if l.SymExtname(src) != "" {
|
||||
dst.SetExtname(l.SymExtname(src))
|
||||
}
|
||||
if l.SymDynimplib(src) != "" {
|
||||
dst.SetDynimplib(l.SymDynimplib(src))
|
||||
}
|
||||
if l.SymDynimpvers(src) != "" {
|
||||
dst.SetDynimpvers(l.SymDynimpvers(src))
|
||||
}
|
||||
|
||||
// Copy ELF type if set.
|
||||
if et, ok := l.elfType[src]; ok {
|
||||
dst.SetElfType(et)
|
||||
}
|
||||
}
|
||||
|
||||
// CreateExtSym creates a new external symbol with the specified name
|
||||
// without adding it to any lookup tables, returning a Sym index for it.
|
||||
func (l *Loader) CreateExtSym(name string) Sym {
|
||||
|
|
@ -2396,6 +2434,36 @@ func patchDWARFName(s *sym.Symbol, r *oReader) {
|
|||
}
|
||||
}
|
||||
|
||||
// UndefinedRelocTargets iterates through the global symbol index
|
||||
// space, looking for symbols with relocations targeting undefined
|
||||
// references. The linker's loadlib method uses this to determine if
|
||||
// there are unresolved references to functions in system libraries
|
||||
// (for example, libgcc.a), presumably due to CGO code. Return
|
||||
// value is a list of loader.Sym's corresponding to the undefined
|
||||
// cross-refs. The "limit" param controls the maximum number of
|
||||
// results returned; if "limit" is -1, then all undefs are returned.
|
||||
func (l *Loader) UndefinedRelocTargets(limit int) []Sym {
|
||||
result := []Sym{}
|
||||
rslice := []Reloc{}
|
||||
for si := Sym(1); si <= l.max; si++ {
|
||||
if _, ok := l.overwrite[si]; ok {
|
||||
continue
|
||||
}
|
||||
relocs := l.Relocs(si)
|
||||
rslice = relocs.ReadAll(rslice)
|
||||
for ri := 0; ri < relocs.Count; ri++ {
|
||||
r := &rslice[ri]
|
||||
if r.Sym != 0 && l.SymType(r.Sym) == sym.SXREF && l.RawSymName(r.Sym) != ".got" {
|
||||
result = append(result, r.Sym)
|
||||
if limit != -1 && len(result) >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// For debugging.
|
||||
func (l *Loader) Dump() {
|
||||
fmt.Println("objs")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue