"cmd/link/internal/sym"
"debug/elf"
"fmt"
+ "internal/abi"
+ "io"
"log"
"math/bits"
"os"
// 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
+type Sym = sym.LoaderSym
// Relocs encapsulates the set of relocations on a given symbol; an
// instance of this type is returned by the Loader Relocs() method.
type oReader struct {
*goobj.Reader
unit *sym.CompilationUnit
- version int // version of static symbol
- flags uint32 // read from object file
+ version int // version of static symbol
pkgprefix string
syms []Sym // Sym's global index, indexed by local index
pkg []uint32 // indices of referenced package by PkgIdx (index into loader.objs array)
//
// Notes on the layout of global symbol index space:
//
-// - Go object files are read before host object files; each Go object
-// read adds its defined package symbols to the global index space.
-// Nonpackage symbols are not yet added.
+// - Go object files are read before host object files; each Go object
+// read adds its defined package symbols to the global index space.
+// Nonpackage symbols are not yet added.
//
-// - In loader.LoadNonpkgSyms, add non-package defined symbols and
-// references in all object files to the global index space.
+// - In loader.LoadNonpkgSyms, add non-package defined symbols and
+// references in all object files to the global index space.
//
-// - Host object file loading happens; the host object loader does a
-// name/version lookup for each symbol it finds; this can wind up
-// extending the external symbol index space range. The host object
-// loader stores symbol payloads in loader.payloads using SymbolBuilder.
+// - Host object file loading happens; the host object loader does a
+// name/version lookup for each symbol it finds; this can wind up
+// extending the external symbol index space range. The host object
+// loader stores symbol payloads in loader.payloads using SymbolBuilder.
//
-// - 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.
+// - 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.
type Loader struct {
start map[*oReader]Sym // map from object file to its start index
objs []objIdx // sorted by start index (i.e. objIdx.i)
attrLocal Bitmap // "local" symbols, indexed by global index
attrNotInSymbolTable Bitmap // "not in symtab" symbols, indexed by global idx
attrUsedInIface Bitmap // "used in interface" symbols, indexed by global idx
+ attrSpecial Bitmap // "special" frame 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
+ generatedSyms Bitmap // symbols that generate their content, indexed by ext sym idx
attrReadOnly map[Sym]bool // readonly data for this sym
- 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
+ outer []Sym // indexed by global index
sub map[Sym]Sym
dynimplib map[Sym]string // stores Dynimplib symbol attribute
flags uint32
- hasUnknownPkgPath bool // if any Go object has unknown package path
-
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
- elfsetstring elfsetstringFunc
-
errorReporter *ErrorReporter
npkgsyms int // number of package symbols, for accounting
goObjStart
)
-type elfsetstringFunc func(str string, off int)
-
// extSymPayload holds the payload (data + relocations) for linker-synthesized
// external symbols (note that symbol value is stored in a separate slice).
type extSymPayload struct {
const (
// Loader.flags
FlagStrictDups = 1 << iota
- FlagUseABIAlias
)
-func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
+func NewLoader(flags uint32, reporter *ErrorReporter) *Loader {
nbuiltin := goobj.NBuiltin()
extReader := &oReader{objidx: extObj}
ldr := &Loader{
extReader: extReader,
symsByName: [2]map[string]Sym{make(map[string]Sym, 80000), make(map[string]Sym, 50000)}, // preallocate ~2MB for ABI0 and ~1MB for ABI1 symbols
objByPkg: make(map[string]uint32),
- outer: make(map[Sym]Sym),
sub: make(map[Sym]Sym),
dynimplib: make(map[Sym]string),
dynimpvers: make(map[Sym]string),
plt: make(map[Sym]int32),
got: make(map[Sym]int32),
dynid: make(map[Sym]int32),
- attrSpecial: make(map[Sym]struct{}),
attrCgoExportDynamic: make(map[Sym]struct{}),
attrCgoExportStatic: make(map[Sym]struct{}),
- generatedSyms: make(map[Sym]struct{}),
deferReturnTramp: make(map[Sym]bool),
extStaticSyms: make(map[nameVer]Sym),
builtinSyms: make([]Sym, nbuiltin),
flags: flags,
- elfsetstring: elfsetstring,
errorReporter: reporter,
sects: []*sym.Section{nil}, // reserve index 0 for nil section
}
i := Sym(len(l.objSyms))
l.start[r] = i
l.objs = append(l.objs, objIdx{r, i})
- if r.NeedNameExpansion() && !r.FromAssembly() {
- l.hasUnknownPkgPath = true
- }
return i
}
panic("addSym called after external symbol is created")
}
i := Sym(len(l.objSyms))
+ if int(i) != len(l.objSyms) { // overflow
+ panic("too many symbols")
+ }
addToGlobal := func() {
l.objSyms = append(l.objSyms, objSym{r.objidx, li})
}
// name/version.
func (l *Loader) newExtSym(name string, ver int) Sym {
i := Sym(len(l.objSyms))
+ if int(i) != len(l.objSyms) { // overflow
+ panic("too many symbols")
+ }
if l.extStart == 0 {
l.extStart = i
}
l.growValues(int(i) + 1)
+ l.growOuter(int(i) + 1)
l.growAttrBitmaps(int(i) + 1)
pi := l.newPayload(name, ver)
l.objSyms = append(l.objSyms, objSym{l.extReader.objidx, uint32(pi)})
// when the runtime package is built. The canonical example is
// "runtime.racefuncenter" -- currently if you do something like
//
-// go build -gcflags=-race myprogram.go
+// go build -gcflags=-race myprogram.go
//
// the compiler will insert calls to the builtin runtime.racefuncenter,
// but the version of the runtime used for linkage won't actually contain
// 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")
+ allowed := strings.HasPrefix(name, "go:info.go.interface") ||
+ strings.HasPrefix(name, "go:info.go.builtin") ||
+ strings.HasPrefix(name, "go:debuglines")
if !allowed {
l.strictDupMsgs++
}
return l.attrReachable.Count()
}
-// SymNameLen returns the length of the symbol name, trying hard not to load
-// the name.
-func (l *Loader) SymNameLen(i Sym) int {
- // Not much we can do about external symbols.
- if l.IsExternal(i) {
- return len(l.SymName(i))
- }
- r, li := l.toLocal(i)
- le := r.Sym(li).NameLen(r.Reader)
- if !r.NeedNameExpansion() {
- return le
- }
- // Just load the symbol name. We don't know how expanded it'll be.
- return len(l.SymName(i))
-}
-
-// Returns the raw (unpatched) name of the i-th symbol.
-func (l *Loader) RawSymName(i Sym) string {
- if l.IsExternal(i) {
- 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.
+// Returns the name of the i-th symbol.
func (l *Loader) SymName(i Sym) string {
if l.IsExternal(i) {
pp := l.getPayload(i)
if r == nil {
return "?"
}
- name := r.Sym(li).Name(r.Reader)
- if !r.NeedNameExpansion() {
- return name
- }
- return strings.Replace(name, "\"\".", r.pkgprefix, -1)
+ return r.Sym(li).Name(r.Reader)
}
// Returns the version of the i-th symbol.
// 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)))
+ panic(fmt.Sprintf("tried to set external attr on non-external symbol %q", l.SymName(i)))
}
if v {
l.attrExternal.Set(l.extIndex(i))
// 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
+ 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 {
- l.attrSpecial[i] = struct{}{}
+ l.attrSpecial.Set(i)
} else {
- delete(l.attrSpecial, i)
+ l.attrSpecial.Unset(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.
// 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
+ if !l.IsExternal(i) {
+ return false
+ }
+ return l.generatedSyms.Has(l.extIndex(i))
}
// SetIsGeneratedSym marks symbols as generated symbols. Data shouldn't be
panic("only external symbols can be generated")
}
if v {
- l.generatedSyms[i] = struct{}{}
+ l.generatedSyms.Set(l.extIndex(i))
} else {
- delete(l.generatedSyms, i)
+ l.generatedSyms.Unset(l.extIndex(i))
}
}
//
// - 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
+// - 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!)
//
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]
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.
l.align[i] = uint8(bits.Len32(uint32(align)))
}
-// SymValue returns the section of the i-th symbol. i is global index.
+// 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
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)
return sect
}
-// SymDynImplib returns the "dynimplib" attribute for the specified
+// 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 {
}
}
-// DynIdSyms returns the set of symbols for which dynID is set to an
+// 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 {
// 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 []goobj.Aux
- if l.IsExternal(i) {
- pp := l.getPayload(i)
- r = l.objs[pp.objidx].r
- auxs = pp.auxs
- } else {
- var li uint32
- r, li = l.toLocal(i)
- auxs = r.Auxs(li)
- }
- for j := range auxs {
- a := &auxs[j]
- switch a.Type() {
- case goobj.AuxGotype:
- return l.resolve(r, a.Sym())
- }
- }
- return 0
-}
+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).
l.symPkg[i] = pkg
}
-// SymLocalentry returns the "local entry" value for the specified
-// symbol.
+// 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" attribute for a symbol.
+// 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 {
return Aux{r.Aux(li, j), r, l}
}
+// 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
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)
- auxs := r.Auxs(li)
+ r, auxs := l.auxs(fnSymIdx)
+
for i := range auxs {
a := &auxs[i]
switch a.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
+}
+
// 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
l.outer[interior] = container
}
-// OuterSym gets the outer symbol for host object loaded symbols.
+// OuterSym gets the outer/container symbol.
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]
}
+// 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)...)
+ }
+}
+
// 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
// 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
+// "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 {
l.attrLocal = growBitmap(reqLen, l.attrLocal)
l.attrNotInSymbolTable = growBitmap(reqLen, l.attrNotInSymbolTable)
l.attrUsedInIface = growBitmap(reqLen, l.attrUsedInIface)
+ l.attrSpecial = growBitmap(reqLen, l.attrSpecial)
}
l.growExtAttrBitmaps()
}
l.attrDuplicateOK = growBitmap(extReqLen, l.attrDuplicateOK)
l.attrShared = growBitmap(extReqLen, l.attrShared)
l.attrExternal = growBitmap(extReqLen, l.attrExternal)
+ l.generatedSyms = growBitmap(extReqLen, l.generatedSyms)
}
}
return l.relocs(r, li)
}
-// Relocs returns a Relocs object given a local sym index and reader.
+// relocs returns a Relocs object given a local sym index and reader.
func (l *Loader) relocs(r *oReader, li uint32) Relocs {
var rs []goobj.Reloc
if l.isExtReader(r) {
}
}
+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
+ _, auxs := l.auxs(i)
+ for j := range auxs {
+ a := &auxs[j]
+ if a.Type() == goobj.AuxFuncdata {
+ n++
+ }
+ }
+ return n
+}
+
// FuncInfo provides hooks to access goobj.FuncInfo in the objects.
type FuncInfo struct {
l *Loader
r *oReader
data []byte
- auxs []goobj.Aux
lengths goobj.FuncInfoLengths
}
return int((*goobj.FuncInfo)(nil).ReadLocals(fi.data))
}
-func (fi *FuncInfo) FuncID() objabi.FuncID {
+func (fi *FuncInfo) FuncID() abi.FuncID {
return (*goobj.FuncInfo)(nil).ReadFuncID(fi.data)
}
-func (fi *FuncInfo) FuncFlag() objabi.FuncFlag {
+func (fi *FuncInfo) FuncFlag() abi.FuncFlag {
return (*goobj.FuncInfo)(nil).ReadFuncFlag(fi.data)
}
-func (fi *FuncInfo) Pcsp() Sym {
- sym := (*goobj.FuncInfo)(nil).ReadPcsp(fi.data)
- return fi.l.resolve(fi.r, sym)
-}
-
-func (fi *FuncInfo) Pcfile() Sym {
- sym := (*goobj.FuncInfo)(nil).ReadPcfile(fi.data)
- return fi.l.resolve(fi.r, sym)
-}
-
-func (fi *FuncInfo) Pcline() Sym {
- sym := (*goobj.FuncInfo)(nil).ReadPcline(fi.data)
- return fi.l.resolve(fi.r, sym)
-}
-
-func (fi *FuncInfo) Pcinline() Sym {
- sym := (*goobj.FuncInfo)(nil).ReadPcinline(fi.data)
- return fi.l.resolve(fi.r, sym)
+func (fi *FuncInfo) StartLine() int32 {
+ return (*goobj.FuncInfo)(nil).ReadStartLine(fi.data)
}
// Preload has to be called prior to invoking the various methods
fi.lengths = (*goobj.FuncInfo)(nil).ReadFuncInfoLengths(fi.data)
}
-func (fi *FuncInfo) Pcdata() []Sym {
- if !fi.lengths.Initialized {
- panic("need to call Preload first")
- }
- syms := (*goobj.FuncInfo)(nil).ReadPcdata(fi.data)
- ret := make([]Sym, len(syms))
- for i := range ret {
- ret[i] = fi.l.resolve(fi.r, syms[i])
- }
- return ret
-}
-
-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 (*goobj.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]
- if a.Type() == goobj.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")
// is an entry point, meaning that unwinders should stop when they hit
// this function.
func (fi *FuncInfo) TopFrame() bool {
- return (fi.FuncFlag() & objabi.FuncFlag_TOPFRAME) != 0
+ return (fi.FuncFlag() & abi.FuncFlagTopFrame) != 0
}
type InlTreeNode struct {
}
func (l *Loader) FuncInfo(i Sym) FuncInfo {
- var r *oReader
- var auxs []goobj.Aux
- if l.IsExternal(i) {
- pp := l.getPayload(i)
- if pp.objidx == 0 {
- return FuncInfo{}
- }
- r = l.objs[pp.objidx].r
- auxs = pp.auxs
- } else {
- var li uint32
- r, li = l.toLocal(i)
- auxs = r.Auxs(li)
- }
+ r, auxs := l.auxs(i)
for j := range auxs {
a := &auxs[j]
if a.Type() == goobj.AuxFuncInfo {
b := r.Data(a.Sym().SymIdx)
- return FuncInfo{l, r, b, auxs, goobj.FuncInfoLengths{}}
+ return FuncInfo{l, r, b, goobj.FuncInfoLengths{}}
}
}
return FuncInfo{}
Reader: r,
unit: unit,
version: localSymVersion,
- flags: r.Flags(),
pkgprefix: pkgprefix,
syms: make([]Sym, ndef+nhashed64def+nhasheddef+r.NNonpkgdef()+r.NNonpkgref()),
ndef: ndef,
objidx: uint32(len(l.objs)),
}
+ if r.Unlinkable() {
+ log.Fatalf("link: unlinkable object (from package %s) - compiler requires -p flag", lib.Pkg)
+ }
+
// Autolib
lib.Autolib = append(lib.Autolib, r.Autolib()...)
l.addObj(lib.Pkg, or)
// The caller expects us consuming all the data
- f.MustSeek(length, os.SEEK_CUR)
+ f.MustSeek(length, io.SeekCurrent)
return r.Fingerprint()
}
case hashedDef:
start = uint32(r.ndef + r.nhashed64def)
end = uint32(r.ndef + r.nhashed64def + r.nhasheddef)
- if l.hasUnknownPkgPath {
- // The content hash depends on symbol name expansion. If any package is
- // built without fully expanded names, the content hash is unreliable.
- // Treat them as named symbols.
- // This is rare.
- // (We don't need to do this for hashed64Def case, as there the hash
- // function is simply the identity function, which doesn't depend on
- // name expansion.)
- kind = nonPkgDef
- }
case nonPkgDef:
start = uint32(r.ndef + r.nhashed64def + r.nhasheddef)
end = uint32(r.ndef + r.nhashed64def + r.nhasheddef + r.NNonpkgdef())
panic("preloadSyms: bad kind")
}
l.growAttrBitmaps(len(l.objSyms) + int(end-start))
- needNameExpansion := r.NeedNameExpansion()
loadingRuntimePkg := r.unit.Lib.Pkg == "runtime"
for i := start; i < end; i++ {
osym := r.Sym(i)
var v int
if kind != hashed64Def && kind != hashedDef { // we don't need the name, etc. for hashed symbols
name = osym.Name(r.Reader)
- if needNameExpansion {
- name = strings.Replace(name, "\"\".", r.pkgprefix, -1)
- }
v = abiToVer(osym.ABI(), r.version)
}
gi := st.addSym(name, v, r, i, kind, osym)
l.SetAttrUsedInIface(gi, true)
}
if strings.HasPrefix(name, "runtime.") ||
- (loadingRuntimePkg && strings.HasPrefix(name, "type.")) {
- if bi := goobj.BuiltinIdx(name, v); bi != -1 {
+ (loadingRuntimePkg && strings.HasPrefix(name, "type:")) {
+ if bi := goobj.BuiltinIdx(name, int(osym.ABI())); bi != -1 {
// This is a definition of a builtin symbol. Record where it is.
l.builtinSyms[bi] = gi
}
loadObjRefs(l, o.r, arch)
}
l.values = make([]int64, l.NSym(), l.NSym()+1000) // +1000 make some room for external symbols
+ l.outer = make([]Sym, l.NSym(), l.NSym()+1000)
}
func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
// load non-package refs
ndef := uint32(r.NAlldef())
- needNameExpansion := r.NeedNameExpansion()
for i, n := uint32(0), uint32(r.NNonpkgref()); i < n; i++ {
osym := r.Sym(ndef + 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]
return v
}
-// 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 l.flags&FlagUseABIAlias == 0 {
- return s
- }
- if s == 0 {
- return 0
- }
- if l.SymType(s) != sym.SABIALIAS {
- return s
- }
- relocs := l.Relocs(s)
- target := relocs.At(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))
+ return topLevelSym(l.SymName(s), l.SymType(s))
}
// topLevelSym tests a symbol name and kind to determine whether
r, li := l.toLocal(symIdx)
osym := r.Sym(li)
sname := osym.Name(r.Reader)
- if r.NeedNameExpansion() {
- sname = strings.Replace(sname, "\"\".", r.pkgprefix, -1)
- }
sver := abiToVer(osym.ABI(), r.version)
skind := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
// need to access the old symbol content.)
l.objSyms[symIdx] = objSym{l.extReader.objidx, uint32(pi)}
l.extReader.syms = append(l.extReader.syms, symIdx)
+
+ // Some attributes were encoded in the object file. Copy them over.
+ l.SetAttrDuplicateOK(symIdx, r.Sym(li).Dupok())
+ l.SetAttrShared(symIdx, r.Shared())
}
// Copy the payload of symbol src to dst. Both src and dst must be external
// TODO: other attributes?
}
-// CopyAttributes copies over all of the attributes of symbol 'src' to
-// symbol 'dst'.
-func (l *Loader) CopyAttributes(src Sym, dst Sym) {
- l.SetAttrReachable(dst, l.AttrReachable(src))
- l.SetAttrOnList(dst, l.AttrOnList(src))
- l.SetAttrLocal(dst, l.AttrLocal(src))
- l.SetAttrNotInSymbolTable(dst, l.AttrNotInSymbolTable(src))
- if l.IsExternal(dst) {
- l.SetAttrVisibilityHidden(dst, l.AttrVisibilityHidden(src))
- l.SetAttrDuplicateOK(dst, l.AttrDuplicateOK(src))
- l.SetAttrShared(dst, l.AttrShared(src))
- l.SetAttrExternal(dst, l.AttrExternal(src))
- } else {
- // Some attributes are modifiable only for external symbols.
- // In such cases, don't try to transfer over the attribute
- // from the source even if there is a clash. This comes up
- // when copying attributes from a dupOK ABI wrapper symbol to
- // the real target symbol (which may not be marked dupOK).
- }
- l.SetAttrSpecial(dst, l.AttrSpecial(src))
- l.SetAttrCgoExportDynamic(dst, l.AttrCgoExportDynamic(src))
- l.SetAttrCgoExportStatic(dst, l.AttrCgoExportStatic(src))
- l.SetAttrReadOnly(dst, l.AttrReadOnly(src))
-}
-
// CreateExtSym creates a new external symbol with the specified name
// without adding it to any lookup tables, returning a Sym index for it.
func (l *Loader) CreateExtSym(name string, ver int) Sym {
// space, looking for symbols with relocations targeting undefined
// references. The linker's loadlib method uses this to determine if
// there are unresolved references to functions in system libraries
-// (for example, libgcc.a), presumably due to CGO code. Return
-// value is a list of loader.Sym's corresponding to the undefined
-// cross-refs. The "limit" param controls the maximum number of
-// results returned; if "limit" is -1, then all undefs are returned.
-func (l *Loader) UndefinedRelocTargets(limit int) []Sym {
- result := []Sym{}
+// (for example, libgcc.a), presumably due to CGO code. Return value
+// is a pair of lists of loader.Sym's. First list corresponds to the
+// corresponding to the undefined symbols themselves, the second list
+// is the symbol that is making a reference to the undef. The "limit"
+// param controls the maximum number of results returned; if "limit"
+// is -1, then all undefs are returned.
+func (l *Loader) UndefinedRelocTargets(limit int) ([]Sym, []Sym) {
+ result, fromr := []Sym{}, []Sym{}
+outerloop:
for si := Sym(1); si < Sym(len(l.objSyms)); si++ {
relocs := l.Relocs(si)
for ri := 0; ri < relocs.Count(); ri++ {
r := relocs.At(ri)
rs := r.Sym()
- if rs != 0 && l.SymType(rs) == sym.SXREF && l.RawSymName(rs) != ".got" {
+ if rs != 0 && l.SymType(rs) == sym.SXREF && l.SymName(rs) != ".got" {
result = append(result, rs)
+ fromr = append(fromr, si)
if limit != -1 && len(result) >= limit {
- break
+ break outerloop
}
}
}
}
- return result
+ return result, fromr
}
// AssignTextSymbolOrder populates the Textp slices within each
//
// Logging an error means that on exit cmd/link will delete any
// output file and return a non-zero error code.
-//
func (reporter *ErrorReporter) Errorf(s Sym, format string, args ...interface{}) {
if s != 0 && reporter.ldr.SymName(s) != "" {
- format = reporter.ldr.SymName(s) + ": " + format
+ // Note: Replace is needed here because symbol names might have % in them,
+ // due to the use of LinkString for names of instantiating types.
+ format = strings.Replace(reporter.ldr.SymName(s), "%", "%%", -1) + ": " + format
} else {
format = fmt.Sprintf("sym %d: %s", s, format)
}