Skip to content
Snippets Groups Projects
loader.go 86.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		// 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)
    
    		case "$f64.", "$i64.":
    
    			log.Panicf("unrecognized $-symbol: %s", name)
    
    func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
    
    
    	nr := 0 // total number of sym.Reloc's we'll need
    
    		nr += loadObjSyms(l, syms, o.r)
    
    	// 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 {
    
    			continue
    		}
    		pp := l.getPayload(i)
    		nr += len(pp.relocs)
    		// 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().
    
    		l.installSym(i, s)
    		toConvert = append(toConvert, i)
    	}
    
    	// allocate a single large slab of relocations for all live symbols
    
    	if needReloc {
    		l.relocBatch = make([]sym.Reloc, 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)
    		}
    
    		// Transfer over attributes.
    		l.migrateAttributes(i, s)
    
    	// 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.
    
    	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
    	l.relocVariant = nil
    	l.extRelocs = 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.
    func (l *Loader) ResolveABIAlias(s Sym) Sym {
    
    	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
    }
    
    
    // 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)
    
    			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 {
    
    				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
    
    			}
    		}
    		result = append(result, s)
    
    		// Always copy these from new to old.
    		s.Value = l.SymValue(cand)
    
    
    		// 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)
    
    // 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()
    
    		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.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")
    
    // 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
    
    // 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.
    func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
    	nr := 0
    
    	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
    		}
    
    		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.
    
    		l.addNewSym(gi, name, ver, r.unit, t)
    
    // 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")
    	}
    
    
    	// Read the particulars from object.
    	r, li := l.toLocal(symIdx)
    
    	osym := r.Sym(li)
    
    	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]
    
    
    	// 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()
    		}
    
    	// If we're overriding a data symbol, collect the associated
    	// Gotype, so as to propagate it to the new symbol.
    
    	auxs := r.Auxs(li)
    
    	for j := range auxs {
    		a := &auxs[j]
    		switch a.Type() {
    
    			pp.gotype = l.resolve(r, a.Sym())
    
    	// 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))
    
    // 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) {
    
    	dst.Value = l.SymValue(src)
    	dst.Align = l.SymAlign(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 {
    	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)
    
    func (l *Loader) FreeSym(i Sym) {
    	if l.IsExternal(i) {
    		pp := l.getPayload(i)
    		*pp = extSymPayload{}
    	}
    }
    
    
    func loadObjFull(l *Loader, r *oReader, needReloc 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
    
    		l.migrateAttributes(gi, s)
    		// Be careful not to overwrite attributes set by the linker.
    		// Don't use the attributes from the object file.
    
    
    		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)
    		}
    
    		auxs := r.Auxs(i)
    
    		for j := range auxs {
    			a := &auxs[j]
    			switch a.Type() {
    
    			case goobj2.AuxFuncInfo, goobj2.AuxFuncdata, goobj2.AuxGotype:
    
    			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) {
    
    		r := src.At2(j)
    		rs := r.Sym()
    		sz := r.Siz()
    		rt := r.Type()
    
    			if l.attrReachable.Has(rs) {
    
    		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)
    
    		if strict && rs != 0 && l.Syms[rs] == nil && rt != objabi.R_USETYPE {
    			panic("nil reloc target in convertRelocations")
    		}
    
    		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 {
    
    	dst.R = make([]sym.Reloc, len(extRelocs))
    	relocs := l.Relocs(src)
    
    		er := &extRelocs[i]
    		sr := relocs.At2(er.Idx)
    
    		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 {
    	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++ {
    
    		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)
    
    // 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)
    
    			osym := r.Sym(i)
    
    			st := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
    
    			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))
    
    
    			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
    			}
    
    			lists := [2][]sym.LoaderSym{lib.Textp2, lib.DupTextSyms2}
    
    			for i, list := range lists {
    
    					if l.attrReachable.Has(sym) && !assignedToUnit.Has(sym) {
    
    						unit := l.SymUnit(sym)
    						if unit != nil {
    							unit.Textp2 = append(unit.Textp2, s)
    
    							assignedToUnit.Set(sym)
    
    						// Dupok symbols may be defined in multiple packages; the
    						// associated package for a dupok sym is chosen sort of
    						// arbitrarily (the first containing package that the linker
    						// loads). Canonicalizes its Pkg to the package with which
    						// it will be laid down in text.
    						if i == 1 /* DupTextSyms2 */ && l.SymPkg(sym) != lib.Pkg {
    							l.SetSymPkg(sym, lib.Pkg)
    						}
    
    			lib.Textp2 = nil
    			lib.DupTextSyms2 = nil
    
    // ErrorReporter is a helper class for reporting errors.
    type ErrorReporter struct {
    	ldr              *Loader
    	AfterErrorAction func()
    }
    
    // Errorf method logs an error message.
    //
    // After each error, the error actions function will be invoked; this
    // will either terminate the link immediately (if -h option given)
    // or it will keep a count and exit if more than 20 errors have been printed.
    //
    // Logging an error means that on exit cmd/link will delete any
    // output file and return a non-zero error code.
    //
    func (reporter *ErrorReporter) Errorf(s Sym, format string, args ...interface{}) {
    	if s != 0 && reporter.ldr.SymName(s) != "" {
    		format = reporter.ldr.SymName(s) + ": " + format
    	} else {
    		format = fmt.Sprintf("sym %d: %s", s, format)
    	}
    	format += "\n"
    	fmt.Fprintf(os.Stderr, format, args...)
    	reporter.AfterErrorAction()
    }
    
    // GetErrorReporter returns the loader's associated error reporter.
    func (l *Loader) GetErrorReporter() *ErrorReporter {
    	return l.errorReporter
    }
    
    // Errorf method logs an error message. See ErrorReporter.Errorf for details.
    func (l *Loader) Errorf(s Sym, format string, args ...interface{}) {
    
    	l.errorReporter.Errorf(s, format, args...)
    
    // For debugging.
    func (l *Loader) Dump() {
    	fmt.Println("objs")
    	for _, obj := range l.objs {
    		if obj.r != nil {
    			fmt.Println(obj.i, obj.r.unit.Lib)
    		}
    	}
    
    	fmt.Println("Nsyms:", len(l.objSyms))
    
    	for i := Sym(1); i < Sym(len(l.objSyms)); i++ {
    
    		pi := interface{}("")
    		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]