Skip to content
Snippets Groups Projects
loader.go 77.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
    // 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
    }
    
    // SetAttrSpecial sets the "special" property for a symbol (see
    // AttrSpecial).
    func (l *Loader) SetAttrSpecial(i Sym, v bool) {
    	if v {
    		l.attrSpecial[i] = struct{}{}
    	} else {
    		delete(l.attrSpecial, i)
    	}
    }
    
    // AttrCgoExportDynamic returns true for a symbol that has been
    // specially marked via the "cgo_export_dynamic" compiler directive
    // written by cgo (in response to //export directives in the source).
    func (l *Loader) AttrCgoExportDynamic(i Sym) bool {
    	_, ok := l.attrCgoExportDynamic[i]
    	return ok
    }
    
    // SetAttrCgoExportDynamic sets the "cgo_export_dynamic" for a symbol
    // (see AttrCgoExportDynamic).
    func (l *Loader) SetAttrCgoExportDynamic(i Sym, v bool) {
    	if v {
    		l.attrCgoExportDynamic[i] = struct{}{}
    	} else {
    		delete(l.attrCgoExportDynamic, i)
    	}
    }
    
    // AttrCgoExportStatic returns true for a symbol that has been
    // specially marked via the "cgo_export_static" directive
    // written by cgo.
    func (l *Loader) AttrCgoExportStatic(i Sym) bool {
    	_, ok := l.attrCgoExportStatic[i]
    	return ok
    }
    
    
    // SetAttrCgoExportStatic sets the "cgo_export_static" for a symbol
    
    // (see AttrCgoExportStatic).
    func (l *Loader) SetAttrCgoExportStatic(i Sym, v bool) {
    	if v {
    		l.attrCgoExportStatic[i] = struct{}{}
    	} else {
    		delete(l.attrCgoExportStatic, i)
    	}
    }
    
    
    // IsGeneratedSym returns true if a symbol's been previously marked as a
    // generator symbol through the SetIsGeneratedSym. The functions for generator
    // symbols are kept in the Link context.
    func (l *Loader) IsGeneratedSym(i Sym) bool {
    	_, ok := l.generatedSyms[i]
    	return ok
    }
    
    // SetIsGeneratedSym marks symbols as generated symbols. Data shouldn't be
    // stored in generated symbols, and a function is registered and called for
    // each of these symbols.
    func (l *Loader) SetIsGeneratedSym(i Sym, v bool) {
    	if !l.IsExternal(i) {
    		panic("only external symbols can be generated")
    	}
    	if v {
    		l.generatedSyms[i] = struct{}{}
    	} else {
    		delete(l.generatedSyms, i)
    	}
    }
    
    
    func (l *Loader) AttrCgoExport(i Sym) bool {
    	return l.AttrCgoExportDynamic(i) || l.AttrCgoExportStatic(i)
    }
    
    
    // AttrReadOnly returns true for a symbol whose underlying data
    // is stored via a read-only mmap.
    func (l *Loader) AttrReadOnly(i Sym) bool {
    	if v, ok := l.attrReadOnly[i]; ok {
    		return v
    	}
    
    		pp := l.getPayload(i)
    		if pp.objidx != 0 {
    			return l.objs[pp.objidx].r.ReadOnly()
    		}
    
    		return false
    	}
    	r, _ := l.toLocal(i)
    	return r.ReadOnly()
    }
    
    
    // SetAttrReadOnly sets the "data is read only" property for a symbol
    
    // (see AttrReadOnly).
    func (l *Loader) SetAttrReadOnly(i Sym, v bool) {
    	l.attrReadOnly[i] = v
    }
    
    
    // AttrSubSymbol returns true for symbols that are listed as a
    // sub-symbol of some other outer symbol. The sub/outer mechanism is
    // used when loading host objects (sections from the host object
    // become regular linker symbols and symbols go on the Sub list of
    // their section) and for constructing the global offset table when
    // internally linking a dynamic executable.
    
    //
    // Note that in later stages of the linker, we set Outer(S) to some
    // container symbol C, but don't set Sub(C). Thus we have two
    // distinct scenarios:
    //
    // - Outer symbol covers the address ranges of its sub-symbols.
    //   Outer.Sub is set in this case.
    // - Outer symbol doesn't conver the address ranges. It is zero-sized
    //   and doesn't have sub-symbols. In the case, the inner symbol is
    //   not actually a "SubSymbol". (Tricky!)
    //
    // This method returns TRUE only for sub-symbols in the first scenario.
    //
    // FIXME: would be better to do away with this and have a better way
    // to represent container symbols.
    
    
    func (l *Loader) AttrSubSymbol(i Sym) bool {
    	// we don't explicitly store this attribute any more -- return
    	// a value based on the sub-symbol setting.
    
    	o := l.OuterSym(i)
    	if o == 0 {
    		return false
    	}
    	return l.SubSym(o) != 0
    
    // Note that we don't have a 'SetAttrSubSymbol' method in the loader;
    
    // clients should instead use the AddInteriorSym method to establish
    // containment relationships for host object symbols.
    
    // Returns whether the i-th symbol has ReflectMethod attribute set.
    func (l *Loader) IsReflectMethod(i Sym) bool {
    
    	return l.SymAttr(i)&goobj.SymFlagReflectMethod != 0
    
    // Returns whether the i-th symbol is nosplit.
    func (l *Loader) IsNoSplit(i Sym) bool {
    
    	return l.SymAttr(i)&goobj.SymFlagNoSplit != 0
    
    // Returns whether this is a Go type symbol.
    func (l *Loader) IsGoType(i Sym) bool {
    
    	return l.SymAttr(i)&goobj.SymFlagGoType != 0
    
    // Returns whether this symbol should be included in typelink.
    func (l *Loader) IsTypelink(i Sym) bool {
    
    	return l.SymAttr(i)&goobj.SymFlagTypelink != 0
    
    // Returns whether this symbol is an itab symbol.
    func (l *Loader) IsItab(i Sym) bool {
    	if l.IsExternal(i) {
    		return false
    
    	r, li := l.toLocal(i)
    	return r.Sym(li).IsItab()
    
    // Return whether this is a trampoline of a deferreturn call.
    func (l *Loader) IsDeferReturnTramp(i Sym) bool {
    	return l.deferReturnTramp[i]
    }
    
    // Set that i is a trampoline of a deferreturn call.
    func (l *Loader) SetIsDeferReturnTramp(i Sym, v bool) {
    	l.deferReturnTramp[i] = v
    }
    
    
    // growValues grows the slice used to store symbol values.
    func (l *Loader) growValues(reqLen int) {
    	curLen := len(l.values)
    	if reqLen > curLen {
    		l.values = append(l.values, make([]int64, reqLen+1-curLen)...)
    	}
    }
    
    // SymValue returns the value of the i-th symbol. i is global index.
    func (l *Loader) SymValue(i Sym) int64 {
    	return l.values[i]
    }
    
    // SetSymValue sets the value of the i-th symbol. i is global index.
    func (l *Loader) SetSymValue(i Sym, val int64) {
    	l.values[i] = val
    }
    
    
    // AddToSymValue adds to the value of the i-th symbol. i is the global index.
    func (l *Loader) AddToSymValue(i Sym, val int64) {
    	l.values[i] += val
    }
    
    
    // Returns the symbol content of the i-th symbol. i is global index.
    func (l *Loader) Data(i Sym) []byte {
    
    // FreeData clears the symbol data of an external symbol, allowing the memory
    // to be freed earlier. No-op for non-external symbols.
    
    func (l *Loader) FreeData(i Sym) {
    
    	if l.IsExternal(i) {
    		pp := l.getPayload(i)
    		if pp != nil {
    
    			pp.data = nil
    
    // SymAlign returns the alignment for a symbol.
    func (l *Loader) SymAlign(i Sym) int32 {
    
    	if int(i) >= len(l.align) {
    		// align is extended lazily -- it the sym in question is
    		// outside the range of the existing slice, then we assume its
    		// alignment has not yet been set.
    		return 0
    
    	}
    	// TODO: would it make sense to return an arch-specific
    	// alignment depending on section type? E.g. STEXT => 32,
    	// SDATA => 1, etc?
    
    	abits := l.align[i]
    	if abits == 0 {
    		return 0
    	}
    	return int32(1 << (abits - 1))
    
    }
    
    // SetSymAlign sets the alignment for a symbol.
    func (l *Loader) SetSymAlign(i Sym, align int32) {
    	// Reject nonsense alignments.
    
    		panic("bad alignment value")
    	}
    
    	if int(i) >= len(l.align) {
    		l.align = append(l.align, make([]uint8, l.NSym()-len(l.align))...)
    	}
    
    	l.align[i] = uint8(bits.Len32(uint32(align)))
    
    // SymValue returns the section of the i-th symbol. i is global index.
    func (l *Loader) SymSect(i Sym) *sym.Section {
    
    	if int(i) >= len(l.symSects) {
    		// symSects is extended lazily -- it the sym in question is
    		// outside the range of the existing slice, then we assume its
    		// section has not yet been set.
    		return nil
    	}
    
    // 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))...)
    	}
    	l.symSects[i] = sect.Index
    }
    
    // growSects grows the slice used to store symbol sections.
    func (l *Loader) growSects(reqLen int) {
    	curLen := len(l.symSects)
    	if reqLen > curLen {
    		l.symSects = append(l.symSects, make([]uint16, reqLen+1-curLen)...)
    	}
    }
    
    // NewSection creates a new (output) section.
    func (l *Loader) NewSection() *sym.Section {
    	sect := new(sym.Section)
    	idx := len(l.sects)
    	if idx != int(uint16(idx)) {
    		panic("too many sections created")
    	}
    	sect.Index = uint16(idx)
    	l.sects = append(l.sects, sect)
    	return sect
    
    // SymDynImplib returns the "dynimplib" attribute for the specified
    // symbol, making up a portion of the info for a symbol specified
    // on a "cgo_import_dynamic" compiler directive.
    func (l *Loader) SymDynimplib(i Sym) string {
    	return l.dynimplib[i]
    }
    
    // SetSymDynimplib sets the "dynimplib" attribute for a symbol.
    func (l *Loader) SetSymDynimplib(i Sym, value string) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetDynimplib")
    	}
    	if value == "" {
    		delete(l.dynimplib, i)
    	} else {
    		l.dynimplib[i] = value
    	}
    }
    
    // SymDynimpvers returns the "dynimpvers" attribute for the specified
    // symbol, making up a portion of the info for a symbol specified
    // on a "cgo_import_dynamic" compiler directive.
    func (l *Loader) SymDynimpvers(i Sym) string {
    	return l.dynimpvers[i]
    }
    
    // SetSymDynimpvers sets the "dynimpvers" attribute for a symbol.
    func (l *Loader) SetSymDynimpvers(i Sym, value string) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetDynimpvers")
    	}
    	if value == "" {
    		delete(l.dynimpvers, i)
    	} else {
    		l.dynimpvers[i] = value
    	}
    }
    
    // SymExtname returns the "extname" value for the specified
    // symbol.
    func (l *Loader) SymExtname(i Sym) string {
    
    	if s, ok := l.extname[i]; ok {
    		return s
    	}
    	return l.SymName(i)
    
    }
    
    // SetSymExtname sets the  "extname" attribute for a symbol.
    func (l *Loader) SetSymExtname(i Sym, value string) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetExtname")
    	}
    	if value == "" {
    		delete(l.extname, i)
    	} else {
    		l.extname[i] = value
    	}
    }
    
    
    // SymElfType returns the previously recorded ELF type for a symbol
    // (used only for symbols read from shared libraries by ldshlibsyms).
    // It is not set for symbols defined by the packages being linked or
    // by symbols read by ldelf (and so is left as elf.STT_NOTYPE).
    func (l *Loader) SymElfType(i Sym) elf.SymType {
    	if et, ok := l.elfType[i]; ok {
    		return et
    	}
    	return elf.STT_NOTYPE
    }
    
    
    // SetSymElfType sets the elf type attribute for a symbol.
    
    func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetSymElfType")
    	}
    	if et == elf.STT_NOTYPE {
    		delete(l.elfType, i)
    	} else {
    		l.elfType[i] = et
    	}
    }
    
    
    // SymElfSym returns the ELF symbol index for a given loader
    // symbol, assigned during ELF symtab generation.
    func (l *Loader) SymElfSym(i Sym) int32 {
    	return l.elfSym[i]
    }
    
    // SetSymElfSym sets the elf symbol index for a symbol.
    func (l *Loader) SetSymElfSym(i Sym, es int32) {
    	if i == 0 {
    		panic("bad sym index")
    	}
    	if es == 0 {
    		delete(l.elfSym, i)
    	} else {
    		l.elfSym[i] = es
    	}
    }
    
    // SymLocalElfSym returns the "local" ELF symbol index for a given loader
    // symbol, assigned during ELF symtab generation.
    func (l *Loader) SymLocalElfSym(i Sym) int32 {
    	return l.localElfSym[i]
    }
    
    // SetSymLocalElfSym sets the "local" elf symbol index for a symbol.
    func (l *Loader) SetSymLocalElfSym(i Sym, es int32) {
    	if i == 0 {
    		panic("bad sym index")
    	}
    	if es == 0 {
    		delete(l.localElfSym, i)
    	} else {
    		l.localElfSym[i] = es
    	}
    }
    
    
    // SymPlt returns the plt value for pe symbols.
    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.
    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.
    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.
    func (l *Loader) SetGot(i Sym, v int32) {
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    // SymDynid returns the "dynid" property for the specified symbol.
    func (l *Loader) SymDynid(i Sym) int32 {
    	if s, ok := l.dynid[i]; ok {
    		return s
    	}
    	return -1
    }
    
    // SetSymDynid sets the "dynid" property for a symbol.
    func (l *Loader) SetSymDynid(i Sym, val int32) {
    	// reject bad symbols
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    		panic("bad symbol index in SetSymDynid")
    	}
    	if val == -1 {
    		delete(l.dynid, i)
    	} else {
    		l.dynid[i] = val
    	}
    }
    
    
    // DynIdSyms returns the set of symbols for which dynID is set to an
    // interesting (non-default) value. This is expected to be a fairly
    // small set.
    func (l *Loader) DynidSyms() []Sym {
    	sl := make([]Sym, 0, len(l.dynid))
    	for s := range l.dynid {
    		sl = append(sl, s)
    	}
    
    	sort.Slice(sl, func(i, j int) bool { return sl[i] < sl[j] })
    
    // SymGoType returns the 'Gotype' property for a given symbol (set by
    // the Go compiler for variable symbols). This version relies on
    // reading aux symbols for the target sym -- it could be that a faster
    // approach would be to check for gotype during preload and copy the
    // results in to a map (might want to try this at some point and see
    // if it helps speed things up).
    func (l *Loader) SymGoType(i Sym) Sym {
    
    	var auxs []goobj.Aux
    
    	if l.IsExternal(i) {
    		pp := l.getPayload(i)
    
    		r = l.objs[pp.objidx].r
    		auxs = pp.auxs
    	} else {
    
    		r, li = l.toLocal(i)
    		auxs = r.Auxs(li)
    
    	for j := range auxs {
    		a := &auxs[j]
    		switch a.Type() {
    
    		case goobj.AuxGotype:
    
    		}
    	}
    	return 0
    }
    
    // SymUnit returns the compilation unit for a given symbol (which will
    // typically be nil for external or linker-manufactured symbols).
    func (l *Loader) SymUnit(i Sym) *sym.CompilationUnit {
    	if l.IsExternal(i) {
    		pp := l.getPayload(i)
    		if pp.objidx != 0 {
    			r := l.objs[pp.objidx].r
    			return r.unit
    		}
    		return nil
    	}
    	r, _ := l.toLocal(i)
    	return r.unit
    }
    
    
    // SymPkg returns the package where the symbol came from (for
    // regular compiler-generated Go symbols), but in the case of
    // building with "-linkshared" (when a symbol is read from a
    // shared library), will hold the library name.
    // NOTE: this correspondes to sym.Symbol.File field.
    func (l *Loader) SymPkg(i Sym) string {
    
    	if f, ok := l.symPkg[i]; ok {
    		return f
    	}
    
    	if l.IsExternal(i) {
    		pp := l.getPayload(i)
    		if pp.objidx != 0 {
    			r := l.objs[pp.objidx].r
    
    // SetSymPkg sets the package/library for a symbol. This is
    
    // needed mainly for external symbols, specifically those imported
    // from shared libraries.
    
    func (l *Loader) SetSymPkg(i Sym, pkg string) {
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetSymPkg")
    
    // SymLocalentry returns the "local entry" value for the specified
    // symbol.
    func (l *Loader) SymLocalentry(i Sym) uint8 {
    	return l.localentry[i]
    }
    
    
    // SetSymLocalentry sets the "local entry" attribute for a symbol.
    
    func (l *Loader) SetSymLocalentry(i Sym, value uint8) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetSymLocalentry")
    
    	}
    	if value == 0 {
    		delete(l.localentry, i)
    	} else {
    		l.localentry[i] = value
    	}
    }
    
    
    // Returns the number of aux symbols given a global index.
    func (l *Loader) NAux(i Sym) int {
    
    // Returns the "handle" to the j-th aux symbol of the i-th symbol.
    
    func (l *Loader) Aux(i Sym, j int) Aux {
    
    	return Aux{r.Aux(li, j), r, l}
    
    // GetFuncDwarfAuxSyms collects and returns the auxiliary DWARF
    // symbols associated with a given function symbol.  Prior to the
    // introduction of the loader, this was done purely using name
    // lookups, e.f. for function with name XYZ we would then look up
    // go.info.XYZ, etc.
    func (l *Loader) GetFuncDwarfAuxSyms(fnSymIdx Sym) (auxDwarfInfo, auxDwarfLoc, auxDwarfRanges, auxDwarfLines Sym) {
    	if l.SymType(fnSymIdx) != sym.STEXT {
    		log.Fatalf("error: non-function sym %d/%s t=%s passed to GetFuncDwarfAuxSyms", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
    	}
    	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)
    
    	for i := range auxs {
    		a := &auxs[i]
    		switch a.Type() {
    
    		case goobj.AuxDwarfInfo:
    
    			auxDwarfInfo = l.resolve(r, a.Sym())
    
    			if l.SymType(auxDwarfInfo) != sym.SDWARFFCN {
    
    				panic("aux dwarf info sym with wrong type")
    			}
    
    		case goobj.AuxDwarfLoc:
    
    			auxDwarfLoc = l.resolve(r, a.Sym())
    
    			if l.SymType(auxDwarfLoc) != sym.SDWARFLOC {
    				panic("aux dwarf loc sym with wrong type")
    			}
    
    		case goobj.AuxDwarfRanges:
    
    			auxDwarfRanges = l.resolve(r, a.Sym())
    
    			if l.SymType(auxDwarfRanges) != sym.SDWARFRANGE {
    				panic("aux dwarf ranges sym with wrong type")
    			}
    
    		case goobj.AuxDwarfLines:
    
    			auxDwarfLines = l.resolve(r, a.Sym())
    
    			if l.SymType(auxDwarfLines) != sym.SDWARFLINES {
    				panic("aux dwarf lines sym with wrong type")
    			}
    		}
    	}
    	return
    }
    
    
    // AddInteriorSym sets up 'interior' as an interior symbol of
    // container/payload symbol 'container'. An interior symbol does not
    // itself have data, but gives a name to a subrange of the data in its
    // container symbol. The container itself may or may not have a name.
    // This method is intended primarily for use in the host object
    // loaders, to capture the semantics of symbols and sections in an
    // object file. When reading a host object file, we'll typically
    // encounter a static section symbol (ex: ".text") containing content
    // for a collection of functions, then a series of ELF (or macho, etc)
    // symbol table entries each of which points into a sub-section
    // (offset and length) of its corresponding container symbol. Within
    // the go linker we create a loader.Sym for the container (which is
    // expected to have the actual content/payload) and then a set of
    // interior loader.Sym's that point into a portion of the container.
    func (l *Loader) AddInteriorSym(container Sym, interior Sym) {
    	// Container symbols are expected to have content/data.
    	// NB: this restriction may turn out to be too strict (it's possible
    	// to imagine a zero-sized container with an interior symbol pointing
    	// into it); it's ok to relax or remove it if we counter an
    	// oddball host object that triggers this.
    	if l.SymSize(container) == 0 && len(l.Data(container)) == 0 {
    		panic("unexpected empty container symbol")
    	}
    	// The interior symbols for a container are not expected to have
    	// content/data or relocations.
    	if len(l.Data(interior)) != 0 {
    		panic("unexpected non-empty interior symbol")
    	}
    	// Interior symbol is expected to be in the symbol table.
    	if l.AttrNotInSymbolTable(interior) {
    		panic("interior symbol must be in symtab")
    	}
    	// Only a single level of containment is allowed.
    	if l.OuterSym(container) != 0 {
    
    	// Interior sym should not already have a sibling.
    	if l.SubSym(interior) != 0 {
    
    	// Interior sym should not already point at a container.
    	if l.OuterSym(interior) != 0 {
    
    	l.sub[interior] = l.sub[container]
    	l.sub[container] = interior
    	l.outer[interior] = container
    
    // OuterSym gets the outer symbol for host object loaded symbols.
    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]
    
    // SetCarrierSym declares that 'c' is the carrier or container symbol
    // for 's'. Carrier symbols are used in the linker to as a container
    // for a collection of sub-symbols where the content of the
    // sub-symbols is effectively concatenated to form the content of the
    // carrier. The carrier is given a name in the output symbol table
    // while the sub-symbol names are not. For example, the Go compiler
    // emits named string symbols (type SGOSTRING) when compiling a
    // package; after being deduplicated, these symbols are collected into
    // a single unit by assigning them a new carrier symbol named
    // "go.string.*" (which appears in the final symbol table for the
    // output load module).
    func (l *Loader) SetCarrierSym(s Sym, c Sym) {
    	if c == 0 {
    		panic("invalid carrier in SetCarrierSym")
    	}
    	if s == 0 {
    		panic("invalid sub-symbol in SetCarrierSym")
    	}
    	// Carrier symbols are not expected to have content/data. It is
    	// ok for them to have non-zero size (to allow for use of generator
    	// symbols).
    	if len(l.Data(c)) != 0 {
    		panic("unexpected non-empty carrier symbol")
    	}
    	l.outer[s] = c
    	// relocsym's foldSubSymbolOffset requires that we only
    	// have a single level of containment-- enforce here.
    	if l.outer[c] != 0 {
    		panic("invalid nested carrier sym")
    
    // Initialize Reachable bitmap and its siblings for running deadcode pass.
    
    func (l *Loader) InitReachable() {
    
    	l.growAttrBitmaps(l.NSym() + 1)
    
    type symWithVal struct {
    	s Sym
    	v int64
    }
    type bySymValue []symWithVal
    
    func (s bySymValue) Len() int           { return len(s) }
    func (s bySymValue) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    func (s bySymValue) Less(i, j int) bool { return s[i].v < s[j].v }
    
    // SortSub walks through the sub-symbols for 's' and sorts them
    // in place by increasing value. Return value is the new
    // sub symbol for the specified outer symbol.
    func (l *Loader) SortSub(s Sym) Sym {
    
    	if s == 0 || l.sub[s] == 0 {
    		return s
    	}
    
    	// Sort symbols using a slice first. Use a stable sort on the off
    	// chance that there's more than once symbol with the same value,
    	// so as to preserve reproducible builds.
    	sl := []symWithVal{}
    	for ss := l.sub[s]; ss != 0; ss = l.sub[ss] {
    		sl = append(sl, symWithVal{s: ss, v: l.SymValue(ss)})
    	}
    	sort.Stable(bySymValue(sl))
    
    	// Then apply any changes needed to the sub map.
    	ns := Sym(0)
    	for i := len(sl) - 1; i >= 0; i-- {
    		s := sl[i].s
    		l.sub[s] = ns
    		ns = s
    	}
    
    	// Update sub for outer symbol, then return
    	l.sub[s] = sl[0].s
    	return sl[0].s
    }
    
    
    // SortSyms sorts a list of symbols by their value.
    func (l *Loader) SortSyms(ss []Sym) {
    	sort.SliceStable(ss, func(i, j int) bool { return l.SymValue(ss[i]) < l.SymValue(ss[j]) })
    }
    
    
    // Insure that reachable bitmap and its siblings have enough size.
    func (l *Loader) growAttrBitmaps(reqLen int) {
    
    	if reqLen > l.attrReachable.Len() {
    
    		// These are indexed by global symbol
    		l.attrReachable = growBitmap(reqLen, l.attrReachable)
    
    		l.attrOnList = growBitmap(reqLen, l.attrOnList)
    
    		l.attrLocal = growBitmap(reqLen, l.attrLocal)
    
    		l.attrNotInSymbolTable = growBitmap(reqLen, l.attrNotInSymbolTable)
    
    		l.attrUsedInIface = growBitmap(reqLen, l.attrUsedInIface)
    
    	l.growExtAttrBitmaps()
    }
    
    func (l *Loader) growExtAttrBitmaps() {
    	// These are indexed by external symbol index (e.g. l.extIndex(i))
    	extReqLen := len(l.payloads)
    
    	if extReqLen > l.attrVisibilityHidden.Len() {
    
    		l.attrVisibilityHidden = growBitmap(extReqLen, l.attrVisibilityHidden)
    		l.attrDuplicateOK = growBitmap(extReqLen, l.attrDuplicateOK)
    		l.attrShared = growBitmap(extReqLen, l.attrShared)
    		l.attrExternal = growBitmap(extReqLen, l.attrExternal)
    
    func (relocs *Relocs) Count() int { return len(relocs.rs) }
    
    
    // At returns the j-th reloc for a global symbol.
    func (relocs *Relocs) At(j int) Reloc {
    
    		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, 0}
    
    // Relocs returns a Relocs object for the given global sym.
    func (l *Loader) Relocs(i Sym) Relocs {
    
    	if r == nil {
    		panic(fmt.Sprintf("trying to get oreader for invalid sym %d\n\n", i))
    	}
    
    	return l.relocs(r, li)
    }
    
    // Relocs returns a Relocs object given a local sym index and reader.
    
    func (l *Loader) relocs(r *oReader, li uint32) Relocs {
    
    	var rs []goobj.Reloc
    
    	if l.isExtReader(r) {
    		pp := l.payloads[li]
    
    		rs = r.Relocs(li)
    
    // FuncInfo provides hooks to access goobj.FuncInfo in the objects.
    
    	auxs    []goobj.Aux
    	lengths goobj.FuncInfoLengths
    
    }
    
    func (fi *FuncInfo) Valid() bool { return fi.r != nil }
    
    
    func (fi *FuncInfo) Args() int {
    
    	return int((*goobj.FuncInfo)(nil).ReadArgs(fi.data))
    
    	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) Pcline() Sym {
    	sym := (*goobj.FuncInfo)(nil).ReadPcline(fi.data)
    	return fi.l.resolve(fi.r, sym)
    }
    
    func (fi *FuncInfo) Pcinline() Sym {
    	sym := (*goobj.FuncInfo)(nil).ReadPcinline(fi.data)
    	return fi.l.resolve(fi.r, sym)
    
    }
    
    // Preload has to be called prior to invoking the various methods
    // below related to pcdata, funcdataoff, files, and inltree nodes.
    func (fi *FuncInfo) Preload() {
    
    	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])
    
    }
    
    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 fi.lengths.NumFile
    }
    
    
    func (fi *FuncInfo) File(k int) goobj.CUFileIndex {
    
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    
    	return (*goobj.FuncInfo)(nil).ReadFile(fi.data, fi.lengths.FileOff, uint32(k))
    
    	File     goobj.CUFileIndex
    
    	Line     int32
    	Func     Sym
    	ParentPC int32
    }
    
    func (fi *FuncInfo) NumInlTree() uint32 {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	return fi.lengths.NumInlTree
    }
    
    func (fi *FuncInfo) InlTree(k int) InlTreeNode {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    
    	node := (*goobj.FuncInfo)(nil).ReadInlTree(fi.data, fi.lengths.InlTreeOff, uint32(k))
    
    	return InlTreeNode{
    		Parent:   node.Parent,
    
    		Line:     node.Line,
    		Func:     fi.l.resolve(fi.r, node.Func),
    		ParentPC: node.ParentPC,
    	}
    }
    
    	var auxs []goobj.Aux