Newer
Older
// 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.
package loader
Cherry Zhang
committed
"bytes"
Cherry Zhang
committed
"cmd/internal/dwarf"
"cmd/internal/goobj2"
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/sym"
"debug/elf"
"os"
"sort"
"strconv"
"strings"
)
var _ = fmt.Print
Than McIntosh
committed
// Sym encapsulates a global symbol index, used to identify a specific
// Go symbol. The 0-valued Sym is corresponds to an invalid symbol.
type Sym int
// Relocs encapsulates the set of relocations on a given symbol; an
// instance of this type is returned by the Loader Relocs() method.
type Relocs struct {
Count int // number of relocs
li int // local index of symbol whose relocs we're examining
r *oReader // object reader for containing package
l *Loader // loader
Than McIntosh
committed
extIdx Sym // index of external symbol we're examining or 0
}
// Reloc contains the payload for a specific relocation.
// TODO: replace this with sym.Reloc, once we change the
// relocation target from "*sym.Symbol" to "loader.Sym" in sym.Reloc.
type Reloc struct {
Off int32 // offset to rewrite
Size uint8 // number of bytes to rewrite: 0, 1, 2, or 4
Type objabi.RelocType // the relocation type
Add int64 // addend
Sym Sym // global index of symbol the reloc addresses
}
Cherry Zhang
committed
// oReader is a wrapper type of obj.Reader, along with some
// extra information.
// TODO: rename to objReader once the old one is gone?
type oReader struct {
*goobj2.Reader
unit *sym.CompilationUnit
version int // version of static symbol
flags uint32 // read from object file
Cherry Zhang
committed
pkgprefix string
rcache []Sym // cache mapping local PkgNone symbol to resolved Sym
Cherry Zhang
committed
}
Cherry Zhang
committed
r *oReader
Than McIntosh
committed
i Sym // start index
Than McIntosh
committed
e Sym // end index
}
type nameVer struct {
name string
v int
}
type bitmap []uint32
// set the i-th bit.
func (bm bitmap) set(i Sym) {
n, r := uint(i)/32, uint(i)%32
bm[n] |= 1 << r
}
// unset the i-th bit.
func (bm bitmap) unset(i Sym) {
n, r := uint(i)/32, uint(i)%32
bm[n] &^= (1 << r)
}
// whether the i-th bit is set.
func (bm bitmap) has(i Sym) bool {
n, r := uint(i)/32, uint(i)%32
return bm[n]&(1<<r) != 0
}
Than McIntosh
committed
// return current length of bitmap in bits.
func (bm bitmap) len() int {
return len(bm) * 32
}
func makeBitmap(n int) bitmap {
return make(bitmap, (n+31)/32)
}
Than McIntosh
committed
// growBitmap insures that the specified bitmap has enough capacity,
// reallocating (doubling the size) if needed.
func growBitmap(reqLen int, b bitmap) bitmap {
curLen := b.len()
if reqLen > curLen {
b = append(b, makeBitmap(reqLen+1-curLen)...)
Than McIntosh
committed
}
return b
}
// A Loader loads new object files and resolves indexed symbol references.
Than McIntosh
committed
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//
// Notes on the layout of global symbol index space:
//
// - Go object files are read before host object files; each Go object
// read allocates a new chunk of global index space of size P + NP,
// where P is the number of package defined symbols in the object and
// NP is the number of non-package defined symbols.
//
// - In loader.LoadRefs(), the loader makes a sweep through all of the
// non-package references in each object file and allocates sym indices
// for any symbols that have not yet been defined (start of this space
// is marked by loader.extStart).
//
// - Host object file loading happens; the host object loader does a
// name/version lookup for each symbol it finds; this can wind up
// extending the external symbol index space range. The host object
// loader currently stores symbol payloads in sym.Symbol objects,
// which get handed off to the loader.
//
// - A given external symbol (Sym) either has a sym.Symbol acting as
// its backing store (this will continue to be the case until we
// finish rewriting the host object loader to work entirely with
// loader.Sym) or it has a "payload" backing store (represented by
// extSymPayload). Newly created external symbols (created by
// a call to AddExtSym or equivalent) start out in the "has payload"
// state, and continue until installSym is called for the sym
// index in question.
//
// - At some point (when the wayfront is pushed through all of the
// linker), all external symbols will be payload-based, and we can
// get rid of the loader.Syms array.
//
start map[*oReader]Sym // map from object file to its start index
objs []objIdx // sorted by start index (i.e. objIdx.i)
max Sym // current max index
extStart Sym // from this index on, the symbols are externally defined
builtinSyms []Sym // global index of builtin symbols
Than McIntosh
committed
ocache int // index (into 'objs') of most recent lookup
symsByName [2]map[string]Sym // map symbol name to index, two maps are for ABI0 and ABIInternal
extStaticSyms map[nameVer]Sym // externally defined static symbols, keyed by name
overwrite map[Sym]Sym // overwrite[i]=j if symbol j overwrites symbol i
payloadBatch []extSymPayload
payloads []*extSymPayload // contents of linker-materialized external syms
values []int64 // symbol values, indexed by global sym index
Than McIntosh
committed
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
Cherry Zhang
committed
objByPkg map[string]*oReader // map package path to its Go object reader
Syms []*sym.Symbol // indexed symbols. XXX we still make sym.Symbol for now.
symBatch []sym.Symbol // batch of symbols.
anonVersion int // most recently assigned ext static sym pseudo-version
// Bitmaps and other side structures used to store data used to store
// symbol flags/attributes; these are to be accessed via the
// corresponding loader "AttrXXX" and "SetAttrXXX" methods. Please
// visit the comments on these methods for more details on the
// semantics / interpretation of the specific flags or attribute.
attrReachable bitmap // reachable symbols, indexed by global index
attrOnList bitmap // "on list" symbols, indexed by global index
attrLocal bitmap // "local" symbols, indexed by global index
attrNotInSymbolTable bitmap // "not in symtab" symbols, indexed by glob idx
attrVisibilityHidden bitmap // hidden symbols, indexed by ext sym index
attrDuplicateOK bitmap // dupOK symbols, indexed by ext sym index
attrShared bitmap // shared symbols, indexed by ext sym index
attrExternal bitmap // external symbols, indexed by ext sym index
attrReadOnly map[Sym]bool // readonly data for this sym
attrTopFrame map[Sym]struct{} // top frame symbols
attrSpecial map[Sym]struct{} // "special" frame symbols
attrCgoExportDynamic map[Sym]struct{} // "cgo_export_dynamic" symbols
attrCgoExportStatic map[Sym]struct{} // "cgo_export_static" symbols
// Outer and Sub relations for symbols.
// TODO: figure out whether it's more efficient to just have these
// as fields on extSymPayload (note that this won't be a viable
// strategy if somewhere in the linker we set sub/outer for a
// non-external sym).
outer map[Sym]Sym
sub map[Sym]Sym
align map[Sym]int32 // stores alignment for symbols
dynimplib map[Sym]string // stores Dynimplib symbol attribute
dynimpvers map[Sym]string // stores Dynimpvers symbol attribute
localentry map[Sym]uint8 // stores Localentry symbol attribute
extname map[Sym]string // stores Extname symbol attribute
elfType map[Sym]elf.SymType // stores elf type symbol property
symFile map[Sym]string // stores file for shlib-derived syms
// Used to implement field tracking; created during deadcode if
// field tracking is enabled. Reachparent[K] contains the index of
// the symbol that triggered the marking of symbol K as live.
Reachparent []Sym
relocBatch []sym.Reloc // for bulk allocation of relocations
flags uint32
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
elfsetstring elfsetstringFunc
type elfsetstringFunc func(s *sym.Symbol, str string, off int)
Than McIntosh
committed
// extSymPayload holds the payload (data + relocations) for linker-synthesized
// external symbols (note that symbol value is stored in a separate slice).
Than McIntosh
committed
type extSymPayload struct {
name string // TODO: would this be better as offset into str table?
size int64
ver int
kind sym.SymKind
objidx uint32 // index of original object if sym made by cloneToExternal
gotype Sym // Gotype (0 if not present)
Than McIntosh
committed
relocs []Reloc
data []byte
}
const (
// Loader.flags
FlagStrictDups = 1 << iota
)
func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
nbuiltin := goobj2.NBuiltin()
start: make(map[*oReader]Sym),
objs: []objIdx{{nil, 0, 0}},
symsByName: [2]map[string]Sym{make(map[string]Sym), make(map[string]Sym)},
objByPkg: make(map[string]*oReader),
outer: make(map[Sym]Sym),
sub: make(map[Sym]Sym),
align: make(map[Sym]int32),
dynimplib: make(map[Sym]string),
dynimpvers: make(map[Sym]string),
localentry: make(map[Sym]uint8),
extname: make(map[Sym]string),
attrReadOnly: make(map[Sym]bool),
elfType: make(map[Sym]elf.SymType),
symFile: make(map[Sym]string),
attrTopFrame: make(map[Sym]struct{}),
attrSpecial: make(map[Sym]struct{}),
attrCgoExportDynamic: make(map[Sym]struct{}),
attrCgoExportStatic: make(map[Sym]struct{}),
overwrite: make(map[Sym]Sym),
itablink: make(map[Sym]struct{}),
extStaticSyms: make(map[nameVer]Sym),
builtinSyms: make([]Sym, nbuiltin),
flags: flags,
elfsetstring: elfsetstring,
}
}
// Return the start index in the global index space for a given object file.
func (l *Loader) startIndex(r *oReader) Sym {
return l.start[r]
}
// Add object file r, return the start index.
func (l *Loader) addObj(pkg string, r *oReader) Sym {
if _, ok := l.start[r]; ok {
panic("already added")
}
pkg = objabi.PathToPrefix(pkg) // the object file contains escaped package path
Cherry Zhang
committed
if _, ok := l.objByPkg[pkg]; !ok {
l.objByPkg[pkg] = r
}
n := r.NSym() + r.NNonpkgdef()
i := l.max + 1
l.start[r] = i
Than McIntosh
committed
l.objs = append(l.objs, objIdx{r, i, i + Sym(n) - 1})
Than McIntosh
committed
l.max += Sym(n)
l.growValues(int(l.max))
return i
}
// Add a symbol with a given index, return if it is added.
func (l *Loader) AddSym(name string, ver int, i Sym, r *oReader, dupok bool, typ sym.SymKind) bool {
if l.extStart != 0 {
panic("AddSym called after AddExtSym is called")
}
if ver == r.version {
// Static symbol. Add its global index but don't
// add to name lookup table, as it cannot be
// referenced by name.
return true
}
if oldi, ok := l.symsByName[ver][name]; ok {
if l.flags&FlagStrictDups != 0 {
l.checkdup(name, i, r, oldi)
}
oldr, li := l.toLocal(oldi)
oldsym := goobj2.Sym{}
oldsym.Read(oldr.Reader, oldr.SymOff(li))
if oldsym.Dupok() {
return false
}
overwrite := r.DataSize(int(i-l.startIndex(r))) != 0
if overwrite {
// new symbol overwrites old symbol.
oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type)]
if !(oldtyp.IsData() && oldr.DataSize(li) == 0) {
log.Fatalf("duplicated definition of symbol " + name)
}
l.overwrite[oldi] = i
} else {
// old symbol overwrites new symbol.
if typ != sym.SDATA && typ != sym.SNOPTRDATA && typ != sym.SBSS && typ != sym.SNOPTRBSS { // only allow overwriting data symbol
log.Fatalf("duplicated definition of symbol " + name)
}
l.overwrite[i] = oldi
return false
}
}
l.symsByName[ver][name] = i
return true
}
Than McIntosh
committed
// newExtSym creates a new external sym with the specified
// name/version.
func (l *Loader) newExtSym(name string, ver int) Sym {
l.max++
i := l.max
if l.extStart == 0 {
l.extStart = i
}
l.growSyms(int(i))
pi := i - l.extStart
l.payloads[pi] = l.allocPayload()
Than McIntosh
committed
l.payloads[pi].name = name
l.payloads[pi].ver = ver
return i
}
// Add an external symbol (without index). Return the index of newly added
// symbol, or 0 if not added.
Than McIntosh
committed
func (l *Loader) AddExtSym(name string, ver int) Sym {
Than McIntosh
committed
i := l.Lookup(name, ver)
if i != 0 {
return 0
}
i = l.newExtSym(name, ver)
static := ver >= sym.SymVerStatic || ver < 0
Than McIntosh
committed
l.extStaticSyms[nameVer{name, ver}] = i
Than McIntosh
committed
l.symsByName[ver][name] = i
Than McIntosh
committed
return i
}
// LookupOrCreateSym looks up the symbol with the specified name/version,
// returning its Sym index if found. If the lookup fails, a new external
// Sym will be created, entered into the lookup tables, and returned.
func (l *Loader) LookupOrCreateSym(name string, ver int) Sym {
i := l.Lookup(name, ver)
if i != 0 {
return i
}
i = l.newExtSym(name, ver)
static := ver >= sym.SymVerStatic || ver < 0
if static {
l.extStaticSyms[nameVer{name, ver}] = i
} else {
l.symsByName[ver][name] = i
}
func (l *Loader) IsExternal(i Sym) bool {
return l.extStart != 0 && i >= l.extStart
}
Than McIntosh
committed
// getPayload returns a pointer to the extSymPayload struct for an
// external symbol if the symbol has a payload, or nil if the
// data for the sym is being stored in a sym.Symbol. Will panic if
// the symbol in question is bogus (zero or not an external sym).
func (l *Loader) getPayload(i Sym) *extSymPayload {
if l.extStart == 0 || i < l.extStart {
panic(fmt.Sprintf("bogus symbol index %d in getPayload", i))
}
if l.Syms[i] != nil {
return nil
}
pi := i - l.extStart
return l.payloads[pi]
}
// allocPayload allocates a new payload.
func (l *Loader) allocPayload() *extSymPayload {
batch := l.payloadBatch
if len(batch) == 0 {
batch = make([]extSymPayload, 1000)
}
p := &batch[0]
l.payloadBatch = batch[1:]
return p
Than McIntosh
committed
}
func (ms *extSymPayload) Grow(siz int64) {
if int64(int(siz)) != siz {
log.Fatalf("symgrow size %d too long", siz)
}
if int64(len(ms.data)) >= siz {
return
}
if cap(ms.data) < int(siz) {
cl := len(ms.data)
ms.data = append(ms.data, make([]byte, int(siz)+1-cl)...)
ms.data = ms.data[0:cl]
}
ms.data = ms.data[:siz]
}
// Ensure Syms slice has enough space, as well as growing the
// 'payloads' slice.
func (l *Loader) growSyms(i int) {
n := len(l.Syms)
if n > i {
return
}
l.Syms = append(l.Syms, make([]*sym.Symbol, i+1-n)...)
l.payloads = append(l.payloads, make([]*extSymPayload, i+1-n)...)
l.growValues(int(i) + 1)
l.growAttrBitmaps(int(i) + 1)
}
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
// getOverwrite returns the overwrite symbol for 'symIdx', while
// collapsing any chains of overwrites along the way. This is
// apparently needed in cases where we add an overwrite entry X -> Y
// during preload (where both X and Y are non-external symbols), and
// then we add an additional entry to the overwrite map Y -> W in
// cloneToExternal when we encounter the real definition of the symbol
// in a host object file, and we need to build up W's content.
//
// Note: it would be nice to avoid this sort of complexity. One of the
// main reasons we wind up with overwrites has to do with the way the
// compiler handles link-named symbols that are 'defined elsewhere':
// at the moment they wind up as no-package defs. For example, consider
// the variable "runtime.no_pointers_stackmap". This variable is defined
// in an assembly file as RODATA, then in one of the Go files it is
// declared this way:
//
// var no_pointers_stackmap uint64 // defined in assembly
//
// This generates what amounts to a weak definition (in the object
// containing the line of code above), which is then overriden by the
// stronger def from the assembly file. Rather than have things work
// this way, it would be better if in the Go file we emitted a
// no-package ref instead of a no-package def, which would eliminate
// the need for overwrites. Doing this would also require changing the
// semantics of //go:linkname, however; we'd have to insure that in
// the cross-package case there is a go:linkname directive on both
// ends.
func (l *Loader) getOverwrite(symIdx Sym) Sym {
var seen map[Sym]bool
result := symIdx
cur := symIdx
for {
if ov, ok := l.overwrite[cur]; ok {
if seen == nil {
seen = make(map[Sym]bool)
seen[symIdx] = true
}
if _, ok := seen[ov]; ok {
panic("cycle in overwrite map")
} else {
seen[cur] = true
}
cur = ov
} else {
break
}
}
if cur != symIdx {
result = cur
cur = symIdx
for {
if ov, ok := l.overwrite[cur]; ok {
l.overwrite[cur] = result
cur = ov
} else {
break
}
}
}
return result
}
// Convert a local index to a global index.
func (l *Loader) toGlobal(r *oReader, i int) Sym {
g := l.startIndex(r) + Sym(i)
g = l.getOverwrite(g)
Cherry Zhang
committed
// Convert a global index to a local index.
func (l *Loader) toLocal(i Sym) (*oReader, int) {
if ov, ok := l.overwrite[i]; ok {
i = ov
}
if l.IsExternal(i) {
return nil, int(i - l.extStart)
Than McIntosh
committed
oc := l.ocache
if oc != 0 && i >= l.objs[oc].i && i <= l.objs[oc].e {
return l.objs[oc].r, int(i - l.objs[oc].i)
}
// Search for the local object holding index i.
// Below k is the first one that has its start index > i,
// so k-1 is the one we want.
k := sort.Search(len(l.objs), func(k int) bool {
return l.objs[k].i > i
})
Than McIntosh
committed
l.ocache = k - 1
return l.objs[k-1].r, int(i - l.objs[k-1].i)
// rcacheGet checks for a valid entry for 's' in the readers cache,
// where 's' is a local PkgIdxNone ref or def, or zero if
// the cache is empty or doesn't contain a value for 's'.
func (or *oReader) rcacheGet(symIdx uint32) Sym {
if len(or.rcache) > 0 {
return or.rcache[symIdx]
}
return 0
}
// rcacheSet installs a new entry in the oReader's PkgNone
// resolver cache for the specified PkgIdxNone ref or def,
// allocating a new cache if needed.
func (or *oReader) rcacheSet(symIdx uint32, gsym Sym) {
if len(or.rcache) == 0 {
or.rcache = make([]Sym, or.NNonpkgdef()+or.NNonpkgref())
}
or.rcache[symIdx] = gsym
}
Cherry Zhang
committed
// Resolve a local symbol reference. Return global index.
func (l *Loader) resolve(r *oReader, s goobj2.SymRef) Sym {
Cherry Zhang
committed
var rr *oReader
switch p := s.PkgIdx; p {
case goobj2.PkgIdxInvalid:
if s.SymIdx != 0 {
panic("bad sym ref")
}
return 0
case goobj2.PkgIdxNone:
// Check for cached version first
if cached := r.rcacheGet(s.SymIdx); cached != 0 {
ov := l.getOverwrite(cached)
if cached != ov {
r.rcacheSet(s.SymIdx, ov)
return ov
}
Cherry Zhang
committed
// Resolve by name
i := int(s.SymIdx) + r.NSym()
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(i))
name := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
v := abiToVer(osym.ABI, r.version)
gsym := l.getOverwrite(l.Lookup(name, v))
// Add to cache, then return.
r.rcacheSet(s.SymIdx, gsym)
return gsym
Cherry Zhang
committed
case goobj2.PkgIdxBuiltin:
return l.builtinSyms[s.SymIdx]
Cherry Zhang
committed
case goobj2.PkgIdxSelf:
rr = r
default:
pkg := r.Pkg(int(p))
var ok bool
rr, ok = l.objByPkg[pkg]
if !ok {
log.Fatalf("reference of nonexisted package %s, from %v", pkg, r.unit.Lib)
}
Cherry Zhang
committed
}
return l.toGlobal(rr, int(s.SymIdx))
Cherry Zhang
committed
}
// Look up a symbol by name, return global index, or 0 if not found.
// This is more like Syms.ROLookup than Lookup -- it doesn't create
// new symbol.
Than McIntosh
committed
func (l *Loader) Lookup(name string, ver int) Sym {
if ver >= sym.SymVerStatic || ver < 0 {
return l.extStaticSyms[nameVer{name, ver}]
}
return l.symsByName[ver][name]
// Returns whether i is a dup of another symbol, and i is not
// "primary", i.e. Lookup i by name will not return i.
func (l *Loader) IsDup(i Sym) bool {
if _, ok := l.overwrite[i]; ok {
return true
}
if l.IsExternal(i) {
return false
}
r, li := l.toLocal(i)
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(li))
if !osym.Dupok() {
return false
}
if osym.Name == "" {
return false // Unnamed aux symbol cannot be dup.
}
if osym.ABI == goobj2.SymABIstatic {
return false // Static symbol cannot be dup.
}
name := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
ver := abiToVer(osym.ABI, r.version)
return l.symsByName[ver][name] != i
}
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
// Check that duplicate symbols have same contents.
func (l *Loader) checkdup(name string, i Sym, r *oReader, dup Sym) {
li := int(i - l.startIndex(r))
p := r.Data(li)
if strings.HasPrefix(name, "go.info.") {
p, _ = patchDWARFName1(p, r)
}
rdup, ldup := l.toLocal(dup)
pdup := rdup.Data(ldup)
if strings.HasPrefix(name, "go.info.") {
pdup, _ = patchDWARFName1(pdup, rdup)
}
if bytes.Equal(p, pdup) {
return
}
reason := "same length but different contents"
if len(p) != len(pdup) {
reason = fmt.Sprintf("new length %d != old length %d", len(p), len(pdup))
}
fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason)
// For the moment, whitelist DWARF subprogram DIEs for
// auto-generated wrapper functions. What seems to happen
// here is that we get different line numbers on formal
// params; I am guessing that the pos is being inherited
// from the spot where the wrapper is needed.
whitelist := strings.HasPrefix(name, "go.info.go.interface") ||
strings.HasPrefix(name, "go.info.go.builtin") ||
strings.HasPrefix(name, "go.debuglines")
if !whitelist {
l.strictDupMsgs++
}
}
func (l *Loader) NStrictDupMsgs() int { return l.strictDupMsgs }
// Number of total symbols.
func (l *Loader) NSym() int {
return int(l.max + 1)
}
// Number of defined Go symbols.
func (l *Loader) NDef() int {
return int(l.extStart)
}
// Returns the raw (unpatched) name of the i-th symbol.
func (l *Loader) RawSymName(i Sym) string {
if ov, ok := l.overwrite[i]; ok {
i = ov
}
if l.IsExternal(i) {
if s := l.Syms[i]; s != nil {
return s.Name
}
Than McIntosh
committed
pp := l.getPayload(i)
return pp.name
r, li := l.toLocal(i)
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(li))
return osym.Name
}
// Returns the (patched) name of the i-th symbol.
func (l *Loader) SymName(i Sym) string {
if l.IsExternal(i) {
if s := l.Syms[i]; s != nil {
return s.Name // external name should already be patched?
}
Than McIntosh
committed
pp := l.getPayload(i)
return pp.name
r, li := l.toLocal(i)
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(li))
return strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
}
// Returns the version of the i-th symbol.
func (l *Loader) SymVersion(i Sym) int {
if l.IsExternal(i) {
if s := l.Syms[i]; s != nil {
return int(s.Version)
}
pp := l.getPayload(i)
return pp.ver
}
r, li := l.toLocal(i)
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(li))
return int(abiToVer(osym.ABI, r.version))
}
// Returns the type of the i-th symbol.
func (l *Loader) SymType(i Sym) sym.SymKind {
if l.IsExternal(i) {
if s := l.Syms[i]; s != nil {
return s.Type
}
Than McIntosh
committed
pp := l.getPayload(i)
if pp != nil {
return pp.kind
}
r, li := l.toLocal(i)
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(li))
return sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
}
// Returns the attributes of the i-th symbol.
func (l *Loader) SymAttr(i Sym) uint8 {
if l.IsExternal(i) {
// TODO: do something? External symbols have different representation of attributes. For now, ReflectMethod is the only thing matters and it cannot be set by external symbol.
return 0
}
r, li := l.toLocal(i)
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(li))
return osym.Flag
}
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
// AttrReachable returns true for symbols that are transitively
// referenced from the entry points. Unreachable symbols are not
// written to the output.
func (l *Loader) AttrReachable(i Sym) bool {
return l.attrReachable.has(i)
}
// SetAttrReachable sets the reachability property for a symbol (see
// AttrReachable).
func (l *Loader) SetAttrReachable(i Sym, v bool) {
if v {
l.attrReachable.set(i)
} else {
l.attrReachable.unset(i)
}
}
// AttrOnList returns true for symbols that are on some list (such as
// the list of all text symbols, or one of the lists of data symbols)
// and is consulted to avoid bugs where a symbol is put on a list
// twice.
func (l *Loader) AttrOnList(i Sym) bool {
return l.attrOnList.has(i)
}
// SetAttrOnList sets the "on list" property for a symbol (see
// AttrOnList).
func (l *Loader) SetAttrOnList(i Sym, v bool) {
if v {
l.attrOnList.set(i)
} else {
l.attrOnList.unset(i)
}
}
// AttrLocal returns true for symbols that are only visible within the
// module (executable or shared library) being linked. This attribute
// is applied to thunks and certain other linker-generated symbols.
func (l *Loader) AttrLocal(i Sym) bool {
return l.attrLocal.has(i)
}
// SetAttrLocal the "local" property for a symbol (see AttrLocal above).
func (l *Loader) SetAttrLocal(i Sym, v bool) {
if v {
l.attrLocal.set(i)
} else {
l.attrLocal.unset(i)
}
}
// AttrNotInSymbolTable returns true for symbols that should not be
// added to the symbol table of the final generated load module.
func (l *Loader) AttrNotInSymbolTable(i Sym) bool {
return l.attrNotInSymbolTable.has(i)
}
// SetAttrNotInSymbolTable the "not in symtab" property for a symbol
// (see AttrNotInSymbolTable above).
func (l *Loader) SetAttrNotInSymbolTable(i Sym, v bool) {
if v {
l.attrNotInSymbolTable.set(i)
} else {
l.attrNotInSymbolTable.unset(i)
}
}
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
// AttrVisibilityHidden symbols returns true for ELF symbols with
// visibility set to STV_HIDDEN. They become local symbols in
// the final executable. Only relevant when internally linking
// on an ELF platform.
func (l *Loader) AttrVisibilityHidden(i Sym) bool {
if i < l.extStart {
return false
}
return l.attrVisibilityHidden.has(i - l.extStart)
}
// SetAttrVisibilityHidden sets the "hidden visibility" property for a
// symbol (see AttrVisibilityHidden).
func (l *Loader) SetAttrVisibilityHidden(i Sym, v bool) {
if i < l.extStart {
panic("tried to set visibility attr on non-external symbol")
}
if v {
l.attrVisibilityHidden.set(i - l.extStart)
} else {
l.attrVisibilityHidden.unset(i - l.extStart)
}
}
// AttrDuplicateOK returns true for a symbol that can be present in
// multiple object files.
func (l *Loader) AttrDuplicateOK(i Sym) bool {
if i < l.extStart {
// TODO: if this path winds up being taken frequently, it
// might make more sense to copy the flag value out of the object
// into a larger bitmap during preload.
r, li := l.toLocal(i)
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(li))
return osym.Dupok()
}
return l.attrDuplicateOK.has(i - l.extStart)
}
// SetAttrDuplicateOK sets the "duplicate OK" property for an external
// symbol (see AttrDuplicateOK).
func (l *Loader) SetAttrDuplicateOK(i Sym, v bool) {
if i < l.extStart {
panic("tried to set dupok attr on non-external symbol")
}
if v {
l.attrDuplicateOK.set(i - l.extStart)
} else {
l.attrDuplicateOK.unset(i - l.extStart)
}
}
// AttrShared returns true for symbols compiled with the -shared option.
func (l *Loader) AttrShared(i Sym) bool {
if i < l.extStart {
// TODO: if this path winds up being taken frequently, it
// might make more sense to copy the flag value out of the
// object into a larger bitmap during preload.
r, _ := l.toLocal(i)
return (r.Flags() & goobj2.ObjFlagShared) != 0
}
return l.attrShared.has(i - l.extStart)
}
// SetAttrShared sets the "shared" property for an external
// symbol (see AttrShared).
func (l *Loader) SetAttrShared(i Sym, v bool) {
if i < l.extStart {
panic("tried to set shared attr on non-external symbol")
}
if v {
l.attrShared.set(i - l.extStart)
} else {
l.attrShared.unset(i - l.extStart)
}
}
// AttrExternal returns true for function symbols loaded from host
// object files.
func (l *Loader) AttrExternal(i Sym) bool {
if i < l.extStart {
return false
}
return l.attrExternal.has(i - l.extStart)
}
// SetAttrExternal sets the "external" property for an host object
// symbol (see AttrExternal).
func (l *Loader) SetAttrExternal(i Sym, v bool) {
if i < l.extStart {
panic(fmt.Sprintf("tried to set external attr on non-external symbol %q", l.RawSymName(i)))
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
}
if v {
l.attrExternal.set(i - l.extStart)
} else {
l.attrExternal.unset(i - l.extStart)
}
}
// AttrTopFrame returns true for a function symbol that is an entry
// point, meaning that unwinders should stop when they hit this
// function.
func (l *Loader) AttrTopFrame(i Sym) bool {
_, ok := l.attrTopFrame[i]
return ok
}
// SetAttrTopFrame sets the "top frame" property for a symbol (see
// AttrTopFrame).
func (l *Loader) SetAttrTopFrame(i Sym, v bool) {
if v {
l.attrTopFrame[i] = struct{}{}
} else {
delete(l.attrTopFrame, i)
}
}
// AttrSpecial returns true for a symbols that do not have their
// address (i.e. Value) computed by the usual mechanism of
// data.go:dodata() & data.go:address().
func (l *Loader) AttrSpecial(i Sym) bool {
_, ok := l.attrSpecial[i]
return ok
}
// SetAttrSpecial sets the "special" property for a symbol (see
// AttrSpecial).
func (l *Loader) SetAttrSpecial(i Sym, v bool) {
if v {
l.attrSpecial[i] = struct{}{}
} else {
delete(l.attrSpecial, i)
}
}
// AttrCgoExportDynamic returns true for a symbol that has been
// specially marked via the "cgo_export_dynamic" compiler directive
// written by cgo (in response to //export directives in the source).
func (l *Loader) AttrCgoExportDynamic(i Sym) bool {
_, ok := l.attrCgoExportDynamic[i]
return ok
}
// SetAttrCgoExportDynamic sets the "cgo_export_dynamic" for a symbol
// (see AttrCgoExportDynamic).
func (l *Loader) SetAttrCgoExportDynamic(i Sym, v bool) {
if v {
l.attrCgoExportDynamic[i] = struct{}{}
} else {
delete(l.attrCgoExportDynamic, i)
}
}
// AttrCgoExportStatic returns true for a symbol that has been
// specially marked via the "cgo_export_static" directive
// written by cgo.
func (l *Loader) AttrCgoExportStatic(i Sym) bool {
_, ok := l.attrCgoExportStatic[i]
return ok
}
// SetAttrCgoExportStatic sets the "cgo_export_dynamic" for a symbol
// (see AttrCgoExportStatic).
func (l *Loader) SetAttrCgoExportStatic(i Sym, v bool) {
if v {
l.attrCgoExportStatic[i] = struct{}{}
} else {
delete(l.attrCgoExportStatic, i)