"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.
*goobj.Reloc
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 goobj.Reloc.
- // For Go symbols this will always be zero.
- // goobj.Reloc.Type() + typ is always the right type, for both Go and external
- // symbols.
- typ objabi.RelocType
}
-func (rel Reloc) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) + rel.typ }
-func (rel Reloc) Sym() Sym { return rel.l.resolve(rel.r, rel.Reloc.Sym()) }
-func (rel Reloc) SetSym(s Sym) { rel.Reloc.SetSym(goobj.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) }
-func (rel Reloc) IsMarker() bool { return rel.Siz() == 0 }
-
-func (rel Reloc) SetType(t objabi.RelocType) {
- if t != objabi.RelocType(uint8(t)) {
- panic("SetType: type doesn't fit into Reloc")
- }
- rel.Reloc.SetType(uint8(t))
- if rel.typ != 0 {
- // should use SymbolBuilder.SetRelocType
- panic("wrong method to set reloc type")
- }
-}
+func (rel Reloc) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) &^ objabi.R_WEAK }
+func (rel Reloc) Weak() bool { return objabi.RelocType(rel.Reloc.Type())&objabi.R_WEAK != 0 }
+func (rel Reloc) SetType(t objabi.RelocType) { rel.Reloc.SetType(uint16(t)) }
+func (rel Reloc) Sym() Sym { return rel.l.resolve(rel.r, rel.Reloc.Sym()) }
+func (rel Reloc) SetSym(s Sym) { rel.Reloc.SetSym(goobj.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) }
+func (rel Reloc) IsMarker() bool { return rel.Siz() == 0 }
// Aux holds a "handle" to access an aux symbol record from an
// object file.
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
- 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
+ outer []Sym // indexed by global index
sub map[Sym]Sym
dynimplib map[Sym]string // stores Dynimplib symbol attribute
// the symbol that triggered the marking of symbol K as live.
Reachparent []Sym
- flags uint32
+ // CgoExports records cgo-exported symbols by SymName.
+ CgoExports map[string]Sym
- hasUnknownPkgPath bool // if any Go object has unknown package path
+ flags uint32
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 {
- 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
- relocs []goobj.Reloc
- reltypes []objabi.RelocType // relocation types
- data []byte
- auxs []goobj.Aux
+ 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
+ relocs []goobj.Reloc
+ data []byte
+ auxs []goobj.Aux
}
const (
FlagStrictDups = 1 << iota
)
-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),
- 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{}),
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})
}
if l.flags&FlagStrictDups != 0 {
l.checkdup(name, r, li, oldi)
}
+ // Fix for issue #47185 -- given two dupok symbols with
+ // different sizes, favor symbol with larger size. See
+ // also issue #46653.
+ szdup := l.SymSize(oldi)
+ sz := int64(r.Sym(li).Siz())
+ if szdup < sz {
+ // new symbol overwrites old symbol.
+ l.objSyms[oldi] = objSym{r.objidx, li}
+ }
return oldi
}
oldr, oldli := l.toLocal(oldi)
// 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)
+ log.Fatalf("duplicated definition of symbol %s, from %s and %s", name, r.unit.Lib.Pkg, oldr.unit.Lib.Pkg)
}
l.objSyms[oldi] = objSym{r.objidx, li}
} else {
// old symbol overwrites new symbol.
typ := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())]
if !typ.IsData() { // only allow overwriting data symbol
- log.Fatalf("duplicated definition of symbol " + name)
+ log.Fatalf("duplicated definition of symbol %s, from %s and %s", name, r.unit.Lib.Pkg, oldr.unit.Lib.Pkg)
}
}
return oldi
// 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)})
return i
}
+// AddCgoExport records a cgo-exported symbol in l.CgoExports.
+// This table is used to identify the correct Go symbol ABI to use
+// to resolve references from host objects (which don't have ABIs).
+func (l *Loader) AddCgoExport(s Sym) {
+ if l.CgoExports == nil {
+ l.CgoExports = make(map[string]Sym)
+ }
+ l.CgoExports[l.SymName(s)] = s
+}
+
+// LookupOrCreateCgoExport is like LookupOrCreateSym, but if ver
+// indicates a global symbol, it uses the CgoExport table to determine
+// the appropriate symbol version (ABI) to use. ver must be either 0
+// or a static symbol version.
+func (l *Loader) LookupOrCreateCgoExport(name string, ver int) Sym {
+ if ver >= sym.SymVerStatic {
+ return l.LookupOrCreateSym(name, ver)
+ }
+ if ver != 0 {
+ panic("ver must be 0 or a static version")
+ }
+ // Look for a cgo-exported symbol from Go.
+ if s, ok := l.CgoExports[name]; ok {
+ return s
+ }
+ // Otherwise, this must just be a symbol in the host object.
+ // Create a version 0 symbol for it.
+ return l.LookupOrCreateSym(name, 0)
+}
+
func (l *Loader) IsExternal(i Sym) bool {
r, _ := l.toLocal(i)
return l.isExtReader(r)
// 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
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))
+ } else if bytes.Equal(p, pdup) {
+ // For BSS symbols, we need to check size as well, see issue 46653.
+ szdup := l.SymSize(dup)
+ sz := int64(r.Sym(li).Siz())
+ if szdup == sz {
+ return
+ }
+ reason = fmt.Sprintf("different sizes: new size %d != old size %d",
+ sz, szdup)
}
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)
// 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)
return pp.name
}
r, li := l.toLocal(i)
- name := r.Sym(li).Name(r.Reader)
- if !r.NeedNameExpansion() {
- return name
+ if r == nil {
+ return "?"
}
- 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))
}
}
-// 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
+ 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).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]
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 {
}
}
-// SymPlt returns the plt value for pe symbols.
+// 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 value for pe symbols.
+// 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")
}
}
-// SymGot returns the got value for pe symbols.
+// 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 value for pe symbols.
+// 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")
}
}
-// 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).
// 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.
+// NOTE: this corresponds to sym.Symbol.File field.
func (l *Loader) SymPkg(i Sym) string {
if f, ok := l.symPkg[i]; ok {
return f
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)
}
}
// At returns the j-th reloc for a global symbol.
func (relocs *Relocs) At(j int) Reloc {
if relocs.l.isExtReader(relocs.r) {
- pp := relocs.l.payloads[relocs.li]
- return Reloc{&relocs.rs[j], relocs.r, relocs.l, pp.reltypes[j]}
+ return Reloc{&relocs.rs[j], relocs.r, relocs.l}
}
- return Reloc{&relocs.rs[j], relocs.r, relocs.l, 0}
+ return Reloc{&relocs.rs[j], relocs.r, relocs.l}
}
// Relocs returns a Relocs object for the given global sym.
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 {
- return objabi.FuncID((*goobj.FuncInfo)(nil).ReadFuncID(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) FuncID() abi.FuncID {
+ return (*goobj.FuncInfo)(nil).ReadFuncID(fi.data)
}
-func (fi *FuncInfo) Pcline() Sym {
- sym := (*goobj.FuncInfo)(nil).ReadPcline(fi.data)
- return fi.l.resolve(fi.r, sym)
+func (fi *FuncInfo) FuncFlag() abi.FuncFlag {
+ return (*goobj.FuncInfo)(nil).ReadFuncFlag(fi.data)
}
-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")
return (*goobj.FuncInfo)(nil).ReadFile(fi.data, fi.lengths.FileOff, uint32(k))
}
+// TopFrame returns true if the function associated with this FuncInfo
+// is an entry point, meaning that unwinders should stop when they hit
+// this function.
+func (fi *FuncInfo) TopFrame() bool {
+ return (fi.FuncFlag() & abi.FuncFlagTopFrame) != 0
+}
+
type InlTreeNode struct {
Parent int32
File goobj.CUFileIndex
}
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)
r.syms[i] = gi
- if osym.TopFrame() {
- l.SetAttrTopFrame(gi, true)
- }
if osym.Local() {
l.SetAttrLocal(gi, true)
}
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
}
// Index 0 is invalid for symbols.
l.objSyms = make([]objSym, 1, symSize)
- l.npkgsyms = l.NSym()
st := loadState{
l: l,
hashed64Syms: make(map[uint64]symAndSize, hashed64Size),
for _, o := range l.objs[goObjStart:] {
st.preloadSyms(o.r, pkgDef)
}
+ l.npkgsyms = l.NSym()
for _, o := range l.objs[goObjStart:] {
st.preloadSyms(o.r, hashed64Def)
st.preloadSyms(o.r, hashedDef)
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]
pkg := r.Pkg(i)
objidx, ok := l.objByPkg[pkg]
if !ok {
- log.Fatalf("reference of nonexisted package %s, from %v", pkg, r.unit.Lib)
+ log.Fatalf("%v: reference to nonexistent package %s", r.unit.Lib, pkg)
}
r.pkg[i] = objidx
}
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 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())]
// Copy relocations
relocs := l.Relocs(symIdx)
pp.relocs = make([]goobj.Reloc, relocs.Count())
- pp.reltypes = make([]objabi.RelocType, relocs.Count())
for i := range pp.relocs {
// Copy the relocs slice.
// Convert local reference to global reference.
rel := relocs.At(i)
- pp.relocs[i].Set(rel.Off(), rel.Siz(), 0, rel.Add(), goobj.SymRef{PkgIdx: 0, SymIdx: uint32(rel.Sym())})
- pp.reltypes[i] = rel.Type()
+ pp.relocs[i].Set(rel.Off(), rel.Siz(), uint16(rel.Type()), rel.Add(), goobj.SymRef{PkgIdx: 0, SymIdx: uint32(rel.Sym())})
}
// Copy data
// 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.SetAttrTopFrame(dst, l.AttrTopFrame(src))
- 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
for i, list := range lists {
for _, s := range list {
sym := Sym(s)
- if l.attrReachable.Has(sym) && !assignedToUnit.Has(sym) {
+ if !assignedToUnit.Has(sym) {
textp = append(textp, sym)
unit := l.SymUnit(sym)
if unit != nil {
//
// 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)
}