type Relocs struct {
rs []goobj2.Reloc
- li int // local index of symbol whose relocs we're examining
+ li uint32 // local index of symbol whose relocs we're examining
r *oReader // object reader for containing package
l *Loader // loader
}
// objSym represents a symbol in an object file. It is a tuple of
// the object and the symbol's local index.
-// For external symbols, r is l.extReader, s is its index into the
-// payload array.
-// {nil, 0} represents the nil symbol.
+// For external symbols, objidx is the index of l.extReader (extObj),
+// s is its index into the payload array.
+// {0, 0} represents the nil symbol.
type objSym struct {
- r *oReader
- s int // local index
+ objidx uint32 // index of the object (in l.objs array)
+ s uint32 // local index
}
type nameVer struct {
// extending the external symbol index space range. The host object
// loader stores symbol payloads in loader.payloads using SymbolBuilder.
//
-// - For now, in loader.LoadFull we convert all symbols (Go + external)
-// to sym.Symbols.
-//
-// - At some point (when the wayfront is pushed through all of the
-// linker), all external symbols will be payload-based, and we can
-// get rid of the loader.Syms array.
-//
// - 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.
objByPkg map[string]*oReader // map package path to its Go object reader
- Syms []*sym.Symbol // indexed symbols. XXX we still make sym.Symbol for now.
- symBatch []sym.Symbol // batch of symbols.
-
anonVersion int // most recently assigned ext static sym pseudo-version
// Bitmaps and other side structures used to store data used to store
// the symbol that triggered the marking of symbol K as live.
Reachparent []Sym
- relocBatch []sym.Reloc // for bulk allocation of relocations
- relocExtBatch []sym.RelocExt // for bulk allocation of relocations
-
flags uint32
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
elfsetstring elfsetstringFunc
errorReporter *ErrorReporter
-
- SymLookup func(name string, ver int) *sym.Symbol
}
const (
nonPkgRef
)
-type elfsetstringFunc func(s *sym.Symbol, str string, off int)
+// objidx
+const (
+ nilObj = iota
+ extObj
+ 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).
ver int
kind sym.SymKind
objidx uint32 // index of original object if sym made by cloneToExternal
- gotype Sym // Gotype (0 if not present)
relocs []goobj2.Reloc
reltypes []objabi.RelocType // relocation types
data []byte
func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
nbuiltin := goobj2.NBuiltin()
+ extReader := &oReader{objidx: extObj}
ldr := &Loader{
start: make(map[*oReader]Sym),
- objs: []objIdx{{}}, // reserve index 0 for nil symbol
- objSyms: []objSym{{}}, // reserve index 0 for nil symbol
- extReader: &oReader{},
+ objs: []objIdx{{}, {extReader, 0}}, // reserve index 0 for nil symbol, 1 for external symbols
+ objSyms: make([]objSym, 1, 100000), // reserve index 0 for nil symbol
+ extReader: extReader,
symsByName: [2]map[string]Sym{make(map[string]Sym, 100000), make(map[string]Sym, 50000)}, // preallocate ~2MB for ABI0 and ~1MB for ABI1 symbols
objByPkg: make(map[string]*oReader),
outer: make(map[Sym]Sym),
// Add a symbol from an object file, return the global index and whether it is added.
// If the symbol already exist, it returns the index of that symbol.
-func (l *Loader) AddSym(name string, ver int, r *oReader, li int, kind int, dupok bool, typ sym.SymKind) (Sym, bool) {
+func (l *Loader) AddSym(name string, ver int, r *oReader, li uint32, kind int, dupok bool, typ sym.SymKind) (Sym, bool) {
if l.extStart != 0 {
panic("AddSym called after external symbol is created")
}
i := Sym(len(l.objSyms))
addToGlobal := func() {
- l.objSyms = append(l.objSyms, objSym{r, li})
+ l.objSyms = append(l.objSyms, objSym{r.objidx, li})
}
if name == "" {
addToGlobal()
if !(oldtyp.IsData() && oldr.DataSize(oldli) == 0) {
log.Fatalf("duplicated definition of symbol " + name)
}
- l.objSyms[oldi] = objSym{r, li}
+ l.objSyms[oldi] = objSym{r.objidx, li}
} else {
// old symbol overwrites new symbol.
if !typ.IsData() { // only allow overwriting data symbol
if l.extStart == 0 {
l.extStart = i
}
- l.growSyms(int(i))
+ l.growValues(int(i) + 1)
+ l.growAttrBitmaps(int(i) + 1)
pi := l.newPayload(name, ver)
- l.objSyms = append(l.objSyms, objSym{l.extReader, int(pi)})
+ l.objSyms = append(l.objSyms, objSym{l.extReader.objidx, uint32(pi)})
l.extReader.syms = append(l.extReader.syms, i)
return i
}
ms.data = ms.data[:siz]
}
-// Ensure Syms slice has enough space.
-func (l *Loader) growSyms(i int) {
- n := len(l.Syms)
- if n > i {
- return
- }
- l.Syms = append(l.Syms, make([]*sym.Symbol, i+1-n)...)
- l.growValues(int(i) + 1)
- l.growAttrBitmaps(int(i) + 1)
-}
-
// Convert a local index to a global index.
-func (l *Loader) toGlobal(r *oReader, i int) Sym {
+func (l *Loader) toGlobal(r *oReader, i uint32) Sym {
return r.syms[i]
}
// Convert a global index to a local index.
-func (l *Loader) toLocal(i Sym) (*oReader, int) {
- return l.objSyms[i].r, int(l.objSyms[i].s)
+func (l *Loader) toLocal(i Sym) (*oReader, uint32) {
+ return l.objs[l.objSyms[i].objidx].r, l.objSyms[i].s
}
// Resolve a local symbol reference. Return global index.
log.Fatalf("reference of nonexisted package %s, from %v", pkg, r.unit.Lib)
}
}
- return l.toGlobal(rr, int(s.SymIdx))
+ return l.toGlobal(rr, s.SymIdx)
}
// Look up a symbol by name, return global index, or 0 if not found.
}
// Check that duplicate symbols have same contents.
-func (l *Loader) checkdup(name string, r *oReader, li int, dup Sym) {
+func (l *Loader) checkdup(name string, r *oReader, li uint32, dup Sym) {
p := r.Data(li)
rdup, ldup := l.toLocal(dup)
pdup := rdup.Data(ldup)
}
fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason)
- // For the moment, whitelist DWARF subprogram DIEs for
+ // For the moment, allow DWARF subprogram DIEs for
// auto-generated wrapper functions. What seems to happen
// here is that we get different line numbers on formal
// params; I am guessing that the pos is being inherited
// from the spot where the wrapper is needed.
- whitelist := strings.HasPrefix(name, "go.info.go.interface") ||
+ allowed := strings.HasPrefix(name, "go.info.go.interface") ||
strings.HasPrefix(name, "go.info.go.builtin") ||
strings.HasPrefix(name, "go.debuglines")
- if !whitelist {
+ if !allowed {
l.strictDupMsgs++
}
}
return pp.name
}
r, li := l.toLocal(i)
- return strings.Replace(r.Sym(li).Name(r.Reader), "\"\".", r.pkgprefix, -1)
+ name := r.Sym(li).Name(r.Reader)
+ if !r.NeedNameExpansion() {
+ return name
+ }
+ return strings.Replace(name, "\"\".", r.pkgprefix, -1)
}
// Returns the version of the i-th symbol.
return int(abiToVer(r.Sym(li).ABI(), r.version))
}
+func (l *Loader) IsFileLocal(i Sym) bool { return l.SymVersion(i) >= sym.SymVerStatic }
+
// Returns the type of the i-th symbol.
func (l *Loader) SymType(i Sym) sym.SymKind {
if l.IsExternal(i) {
// might make more sense to copy the flag value out of the
// object into a larger bitmap during preload.
r, _ := l.toLocal(i)
- return (r.Flags() & goobj2.ObjFlagShared) != 0
+ return r.Shared()
}
return l.attrShared.Has(l.extIndex(i))
}
return l.sects[l.symSects[i]]
}
-// SetSymValue sets the section of the i-th symbol. i is global index.
+// SetSymSect sets the section of the i-th symbol. i is global index.
func (l *Loader) SetSymSect(i Sym, sect *sym.Section) {
if int(i) >= len(l.symSects) {
l.symSects = append(l.symSects, make([]uint16, l.NSym()-len(l.symSects))...)
// results in to a map (might want to try this at some point and see
// if it helps speed things up).
func (l *Loader) SymGoType(i Sym) Sym {
+ var r *oReader
+ var auxs []goobj2.Aux
if l.IsExternal(i) {
pp := l.getPayload(i)
- return pp.gotype
+ r = l.objs[pp.objidx].r
+ auxs = pp.auxs
+ } else {
+ var li uint32
+ r, li = l.toLocal(i)
+ auxs = r.Auxs(li)
}
- r, li := l.toLocal(i)
- auxs := r.Auxs(li)
for j := range auxs {
a := &auxs[j]
switch a.Type() {
switch a.Type() {
case goobj2.AuxDwarfInfo:
auxDwarfInfo = l.resolve(r, a.Sym())
- if l.SymType(auxDwarfInfo) != sym.SDWARFINFO {
+ if l.SymType(auxDwarfInfo) != sym.SDWARFFCN {
panic("aux dwarf info sym with wrong type")
}
case goobj2.AuxDwarfLoc:
func (l *Loader) SetOuterSym(i Sym, o Sym) {
if o != 0 {
l.outer[i] = o
+ // relocsym's foldSubSymbolOffset requires that we only
+ // have a single level of containment-- enforce here.
+ if l.outer[o] != 0 {
+ panic("multiply nested outer sym")
+ }
} else {
delete(l.outer, i)
}
}
// Relocs returns a Relocs object given a local sym index and reader.
-func (l *Loader) relocs(r *oReader, li int) Relocs {
+func (l *Loader) relocs(r *oReader, li uint32) Relocs {
var rs []goobj2.Reloc
if l.isExtReader(r) {
pp := l.payloads[li]
r = l.objs[pp.objidx].r
auxs = pp.auxs
} else {
- var li int
+ var li uint32
r, li = l.toLocal(i)
auxs = r.Auxs(li)
}
for j := range auxs {
a := &auxs[j]
if a.Type() == goobj2.AuxFuncInfo {
- b := r.Data(int(a.Sym().SymIdx))
+ b := r.Data(a.Sym().SymIdx)
return FuncInfo{l, r, b, auxs, goobj2.FuncInfoLengths{}}
}
}
// Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
// Does not read symbol data.
// Returns the fingerprint of the object.
-func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj2.FingerprintType {
+func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj2.FingerprintType {
roObject, readonly, err := f.Slice(uint64(length)) // TODO: no need to map blocks that are for tools only (e.g. RefName)
if err != nil {
log.Fatal("cannot read object file:", err)
r := goobj2.NewReaderFromBytes(roObject, readonly)
if r == nil {
if len(roObject) >= 8 && bytes.Equal(roObject[:8], []byte("\x00go114ld")) {
- log.Fatalf("found object file %s in old format, but -go115newobj is true\nset -go115newobj consistently in all -gcflags, -asmflags, and -ldflags", f.File().Name())
+ log.Fatalf("found object file %s in old format", f.File().Name())
}
panic("cannot read object file")
}
- localSymVersion := syms.IncVersion()
pkgprefix := objabi.PathToPrefix(lib.Pkg) + "."
ndef := r.NSym()
nnonpkgdef := r.NNonpkgdef()
// Preload symbols of given kind from an object.
func (l *Loader) preloadSyms(r *oReader, kind int) {
- ndef := r.NSym()
- nnonpkgdef := r.NNonpkgdef()
- var start, end int
+ ndef := uint32(r.NSym())
+ nnonpkgdef := uint32(r.NNonpkgdef())
+ var start, end uint32
switch kind {
case pkgDef:
start = 0
default:
panic("preloadSyms: bad kind")
}
- l.growSyms(len(l.objSyms) + end - start)
- l.growAttrBitmaps(len(l.objSyms) + end - start)
+ l.growAttrBitmaps(len(l.objSyms) + int(end-start))
+ needNameExpansion := r.NeedNameExpansion()
for i := start; i < end; i++ {
osym := r.Sym(i)
- name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
+ name := osym.Name(r.Reader)
+ if needNameExpansion {
+ name = strings.Replace(name, "\"\".", r.pkgprefix, -1)
+ }
v := abiToVer(osym.ABI(), r.version)
dupok := osym.Dupok()
gi, added := l.AddSym(name, v, r, i, kind, dupok, sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())])
l.builtinSyms[bi] = gi
}
}
- if strings.HasPrefix(name, "go.string.") ||
- strings.HasPrefix(name, "gclocals·") ||
- strings.HasPrefix(name, "runtime.gcbits.") {
- l.SetAttrNotInSymbolTable(gi, true)
- }
if a := osym.Align(); a != 0 {
l.SetSymAlign(gi, int32(a))
}
// Add non-package symbols and references to external symbols (which are always
// named).
func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
- for _, o := range l.objs[1:] {
+ for _, o := range l.objs[goObjStart:] {
l.preloadSyms(o.r, nonPkgDef)
}
- for _, o := range l.objs[1:] {
+ for _, o := range l.objs[goObjStart:] {
loadObjRefs(l, o.r, arch)
}
+ l.values = make([]int64, l.NSym(), l.NSym()+1000) // +1000 make some room for external symbols
}
func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
- ndef := r.NSym() + r.NNonpkgdef()
- for i, n := 0, r.NNonpkgref(); i < n; i++ {
+ ndef := uint32(r.NSym() + r.NNonpkgdef())
+ needNameExpansion := r.NeedNameExpansion()
+ for i, n := uint32(0), uint32(r.NNonpkgref()); i < n; i++ {
osym := r.Sym(ndef + i)
- name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
+ 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]
}
}
-// Load full contents.
-func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc, needExtReloc bool) {
- // create all Symbols first.
- l.growSyms(l.NSym())
- l.growSects(l.NSym())
-
- if needReloc && len(l.extRelocs) != 0 {
- // If needReloc is true, we are going to convert the loader's
- // "internal" relocations to sym.Relocs. In this case, external
- // relocations shouldn't be used.
- panic("phase error")
- }
-
- nr := 0 // total number of sym.Reloc's we'll need
- for _, o := range l.objs[1:] {
- nr += loadObjSyms(l, syms, o.r, needReloc, needExtReloc)
- }
-
- // Make a first pass through the external symbols, making
- // sure that each external symbol has a non-nil entry in
- // l.Syms (note that relocations and symbol content will
- // be copied in a later loop).
- toConvert := make([]Sym, 0, len(l.payloads))
- for _, i := range l.extReader.syms {
- if !l.attrReachable.Has(i) {
- continue
- }
- pp := l.getPayload(i)
- if needReloc {
- nr += len(pp.relocs)
- }
- if needExtReloc && int(i) < len(l.extRelocs) {
- nr += len(l.extRelocs[i])
- }
- // create and install the sym.Symbol here so that l.Syms will
- // be fully populated when we do relocation processing and
- // outer/sub processing below. Note that once we do this,
- // we'll need to get at the payload for a symbol with direct
- // reference to l.payloads[] as opposed to calling l.getPayload().
- s := l.allocSym(pp.name, 0)
- l.installSym(i, s)
- toConvert = append(toConvert, i)
- }
-
- // allocate a single large slab of relocations for all live symbols
- if nr != 0 {
- l.relocBatch = make([]sym.Reloc, nr)
- if needExtReloc {
- l.relocExtBatch = make([]sym.RelocExt, nr)
- }
- }
-
- // convert payload-based external symbols into sym.Symbol-based
- for _, i := range toConvert {
-
- // Copy kind/size/value etc.
- pp := l.payloads[l.extIndex(i)]
- s := l.Syms[i]
- s.Version = int16(pp.ver)
- s.Type = pp.kind
- s.Size = pp.size
-
- // Copy relocations
- if needReloc {
- batch := l.relocBatch
- s.R = batch[:len(pp.relocs):len(pp.relocs)]
- l.relocBatch = batch[len(pp.relocs):]
- relocs := l.Relocs(i)
- l.convertRelocations(i, &relocs, s, false)
- }
- if needExtReloc {
- l.convertExtRelocs(s, i)
- }
-
- // Copy data
- s.P = pp.data
-
- // Transfer over attributes.
- l.migrateAttributes(i, s)
- }
-
- // load contents of defined symbols
- for _, o := range l.objs[1:] {
- loadObjFull(l, o.r, needReloc, needExtReloc)
- }
-
- // Sanity check: we should have consumed all batched allocations.
- if len(l.relocBatch) != 0 || len(l.relocExtBatch) != 0 {
- panic("batch allocation mismatch")
- }
-
- // Note: resolution of ABI aliases is now also handled in
- // loader.convertRelocations, so once the host object loaders move
- // completely to loader.Sym, we can remove the code below.
-
- // Resolve ABI aliases for external symbols. This is only
- // needed for internal cgo linking.
- if needReloc {
- for _, i := range l.extReader.syms {
- if s := l.Syms[i]; s != nil && s.Attr.Reachable() {
- for ri := range s.R {
- r := &s.R[ri]
- if r.Sym != nil && r.Sym.Type == sym.SABIALIAS {
- r.Sym = r.Sym.R[0].Sym
- }
- }
- }
- }
- }
-
- // Free some memory.
- // At this point we still need basic index mapping, and some fields of
- // external symbol payloads, but not much else.
- l.values = nil
- l.symSects = nil
- l.outdata = nil
- l.itablink = nil
- l.attrOnList = nil
- l.attrLocal = nil
- l.attrNotInSymbolTable = nil
- l.attrVisibilityHidden = nil
- l.attrDuplicateOK = nil
- l.attrShared = nil
- l.attrExternal = nil
- l.attrReadOnly = nil
- l.attrTopFrame = nil
- l.attrSpecial = nil
- l.attrCgoExportDynamic = nil
- l.attrCgoExportStatic = nil
- l.outer = nil
- l.align = nil
- l.dynimplib = nil
- l.dynimpvers = nil
- l.localentry = nil
- l.extname = nil
- l.elfType = nil
- l.plt = nil
- l.got = nil
- l.dynid = nil
- if needExtReloc { // converted to sym.Relocs, drop loader references
- l.relocVariant = nil
- l.extRelocs = nil
- }
-
- // Drop fields that are no longer needed.
- for _, i := range l.extReader.syms {
- pp := l.getPayload(i)
- pp.name = ""
- pp.auxs = nil
- pp.data = nil
- if needExtReloc {
- pp.relocs = nil
- pp.reltypes = nil
- }
- }
-}
-
// 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.
return target
}
-// PropagateSymbolChangesBackToLoader is a temporary shim function
-// that copies over a given sym.Symbol into the equivalent representation
-// in the loader world. The intent is to enable converting a given
-// linker phase/pass from dealing with sym.Symbol's to a modernized
-// pass that works with loader.Sym, in cases where the "loader.Sym
-// wavefront" has not yet reached the pass in question. For such work
-// the recipe is to first call PropagateSymbolChangesBackToLoader(),
-// then exexute the pass working with the loader, then call
-// PropagateLoaderChangesToSymbols to copy the changes made by the
-// pass back to the sym.Symbol world.
-func (l *Loader) PropagateSymbolChangesBackToLoader() {
-
- // For the moment we only copy symbol values, and we don't touch
- // any new sym.Symbols created since loadlibfull() was run. This
- // seems to be what's needed for DWARF gen.
- for i := Sym(1); i < Sym(len(l.objSyms)); i++ {
- s := l.Syms[i]
- if s != nil {
- if s.Value != l.SymValue(i) {
- l.SetSymValue(i, s.Value)
- }
- }
- }
-}
-
-// PropagateLoaderChangesToSymbols is a temporary shim function that
-// takes a list of loader.Sym symbols and works to copy their contents
-// and attributes over to a corresponding sym.Symbol. The parameter
-// anonVerReplacement specifies a version number for any new anonymous
-// symbols encountered on the list, when creating sym.Symbols for them
-// (or zero if we don't expect to encounter any new anon symbols). See
-// the PropagateSymbolChangesBackToLoader header comment for more
-// info.
-//
-// WARNING: this function is brittle and depends heavily on loader
-// implementation. A key problem with doing this is that as things
-// stand at the moment, some sym.Symbol contents/attributes are
-// populated only when converting from loader.Sym to sym.Symbol in
-// loadlibfull, meaning we may wipe out some information when copying
-// back.
-
-func (l *Loader) PropagateLoaderChangesToSymbols(toconvert []Sym, anonVerReplacement int) []*sym.Symbol {
-
- result := []*sym.Symbol{}
- relocfixup := []Sym{}
-
- // Note: this loop needs to allow for the possibility that we may
- // see "new" symbols on the 'toconvert' list that come from object
- // files (for example, DWARF location lists), as opposed to just
- // newly manufactured symbols (ex: DWARF section symbols such as
- // ".debug_info"). This means that we have to be careful not to
- // stomp on sym.Symbol attributes/content that was set up in
- // in loadlibfull().
-
- // Also note that in order for the relocation fixup to work, we
- // have to do this in two passes -- one pass to create the symbols,
- // and then a second fix up the relocations once all necessary
- // sym.Symbols are created.
-
- // First pass, symbol creation and symbol data fixup.
- for _, cand := range toconvert {
-
- sn := l.SymName(cand)
- sv := l.SymVersion(cand)
- st := l.SymType(cand)
- if sv < 0 {
- if anonVerReplacement == 0 {
- panic("expected valid anon version replacement")
- }
- sv = anonVerReplacement
- }
-
- s := l.Syms[cand]
-
- isnew := false
- if sn == "" {
- // Don't install anonymous symbols in the lookup tab.
- if s == nil {
- s = l.allocSym(sn, sv)
- l.installSym(cand, s)
- }
- isnew = true
- } else {
- if s != nil {
- // Already have a symbol for this -- it must be
- // something that was previously processed by
- // loadObjFull. Note that the symbol in question may
- // or may not be in the name lookup map.
- } else {
- isnew = true
- s = l.SymLookup(sn, sv)
- }
- }
- result = append(result, s)
-
- // Always copy these from new to old.
- s.Value = l.SymValue(cand)
- s.Type = st
-
- // If the data for a symbol has increased in size, make sure
- // we bring the new content across.
- relfix := isnew
- if isnew || len(l.Data(cand)) > len(s.P) {
- s.P = l.Data(cand)
- s.Size = int64(len(s.P))
- relfix = true
- }
-
- // For 'new' symbols, copy other content.
- if relfix {
- relocfixup = append(relocfixup, cand)
- }
-
- // If new symbol, call a helper to migrate attributes.
- // Otherwise touch only not-in-symbol-table, since there are
- // some attrs that are only set up at the point where we
- // convert loader.Sym to sym.Symbol.
- if isnew {
- l.migrateAttributes(cand, s)
- } else {
- if l.AttrNotInSymbolTable(cand) {
- s.Attr.Set(sym.AttrNotInSymbolTable, true)
- }
- }
- }
-
- // Second pass to fix up relocations.
- for _, cand := range relocfixup {
- s := l.Syms[cand]
- relocs := l.Relocs(cand)
- if len(s.R) != relocs.Count() {
- s.R = make([]sym.Reloc, relocs.Count())
- }
- l.convertRelocations(cand, &relocs, s, true)
- }
-
- return result
-}
-
-// ExtractSymbols grabs the symbols out of the loader for work that hasn't been
-// ported to the new symbol type.
-func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
- // Add symbols to the ctxt.Syms lookup table. This explicitly skips things
- // created via loader.Create (marked with versions less than zero), since
- // if we tried to add these we'd wind up with collisions. We do, however,
- // add these symbols to the list of global symbols so that other future
- // steps (like pclntab generation) can find these symbols if neceassary.
- // Along the way, update the version from the negative anon version to
- // something larger than sym.SymVerStatic (needed so that
- // sym.symbol.IsFileLocal() works properly).
- anonVerReplacement := syms.IncVersion()
- for _, s := range l.Syms {
- if s == nil {
- continue
- }
- if s.Version < 0 {
- s.Version = int16(anonVerReplacement)
- }
- }
-
- // Provide lookup functions for sym.Symbols.
- l.SymLookup = func(name string, ver int) *sym.Symbol {
- i := l.LookupOrCreateSym(name, ver)
- if s := l.Syms[i]; s != nil {
- return s
- }
- s := l.allocSym(name, ver)
- l.installSym(i, s)
- return s
- }
- syms.Lookup = l.SymLookup
- syms.ROLookup = func(name string, ver int) *sym.Symbol {
- i := l.Lookup(name, ver)
- return l.Syms[i]
- }
-}
-
-// allocSym allocates a new symbol backing.
-func (l *Loader) allocSym(name string, version int) *sym.Symbol {
- batch := l.symBatch
- if len(batch) == 0 {
- batch = make([]sym.Symbol, 1000)
- }
- s := &batch[0]
- l.symBatch = batch[1:]
-
- s.Dynid = -1
- s.Name = name
- s.Version = int16(version)
-
- return s
-}
-
-// installSym sets the underlying sym.Symbol for the specified sym index.
-func (l *Loader) installSym(i Sym, s *sym.Symbol) {
- if s == nil {
- panic("installSym nil symbol")
- }
- if l.Syms[i] != nil {
- panic("sym already present in installSym")
- }
- l.Syms[i] = s
- s.SymIdx = sym.LoaderSym(i)
-}
-
-// addNewSym adds a new sym.Symbol to the i-th index in the list of symbols.
-func (l *Loader) addNewSym(i Sym, name string, ver int, unit *sym.CompilationUnit, t sym.SymKind) *sym.Symbol {
- s := l.allocSym(name, ver)
- if s.Type != 0 && s.Type != sym.SXREF {
- fmt.Println("symbol already processed:", unit.Lib, i, s)
- panic("symbol already processed")
- }
- if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
- t = s.Type
- }
- s.Type = t
- l.growSyms(int(i))
- l.installSym(i, s)
- return s
-}
-
// 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
return true
}
switch skind {
- case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES, sym.SGOFUNC:
+ case sym.SDWARFFCN, sym.SDWARFABSFCN, sym.SDWARFTYPE, sym.SDWARFCONST, sym.SDWARFCUINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES, sym.SGOFUNC:
return true
default:
return false
}
}
-// loadObjSyms creates sym.Symbol objects for the live Syms in the
-// object corresponding to object reader "r". Return value is the
-// number of sym.Reloc entries required for all the new symbols.
-func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader, needReloc, needExtReloc bool) int {
- nr := 0
- for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
- gi := r.syms[i]
- if r2, i2 := l.toLocal(gi); r2 != r || i2 != i {
- continue // come from a different object
- }
- osym := r.Sym(i)
- name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
- t := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
-
- // Skip non-dwarf anonymous symbols (e.g. funcdata),
- // since they will never be turned into sym.Symbols.
- if !topLevelSym(name, t) {
- continue
- }
- ver := abiToVer(osym.ABI(), r.version)
- if t == sym.SXREF {
- log.Fatalf("bad sxref")
- }
- if t == 0 {
- log.Fatalf("missing type for %s in %s", name, r.unit.Lib)
- }
- if !l.attrReachable.Has(gi) && name != "runtime.addmoduledata" && name != "runtime.lastmoduledatap" {
- // No need to load unreachable symbols.
- // XXX reference to runtime.addmoduledata may be generated later by the linker in plugin mode.
- continue
- }
-
- l.addNewSym(gi, name, ver, r.unit, t)
- if needReloc {
- nr += r.NReloc(i)
- }
- if needExtReloc && int(gi) < len(l.extRelocs) {
- nr += len(l.extRelocs[gi])
- }
- }
- return nr
-}
-
// cloneToExternal takes the existing object file symbol (symIdx)
// and creates a new external symbol payload that is a clone with
// respect to name, version, type, relocations, etc. The idea here
// a symbol originally discovered as part of an object file, it's
// easier to do this if we make the updates to an external symbol
// payload.
-// XXX maybe rename? makeExtPayload?
func (l *Loader) cloneToExternal(symIdx Sym) {
if l.IsExternal(symIdx) {
panic("sym is already external, no need for clone")
}
- l.growSyms(int(symIdx))
// Read the particulars from object.
r, li := l.toLocal(symIdx)
osym := r.Sym(li)
- sname := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
+ 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())]
// If this is a def, then copy the guts. We expect this case
// to be very rare (one case it may come up is with -X).
- if li < (r.NSym() + r.NNonpkgdef()) {
+ if li < uint32(r.NSym()+r.NNonpkgdef()) {
// Copy relocations
relocs := l.Relocs(symIdx)
// Gotype, so as to propagate it to the new symbol.
auxs := r.Auxs(li)
pp.auxs = auxs
-loop:
- for j := range auxs {
- a := &auxs[j]
- switch a.Type() {
- case goobj2.AuxGotype:
- pp.gotype = l.resolve(r, a.Sym())
- break loop
- default:
- // nothing to do
- }
- }
// Install new payload to global index space.
// (This needs to happen at the end, as the accessors above
// need to access the old symbol content.)
- l.objSyms[symIdx] = objSym{l.extReader, pi}
+ l.objSyms[symIdx] = objSym{l.extReader.objidx, uint32(pi)}
l.extReader.syms = append(l.extReader.syms, symIdx)
}
l.SetAttrReadOnly(dst, l.AttrReadOnly(src))
}
-// migrateAttributes copies over all of the attributes of symbol 'src' to
-// sym.Symbol 'dst'.
-func (l *Loader) migrateAttributes(src Sym, dst *sym.Symbol) {
- dst.Value = l.SymValue(src)
- dst.Align = l.SymAlign(src)
- dst.Sect = l.SymSect(src)
-
- dst.Attr.Set(sym.AttrReachable, l.AttrReachable(src))
- dst.Attr.Set(sym.AttrOnList, l.AttrOnList(src))
- dst.Attr.Set(sym.AttrLocal, l.AttrLocal(src))
- dst.Attr.Set(sym.AttrNotInSymbolTable, l.AttrNotInSymbolTable(src))
- dst.Attr.Set(sym.AttrNoSplit, l.IsNoSplit(src))
- dst.Attr.Set(sym.AttrVisibilityHidden, l.AttrVisibilityHidden(src))
- dst.Attr.Set(sym.AttrDuplicateOK, l.AttrDuplicateOK(src))
- dst.Attr.Set(sym.AttrShared, l.AttrShared(src))
- dst.Attr.Set(sym.AttrExternal, l.AttrExternal(src))
- dst.Attr.Set(sym.AttrTopFrame, l.AttrTopFrame(src))
- dst.Attr.Set(sym.AttrSpecial, l.AttrSpecial(src))
- dst.Attr.Set(sym.AttrCgoExportDynamic, l.AttrCgoExportDynamic(src))
- dst.Attr.Set(sym.AttrCgoExportStatic, l.AttrCgoExportStatic(src))
- dst.Attr.Set(sym.AttrReadOnly, l.AttrReadOnly(src))
-
- // Convert outer relationship
- if outer, ok := l.outer[src]; ok {
- dst.Outer = l.Syms[outer]
- }
-
- // Set sub-symbol attribute. See the comment on the AttrSubSymbol
- // method for more on this, there is some tricky stuff here.
- dst.Attr.Set(sym.AttrSubSymbol, l.outer[src] != 0 && l.sub[l.outer[src]] != 0)
-
- // Copy over dynimplib, dynimpvers, extname.
- if name, ok := l.extname[src]; ok {
- dst.SetExtname(name)
- }
- if l.SymDynimplib(src) != "" {
- dst.SetDynimplib(l.SymDynimplib(src))
- }
- if l.SymDynimpvers(src) != "" {
- dst.SetDynimpvers(l.SymDynimpvers(src))
- }
-
- // Copy ELF type if set.
- if et, ok := l.elfType[src]; ok {
- dst.SetElfType(et)
- }
-
- // Copy pe objects values if set.
- if plt, ok := l.plt[src]; ok {
- dst.SetPlt(plt)
- }
- if got, ok := l.got[src]; ok {
- dst.SetGot(got)
- }
-
- // Copy dynid
- if dynid, ok := l.dynid[src]; ok {
- dst.Dynid = dynid
- }
-}
-
// 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 {
// without adding it to any lookup tables, returning a Sym index for it.
func (l *Loader) CreateStaticSym(name string) Sym {
// Assign a new unique negative version -- this is to mark the
- // symbol so that it can be skipped when ExtractSymbols is adding
- // ext syms to the sym.Symbols hash.
+ // symbol so that it is not included in the name lookup table.
l.anonVersion--
return l.newExtSym(name, l.anonVersion)
}
}
}
-func loadObjFull(l *Loader, r *oReader, needReloc, needExtReloc bool) {
- for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
- // A symbol may be a dup or overwritten. In this case, its
- // content will actually be provided by a different object
- // (to which its global index points). Skip those symbols.
- gi := l.toGlobal(r, i)
- if r2, i2 := l.toLocal(gi); r2 != r || i2 != i {
- continue
- }
- s := l.Syms[gi]
- if s == nil {
- continue
- }
-
- l.migrateAttributes(gi, s)
- // Be careful not to overwrite attributes set by the linker.
- // Don't use the attributes from the object file.
-
- osym := r.Sym(i)
- size := osym.Siz()
-
- // Symbol data
- s.P = l.OutData(gi)
-
- // Relocs
- if needReloc {
- relocs := l.relocs(r, i)
- batch := l.relocBatch
- s.R = batch[:relocs.Count():relocs.Count()]
- l.relocBatch = batch[relocs.Count():]
- l.convertRelocations(gi, &relocs, s, false)
- }
- if needExtReloc {
- l.convertExtRelocs(s, gi)
- }
-
- // Aux symbol info
- auxs := r.Auxs(i)
- for j := range auxs {
- a := &auxs[j]
- switch a.Type() {
- case goobj2.AuxFuncInfo, goobj2.AuxFuncdata, goobj2.AuxGotype:
- // already handled
- case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines:
- // ignored for now
- default:
- panic("unknown aux type")
- }
- }
-
- if s.Size < int64(size) {
- s.Size = int64(size)
- }
- }
-}
-
-// convertRelocations takes a vector of loader.Reloc relocations and
-// translates them into an equivalent set of sym.Reloc relocations on
-// the symbol "dst", performing fixups along the way for ABI aliases,
-// etc. It is assumed that the caller has pre-allocated the dst symbol
-// relocations slice. If 'strict' is set, then this method will
-// panic if it finds a relocation targeting a nil symbol.
-func (l *Loader) convertRelocations(symIdx Sym, src *Relocs, dst *sym.Symbol, strict bool) {
- for j := range dst.R {
- r := src.At2(j)
- rs := r.Sym()
- sz := r.Siz()
- rt := r.Type()
- if rt == objabi.R_METHODOFF {
- if l.attrReachable.Has(rs) {
- rt = objabi.R_ADDROFF
- } else {
- sz = 0
- rs = 0
- }
- }
- if rt == objabi.R_WEAKADDROFF && !l.attrReachable.Has(rs) {
- rs = 0
- sz = 0
- }
- if rs != 0 && l.Syms[rs] != nil && l.Syms[rs].Type == sym.SABIALIAS {
- rsrelocs := l.Relocs(rs)
- rs = rsrelocs.At2(0).Sym()
- }
- if strict && rs != 0 && l.Syms[rs] == nil && rt != objabi.R_USETYPE {
- panic("nil reloc target in convertRelocations")
- }
- dst.R[j] = sym.Reloc{
- Off: r.Off(),
- Siz: sz,
- Type: rt,
- Add: r.Add(),
- Sym: l.Syms[rs],
- }
- if rv := l.RelocVariant(symIdx, j); rv != 0 {
- dst.R[j].InitExt()
- dst.R[j].Variant = rv
- }
- }
-}
-
-// Convert external relocations to sym.Relocs on symbol dst.
-func (l *Loader) convertExtRelocs(dst *sym.Symbol, src Sym) {
- if int(src) >= len(l.extRelocs) {
- return
- }
- extRelocs := l.extRelocs[src]
- if len(extRelocs) == 0 {
- return
- }
- if len(dst.R) != 0 {
- panic("bad")
- }
-
- n := len(extRelocs)
- batch := l.relocBatch
- dst.R = batch[:n:n]
- l.relocBatch = batch[n:]
- relocs := l.Relocs(src)
- for i := range dst.R {
- er := &extRelocs[i]
- sr := relocs.At2(er.Idx)
- r := &dst.R[i]
- r.RelocExt = &l.relocExtBatch[0]
- l.relocExtBatch = l.relocExtBatch[1:]
- r.Off = sr.Off()
- r.Siz = sr.Siz()
- r.Type = sr.Type()
- r.Sym = l.Syms[l.ResolveABIAlias(sr.Sym())]
- r.Add = sr.Add()
- r.Xsym = l.Syms[er.Xsym]
- r.Xadd = er.Xadd
- if rv := l.RelocVariant(src, er.Idx); rv != 0 {
- r.Variant = rv
- }
- }
-}
-
// relocId is essentially a <S,R> tuple identifying the Rth
// relocation of symbol S.
type relocId struct {
return result
}
-// AssignTextSymbolOrder populates the Textp2 slices within each
+// AssignTextSymbolOrder populates the Textp slices within each
// library and compilation unit, insuring that packages are laid down
// in dependency order (internal first, then everything else). Return value
// is a slice of all text syms.
func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, extsyms []Sym) []Sym {
- // Library Textp2 lists should be empty at this point.
+ // Library Textp lists should be empty at this point.
for _, lib := range libs {
- if len(lib.Textp2) != 0 {
- panic("expected empty Textp2 slice for library")
+ if len(lib.Textp) != 0 {
+ panic("expected empty Textp slice for library")
}
- if len(lib.DupTextSyms2) != 0 {
- panic("expected empty DupTextSyms2 slice for library")
+ if len(lib.DupTextSyms) != 0 {
+ panic("expected empty DupTextSyms slice for library")
}
}
// call the regular addToTextp.
assignedToUnit := MakeBitmap(l.NSym() + 1)
- // Start off textp2 with reachable external syms.
- textp2 := []Sym{}
+ // Start off textp with reachable external syms.
+ textp := []Sym{}
for _, sym := range extsyms {
if !l.attrReachable.Has(sym) {
continue
}
- textp2 = append(textp2, sym)
+ textp = append(textp, sym)
}
// Walk through all text symbols from Go object files and append
- // them to their corresponding library's textp2 list.
- for _, o := range l.objs[1:] {
+ // them to their corresponding library's textp list.
+ for _, o := range l.objs[goObjStart:] {
r := o.r
lib := r.unit.Lib
- for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
+ for i, n := uint32(0), uint32(r.NSym()+r.NNonpkgdef()); i < n; i++ {
gi := l.toGlobal(r, i)
if !l.attrReachable.Has(gi) {
continue
// We still need to record its presence in the current
// package, as the trampoline pass expects packages
// are laid out in dependency order.
- lib.DupTextSyms2 = append(lib.DupTextSyms2, sym.LoaderSym(gi))
+ lib.DupTextSyms = append(lib.DupTextSyms, sym.LoaderSym(gi))
continue // symbol in different object
}
if dupok {
- lib.DupTextSyms2 = append(lib.DupTextSyms2, sym.LoaderSym(gi))
+ lib.DupTextSyms = append(lib.DupTextSyms, sym.LoaderSym(gi))
continue
}
- lib.Textp2 = append(lib.Textp2, sym.LoaderSym(gi))
+ lib.Textp = append(lib.Textp, sym.LoaderSym(gi))
}
}
if intlibs[idx] != doInternal {
continue
}
- lists := [2][]sym.LoaderSym{lib.Textp2, lib.DupTextSyms2}
+ lists := [2][]sym.LoaderSym{lib.Textp, lib.DupTextSyms}
for i, list := range lists {
for _, s := range list {
sym := Sym(s)
if l.attrReachable.Has(sym) && !assignedToUnit.Has(sym) {
- textp2 = append(textp2, sym)
+ textp = append(textp, sym)
unit := l.SymUnit(sym)
if unit != nil {
- unit.Textp2 = append(unit.Textp2, s)
+ unit.Textp = append(unit.Textp, s)
assignedToUnit.Set(sym)
}
// Dupok symbols may be defined in multiple packages; the
}
}
}
- lib.Textp2 = nil
- lib.DupTextSyms2 = nil
+ lib.Textp = nil
+ lib.DupTextSyms = nil
}
}
- return textp2
+ return textp
}
// ErrorReporter is a helper class for reporting errors.
// For debugging.
func (l *Loader) Dump() {
fmt.Println("objs")
- for _, obj := range l.objs {
+ for _, obj := range l.objs[goObjStart:] {
if obj.r != nil {
fmt.Println(obj.i, obj.r.unit.Lib)
}
if l.IsExternal(i) {
pi = fmt.Sprintf("<ext %d>", l.extIndex(i))
}
- var s *sym.Symbol
- if int(i) < len(l.Syms) {
- s = l.Syms[i]
- }
- if s != nil {
- fmt.Println(i, s, s.Type, pi)
- } else {
- fmt.Println(i, l.SymName(i), "<not loaded>", pi)
- }
+ fmt.Println(i, l.SymName(i), l.SymType(i), pi)
}
fmt.Println("symsByName")
for name, i := range l.symsByName[0] {