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"
"cmd/internal/bio"
"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 {
Cherry Zhang
committed
li uint32 // local index of symbol whose relocs we're examining
r *oReader // object reader for containing package
l *Loader // loader
}
// 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
}
// ExtReloc contains the payload for an external relocation.
type ExtReloc struct {
Cherry Zhang
committed
Idx int // index of the original relocation
Xsym Sym
Xadd int64
}
Cherry Zhang
committed
// ExtRelocView is a view of an external relocation.
// It is intended to be constructed on the fly, such as ExtRelocs.At.
// It is not the data structure used to store the payload internally.
type ExtRelocView struct {
Reloc2
*ExtReloc
}
Cherry Zhang
committed
// Reloc2 holds a "handle" to access a relocation record from an
// object file.
type Reloc2 struct {
Cherry Zhang
committed
r *oReader
l *Loader
// External reloc types may not fit into a uint8 which the Go object file uses.
// Store it here, instead of in the byte of goobj2.Reloc2.
// For Go symbols this will always be zero.
// goobj2.Reloc2.Type() + typ is always the right type, for both Go and external
// symbols.
typ objabi.RelocType
Cherry Zhang
committed
}
func (rel Reloc2) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) + rel.typ }
func (rel Reloc2) Sym() Sym { return rel.l.resolve(rel.r, rel.Reloc.Sym()) }
func (rel Reloc2) SetSym(s Sym) { rel.Reloc.SetSym(goobj2.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) }
func (rel Reloc2) SetType(t objabi.RelocType) {
if t != objabi.RelocType(uint8(t)) {
panic("SetType: type doesn't fit into Reloc2")
}
if rel.typ != 0 {
// should use SymbolBuilder.SetRelocType
panic("wrong method to set reloc type")
}
Cherry Zhang
committed
Cherry Zhang
committed
// Aux2 holds a "handle" to access an aux symbol record from an
// object file.
type Aux2 struct {
Cherry Zhang
committed
r *oReader
l *Loader
}
func (a Aux2) Sym() Sym { return a.l.resolve(a.r, a.Aux.Sym()) }
Cherry Zhang
committed
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
syms []Sym // Sym's global index, indexed by local index
ndef int // cache goobj2.Reader.NSym()
objidx uint32 // index of this reader in the objs slice
Cherry Zhang
committed
}
Cherry Zhang
committed
r *oReader
Than McIntosh
committed
i Sym // start index
// objSym represents a symbol in an object file. It is a tuple of
// the object and the symbol's local index.
Cherry Zhang
committed
// For external symbols, objidx is the index of l.extReader (extObj),
// s is its index into the payload array.
// {0, 0} represents the nil symbol.
type objSym struct {
Cherry Zhang
committed
objidx uint32 // index of the object (in l.objs array)
s uint32 // local index
type nameVer struct {
name string
v int
}
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 {
Than McIntosh
committed
return len(bm) * 32
}
// return the number of bits set.
func (bm Bitmap) Count() int {
s := 0
for _, x := range bm {
s += bits.OnesCount32(x)
}
return s
}
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()
Than McIntosh
committed
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
//
// Notes on the layout of global symbol index space:
//
// - Go object files are read before host object files; each Go object
Cherry Zhang
committed
// read adds its defined package symbols to the global index space.
// Nonpackage symbols are not yet added.
Than McIntosh
committed
//
Cherry Zhang
committed
// - In loader.LoadNonpkgSyms, add non-package defined symbols and
// references in all object files to the global index space.
Than McIntosh
committed
//
// - Host object file loading happens; the host object loader does a
Than McIntosh
committed
// name/version lookup for each symbol it finds; this can wind up
// extending the external symbol index space range. The host object
Cherry Zhang
committed
// loader stores symbol payloads in loader.payloads using SymbolBuilder.
Than McIntosh
committed
//
// - Each symbol gets a unique global index. For duplicated and
// overwriting/overwritten symbols, the second (or later) appearance
// of the symbol gets the same global index as the first appearance.
start map[*oReader]Sym // map from object file to its start index
objs []objIdx // sorted by start index (i.e. objIdx.i)
extStart Sym // from this index on, the symbols are externally defined
builtinSyms []Sym // global index of builtin symbols
objSyms []objSym // global index mapping to local index
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
extReader *oReader // a dummy oReader, for external symbols
payloadBatch []extSymPayload
payloads []*extSymPayload // contents of linker-materialized external syms
values []int64 // symbol values, indexed by global sym index
Cherry Zhang
committed
sects []*sym.Section // sections
symSects []uint16 // symbol's section, index to sects array
Than McIntosh
committed
Than McIntosh
committed
align []uint8 // symbol 2^N alignment, indexed by global index
outdata [][]byte // symbol's data in the output buffer
extRelocs [][]ExtReloc // symbol's external relocations
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
deferReturnTramp map[Sym]bool // whether the symbol is a trampoline of a deferreturn call
Cherry Zhang
committed
objByPkg map[string]*oReader // map package path to its Go object reader
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
Cherry Zhang
committed
attrNotInSymbolTable Bitmap // "not in symtab" symbols, indexed by global idx
attrUsedInIface Bitmap // "used in interface" symbols, indexed by global 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
generatedSyms map[Sym]struct{} // symbols that generate their content
// 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
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
elfSym map[Sym]int32 // stores elf sym symbol property
localElfSym map[Sym]int32 // stores "local" elf sym symbol property
symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms
plt map[Sym]int32 // stores dynimport for pe objects
got map[Sym]int32 // stores got for pe objects
dynid map[Sym]int32 // stores Dynid for symbol
relocVariant map[relocId]sym.RelocVariant // stores variant relocs
// 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
flags uint32
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
elfsetstring elfsetstringFunc
errorReporter *ErrorReporter
Cherry Zhang
committed
const (
pkgDef = iota
Cherry Zhang
committed
nonPkgDef
nonPkgRef
)
Cherry Zhang
committed
// objidx
const (
nilObj = iota
extObj
goObjStart
)
type elfsetstringFunc func(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
reltypes []objabi.RelocType // relocation types
data []byte
Than McIntosh
committed
}
const (
// Loader.flags
FlagStrictDups = 1 << iota
)
func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
nbuiltin := goobj2.NBuiltin()
Cherry Zhang
committed
extReader := &oReader{objidx: extObj}
ldr := &Loader{
start: make(map[*oReader]Sym),
Cherry Zhang
committed
objs: []objIdx{{}, {extReader, 0}}, // reserve index 0 for nil symbol, 1 for external symbols
objSyms: make([]objSym, 1, 100000), // reserve index 0 for nil symbol
extReader: extReader,
symsByName: [2]map[string]Sym{make(map[string]Sym, 100000), make(map[string]Sym, 50000)}, // preallocate ~2MB for ABI0 and ~1MB for ABI1 symbols
objByPkg: make(map[string]*oReader),
outer: make(map[Sym]Sym),
sub: make(map[Sym]Sym),
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),
elfSym: make(map[Sym]int32),
localElfSym: make(map[Sym]int32),
symPkg: make(map[Sym]string),
plt: make(map[Sym]int32),
got: make(map[Sym]int32),
dynid: make(map[Sym]int32),
attrTopFrame: make(map[Sym]struct{}),
attrSpecial: make(map[Sym]struct{}),
attrCgoExportDynamic: make(map[Sym]struct{}),
attrCgoExportStatic: make(map[Sym]struct{}),
generatedSyms: make(map[Sym]struct{}),
itablink: make(map[Sym]struct{}),
deferReturnTramp: make(map[Sym]bool),
extStaticSyms: make(map[nameVer]Sym),
builtinSyms: make([]Sym, nbuiltin),
flags: flags,
elfsetstring: elfsetstring,
errorReporter: reporter,
Cherry Zhang
committed
sects: []*sym.Section{nil}, // reserve index 0 for nil section
reporter.ldr = ldr
return ldr
}
// 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
}
l.objs = append(l.objs, objIdx{r, i})
// Add a symbol from an object file, return the global index and whether it is added.
// If the symbol already exist, it returns the index of that symbol.
Cherry Zhang
committed
func (l *Loader) AddSym(name string, ver int, r *oReader, li uint32, kind int, dupok bool, typ sym.SymKind) (Sym, bool) {
panic("AddSym called after external symbol is created")
i := Sym(len(l.objSyms))
addToGlobal := func() {
Cherry Zhang
committed
l.objSyms = append(l.objSyms, objSym{r.objidx, li})
}
if name == "" {
return i, true // unnamed aux symbol
}
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.
Cherry Zhang
committed
if kind == pkgDef {
// Defined package symbols cannot be dup to each other.
// We load all the package symbols first, so we don't need
// to check dup here.
// We still add it to the lookup table, as it may still be
// referenced by name (e.g. through linkname).
l.symsByName[ver][name] = i
addToGlobal()
return i, true
}
// Non-package (named) symbol. Check if it already exists.
oldi, existed := l.symsByName[ver][name]
if !existed {
l.symsByName[ver][name] = i
addToGlobal()
return i, true
}
// symbol already exists
if dupok {
if l.flags&FlagStrictDups != 0 {
l.checkdup(name, r, li, oldi)
}
return oldi, false
}
oldr, oldli := l.toLocal(oldi)
if oldsym.Dupok() {
return oldi, false
}
overwrite := r.DataSize(li) != 0
if overwrite {
// new symbol overwrites old symbol.
oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())]
if !(oldtyp.IsData() && oldr.DataSize(oldli) == 0) {
log.Fatalf("duplicated definition of symbol " + name)
}
Cherry Zhang
committed
l.objSyms[oldi] = objSym{r.objidx, li}
} else {
// old symbol overwrites new symbol.
if !typ.IsData() { // only allow overwriting data symbol
log.Fatalf("duplicated definition of symbol " + name)
return oldi, true
Than McIntosh
committed
// newExtSym creates a new external sym with the specified
// name/version.
func (l *Loader) newExtSym(name string, ver int) Sym {
Than McIntosh
committed
if l.extStart == 0 {
l.extStart = i
}
l.growValues(int(i) + 1)
l.growAttrBitmaps(int(i) + 1)
pi := l.newPayload(name, ver)
Cherry Zhang
committed
l.objSyms = append(l.objSyms, objSym{l.extReader.objidx, uint32(pi)})
l.extReader.syms = append(l.extReader.syms, 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 {
r, _ := l.toLocal(i)
return l.isExtReader(r)
}
func (l *Loader) isExtReader(r *oReader) bool {
return r == l.extReader
}
// For external symbol, return its index in the payloads array.
// XXX result is actually not a global index. We (ab)use the Sym type
// so we don't need conversion for accessing bitmaps.
func (l *Loader) extIndex(i Sym) Sym {
_, li := l.toLocal(i)
return Sym(li)
}
// Get a new payload for external symbol, return its index in
// the payloads array.
func (l *Loader) newPayload(name string, ver int) int {
pi := len(l.payloads)
pp := l.allocPayload()
pp.name = name
pp.ver = ver
l.payloads = append(l.payloads, pp)
l.growExtAttrBitmaps()
return pi
}
Than McIntosh
committed
// getPayload returns a pointer to the extSymPayload struct for an
// external symbol if the symbol has a payload. Will panic if the
// symbol in question is bogus (zero or not an external sym).
Than McIntosh
committed
func (l *Loader) getPayload(i Sym) *extSymPayload {
if !l.IsExternal(i) {
Than McIntosh
committed
panic(fmt.Sprintf("bogus symbol index %d in getPayload", i))
}
pi := l.extIndex(i)
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]
}
// Convert a local index to a global index.
Cherry Zhang
committed
func (l *Loader) toGlobal(r *oReader, i uint32) Sym {
Cherry Zhang
committed
// Convert a global index to a local index.
Cherry Zhang
committed
func (l *Loader) toLocal(i Sym) (*oReader, uint32) {
return l.objs[l.objSyms[i].objidx].r, l.objSyms[i].s
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:
// {0, X} with non-zero X is never a valid sym reference from a Go object.
// We steal this space for symbol references from external objects.
// In this case, X is just the global index.
if l.isExtReader(r) {
return Sym(s.SymIdx)
}
Cherry Zhang
committed
if s.SymIdx != 0 {
panic("bad sym ref")
}
return 0
case goobj2.PkgIdxNone:
i := int(s.SymIdx) + r.ndef
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
}
Cherry Zhang
committed
return l.toGlobal(rr, 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]
// Check that duplicate symbols have same contents.
Cherry Zhang
committed
func (l *Loader) checkdup(name string, r *oReader, li uint32, dup Sym) {
p := r.Data(li)
rdup, ldup := l.toLocal(dup)
pdup := rdup.Data(ldup)
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, allow 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.
allowed := strings.HasPrefix(name, "go.info.go.interface") ||
strings.HasPrefix(name, "go.info.go.builtin") ||
strings.HasPrefix(name, "go.debuglines")
l.strictDupMsgs++
}
}
func (l *Loader) NStrictDupMsgs() int { return l.strictDupMsgs }
// Number of total symbols.
func (l *Loader) NSym() int {
// Number of defined Go symbols.
func (l *Loader) NDef() int {
return int(l.extStart)
}
// Number of reachable symbols.
func (l *Loader) NReachableSym() int {
return l.attrReachable.Count()
}
// Returns the raw (unpatched) name of the i-th symbol.
func (l *Loader) RawSymName(i Sym) string {
if l.IsExternal(i) {
Than McIntosh
committed
pp := l.getPayload(i)
return pp.name
r, li := l.toLocal(i)
return r.Sym(li).Name(r.Reader)
}
// Returns the (patched) name of the i-th symbol.
func (l *Loader) SymName(i Sym) string {
if l.IsExternal(i) {
Than McIntosh
committed
pp := l.getPayload(i)
return pp.name
r, li := l.toLocal(i)
name := r.Sym(li).Name(r.Reader)
if !r.NeedNameExpansion() {
return name
}
return strings.Replace(name, "\"\".", r.pkgprefix, -1)
// Returns the version of the i-th symbol.
func (l *Loader) SymVersion(i Sym) int {
if l.IsExternal(i) {
pp := l.getPayload(i)
return pp.ver
}
r, li := l.toLocal(i)
return int(abiToVer(r.Sym(li).ABI(), r.version))
func (l *Loader) IsFileLocal(i Sym) bool { return l.SymVersion(i) >= sym.SymVerStatic }
// Returns the type of the i-th symbol.
func (l *Loader) SymType(i Sym) sym.SymKind {
if l.IsExternal(i) {
Than McIntosh
committed
pp := l.getPayload(i)
if pp != nil {
return pp.kind
}
r, li := l.toLocal(i)
return sym.AbiSymKindToSymKind[objabi.SymKind(r.Sym(li).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, NoSplit, GoType, and Typelink are used and they cannot be
// set by external symbol.
return 0
}
r, li := l.toLocal(i)
}
// Returns the size of the i-th symbol.
func (l *Loader) SymSize(i Sym) int64 {
if l.IsExternal(i) {
pp := l.getPayload(i)
return pp.size
}
r, li := l.toLocal(i)
// 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)
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 {
}
}
// 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 {
Cherry Zhang
committed
// AttrUsedInIface returns true for a type symbol that is used in
// an interface.
func (l *Loader) AttrUsedInIface(i Sym) bool {
return l.attrUsedInIface.Has(i)
}
func (l *Loader) SetAttrUsedInIface(i Sym, v bool) {
if v {
l.attrUsedInIface.Set(i)
} else {
l.attrUsedInIface.Unset(i)
}
}
// SymAddr checks that a symbol is reachable, and returns its value.
func (l *Loader) SymAddr(i Sym) int64 {
if !l.AttrReachable(i) {
panic("unreachable symbol in symaddr")
}
return l.values[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)
}
}
// 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 !l.IsExternal(i) {
return false
}
return l.attrVisibilityHidden.Has(l.extIndex(i))
}
// SetAttrVisibilityHidden sets the "hidden visibility" property for a
// symbol (see AttrVisibilityHidden).
func (l *Loader) SetAttrVisibilityHidden(i Sym, v bool) {
if !l.IsExternal(i) {
panic("tried to set visibility attr on non-external symbol")
}
if v {
l.attrVisibilityHidden.Set(l.extIndex(i))
l.attrVisibilityHidden.Unset(l.extIndex(i))
}
}
// AttrDuplicateOK returns true for a symbol that can be present in
// multiple object files.
func (l *Loader) AttrDuplicateOK(i Sym) bool {
if !l.IsExternal(i) {
// 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)
return l.attrDuplicateOK.Has(l.extIndex(i))
}
// SetAttrDuplicateOK sets the "duplicate OK" property for an external
// symbol (see AttrDuplicateOK).
func (l *Loader) SetAttrDuplicateOK(i Sym, v bool) {
if !l.IsExternal(i) {
panic("tried to set dupok attr on non-external symbol")
}
if v {
l.attrDuplicateOK.Set(l.extIndex(i))
l.attrDuplicateOK.Unset(l.extIndex(i))
}
}
// AttrShared returns true for symbols compiled with the -shared option.
func (l *Loader) AttrShared(i Sym) bool {
if !l.IsExternal(i) {
// 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.Shared()
return l.attrShared.Has(l.extIndex(i))
// SetAttrShared sets the "shared" property for an external
// symbol (see AttrShared).
func (l *Loader) SetAttrShared(i Sym, v bool) {
if !l.IsExternal(i) {
panic(fmt.Sprintf("tried to set shared attr on non-external symbol %d %s", i, l.SymName(i)))
}
if v {
l.attrShared.Set(l.extIndex(i))
} else {
l.attrShared.Unset(l.extIndex(i))
}
}
// AttrExternal returns true for function symbols loaded from host
// object files.
func (l *Loader) AttrExternal(i Sym) bool {
if !l.IsExternal(i) {
return false
}
return l.attrExternal.Has(l.extIndex(i))
}
// SetAttrExternal sets the "external" property for an host object
// symbol (see AttrExternal).
func (l *Loader) SetAttrExternal(i Sym, v bool) {
if !l.IsExternal(i) {
panic(fmt.Sprintf("tried to set external attr on non-external symbol %q", l.RawSymName(i)))
}
if v {
l.attrExternal.Set(l.extIndex(i))
l.attrExternal.Unset(l.extIndex(i))
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
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
}
}
// 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_static" for a symbol
// (see AttrCgoExportStatic).
func (l *Loader) SetAttrCgoExportStatic(i Sym, v bool) {
if v {
l.attrCgoExportStatic[i] = struct{}{}
} else {
delete(l.attrCgoExportStatic, i)
}
}
// IsGeneratedSym returns true if a symbol's been previously marked as a
// generator symbol through the SetIsGeneratedSym. The functions for generator
// symbols are kept in the Link context.
func (l *Loader) IsGeneratedSym(i Sym) bool {
_, ok := l.generatedSyms[i]
return ok
}
// SetIsGeneratedSym marks symbols as generated symbols. Data shouldn't be
// stored in generated symbols, and a function is registered and called for
// each of these symbols.
func (l *Loader) SetIsGeneratedSym(i Sym, v bool) {
if !l.IsExternal(i) {
panic("only external symbols can be generated")
}
if v {
l.generatedSyms[i] = struct{}{}
} else {
delete(l.generatedSyms, i)
}
}
func (l *Loader) AttrCgoExport(i Sym) bool {
return l.AttrCgoExportDynamic(i) || l.AttrCgoExportStatic(i)
}
// AttrReadOnly returns true for a symbol whose underlying data
// is stored via a read-only mmap.
func (l *Loader) AttrReadOnly(i Sym) bool {
if v, ok := l.attrReadOnly[i]; ok {
return v
}
if l.IsExternal(i) {
pp := l.getPayload(i)
if pp.objidx != 0 {
return l.objs[pp.objidx].r.ReadOnly()
}
return false
}
r, _ := l.toLocal(i)
return r.ReadOnly()
}
// SetAttrReadOnly sets the "data is read only" property for a symbol
// (see AttrReadOnly).
func (l *Loader) SetAttrReadOnly(i Sym, v bool) {
l.attrReadOnly[i] = v
}
// AttrSubSymbol returns true for symbols that are listed as a
// sub-symbol of some other outer symbol. The sub/outer mechanism is
// used when loading host objects (sections from the host object
// become regular linker symbols and symbols go on the Sub list of
// their section) and for constructing the global offset table when
// internally linking a dynamic executable.
//
// Note that in later stages of the linker, we set Outer(S) to some
// container symbol C, but don't set Sub(C). Thus we have two
// distinct scenarios:
//
// - Outer symbol covers the address ranges of its sub-symbols.
// Outer.Sub is set in this case.
// - Outer symbol doesn't conver the address ranges. It is zero-sized
// and doesn't have sub-symbols. In the case, the inner symbol is
// not actually a "SubSymbol". (Tricky!)
//
// This method returns TRUE only for sub-symbols in the first scenario.
//
// FIXME: would be better to do away with this and have a better way
// to represent container symbols.
func (l *Loader) AttrSubSymbol(i Sym) bool {
// we don't explicitly store this attribute any more -- return
// a value based on the sub-symbol setting.
o := l.OuterSym(i)
if o == 0 {
return false
}
return l.SubSym(o) != 0
}
Than McIntosh
committed
// Note that we don't have a 'SetAttrSubSymbol' method in the loader;
Than McIntosh
committed
// clients should instead use the AddInteriorSym method to establish
// containment relationships for host object symbols.
// Returns whether the i-th symbol has ReflectMethod attribute set.
func (l *Loader) IsReflectMethod(i Sym) bool {
return l.SymAttr(i)&goobj2.SymFlagReflectMethod != 0
}
// Returns whether the i-th symbol is nosplit.
func (l *Loader) IsNoSplit(i Sym) bool {
return l.SymAttr(i)&goobj2.SymFlagNoSplit != 0
}
// Returns whether this is a Go type symbol.
func (l *Loader) IsGoType(i Sym) bool {
return l.SymAttr(i)&goobj2.SymFlagGoType != 0
}
// Returns whether this symbol should be included in typelink.
func (l *Loader) IsTypelink(i Sym) bool {
return l.SymAttr(i)&goobj2.SymFlagTypelink != 0
}
// Returns whether this is a "go.itablink.*" symbol.
func (l *Loader) IsItabLink(i Sym) bool {
if _, ok := l.itablink[i]; ok {
return true
}
return false
}
// Return whether this is a trampoline of a deferreturn call.
func (l *Loader) IsDeferReturnTramp(i Sym) bool {
return l.deferReturnTramp[i]
}
// Set that i is a trampoline of a deferreturn call.
func (l *Loader) SetIsDeferReturnTramp(i Sym, v bool) {
l.deferReturnTramp[i] = v
}
// growValues grows the slice used to store symbol values.
func (l *Loader) growValues(reqLen int) {
curLen := len(l.values)
if reqLen > curLen {
l.values = append(l.values, make([]int64, reqLen+1-curLen)...)
}
}
// SymValue returns the value of the i-th symbol. i is global index.
func (l *Loader) SymValue(i Sym) int64 {
return l.values[i]
}
// SetSymValue sets the value of the i-th symbol. i is global index.
func (l *Loader) SetSymValue(i Sym, val int64) {
l.values[i] = val
}
// AddToSymValue adds to the value of the i-th symbol. i is the global index.
func (l *Loader) AddToSymValue(i Sym, val int64) {
l.values[i] += val
}
// Returns the symbol content of the i-th symbol. i is global index.
func (l *Loader) Data(i Sym) []byte {
if l.IsExternal(i) {
Than McIntosh
committed
pp := l.getPayload(i)
if pp != nil {
return pp.data
}
return nil
}
r, li := l.toLocal(i)
return r.Data(li)
}
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
// Returns the data of the i-th symbol in the output buffer.
func (l *Loader) OutData(i Sym) []byte {
if int(i) < len(l.outdata) && l.outdata[i] != nil {
return l.outdata[i]
}
return l.Data(i)
}
// SetOutData sets the position of the data of the i-th symbol in the output buffer.
// i is global index.
func (l *Loader) SetOutData(i Sym, data []byte) {
if l.IsExternal(i) {
pp := l.getPayload(i)
if pp != nil {
pp.data = data
return
}
}
l.outdata[i] = data
}
// InitOutData initializes the slice used to store symbol output data.
func (l *Loader) InitOutData() {
l.outdata = make([][]byte, l.extStart)
}
Cherry Zhang
committed
// SetExtRelocs sets the external relocations of the i-th symbol. i is global index.
func (l *Loader) SetExtRelocs(i Sym, relocs []ExtReloc) {
l.extRelocs[i] = relocs
}
// InitExtRelocs initialize the slice used to store external relocations.
func (l *Loader) InitExtRelocs() {
l.extRelocs = make([][]ExtReloc, l.NSym())
}
// SymAlign returns the alignment for a symbol.
func (l *Loader) SymAlign(i Sym) int32 {
Than McIntosh
committed
if int(i) >= len(l.align) {
// align is extended lazily -- it the sym in question is
// outside the range of the existing slice, then we assume its
// alignment has not yet been set.
return 0
}
// TODO: would it make sense to return an arch-specific
// alignment depending on section type? E.g. STEXT => 32,
// SDATA => 1, etc?
Than McIntosh
committed
abits := l.align[i]
if abits == 0 {
return 0
}
return int32(1 << (abits - 1))
}
// SetSymAlign sets the alignment for a symbol.
func (l *Loader) SetSymAlign(i Sym, align int32) {
// Reject nonsense alignments.
Than McIntosh
committed
if align < 0 || align&(align-1) != 0 {
panic("bad alignment value")
}
Than McIntosh
committed
if int(i) >= len(l.align) {
l.align = append(l.align, make([]uint8, l.NSym()-len(l.align))...)
}
Than McIntosh
committed
l.align[i] = 0
Than McIntosh
committed
l.align[i] = uint8(bits.Len32(uint32(align)))
// SymValue returns the section of the i-th symbol. i is global index.
func (l *Loader) SymSect(i Sym) *sym.Section {
if int(i) >= len(l.symSects) {
// symSects is extended lazily -- it the sym in question is
// outside the range of the existing slice, then we assume its
// section has not yet been set.
return nil
}
Cherry Zhang
committed
return l.sects[l.symSects[i]]
}
// SetSymSect sets the section of the i-th symbol. i is global index.
func (l *Loader) SetSymSect(i Sym, sect *sym.Section) {
Cherry Zhang
committed
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
if int(i) >= len(l.symSects) {
l.symSects = append(l.symSects, make([]uint16, l.NSym()-len(l.symSects))...)
}
l.symSects[i] = sect.Index
}
// growSects grows the slice used to store symbol sections.
func (l *Loader) growSects(reqLen int) {
curLen := len(l.symSects)
if reqLen > curLen {
l.symSects = append(l.symSects, make([]uint16, reqLen+1-curLen)...)
}
}
// NewSection creates a new (output) section.
func (l *Loader) NewSection() *sym.Section {
sect := new(sym.Section)
idx := len(l.sects)
if idx != int(uint16(idx)) {
panic("too many sections created")
}
sect.Index = uint16(idx)
l.sects = append(l.sects, sect)
return sect
}
// SymDynImplib returns the "dynimplib" attribute for the specified
// symbol, making up a portion of the info for a symbol specified
// on a "cgo_import_dynamic" compiler directive.
func (l *Loader) SymDynimplib(i Sym) string {
return l.dynimplib[i]
}
// SetSymDynimplib sets the "dynimplib" attribute for a symbol.
func (l *Loader) SetSymDynimplib(i Sym, value string) {
// reject bad symbols
if i >= Sym(len(l.objSyms)) || i == 0 {
panic("bad symbol index in SetDynimplib")
}
if value == "" {
delete(l.dynimplib, i)
} else {
l.dynimplib[i] = value
}
}
// SymDynimpvers returns the "dynimpvers" attribute for the specified
// symbol, making up a portion of the info for a symbol specified
// on a "cgo_import_dynamic" compiler directive.
func (l *Loader) SymDynimpvers(i Sym) string {
return l.dynimpvers[i]
}
// SetSymDynimpvers sets the "dynimpvers" attribute for a symbol.
func (l *Loader) SetSymDynimpvers(i Sym, value string) {
// reject bad symbols
if i >= Sym(len(l.objSyms)) || i == 0 {
panic("bad symbol index in SetDynimpvers")
}
if value == "" {
delete(l.dynimpvers, i)
} else {
l.dynimpvers[i] = value
}
}
// SymExtname returns the "extname" value for the specified
// symbol.
func (l *Loader) SymExtname(i Sym) string {
if s, ok := l.extname[i]; ok {
return s
}
return l.SymName(i)
}
// SetSymExtname sets the "extname" attribute for a symbol.
func (l *Loader) SetSymExtname(i Sym, value string) {
// reject bad symbols
if i >= Sym(len(l.objSyms)) || i == 0 {
panic("bad symbol index in SetExtname")
}
if value == "" {
delete(l.extname, i)
} else {
l.extname[i] = value
}
}
// SymElfType returns the previously recorded ELF type for a symbol
// (used only for symbols read from shared libraries by ldshlibsyms).
// It is not set for symbols defined by the packages being linked or
// by symbols read by ldelf (and so is left as elf.STT_NOTYPE).
func (l *Loader) SymElfType(i Sym) elf.SymType {
if et, ok := l.elfType[i]; ok {
return et
}
return elf.STT_NOTYPE
}
// SetSymElfType sets the elf type attribute for a symbol.
func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
// reject bad symbols
if i >= Sym(len(l.objSyms)) || i == 0 {
panic("bad symbol index in SetSymElfType")
}
if et == elf.STT_NOTYPE {
delete(l.elfType, i)
} else {
l.elfType[i] = et
}
}
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
// SymElfSym returns the ELF symbol index for a given loader
// symbol, assigned during ELF symtab generation.
func (l *Loader) SymElfSym(i Sym) int32 {
return l.elfSym[i]
}
// SetSymElfSym sets the elf symbol index for a symbol.
func (l *Loader) SetSymElfSym(i Sym, es int32) {
if i == 0 {
panic("bad sym index")
}
if es == 0 {
delete(l.elfSym, i)
} else {
l.elfSym[i] = es
}
}
// SymLocalElfSym returns the "local" ELF symbol index for a given loader
// symbol, assigned during ELF symtab generation.
func (l *Loader) SymLocalElfSym(i Sym) int32 {
return l.localElfSym[i]
}
// SetSymLocalElfSym sets the "local" elf symbol index for a symbol.
func (l *Loader) SetSymLocalElfSym(i Sym, es int32) {
if i == 0 {
panic("bad sym index")
}
if es == 0 {
delete(l.localElfSym, i)
} else {
l.localElfSym[i] = es
}
}
// SymPlt returns the plt value for pe symbols.
func (l *Loader) SymPlt(s Sym) int32 {
if v, ok := l.plt[s]; ok {
return v
}
return -1
}
// SetPlt sets the plt value for pe symbols.
func (l *Loader) SetPlt(i Sym, v int32) {
if i >= Sym(len(l.objSyms)) || i == 0 {
panic("bad symbol for SetPlt")
}
if v == -1 {
delete(l.plt, i)
} else {
l.plt[i] = v
}
}
// SymGot returns the got value for pe symbols.
func (l *Loader) SymGot(s Sym) int32 {
if v, ok := l.got[s]; ok {
return v
}
return -1
}
// SetGot sets the got value for pe symbols.
func (l *Loader) SetGot(i Sym, v int32) {
if i >= Sym(len(l.objSyms)) || i == 0 {
panic("bad symbol for SetGot")
if v == -1 {
delete(l.got, i)
} else {
l.got[i] = v
}
}
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
// SymDynid returns the "dynid" property for the specified symbol.
func (l *Loader) SymDynid(i Sym) int32 {
if s, ok := l.dynid[i]; ok {
return s
}
return -1
}
// SetSymDynid sets the "dynid" property for a symbol.
func (l *Loader) SetSymDynid(i Sym, val int32) {
// reject bad symbols
if i >= Sym(len(l.objSyms)) || i == 0 {
panic("bad symbol index in SetSymDynid")
}
if val == -1 {
delete(l.dynid, i)
} else {
l.dynid[i] = val
}
}
// DynIdSyms returns the set of symbols for which dynID is set to an
// interesting (non-default) value. This is expected to be a fairly
// small set.
func (l *Loader) DynidSyms() []Sym {
sl := make([]Sym, 0, len(l.dynid))
for s := range l.dynid {
sl = append(sl, s)
}
sort.Slice(sl, func(i, j int) bool { return sl[i] < sl[j] })
return sl
}
// SymGoType returns the 'Gotype' property for a given symbol (set by
// the Go compiler for variable symbols). This version relies on
// reading aux symbols for the target sym -- it could be that a faster
// approach would be to check for gotype during preload and copy the
// results in to a map (might want to try this at some point and see
// if it helps speed things up).
func (l *Loader) SymGoType(i Sym) Sym {
var r *oReader
var auxs []goobj2.Aux
if l.IsExternal(i) {
pp := l.getPayload(i)
r = l.objs[pp.objidx].r
auxs = pp.auxs
} else {
Cherry Zhang
committed
var li uint32
r, li = l.toLocal(i)
auxs = r.Auxs(li)
Cherry Zhang
committed
for j := range auxs {
a := &auxs[j]
switch a.Type() {
case goobj2.AuxGotype:
Cherry Zhang
committed
return l.resolve(r, a.Sym())
}
}
return 0
}
// SymUnit returns the compilation unit for a given symbol (which will
// typically be nil for external or linker-manufactured symbols).
func (l *Loader) SymUnit(i Sym) *sym.CompilationUnit {
if l.IsExternal(i) {
pp := l.getPayload(i)
if pp.objidx != 0 {
r := l.objs[pp.objidx].r
return r.unit
}
return nil
}
r, _ := l.toLocal(i)
return r.unit
}
// SymPkg returns the package where the symbol came from (for
// regular compiler-generated Go symbols), but in the case of
// building with "-linkshared" (when a symbol is read from a
// shared library), will hold the library name.
// NOTE: this correspondes to sym.Symbol.File field.
func (l *Loader) SymPkg(i Sym) string {
if f, ok := l.symPkg[i]; ok {
return f
}
if l.IsExternal(i) {
pp := l.getPayload(i)
if pp.objidx != 0 {
r := l.objs[pp.objidx].r
return r.unit.Lib.Pkg
}
return ""
}
r, _ := l.toLocal(i)
return r.unit.Lib.Pkg
}
// SetSymPkg sets the package/library for a symbol. This is
// needed mainly for external symbols, specifically those imported
// from shared libraries.
func (l *Loader) SetSymPkg(i Sym, pkg string) {
// reject bad symbols
if i >= Sym(len(l.objSyms)) || i == 0 {
panic("bad symbol index in SetSymPkg")
}
// SymLocalentry returns the "local entry" value for the specified
// symbol.
func (l *Loader) SymLocalentry(i Sym) uint8 {
return l.localentry[i]
}
// SetSymLocalentry sets the "local entry" attribute for a symbol.
func (l *Loader) SetSymLocalentry(i Sym, value uint8) {
// reject bad symbols
if i >= Sym(len(l.objSyms)) || i == 0 {
panic("bad symbol index in SetSymLocalentry")
}
if value == 0 {
delete(l.localentry, i)
} else {
l.localentry[i] = value
}
}
// Returns the number of aux symbols given a global index.
func (l *Loader) NAux(i Sym) int {
if l.IsExternal(i) {
r, li := l.toLocal(i)
return r.NAux(li)
}
Cherry Zhang
committed
// Returns the "handle" to the j-th aux symbol of the i-th symbol.
func (l *Loader) Aux2(i Sym, j int) Aux2 {
if l.IsExternal(i) {
return Aux2{}
}
r, li := l.toLocal(i)
if j >= r.NAux(li) {
return Aux2{}
}
return Aux2{r.Aux(li, j), r, l}
Cherry Zhang
committed
}
// GetFuncDwarfAuxSyms collects and returns the auxiliary DWARF
// symbols associated with a given function symbol. Prior to the
// introduction of the loader, this was done purely using name
// lookups, e.f. for function with name XYZ we would then look up
// go.info.XYZ, etc.
func (l *Loader) GetFuncDwarfAuxSyms(fnSymIdx Sym) (auxDwarfInfo, auxDwarfLoc, auxDwarfRanges, auxDwarfLines Sym) {
if l.SymType(fnSymIdx) != sym.STEXT {
log.Fatalf("error: non-function sym %d/%s t=%s passed to GetFuncDwarfAuxSyms", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
}
if l.IsExternal(fnSymIdx) {
// Current expectation is that any external function will
// not have auxsyms.
return
}
r, li := l.toLocal(fnSymIdx)
for i := range auxs {
a := &auxs[i]
switch a.Type() {
case goobj2.AuxDwarfInfo:
auxDwarfInfo = l.resolve(r, a.Sym())
if l.SymType(auxDwarfInfo) != sym.SDWARFFCN {
panic("aux dwarf info sym with wrong type")
}
case goobj2.AuxDwarfLoc:
auxDwarfLoc = l.resolve(r, a.Sym())
if l.SymType(auxDwarfLoc) != sym.SDWARFLOC {
panic("aux dwarf loc sym with wrong type")
}
case goobj2.AuxDwarfRanges:
auxDwarfRanges = l.resolve(r, a.Sym())
if l.SymType(auxDwarfRanges) != sym.SDWARFRANGE {
panic("aux dwarf ranges sym with wrong type")
}
case goobj2.AuxDwarfLines:
auxDwarfLines = l.resolve(r, a.Sym())
if l.SymType(auxDwarfLines) != sym.SDWARFLINES {
panic("aux dwarf lines sym with wrong type")
}
}
}
return
}
Than McIntosh
committed
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
// AddInteriorSym sets up 'interior' as an interior symbol of
// container/payload symbol 'container'. An interior symbol does not
// itself have data, but gives a name to a subrange of the data in its
// container symbol. The container itself may or may not have a name.
// This method is intended primarily for use in the host object
// loaders, to capture the semantics of symbols and sections in an
// object file. When reading a host object file, we'll typically
// encounter a static section symbol (ex: ".text") containing content
// for a collection of functions, then a series of ELF (or macho, etc)
// symbol table entries each of which points into a sub-section
// (offset and length) of its corresponding container symbol. Within
// the go linker we create a loader.Sym for the container (which is
// expected to have the actual content/payload) and then a set of
// interior loader.Sym's that point into a portion of the container.
func (l *Loader) AddInteriorSym(container Sym, interior Sym) {
// Container symbols are expected to have content/data.
// NB: this restriction may turn out to be too strict (it's possible
// to imagine a zero-sized container with an interior symbol pointing
// into it); it's ok to relax or remove it if we counter an
// oddball host object that triggers this.
if l.SymSize(container) == 0 && len(l.Data(container)) == 0 {
panic("unexpected empty container symbol")
}
// The interior symbols for a container are not expected to have
// content/data or relocations.
if len(l.Data(interior)) != 0 {
panic("unexpected non-empty interior symbol")
}
// Interior symbol is expected to be in the symbol table.
if l.AttrNotInSymbolTable(interior) {
panic("interior symbol must be in symtab")
}
// Only a single level of containment is allowed.
if l.OuterSym(container) != 0 {
panic("outer has outer itself")
}
Than McIntosh
committed
// Interior sym should not already have a sibling.
if l.SubSym(interior) != 0 {
panic("sub set for subsym")
}
Than McIntosh
committed
// Interior sym should not already point at a container.
if l.OuterSym(interior) != 0 {
panic("outer already set for subsym")
}
Than McIntosh
committed
l.sub[interior] = l.sub[container]
l.sub[container] = interior
l.outer[interior] = container
}
// OuterSym gets the outer symbol for host object loaded symbols.
func (l *Loader) OuterSym(i Sym) Sym {
// FIXME: add check for isExternal?
return l.outer[i]
// SubSym gets the subsymbol for host object loaded symbols.
func (l *Loader) SubSym(i Sym) Sym {
// NB: note -- no check for l.isExternal(), since I am pretty sure
// that later phases in the linker set subsym for "type." syms
return l.sub[i]
Than McIntosh
committed
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
// SetCarrierSym declares that 'c' is the carrier or container symbol
// for 's'. Carrier symbols are used in the linker to as a container
// for a collection of sub-symbols where the content of the
// sub-symbols is effectively concatenated to form the content of the
// carrier. The carrier is given a name in the output symbol table
// while the sub-symbol names are not. For example, the Go compiler
// emits named string symbols (type SGOSTRING) when compiling a
// package; after being deduplicated, these symbols are collected into
// a single unit by assigning them a new carrier symbol named
// "go.string.*" (which appears in the final symbol table for the
// output load module).
func (l *Loader) SetCarrierSym(s Sym, c Sym) {
if c == 0 {
panic("invalid carrier in SetCarrierSym")
}
if s == 0 {
panic("invalid sub-symbol in SetCarrierSym")
}
// Carrier symbols are not expected to have content/data. It is
// ok for them to have non-zero size (to allow for use of generator
// symbols).
if len(l.Data(c)) != 0 {
panic("unexpected non-empty carrier symbol")
}
l.outer[s] = c
// relocsym's foldSubSymbolOffset requires that we only
// have a single level of containment-- enforce here.
if l.outer[c] != 0 {
panic("invalid nested carrier sym")
// Initialize Reachable bitmap and its siblings for running deadcode pass.
func (l *Loader) InitReachable() {
l.growAttrBitmaps(l.NSym() + 1)
Than McIntosh
committed
}
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
type symWithVal struct {
s Sym
v int64
}
type bySymValue []symWithVal
func (s bySymValue) Len() int { return len(s) }
func (s bySymValue) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s bySymValue) Less(i, j int) bool { return s[i].v < s[j].v }
// SortSub walks through the sub-symbols for 's' and sorts them
// in place by increasing value. Return value is the new
// sub symbol for the specified outer symbol.
func (l *Loader) SortSub(s Sym) Sym {
if s == 0 || l.sub[s] == 0 {
return s
}
// Sort symbols using a slice first. Use a stable sort on the off
// chance that there's more than once symbol with the same value,
// so as to preserve reproducible builds.
sl := []symWithVal{}
for ss := l.sub[s]; ss != 0; ss = l.sub[ss] {
sl = append(sl, symWithVal{s: ss, v: l.SymValue(ss)})
}
sort.Stable(bySymValue(sl))
// Then apply any changes needed to the sub map.
ns := Sym(0)
for i := len(sl) - 1; i >= 0; i-- {
s := sl[i].s
l.sub[s] = ns
ns = s
}
// Update sub for outer symbol, then return
l.sub[s] = sl[0].s
return sl[0].s
}
// Insure that reachable bitmap and its siblings have enough size.
func (l *Loader) growAttrBitmaps(reqLen int) {
if reqLen > l.attrReachable.Len() {
// These are indexed by global symbol
l.attrReachable = growBitmap(reqLen, l.attrReachable)
l.attrOnList = growBitmap(reqLen, l.attrOnList)
l.attrLocal = growBitmap(reqLen, l.attrLocal)
l.attrNotInSymbolTable = growBitmap(reqLen, l.attrNotInSymbolTable)
Cherry Zhang
committed
l.attrUsedInIface = growBitmap(reqLen, l.attrUsedInIface)
l.growExtAttrBitmaps()
}
func (l *Loader) growExtAttrBitmaps() {
// These are indexed by external symbol index (e.g. l.extIndex(i))
extReqLen := len(l.payloads)
if extReqLen > l.attrVisibilityHidden.Len() {
l.attrVisibilityHidden = growBitmap(extReqLen, l.attrVisibilityHidden)
l.attrDuplicateOK = growBitmap(extReqLen, l.attrDuplicateOK)
l.attrShared = growBitmap(extReqLen, l.attrShared)
l.attrExternal = growBitmap(extReqLen, l.attrExternal)
Than McIntosh
committed
}
func (relocs *Relocs) Count() int { return len(relocs.rs) }
// At2 returns the j-th reloc for a global symbol.
Cherry Zhang
committed
func (relocs *Relocs) At2(j int) Reloc2 {
if relocs.l.isExtReader(relocs.r) {
pp := relocs.l.payloads[relocs.li]
return Reloc2{&relocs.rs[j], relocs.r, relocs.l, pp.reltypes[j]}
Cherry Zhang
committed
}
Cherry Zhang
committed
return Reloc2{&relocs.rs[j], relocs.r, relocs.l, 0}
Cherry Zhang
committed
}
// Relocs returns a Relocs object for the given global sym.
func (l *Loader) Relocs(i Sym) Relocs {
r, li := l.toLocal(i)
Than McIntosh
committed
if r == nil {
panic(fmt.Sprintf("trying to get oreader for invalid sym %d\n\n", i))
}
return l.relocs(r, li)
}
// Relocs returns a Relocs object given a local sym index and reader.
Cherry Zhang
committed
func (l *Loader) relocs(r *oReader, li uint32) Relocs {
if l.isExtReader(r) {
pp := l.payloads[li]
rs = pp.relocs
return Relocs{
rs: rs,
li: li,
r: r,
l: l,
}
}
Cherry Zhang
committed
// ExtRelocs returns the external relocations of the i-th symbol.
func (l *Loader) ExtRelocs(i Sym) ExtRelocs {
return ExtRelocs{l.Relocs(i), l.extRelocs[i]}
}
// ExtRelocs represents the set of external relocations of a symbol.
type ExtRelocs struct {
rs Relocs
es []ExtReloc
}
func (ers ExtRelocs) Count() int { return len(ers.es) }
func (ers ExtRelocs) At(j int) ExtRelocView {
i := ers.es[j].Idx
return ExtRelocView{ers.rs.At2(i), &ers.es[j]}
}
// RelocByOff implements sort.Interface for sorting relocations by offset.
type RelocByOff []Reloc
func (x RelocByOff) Len() int { return len(x) }
func (x RelocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x RelocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
Cherry Zhang
committed
// FuncInfo provides hooks to access goobj2.FuncInfo in the objects.
type FuncInfo struct {
l *Loader
r *oReader
data []byte
auxs []goobj2.Aux
lengths goobj2.FuncInfoLengths
Cherry Zhang
committed
}
func (fi *FuncInfo) Valid() bool { return fi.r != nil }
func (fi *FuncInfo) Args() int {
return int((*goobj2.FuncInfo)(nil).ReadArgs(fi.data))
}
Cherry Zhang
committed
func (fi *FuncInfo) Locals() int {
return int((*goobj2.FuncInfo)(nil).ReadLocals(fi.data))
}
func (fi *FuncInfo) Pcsp() []byte {
pcsp, end := (*goobj2.FuncInfo)(nil).ReadPcsp(fi.data)
return fi.r.BytesAt(fi.r.PcdataBase()+pcsp, int(end-pcsp))
}
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
func (fi *FuncInfo) Pcfile() []byte {
pcf, end := (*goobj2.FuncInfo)(nil).ReadPcfile(fi.data)
return fi.r.BytesAt(fi.r.PcdataBase()+pcf, int(end-pcf))
}
func (fi *FuncInfo) Pcline() []byte {
pcln, end := (*goobj2.FuncInfo)(nil).ReadPcline(fi.data)
return fi.r.BytesAt(fi.r.PcdataBase()+pcln, int(end-pcln))
}
// Preload has to be called prior to invoking the various methods
// below related to pcdata, funcdataoff, files, and inltree nodes.
func (fi *FuncInfo) Preload() {
fi.lengths = (*goobj2.FuncInfo)(nil).ReadFuncInfoLengths(fi.data)
}
func (fi *FuncInfo) Pcinline() []byte {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
pcinl, end := (*goobj2.FuncInfo)(nil).ReadPcinline(fi.data, fi.lengths.PcdataOff)
return fi.r.BytesAt(fi.r.PcdataBase()+pcinl, int(end-pcinl))
}
func (fi *FuncInfo) NumPcdata() uint32 {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
return fi.lengths.NumPcdata
}
func (fi *FuncInfo) Pcdata(k int) []byte {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
pcdat, end := (*goobj2.FuncInfo)(nil).ReadPcdata(fi.data, fi.lengths.PcdataOff, uint32(k))
return fi.r.BytesAt(fi.r.PcdataBase()+pcdat, int(end-pcdat))
}
func (fi *FuncInfo) NumFuncdataoff() uint32 {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
return fi.lengths.NumFuncdataoff
}
func (fi *FuncInfo) Funcdataoff(k int) int64 {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
return (*goobj2.FuncInfo)(nil).ReadFuncdataoff(fi.data, fi.lengths.FuncdataoffOff, uint32(k))
}
func (fi *FuncInfo) Funcdata(syms []Sym) []Sym {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
if int(fi.lengths.NumFuncdataoff) > cap(syms) {
syms = make([]Sym, 0, fi.lengths.NumFuncdataoff)
} else {
syms = syms[:0]
}
for j := range fi.auxs {
a := &fi.auxs[j]
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
if a.Type() == goobj2.AuxFuncdata {
syms = append(syms, fi.l.resolve(fi.r, a.Sym()))
}
}
return syms
}
func (fi *FuncInfo) NumFile() uint32 {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
return fi.lengths.NumFile
}
func (fi *FuncInfo) File(k int) Sym {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
sr := (*goobj2.FuncInfo)(nil).ReadFile(fi.data, fi.lengths.FileOff, uint32(k))
return fi.l.resolve(fi.r, sr)
}
type InlTreeNode struct {
Parent int32
File Sym
Line int32
Func Sym
ParentPC int32
}
func (fi *FuncInfo) NumInlTree() uint32 {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
return fi.lengths.NumInlTree
}
func (fi *FuncInfo) InlTree(k int) InlTreeNode {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
node := (*goobj2.FuncInfo)(nil).ReadInlTree(fi.data, fi.lengths.InlTreeOff, uint32(k))
return InlTreeNode{
Parent: node.Parent,
File: fi.l.resolve(fi.r, node.File),
Line: node.Line,
Func: fi.l.resolve(fi.r, node.Func),
ParentPC: node.ParentPC,
}
}
Cherry Zhang
committed
func (l *Loader) FuncInfo(i Sym) FuncInfo {
var r *oReader
Cherry Zhang
committed
if l.IsExternal(i) {
pp := l.getPayload(i)
if pp.objidx == 0 {
return FuncInfo{}
}
r = l.objs[pp.objidx].r
auxs = pp.auxs
} else {
Cherry Zhang
committed
var li uint32
r, li = l.toLocal(i)
Cherry Zhang
committed
}
Cherry Zhang
committed
for j := range auxs {
a := &auxs[j]
if a.Type() == goobj2.AuxFuncInfo {
Cherry Zhang
committed
b := r.Data(a.Sym().SymIdx)
return FuncInfo{l, r, b, auxs, goobj2.FuncInfoLengths{}}
Cherry Zhang
committed
}
}
return FuncInfo{}
}
Cherry Zhang
committed
// Preload a package: add autolibs, add defined package symbols to the symbol table.
// Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
// Does not read symbol data.
// Returns the fingerprint of the object.
func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj2.FingerprintType {
roObject, readonly, err := f.Slice(uint64(length)) // TODO: no need to map blocks that are for tools only (e.g. RefName)
if err != nil {
log.Fatal("cannot read object file:", err)
}
r := goobj2.NewReaderFromBytes(roObject, readonly)
if len(roObject) >= 8 && bytes.Equal(roObject[:8], []byte("\x00go114ld")) {
log.Fatalf("found object file %s in old format", f.File().Name())
panic("cannot read object file")
}
pkgprefix := objabi.PathToPrefix(lib.Pkg) + "."
ndef := r.NSym()
nnonpkgdef := r.NNonpkgdef()
or := &oReader{r, unit, localSymVersion, r.Flags(), pkgprefix, make([]Sym, ndef+nnonpkgdef+r.NNonpkgref()), ndef, uint32(len(l.objs))}
lib.Autolib = append(lib.Autolib, r.Autolib()...)
Cherry Zhang
committed
// DWARF file table
nfile := r.NDwarfFile()
unit.DWARFFileTable = make([]string, nfile)
for i := range unit.DWARFFileTable {
unit.DWARFFileTable[i] = r.DwarfFile(i)
}
Cherry Zhang
committed
l.addObj(lib.Pkg, or)
l.preloadSyms(or, pkgDef)
// The caller expects us consuming all the data
f.MustSeek(length, os.SEEK_CUR)
return r.Fingerprint()
Cherry Zhang
committed
}
// Preload symbols of given kind from an object.
func (l *Loader) preloadSyms(r *oReader, kind int) {
Cherry Zhang
committed
ndef := uint32(r.NSym())
nnonpkgdef := uint32(r.NNonpkgdef())
var start, end uint32
Cherry Zhang
committed
switch kind {
case pkgDef:
start = 0
end = ndef
case nonPkgDef:
start = ndef
end = ndef + nnonpkgdef
default:
panic("preloadSyms: bad kind")
}
Cherry Zhang
committed
l.growAttrBitmaps(len(l.objSyms) + int(end-start))
needNameExpansion := r.NeedNameExpansion()
loadingRuntimePkg := r.unit.Lib.Pkg == "runtime"
Cherry Zhang
committed
for i := start; i < end; i++ {
name := osym.Name(r.Reader)
if needNameExpansion {
name = strings.Replace(name, "\"\".", r.pkgprefix, -1)
}
v := abiToVer(osym.ABI(), r.version)
dupok := osym.Dupok()
gi, added := l.AddSym(name, v, r, i, kind, dupok, sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())])
Cherry Zhang
committed
r.syms[i] = gi
if !added {
continue
}
if osym.TopFrame() {
l.SetAttrTopFrame(gi, true)
}
if osym.Local() {
l.SetAttrLocal(gi, true)
}
Cherry Zhang
committed
if osym.UsedInIface() {
l.SetAttrUsedInIface(gi, true)
}
if strings.HasPrefix(name, "go.itablink.") {
l.itablink[gi] = struct{}{}
}
if strings.HasPrefix(name, "runtime.") ||
(loadingRuntimePkg && strings.HasPrefix(name, "type.")) {
if bi := goobj2.BuiltinIdx(name, v); bi != -1 {
// This is a definition of a builtin symbol. Record where it is.
l.builtinSyms[bi] = gi
}
}
if a := osym.Align(); a != 0 {
l.SetSymAlign(gi, int32(a))
}
Cherry Zhang
committed
// Add non-package symbols and references to external symbols (which are always
// named).
func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
Cherry Zhang
committed
for _, o := range l.objs[goObjStart:] {
Cherry Zhang
committed
l.preloadSyms(o.r, nonPkgDef)
}
Cherry Zhang
committed
for _, o := range l.objs[goObjStart:] {
loadObjRefs(l, o.r, arch)
Cherry Zhang
committed
}
l.values = make([]int64, l.NSym(), l.NSym()+1000) // +1000 make some room for external symbols
Cherry Zhang
committed
}
func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
Cherry Zhang
committed
ndef := uint32(r.NSym() + r.NNonpkgdef())
needNameExpansion := r.NeedNameExpansion()
Cherry Zhang
committed
for i, n := uint32(0), uint32(r.NNonpkgref()); i < n; i++ {
name := osym.Name(r.Reader)
if needNameExpansion {
name = strings.Replace(name, "\"\".", r.pkgprefix, -1)
}
v := abiToVer(osym.ABI(), r.version)
r.syms[ndef+i] = l.LookupOrCreateSym(name, v)
gi := r.syms[ndef+i]
if osym.Local() {
l.SetAttrLocal(gi, true)
}
Cherry Zhang
committed
if osym.UsedInIface() {
l.SetAttrUsedInIface(gi, true)
}
l.preprocess(arch, gi, name)
}
}
func abiToVer(abi uint16, localSymVersion int) int {
var v int
if abi == goobj2.SymABIstatic {
// Static
v = localSymVersion
} else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {
// Note that data symbols are "ABI0", which maps to version 0.
v = abiver
} else {
log.Fatalf("invalid symbol ABI: %d", abi)
}
return v
}
// preprocess looks for integer/floating point constant symbols whose
// content is encoded into the symbol name, and promotes them into
// real symbols with RODATA type and a payload that matches the
// encoded content.
func (l *Loader) preprocess(arch *sys.Arch, s Sym, name string) {
if name != "" && name[0] == '$' && len(name) > 5 && l.SymType(s) == 0 && len(l.Data(s)) == 0 {
x, err := strconv.ParseUint(name[5:], 16, 64)
log.Panicf("failed to parse $-symbol %s: %v", name, err)
su := l.MakeSymbolUpdater(s)
su.SetType(sym.SRODATA)
su.SetLocal(true)
switch name[:5] {
case "$f32.":
if uint64(uint32(x)) != x {
log.Panicf("$-symbol %s too large: %d", name, x)
su.AddUint32(arch, uint32(x))
case "$f64.", "$i64.":
su.AddUint64(arch, x)
log.Panicf("unrecognized $-symbol: %s", name)
}
}
}
// ResolveABIAlias given a symbol returns the ABI alias target of that
// symbol. If the sym in question is not an alias, the sym itself is
// returned.
func (l *Loader) ResolveABIAlias(s Sym) Sym {
if s == 0 {
return 0
}
if l.SymType(s) != sym.SABIALIAS {
return s
}
relocs := l.Relocs(s)
target := relocs.At2(0).Sym()
if l.SymType(target) == sym.SABIALIAS {
panic(fmt.Sprintf("ABI alias %s references another ABI alias %s", l.SymName(s), l.SymName(target)))
}
return target
}
// TopLevelSym tests a symbol (by name and kind) to determine whether
// the symbol first class sym (participating in the link) or is an
// anonymous aux or sub-symbol containing some sub-part or payload of
// another symbol.
func (l *Loader) TopLevelSym(s Sym) bool {
return topLevelSym(l.RawSymName(s), l.SymType(s))
}
// topLevelSym tests a symbol name and kind to determine whether
// the symbol first class sym (participating in the link) or is an
// anonymous aux or sub-symbol containing some sub-part or payload of
// another symbol.
func topLevelSym(sname string, skind sym.SymKind) bool {
if sname != "" {
return true
}
switch skind {
case sym.SDWARFFCN, sym.SDWARFABSFCN, sym.SDWARFTYPE, sym.SDWARFCONST, sym.SDWARFCUINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES, sym.SGOFUNC:
return true
Loading
Loading full blame...