Newer
Older
}
}
// 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 {
return l.attrSpecial.Has(i)
}
// SetAttrSpecial sets the "special" property for a symbol (see
// AttrSpecial).
func (l *Loader) SetAttrSpecial(i Sym, v bool) {
if v {
} else {
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
}
}
// 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)
}
}
// ForAllCgoExportDynamic calls f for every symbol that has been
// marked with the "cgo_export_dynamic" compiler directive.
func (l *Loader) ForAllCgoExportDynamic(f func(Sym)) {
for s := range l.attrCgoExportDynamic {
f(s)
}
}
// 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 {
if !l.IsExternal(i) {
return false
}
return l.generatedSyms.Has(l.extIndex(i))
}
// 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.Set(l.extIndex(i))
l.generatedSyms.Unset(l.extIndex(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 cover 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)&goobj.SymFlagReflectMethod != 0
}
// Returns whether the i-th symbol is nosplit.
func (l *Loader) IsNoSplit(i Sym) bool {
return l.SymAttr(i)&goobj.SymFlagNoSplit != 0
// Returns whether this is a Go type symbol.
func (l *Loader) IsGoType(i Sym) bool {
return l.SymAttr(i)&goobj.SymFlagGoType != 0
// Returns whether this symbol should be included in typelink.
func (l *Loader) IsTypelink(i Sym) bool {
return l.SymAttr(i)&goobj.SymFlagTypelink != 0
// Returns whether this symbol is an itab symbol.
func (l *Loader) IsItab(i Sym) bool {
if l.IsExternal(i) {
return false
}
r, li := l.toLocal(i)
return r.Sym(li).IsItab()
}
// Returns whether this symbol is a dictionary symbol.
func (l *Loader) IsDict(i Sym) bool {
if l.IsExternal(i) {
return false
}
r, li := l.toLocal(i)
return r.Sym(li).IsDict()
}
// Returns whether this symbol is a compiler-generated package init func.
func (l *Loader) IsPkgInit(i Sym) bool {
if l.IsExternal(i) {
return false
}
r, li := l.toLocal(i)
return r.Sym(li).IsPkgInit()
}
// 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)
}
// Returns the symbol content of the i-th symbol as a string. i is global index.
func (l *Loader) DataString(i Sym) string {
if l.IsExternal(i) {
pp := l.getPayload(i)
return string(pp.data)
}
r, li := l.toLocal(i)
return r.DataString(li)
}
// FreeData clears the symbol data of an external symbol, allowing the memory
// to be freed earlier. No-op for non-external symbols.
// i is global index.
if l.IsExternal(i) {
pp := l.getPayload(i)
if pp != nil {
}
}
}
// 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)))
// SymSect 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
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
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
}
}
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
// 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 offset of symbol s.
func (l *Loader) SymPlt(s Sym) int32 {
if v, ok := l.plt[s]; ok {
return v
}
return -1
}
// SetPlt sets the PLT offset of symbol i.
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 offset of symbol s.
func (l *Loader) SymGot(s Sym) int32 {
if v, ok := l.got[s]; ok {
return v
}
return -1
}
// SetGot sets the GOT offset of symbol i.
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
}
}
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
// 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 { return l.aux1(i, goobj.AuxGotype) }
// 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.
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 an offset in bytes of the "local entry" of a symbol.
//
// On PPC64, a value of 1 indicates the symbol does not use or preserve a TOC
// pointer in R2, nor does it have a distinct local entry.
func (l *Loader) SymLocalentry(i Sym) uint8 {
return l.localentry[i]
}
// SetSymLocalentry sets the "local entry" offset 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) Aux(i Sym, j int) Aux {
Cherry Zhang
committed
if l.IsExternal(i) {
Cherry Zhang
committed
}
r, li := l.toLocal(i)
if j >= r.NAux(li) {
Cherry Zhang
committed
}
return Aux{r.Aux(li, j), r, l}
Cherry Zhang
committed
}
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
// WasmImportSym returns the auxiliary WebAssembly import symbol associated with
// a given function symbol. The aux sym only exists for Go function stubs that
// have been annotated with the //go:wasmimport directive. The aux sym
// contains the information necessary for the linker to add a WebAssembly
// import statement.
// (https://webassembly.github.io/spec/core/syntax/modules.html#imports)
func (l *Loader) WasmImportSym(fnSymIdx Sym) (Sym, bool) {
if l.SymType(fnSymIdx) != sym.STEXT {
log.Fatalf("error: non-function sym %d/%s t=%s passed to WasmImportSym", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
}
r, li := l.toLocal(fnSymIdx)
auxs := r.Auxs(li)
for i := range auxs {
a := &auxs[i]
switch a.Type() {
case goobj.AuxWasmImport:
return l.resolve(r, a.Sym()), true
}
}
return 0, false
}
// SEHUnwindSym returns the auxiliary SEH unwind symbol associated with
// a given function symbol.
func (l *Loader) SEHUnwindSym(fnSymIdx Sym) Sym {
if l.SymType(fnSymIdx) != sym.STEXT {
log.Fatalf("error: non-function sym %d/%s t=%s passed to SEHUnwindSym", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
}
return l.aux1(fnSymIdx, goobj.AuxSehUnwindInfo)
}
// 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())
}
r, auxs := l.auxs(fnSymIdx)
for i := range auxs {
a := &auxs[i]
switch a.Type() {
auxDwarfInfo = l.resolve(r, a.Sym())
if l.SymType(auxDwarfInfo) != sym.SDWARFFCN {
panic("aux dwarf info sym with wrong type")
}
auxDwarfLoc = l.resolve(r, a.Sym())
if l.SymType(auxDwarfLoc) != sym.SDWARFLOC {
panic("aux dwarf loc sym with wrong type")
}
auxDwarfRanges = l.resolve(r, a.Sym())
if l.SymType(auxDwarfRanges) != sym.SDWARFRANGE {
panic("aux dwarf ranges sym with wrong type")
}
auxDwarfLines = l.resolve(r, a.Sym())
if l.SymType(auxDwarfLines) != sym.SDWARFLINES {
panic("aux dwarf lines sym with wrong type")
}
}
}
return
}
func (l *Loader) GetVarDwarfAuxSym(i Sym) Sym {
aux := l.aux1(i, goobj.AuxDwarfInfo)
if aux != 0 && l.SymType(aux) != sym.SDWARFVAR {
fmt.Println(l.SymName(i), l.SymType(i), l.SymType(aux), sym.SDWARFVAR)
panic("aux dwarf info sym with wrong type")
}
return aux
}
Than McIntosh
committed
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
1742
1743
1744
1745
// 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/container symbol.
func (l *Loader) OuterSym(i Sym) Sym {
return l.outer[i]
// SubSym gets the subsymbol for host object loaded symbols.
func (l *Loader) SubSym(i Sym) Sym {
return l.sub[i]
// growOuter grows the slice used to store outer symbol.
func (l *Loader) growOuter(reqLen int) {
curLen := len(l.outer)
if reqLen > curLen {
l.outer = append(l.outer, make([]Sym, reqLen-curLen)...)
}
}
Than McIntosh
committed
// 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
Than McIntosh
committed
// 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
}
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
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
}
// SortSyms sorts a list of symbols by their value.
func (l *Loader) SortSyms(ss []Sym) {
sort.SliceStable(ss, func(i, j int) bool { return l.SymValue(ss[i]) < l.SymValue(ss[j]) })
}
// 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.attrSpecial = growBitmap(reqLen, l.attrSpecial)
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)
l.generatedSyms = growBitmap(extReqLen, l.generatedSyms)
Than McIntosh
committed
}
func (relocs *Relocs) Count() int { return len(relocs.rs) }
// At returns the j-th reloc for a global symbol.
func (relocs *Relocs) At(j int) Reloc {
Cherry Zhang
committed
if relocs.l.isExtReader(relocs.r) {
return Reloc{&relocs.rs[j], relocs.r, relocs.l}
Cherry Zhang
committed
}
return Reloc{&relocs.rs[j], relocs.r, relocs.l}
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,
}
}
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
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
func (l *Loader) auxs(i Sym) (*oReader, []goobj.Aux) {
if l.IsExternal(i) {
pp := l.getPayload(i)
return l.objs[pp.objidx].r, pp.auxs
} else {
r, li := l.toLocal(i)
return r, r.Auxs(li)
}
}
// Returns a specific aux symbol of type t for symbol i.
func (l *Loader) aux1(i Sym, t uint8) Sym {
r, auxs := l.auxs(i)
for j := range auxs {
a := &auxs[j]
if a.Type() == t {
return l.resolve(r, a.Sym())
}
}
return 0
}
func (l *Loader) Pcsp(i Sym) Sym { return l.aux1(i, goobj.AuxPcsp) }
// Returns all aux symbols of per-PC data for symbol i.
// tmp is a scratch space for the pcdata slice.
func (l *Loader) PcdataAuxs(i Sym, tmp []Sym) (pcsp, pcfile, pcline, pcinline Sym, pcdata []Sym) {
pcdata = tmp[:0]
r, auxs := l.auxs(i)
for j := range auxs {
a := &auxs[j]
switch a.Type() {
case goobj.AuxPcsp:
pcsp = l.resolve(r, a.Sym())
case goobj.AuxPcline:
pcline = l.resolve(r, a.Sym())
case goobj.AuxPcfile:
pcfile = l.resolve(r, a.Sym())
case goobj.AuxPcinline:
pcinline = l.resolve(r, a.Sym())
case goobj.AuxPcdata:
pcdata = append(pcdata, l.resolve(r, a.Sym()))
}
}
return
}
// Returns the number of pcdata for symbol i.
func (l *Loader) NumPcdata(i Sym) int {
n := 0
_, auxs := l.auxs(i)
for j := range auxs {
a := &auxs[j]
if a.Type() == goobj.AuxPcdata {
n++
}
}
return n
}
// Returns all funcdata symbols of symbol i.
// tmp is a scratch space.
func (l *Loader) Funcdata(i Sym, tmp []Sym) []Sym {
fd := tmp[:0]
r, auxs := l.auxs(i)
for j := range auxs {
a := &auxs[j]
if a.Type() == goobj.AuxFuncdata {
fd = append(fd, l.resolve(r, a.Sym()))
}
}
return fd
}
// Returns the number of funcdata for symbol i.
func (l *Loader) NumFuncdata(i Sym) int {
n := 0