Newer
Older
Cherry Zhang
committed
// Add non-package symbols and references to external symbols (which are always
// named).
func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
Cherry Zhang
committed
for _, o := range l.objs[1:] {
l.preloadSyms(o.r, nonPkgDef)
}
Cherry Zhang
committed
for _, o := range l.objs[1:] {
loadObjRefs(l, o.r, arch)
Cherry Zhang
committed
}
}
func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
ndef := r.NSym() + r.NNonpkgdef()
for i, n := 0, r.NNonpkgref(); i < n; i++ {
name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
v := abiToVer(osym.ABI(), r.version)
r.syms[ndef+i] = l.LookupOrCreateSym(name, v)
gi := r.syms[ndef+i]
if osym.Local() {
l.SetAttrLocal(gi, true)
}
l.preprocess(arch, gi, name)
}
}
func abiToVer(abi uint16, localSymVersion int) int {
var v int
if abi == goobj2.SymABIstatic {
// Static
v = localSymVersion
} else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {
// Note that data symbols are "ABI0", which maps to version 0.
v = abiver
} else {
log.Fatalf("invalid symbol ABI: %d", abi)
}
return v
}
// preprocess looks for integer/floating point constant symbols whose
// content is encoded into the symbol name, and promotes them into
// real symbols with RODATA type and a payload that matches the
// encoded content.
func (l *Loader) preprocess(arch *sys.Arch, s Sym, name string) {
if name != "" && name[0] == '$' && len(name) > 5 && l.SymType(s) == 0 && len(l.Data(s)) == 0 {
x, err := strconv.ParseUint(name[5:], 16, 64)
log.Panicf("failed to parse $-symbol %s: %v", name, err)
su := l.MakeSymbolUpdater(s)
su.SetType(sym.SRODATA)
su.SetLocal(true)
switch name[:5] {
case "$f32.":
if uint64(uint32(x)) != x {
log.Panicf("$-symbol %s too large: %d", name, x)
su.AddUint32(arch, uint32(x))
case "$f64.", "$i64.":
su.AddUint64(arch, x)
log.Panicf("unrecognized $-symbol: %s", name)
}
}
}
// Load full contents.
Cherry Zhang
committed
func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc, needExtReloc bool) {
// create all Symbols first.
l.growSyms(l.NSym())
Cherry Zhang
committed
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:] {
Cherry Zhang
committed
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)
}
Cherry Zhang
committed
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 {
Cherry Zhang
committed
l.relocBatch = make([]sym.Reloc, nr)
Cherry Zhang
committed
if needExtReloc {
l.relocExtBatch = make([]sym.RelocExt, nr)
}
Cherry Zhang
committed
}
// 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
Cherry Zhang
committed
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)
}
Cherry Zhang
committed
if needExtReloc {
l.convertExtRelocs(s, i)
}
// Copy data
s.P = pp.data
// Transfer over attributes.
l.migrateAttributes(i, s)
}
// load contents of defined symbols
Cherry Zhang
committed
for _, o := range l.objs[1:] {
Cherry Zhang
committed
loadObjFull(l, o.r, needReloc, needExtReloc)
Cherry Zhang
committed
}
// 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
}
}
}
}
}
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
// 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
Cherry Zhang
committed
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
Cherry Zhang
committed
if needExtReloc {
pp.relocs = nil
pp.reltypes = nil
}
Cherry Zhang
committed
}
// ResolveABIAlias given a symbol returns the ABI alias target of that
// symbol. If the sym in question is not an alias, the sym itself is
// returned.
func (l *Loader) ResolveABIAlias(s Sym) Sym {
if s == 0 {
return 0
}
if l.SymType(s) != sym.SABIALIAS {
return s
}
relocs := l.Relocs(s)
target := relocs.At2(0).Sym()
if l.SymType(target) == sym.SABIALIAS {
panic(fmt.Sprintf("ABI alias %s references another ABI alias %s", l.SymName(s), l.SymName(target)))
}
return target
}
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
// 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 {
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
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.
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
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
}
Than McIntosh
committed
// 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")
Than McIntosh
committed
}
l.Syms[i] = s
s.SymIdx = sym.LoaderSym(i)
Than McIntosh
committed
}
// 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))
Than McIntosh
committed
l.installSym(i, s)
return s
}
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
// TopLevelSym tests a symbol (by name and kind) to determine whether
// the symbol first class sym (participating in the link) or is an
// anonymous aux or sub-symbol containing some sub-part or payload of
// another symbol.
func (l *Loader) TopLevelSym(s Sym) bool {
return topLevelSym(l.RawSymName(s), l.SymType(s))
}
// topLevelSym tests a symbol name and kind to determine whether
// the symbol first class sym (participating in the link) or is an
// anonymous aux or sub-symbol containing some sub-part or payload of
// another symbol.
func topLevelSym(sname string, skind sym.SymKind) bool {
if sname != "" {
return true
}
switch skind {
case sym.SDWARFINFO, 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.
Cherry Zhang
committed
func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader, needReloc, needExtReloc bool) int {
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
if r2, i2 := l.toLocal(gi); r2 != r || i2 != i {
continue // come from a different object
}
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.
l.addNewSym(gi, name, ver, r.unit, t)
if needReloc {
nr += r.NReloc(i)
}
Cherry Zhang
committed
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
// is that if the linker decides it wants to update the contents of
// 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)
sname := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
sver := abiToVer(osym.ABI(), r.version)
skind := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
// Create new symbol, update version and kind.
pi := l.newPayload(sname, sver)
pp := l.payloads[pi]
pp.kind = skind
pp.ver = sver
pp.size = int64(osym.Siz())
pp.objidx = r.objidx
// 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()) {
// Copy relocations
relocs := l.Relocs(symIdx)
pp.relocs = make([]goobj2.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.At2(i)
pp.relocs[i].Set(rel.Off(), rel.Siz(), 0, rel.Add(), goobj2.SymRef{PkgIdx: 0, SymIdx: uint32(rel.Sym())})
pp.reltypes[i] = rel.Type()
}
// Copy data
pp.data = r.Data(li)
}
// If we're overriding a data symbol, collect the associated
// Gotype, so as to propagate it to the new symbol.
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.extReader.syms = append(l.extReader.syms, symIdx)
}
// Copy the payload of symbol src to dst. Both src and dst must be external
// symbols.
// The intended use case is that when building/linking against a shared library,
// where we do symbol name mangling, the Go object file may have reference to
// the original symbol name whereas the shared library provides a symbol with
// the mangled name. When we do mangling, we copy payload of mangled to original.
func (l *Loader) CopySym(src, dst Sym) {
if !l.IsExternal(dst) {
panic("dst is not external") //l.newExtSym(l.SymName(dst), l.SymVersion(dst))
}
if !l.IsExternal(src) {
panic("src is not external") //l.cloneToExternal(src)
}
l.payloads[l.extIndex(dst)] = l.payloads[l.extIndex(src)]
l.SetSymPkg(dst, l.SymPkg(src))
// TODO: other attributes?
}
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
// 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))
}
// migrateAttributes copies over all of the attributes of symbol 'src' to
// sym.Symbol 'dst'.
func (l *Loader) migrateAttributes(src Sym, dst *sym.Symbol) {
Cherry Zhang
committed
dst.Value = l.SymValue(src)
dst.Align = l.SymAlign(src)
dst.Sect = l.SymSect(src)
Cherry Zhang
committed
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]
// relocsym's foldSubSymbolOffset requires that we only
// have a single level of containment-- enforce here.
if l.outer[outer] != 0 {
panic("multiply nested outer syms")
}
}
// 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
}
}
Than McIntosh
committed
// 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 {
return l.newExtSym(name, ver)
}
// CreateStaticSym creates a new static symbol with the specified name
// 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.
l.anonVersion--
return l.newExtSym(name, l.anonVersion)
Than McIntosh
committed
}
func (l *Loader) FreeSym(i Sym) {
if l.IsExternal(i) {
pp := l.getPayload(i)
*pp = extSymPayload{}
}
}
Cherry Zhang
committed
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
}
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.
size := osym.Siz()
// Symbol data
// Relocs
Cherry Zhang
committed
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)
}
Cherry Zhang
committed
if needExtReloc {
l.convertExtRelocs(s, gi)
}
// Aux symbol info
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)
}
}
}
Cherry Zhang
committed
// 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
}
Cherry Zhang
committed
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:]
Cherry Zhang
committed
relocs := l.Relocs(src)
for i := range dst.R {
Cherry Zhang
committed
er := &extRelocs[i]
sr := relocs.At2(er.Idx)
r := &dst.R[i]
r.RelocExt = &l.relocExtBatch[0]
l.relocExtBatch = l.relocExtBatch[1:]
Cherry Zhang
committed
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
}
}
}
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
// relocId is essentially a <S,R> tuple identifying the Rth
// relocation of symbol S.
type relocId struct {
sym Sym
ridx int
}
// SetRelocVariant sets the 'variant' property of a relocation on
// some specific symbol.
func (l *Loader) SetRelocVariant(s Sym, ri int, v sym.RelocVariant) {
// sanity check
if relocs := l.Relocs(s); ri >= relocs.Count() {
panic("invalid relocation ID")
}
if l.relocVariant == nil {
l.relocVariant = make(map[relocId]sym.RelocVariant)
}
if v != 0 {
l.relocVariant[relocId{s, ri}] = v
} else {
delete(l.relocVariant, relocId{s, ri})
}
}
// RelocVariant returns the 'variant' property of a relocation on
// some specific symbol.
func (l *Loader) RelocVariant(s Sym, ri int) sym.RelocVariant {
return l.relocVariant[relocId{s, ri}]
}
// UndefinedRelocTargets iterates through the global symbol index
// 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 si := Sym(1); si < Sym(len(l.objSyms)); si++ {
relocs := l.Relocs(si)
for ri := 0; ri < relocs.Count(); ri++ {
r := relocs.At2(ri)
rs := r.Sym()
if rs != 0 && l.SymType(rs) == sym.SXREF && l.RawSymName(rs) != ".got" {
result = append(result, rs)
if limit != -1 && len(result) >= limit {
break
}
}
}
}
return result
}
// AssignTextSymbolOrder populates the Textp2 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.
for _, lib := range libs {
if len(lib.Textp2) != 0 {
panic("expected empty Textp2 slice for library")
}
if len(lib.DupTextSyms2) != 0 {
panic("expected empty DupTextSyms2 slice for library")
}
}
// Used to record which dupok symbol we've assigned to a unit.
// Can't use the onlist attribute here because it will need to
// clear for the later assignment of the sym.Symbol to a unit.
// NB: we can convert to using onList once we no longer have to
// call the regular addToTextp.
assignedToUnit := MakeBitmap(l.NSym() + 1)
// Start off textp2 with reachable external syms.
textp2 := []Sym{}
for _, sym := range extsyms {
if !l.attrReachable.Has(sym) {
continue
}
textp2 = append(textp2, 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:] {
r := o.r
lib := r.unit.Lib
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
gi := l.toGlobal(r, i)
if !l.attrReachable.Has(gi) {
continue
}
st := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
if st != sym.STEXT {
continue
}
dupok := osym.Dupok()
if r2, i2 := l.toLocal(gi); r2 != r || i2 != i {
// A dupok text symbol is resolved to another package.
// 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))
continue // symbol in different object
}
if dupok {
lib.DupTextSyms2 = append(lib.DupTextSyms2, sym.LoaderSym(gi))
continue
}
lib.Textp2 = append(lib.Textp2, sym.LoaderSym(gi))
}
}
// Now assemble global textp, and assign text symbols to units.
for _, doInternal := range [2]bool{true, false} {
for idx, lib := range libs {
if intlibs[idx] != doInternal {
continue
}