]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/link/internal/loader/loader.go
cmd/link/internal/loader: remove some dead code
[gostls13.git] / src / cmd / link / internal / loader / loader.go
index 8fd10b0848da697906505247b838c09841f4c984..5dd657b4d7fc7131a9c8bc8e0108f8654bd94d0b 100644 (file)
@@ -14,6 +14,8 @@ import (
        "cmd/link/internal/sym"
        "debug/elf"
        "fmt"
+       "internal/abi"
+       "io"
        "log"
        "math/bits"
        "os"
@@ -25,7 +27,7 @@ var _ = fmt.Print
 
 // Sym encapsulates a global symbol index, used to identify a specific
 // Go symbol. The 0-valued Sym is corresponds to an invalid symbol.
-type Sym int
+type Sym = sym.LoaderSym
 
 // Relocs encapsulates the set of relocations on a given symbol; an
 // instance of this type is returned by the Loader Relocs() method.
@@ -51,29 +53,14 @@ type Reloc struct {
        *goobj.Reloc
        r *oReader
        l *Loader
-
-       // External reloc types may not fit into a uint8 which the Go object file uses.
-       // Store it here, instead of in the byte of goobj.Reloc.
-       // For Go symbols this will always be zero.
-       // goobj.Reloc.Type() + typ is always the right type, for both Go and external
-       // symbols.
-       typ objabi.RelocType
 }
 
-func (rel Reloc) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) + rel.typ }
-func (rel Reloc) Sym() Sym               { return rel.l.resolve(rel.r, rel.Reloc.Sym()) }
-func (rel Reloc) SetSym(s Sym)           { rel.Reloc.SetSym(goobj.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) }
-
-func (rel Reloc) SetType(t objabi.RelocType) {
-       if t != objabi.RelocType(uint8(t)) {
-               panic("SetType: type doesn't fit into Reloc")
-       }
-       rel.Reloc.SetType(uint8(t))
-       if rel.typ != 0 {
-               // should use SymbolBuilder.SetRelocType
-               panic("wrong method to set reloc type")
-       }
-}
+func (rel Reloc) Type() objabi.RelocType     { return objabi.RelocType(rel.Reloc.Type()) &^ objabi.R_WEAK }
+func (rel Reloc) Weak() bool                 { return objabi.RelocType(rel.Reloc.Type())&objabi.R_WEAK != 0 }
+func (rel Reloc) SetType(t objabi.RelocType) { rel.Reloc.SetType(uint16(t)) }
+func (rel Reloc) Sym() Sym                   { return rel.l.resolve(rel.r, rel.Reloc.Sym()) }
+func (rel Reloc) SetSym(s Sym)               { rel.Reloc.SetSym(goobj.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) }
+func (rel Reloc) IsMarker() bool             { return rel.Siz() == 0 }
 
 // Aux holds a "handle" to access an aux symbol record from an
 // object file.
@@ -90,14 +77,14 @@ func (a Aux) Sym() Sym { return a.l.resolve(a.r, a.Aux.Sym()) }
 type oReader struct {
        *goobj.Reader
        unit         *sym.CompilationUnit
-       version      int    // version of static symbol
-       flags        uint32 // read from object file
+       version      int // version of static symbol
        pkgprefix    string
-       syms         []Sym  // Sym's global index, indexed by local index
-       ndef         int    // cache goobj.Reader.NSym()
-       nhashed64def int    // cache goobj.Reader.NHashed64Def()
-       nhasheddef   int    // cache goobj.Reader.NHashedDef()
-       objidx       uint32 // index of this reader in the objs slice
+       syms         []Sym    // Sym's global index, indexed by local index
+       pkg          []uint32 // indices of referenced package by PkgIdx (index into loader.objs array)
+       ndef         int      // cache goobj.Reader.NSym()
+       nhashed64def int      // cache goobj.Reader.NHashed64Def()
+       nhasheddef   int      // cache goobj.Reader.NHashedDef()
+       objidx       uint32   // index of this reader in the objs slice
 }
 
 // Total number of defined symbols (package symbols, hashed symbols, and
@@ -181,21 +168,21 @@ type symAndSize struct {
 //
 // Notes on the layout of global symbol index space:
 //
-// - Go object files are read before host object files; each Go object
-//   read adds its defined package symbols to the global index space.
-//   Nonpackage symbols are not yet added.
+//   - Go object files are read before host object files; each Go object
+//     read adds its defined package symbols to the global index space.
+//     Nonpackage symbols are not yet added.
 //
-// - In loader.LoadNonpkgSyms, add non-package defined symbols and
-//   references in all object files to the global index space.
+//   - In loader.LoadNonpkgSyms, add non-package defined symbols and
+//     references in all object files to the global index space.
 //
-// - Host object file loading happens; the host object loader does a
-//   name/version lookup for each symbol it finds; this can wind up
-//   extending the external symbol index space range. The host object
-//   loader stores symbol payloads in loader.payloads using SymbolBuilder.
+//   - Host object file loading happens; the host object loader does a
+//     name/version lookup for each symbol it finds; this can wind up
+//     extending the external symbol index space range. The host object
+//     loader stores symbol payloads in loader.payloads using SymbolBuilder.
 //
-// - Each symbol gets a unique global index. For duplicated and
-//   overwriting/overwritten symbols, the second (or later) appearance
-//   of the symbol gets the same global index as the first appearance.
+//   - Each symbol gets a unique global index. For duplicated and
+//     overwriting/overwritten symbols, the second (or later) appearance
+//     of the symbol gets the same global index as the first appearance.
 type Loader struct {
        start       map[*oReader]Sym // map from object file to its start index
        objs        []objIdx         // sorted by start index (i.e. objIdx.i)
@@ -219,7 +206,7 @@ type Loader struct {
 
        deferReturnTramp map[Sym]bool // whether the symbol is a trampoline of a deferreturn call
 
-       objByPkg map[string]*oReader // map package path to its Go object reader
+       objByPkg map[string]uint32 // map package path to the index of its Go object reader
 
        anonVersion int // most recently assigned ext static sym pseudo-version
 
@@ -233,24 +220,19 @@ type Loader struct {
        attrLocal            Bitmap // "local" symbols, indexed by global index
        attrNotInSymbolTable Bitmap // "not in symtab" symbols, indexed by global idx
        attrUsedInIface      Bitmap // "used in interface" symbols, indexed by global idx
+       attrSpecial          Bitmap // "special" frame symbols, indexed by global idx
        attrVisibilityHidden Bitmap // hidden symbols, indexed by ext sym index
        attrDuplicateOK      Bitmap // dupOK symbols, indexed by ext sym index
        attrShared           Bitmap // shared symbols, indexed by ext sym index
        attrExternal         Bitmap // external symbols, indexed by ext sym index
+       generatedSyms        Bitmap // symbols that generate their content, indexed by ext sym idx
 
        attrReadOnly         map[Sym]bool     // readonly data for this sym
-       attrTopFrame         map[Sym]struct{} // top frame symbols
-       attrSpecial          map[Sym]struct{} // "special" frame symbols
        attrCgoExportDynamic map[Sym]struct{} // "cgo_export_dynamic" symbols
        attrCgoExportStatic  map[Sym]struct{} // "cgo_export_static" symbols
-       generatedSyms        map[Sym]struct{} // symbols that generate their content
 
        // Outer and Sub relations for symbols.
-       // TODO: figure out whether it's more efficient to just have these
-       // as fields on extSymPayload (note that this won't be a viable
-       // strategy if somewhere in the linker we set sub/outer for a
-       // non-external sym).
-       outer map[Sym]Sym
+       outer []Sym // indexed by global index
        sub   map[Sym]Sym
 
        dynimplib   map[Sym]string      // stores Dynimplib symbol attribute
@@ -272,14 +254,13 @@ type Loader struct {
        // the symbol that triggered the marking of symbol K as live.
        Reachparent []Sym
 
-       flags uint32
+       // CgoExports records cgo-exported symbols by SymName.
+       CgoExports map[string]Sym
 
-       hasUnknownPkgPath bool // if any Go object has unknown package path
+       flags uint32
 
        strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
 
-       elfsetstring elfsetstringFunc
-
        errorReporter *ErrorReporter
 
        npkgsyms    int // number of package symbols, for accounting
@@ -301,20 +282,17 @@ const (
        goObjStart
 )
 
-type elfsetstringFunc func(str string, off int)
-
 // extSymPayload holds the payload (data + relocations) for linker-synthesized
 // external symbols (note that symbol value is stored in a separate slice).
 type extSymPayload struct {
-       name     string // TODO: would this be better as offset into str table?
-       size     int64
-       ver      int
-       kind     sym.SymKind
-       objidx   uint32 // index of original object if sym made by cloneToExternal
-       relocs   []goobj.Reloc
-       reltypes []objabi.RelocType // relocation types
-       data     []byte
-       auxs     []goobj.Aux
+       name   string // TODO: would this be better as offset into str table?
+       size   int64
+       ver    int
+       kind   sym.SymKind
+       objidx uint32 // index of original object if sym made by cloneToExternal
+       relocs []goobj.Reloc
+       data   []byte
+       auxs   []goobj.Aux
 }
 
 const (
@@ -322,17 +300,16 @@ const (
        FlagStrictDups = 1 << iota
 )
 
-func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
+func NewLoader(flags uint32, reporter *ErrorReporter) *Loader {
        nbuiltin := goobj.NBuiltin()
        extReader := &oReader{objidx: extObj}
        ldr := &Loader{
                start:                make(map[*oReader]Sym),
                objs:                 []objIdx{{}, {extReader, 0}}, // reserve index 0 for nil symbol, 1 for external symbols
-               objSyms:              make([]objSym, 1, 100000),    // reserve index 0 for nil symbol
+               objSyms:              make([]objSym, 1, 1),         // This will get overwritten later.
                extReader:            extReader,
                symsByName:           [2]map[string]Sym{make(map[string]Sym, 80000), make(map[string]Sym, 50000)}, // preallocate ~2MB for ABI0 and ~1MB for ABI1 symbols
-               objByPkg:             make(map[string]*oReader),
-               outer:                make(map[Sym]Sym),
+               objByPkg:             make(map[string]uint32),
                sub:                  make(map[Sym]Sym),
                dynimplib:            make(map[Sym]string),
                dynimpvers:           make(map[Sym]string),
@@ -346,16 +323,12 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorRepor
                plt:                  make(map[Sym]int32),
                got:                  make(map[Sym]int32),
                dynid:                make(map[Sym]int32),
-               attrTopFrame:         make(map[Sym]struct{}),
-               attrSpecial:          make(map[Sym]struct{}),
                attrCgoExportDynamic: make(map[Sym]struct{}),
                attrCgoExportStatic:  make(map[Sym]struct{}),
-               generatedSyms:        make(map[Sym]struct{}),
                deferReturnTramp:     make(map[Sym]bool),
                extStaticSyms:        make(map[nameVer]Sym),
                builtinSyms:          make([]Sym, nbuiltin),
                flags:                flags,
-               elfsetstring:         elfsetstring,
                errorReporter:        reporter,
                sects:                []*sym.Section{nil}, // reserve index 0 for nil section
        }
@@ -370,14 +343,11 @@ func (l *Loader) addObj(pkg string, r *oReader) Sym {
        }
        pkg = objabi.PathToPrefix(pkg) // the object file contains escaped package path
        if _, ok := l.objByPkg[pkg]; !ok {
-               l.objByPkg[pkg] = r
+               l.objByPkg[pkg] = r.objidx
        }
        i := Sym(len(l.objSyms))
        l.start[r] = i
        l.objs = append(l.objs, objIdx{r, i})
-       if r.NeedNameExpansion() && !r.FromAssembly() {
-               l.hasUnknownPkgPath = true
-       }
        return i
 }
 
@@ -389,6 +359,9 @@ func (st *loadState) addSym(name string, ver int, r *oReader, li uint32, kind in
                panic("addSym called after external symbol is created")
        }
        i := Sym(len(l.objSyms))
+       if int(i) != len(l.objSyms) { // overflow
+               panic("too many symbols")
+       }
        addToGlobal := func() {
                l.objSyms = append(l.objSyms, objSym{r.objidx, li})
        }
@@ -472,6 +445,15 @@ func (st *loadState) addSym(name string, ver int, r *oReader, li uint32, kind in
                if l.flags&FlagStrictDups != 0 {
                        l.checkdup(name, r, li, oldi)
                }
+               // Fix for issue #47185 -- given two dupok symbols with
+               // different sizes, favor symbol with larger size. See
+               // also issue #46653.
+               szdup := l.SymSize(oldi)
+               sz := int64(r.Sym(li).Siz())
+               if szdup < sz {
+                       // new symbol overwrites old symbol.
+                       l.objSyms[oldi] = objSym{r.objidx, li}
+               }
                return oldi
        }
        oldr, oldli := l.toLocal(oldi)
@@ -484,14 +466,14 @@ func (st *loadState) addSym(name string, ver int, r *oReader, li uint32, kind in
                // new symbol overwrites old symbol.
                oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())]
                if !(oldtyp.IsData() && oldr.DataSize(oldli) == 0) {
-                       log.Fatalf("duplicated definition of symbol " + name)
+                       log.Fatalf("duplicated definition of symbol %s, from %s and %s", name, r.unit.Lib.Pkg, oldr.unit.Lib.Pkg)
                }
                l.objSyms[oldi] = objSym{r.objidx, li}
        } else {
                // old symbol overwrites new symbol.
                typ := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type())]
                if !typ.IsData() { // only allow overwriting data symbol
-                       log.Fatalf("duplicated definition of symbol " + name)
+                       log.Fatalf("duplicated definition of symbol %s, from %s and %s", name, r.unit.Lib.Pkg, oldr.unit.Lib.Pkg)
                }
        }
        return oldi
@@ -501,10 +483,14 @@ func (st *loadState) addSym(name string, ver int, r *oReader, li uint32, kind in
 // name/version.
 func (l *Loader) newExtSym(name string, ver int) Sym {
        i := Sym(len(l.objSyms))
+       if int(i) != len(l.objSyms) { // overflow
+               panic("too many symbols")
+       }
        if l.extStart == 0 {
                l.extStart = i
        }
        l.growValues(int(i) + 1)
+       l.growOuter(int(i) + 1)
        l.growAttrBitmaps(int(i) + 1)
        pi := l.newPayload(name, ver)
        l.objSyms = append(l.objSyms, objSym{l.extReader.objidx, uint32(pi)})
@@ -530,6 +516,36 @@ func (l *Loader) LookupOrCreateSym(name string, ver int) Sym {
        return i
 }
 
+// AddCgoExport records a cgo-exported symbol in l.CgoExports.
+// This table is used to identify the correct Go symbol ABI to use
+// to resolve references from host objects (which don't have ABIs).
+func (l *Loader) AddCgoExport(s Sym) {
+       if l.CgoExports == nil {
+               l.CgoExports = make(map[string]Sym)
+       }
+       l.CgoExports[l.SymName(s)] = s
+}
+
+// LookupOrCreateCgoExport is like LookupOrCreateSym, but if ver
+// indicates a global symbol, it uses the CgoExport table to determine
+// the appropriate symbol version (ABI) to use. ver must be either 0
+// or a static symbol version.
+func (l *Loader) LookupOrCreateCgoExport(name string, ver int) Sym {
+       if ver >= sym.SymVerStatic {
+               return l.LookupOrCreateSym(name, ver)
+       }
+       if ver != 0 {
+               panic("ver must be 0 or a static version")
+       }
+       // Look for a cgo-exported symbol from Go.
+       if s, ok := l.CgoExports[name]; ok {
+               return s
+       }
+       // Otherwise, this must just be a symbol in the host object.
+       // Create a version 0 symbol for it.
+       return l.LookupOrCreateSym(name, 0)
+}
+
 func (l *Loader) IsExternal(i Sym) bool {
        r, _ := l.toLocal(i)
        return l.isExtReader(r)
@@ -631,20 +647,42 @@ func (l *Loader) resolve(r *oReader, s goobj.SymRef) Sym {
                i := int(s.SymIdx) + r.ndef + r.nhashed64def + r.nhasheddef
                return r.syms[i]
        case goobj.PkgIdxBuiltin:
-               return l.builtinSyms[s.SymIdx]
+               if bi := l.builtinSyms[s.SymIdx]; bi != 0 {
+                       return bi
+               }
+               l.reportMissingBuiltin(int(s.SymIdx), r.unit.Lib.Pkg)
+               return 0
        case goobj.PkgIdxSelf:
                rr = r
        default:
-               pkg := r.Pkg(int(p))
-               var ok bool
-               rr, ok = l.objByPkg[pkg]
-               if !ok {
-                       log.Fatalf("reference of nonexisted package %s, from %v", pkg, r.unit.Lib)
-               }
+               rr = l.objs[r.pkg[p]].r
        }
        return l.toGlobal(rr, s.SymIdx)
 }
 
+// reportMissingBuiltin issues an error in the case where we have a
+// relocation against a runtime builtin whose definition is not found
+// when the runtime package is built. The canonical example is
+// "runtime.racefuncenter" -- currently if you do something like
+//
+//     go build -gcflags=-race myprogram.go
+//
+// the compiler will insert calls to the builtin runtime.racefuncenter,
+// but the version of the runtime used for linkage won't actually contain
+// definitions of that symbol. See issue #42396 for details.
+//
+// As currently implemented, this is a fatal error. This has drawbacks
+// in that if there are multiple missing builtins, the error will only
+// cite the first one. On the plus side, terminating the link here has
+// advantages in that we won't run the risk of panics or crashes later
+// on in the linker due to R_CALL relocations with 0-valued target
+// symbols.
+func (l *Loader) reportMissingBuiltin(bsym int, reflib string) {
+       bname, _ := goobj.BuiltinName(bsym)
+       log.Fatalf("reference to undefined builtin %q from package %q",
+               bname, reflib)
+}
+
 // Look up a symbol by name, return global index, or 0 if not found.
 // This is more like Syms.ROLookup than Lookup -- it doesn't create
 // new symbol.
@@ -660,12 +698,18 @@ func (l *Loader) checkdup(name string, r *oReader, li uint32, dup Sym) {
        p := r.Data(li)
        rdup, ldup := l.toLocal(dup)
        pdup := rdup.Data(ldup)
-       if bytes.Equal(p, pdup) {
-               return
-       }
        reason := "same length but different contents"
        if len(p) != len(pdup) {
                reason = fmt.Sprintf("new length %d != old length %d", len(p), len(pdup))
+       } else if bytes.Equal(p, pdup) {
+               // For BSS symbols, we need to check size as well, see issue 46653.
+               szdup := l.SymSize(dup)
+               sz := int64(r.Sym(li).Siz())
+               if szdup == sz {
+                       return
+               }
+               reason = fmt.Sprintf("different sizes: new size %d != old size %d",
+                       sz, szdup)
        }
        fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason)
 
@@ -674,9 +718,9 @@ func (l *Loader) checkdup(name string, r *oReader, li uint32, dup Sym) {
        // here is that we get different line numbers on formal
        // params; I am guessing that the pos is being inherited
        // from the spot where the wrapper is needed.
-       allowed := strings.HasPrefix(name, "go.info.go.interface") ||
-               strings.HasPrefix(name, "go.info.go.builtin") ||
-               strings.HasPrefix(name, "go.debuglines")
+       allowed := strings.HasPrefix(name, "go:info.go.interface") ||
+               strings.HasPrefix(name, "go:info.go.builtin") ||
+               strings.HasPrefix(name, "go:debuglines")
        if !allowed {
                l.strictDupMsgs++
        }
@@ -699,44 +743,17 @@ func (l *Loader) NReachableSym() int {
        return l.attrReachable.Count()
 }
 
-// SymNameLen returns the length of the symbol name, trying hard not to load
-// the name.
-func (l *Loader) SymNameLen(i Sym) int {
-       // Not much we can do about external symbols.
-       if l.IsExternal(i) {
-               return len(l.SymName(i))
-       }
-       r, li := l.toLocal(i)
-       le := r.Sym(li).NameLen(r.Reader)
-       if !r.NeedNameExpansion() {
-               return le
-       }
-       // Just load the symbol name. We don't know how expanded it'll be.
-       return len(l.SymName(i))
-}
-
-// Returns the raw (unpatched) name of the i-th symbol.
-func (l *Loader) RawSymName(i Sym) string {
-       if l.IsExternal(i) {
-               pp := l.getPayload(i)
-               return pp.name
-       }
-       r, li := l.toLocal(i)
-       return r.Sym(li).Name(r.Reader)
-}
-
-// Returns the (patched) name of the i-th symbol.
+// Returns the name of the i-th symbol.
 func (l *Loader) SymName(i Sym) string {
        if l.IsExternal(i) {
                pp := l.getPayload(i)
                return pp.name
        }
        r, li := l.toLocal(i)
-       name := r.Sym(li).Name(r.Reader)
-       if !r.NeedNameExpansion() {
-               return name
+       if r == nil {
+               return "?"
        }
-       return strings.Replace(name, "\"\".", r.pkgprefix, -1)
+       return r.Sym(li).Name(r.Reader)
 }
 
 // Returns the version of the i-th symbol.
@@ -975,7 +992,7 @@ func (l *Loader) AttrExternal(i Sym) bool {
 // symbol (see AttrExternal).
 func (l *Loader) SetAttrExternal(i Sym, v bool) {
        if !l.IsExternal(i) {
-               panic(fmt.Sprintf("tried to set external attr on non-external symbol %q", l.RawSymName(i)))
+               panic(fmt.Sprintf("tried to set external attr on non-external symbol %q", l.SymName(i)))
        }
        if v {
                l.attrExternal.Set(l.extIndex(i))
@@ -984,39 +1001,20 @@ func (l *Loader) SetAttrExternal(i Sym, v bool) {
        }
 }
 
-// AttrTopFrame returns true for a function symbol that is an entry
-// point, meaning that unwinders should stop when they hit this
-// function.
-func (l *Loader) AttrTopFrame(i Sym) bool {
-       _, ok := l.attrTopFrame[i]
-       return ok
-}
-
-// SetAttrTopFrame sets the "top frame" property for a symbol (see
-// AttrTopFrame).
-func (l *Loader) SetAttrTopFrame(i Sym, v bool) {
-       if v {
-               l.attrTopFrame[i] = struct{}{}
-       } else {
-               delete(l.attrTopFrame, i)
-       }
-}
-
 // AttrSpecial returns true for a symbols that do not have their
 // address (i.e. Value) computed by the usual mechanism of
 // data.go:dodata() & data.go:address().
 func (l *Loader) AttrSpecial(i Sym) bool {
-       _, ok := l.attrSpecial[i]
-       return ok
+       return l.attrSpecial.Has(i)
 }
 
 // SetAttrSpecial sets the "special" property for a symbol (see
 // AttrSpecial).
 func (l *Loader) SetAttrSpecial(i Sym, v bool) {
        if v {
-               l.attrSpecial[i] = struct{}{}
+               l.attrSpecial.Set(i)
        } else {
-               delete(l.attrSpecial, i)
+               l.attrSpecial.Unset(i)
        }
 }
 
@@ -1038,6 +1036,14 @@ func (l *Loader) SetAttrCgoExportDynamic(i Sym, v bool) {
        }
 }
 
+// ForAllCgoExportDynamic calls f for every symbol that has been
+// marked with the "cgo_export_dynamic" compiler directive.
+func (l *Loader) ForAllCgoExportDynamic(f func(Sym)) {
+       for s := range l.attrCgoExportDynamic {
+               f(s)
+       }
+}
+
 // AttrCgoExportStatic returns true for a symbol that has been
 // specially marked via the "cgo_export_static" directive
 // written by cgo.
@@ -1060,8 +1066,10 @@ func (l *Loader) SetAttrCgoExportStatic(i Sym, v bool) {
 // generator symbol through the SetIsGeneratedSym. The functions for generator
 // symbols are kept in the Link context.
 func (l *Loader) IsGeneratedSym(i Sym) bool {
-       _, ok := l.generatedSyms[i]
-       return ok
+       if !l.IsExternal(i) {
+               return false
+       }
+       return l.generatedSyms.Has(l.extIndex(i))
 }
 
 // SetIsGeneratedSym marks symbols as generated symbols. Data shouldn't be
@@ -1072,9 +1080,9 @@ func (l *Loader) SetIsGeneratedSym(i Sym, v bool) {
                panic("only external symbols can be generated")
        }
        if v {
-               l.generatedSyms[i] = struct{}{}
+               l.generatedSyms.Set(l.extIndex(i))
        } else {
-               delete(l.generatedSyms, i)
+               l.generatedSyms.Unset(l.extIndex(i))
        }
 }
 
@@ -1118,7 +1126,7 @@ func (l *Loader) SetAttrReadOnly(i Sym, v bool) {
 //
 // - Outer symbol covers the address ranges of its sub-symbols.
 //   Outer.Sub is set in this case.
-// - Outer symbol doesn't conver the address ranges. It is zero-sized
+// - Outer symbol doesn't cover the address ranges. It is zero-sized
 //   and doesn't have sub-symbols. In the case, the inner symbol is
 //   not actually a "SubSymbol". (Tricky!)
 //
@@ -1170,6 +1178,24 @@ func (l *Loader) IsItab(i Sym) bool {
        return r.Sym(li).IsItab()
 }
 
+// Returns whether this symbol is a dictionary symbol.
+func (l *Loader) IsDict(i Sym) bool {
+       if l.IsExternal(i) {
+               return false
+       }
+       r, li := l.toLocal(i)
+       return r.Sym(li).IsDict()
+}
+
+// Returns whether this symbol is a compiler-generated package init func.
+func (l *Loader) IsPkgInit(i Sym) bool {
+       if l.IsExternal(i) {
+               return false
+       }
+       r, li := l.toLocal(i)
+       return r.Sym(li).IsPkgInit()
+}
+
 // Return whether this is a trampoline of a deferreturn call.
 func (l *Loader) IsDeferReturnTramp(i Sym) bool {
        return l.deferReturnTramp[i]
@@ -1216,6 +1242,16 @@ func (l *Loader) Data(i Sym) []byte {
        return r.Data(li)
 }
 
+// Returns the symbol content of the i-th symbol as a string. i is global index.
+func (l *Loader) DataString(i Sym) string {
+       if l.IsExternal(i) {
+               pp := l.getPayload(i)
+               return string(pp.data)
+       }
+       r, li := l.toLocal(i)
+       return r.DataString(li)
+}
+
 // FreeData clears the symbol data of an external symbol, allowing the memory
 // to be freed earlier. No-op for non-external symbols.
 // i is global index.
@@ -1261,7 +1297,7 @@ func (l *Loader) SetSymAlign(i Sym, align int32) {
        l.align[i] = uint8(bits.Len32(uint32(align)))
 }
 
-// SymValue returns the section of the i-th symbol. i is global index.
+// SymSect returns the section of the i-th symbol. i is global index.
 func (l *Loader) SymSect(i Sym) *sym.Section {
        if int(i) >= len(l.symSects) {
                // symSects is extended lazily -- it the sym in question is
@@ -1280,14 +1316,6 @@ func (l *Loader) SetSymSect(i Sym, sect *sym.Section) {
        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)
@@ -1300,7 +1328,7 @@ func (l *Loader) NewSection() *sym.Section {
        return sect
 }
 
-// SymDynImplib returns the "dynimplib" attribute for the specified
+// SymDynimplib returns the "dynimplib" attribute for the specified
 // symbol, making up a portion of the info for a symbol specified
 // on a "cgo_import_dynamic" compiler directive.
 func (l *Loader) SymDynimplib(i Sym) string {
@@ -1422,7 +1450,7 @@ func (l *Loader) SetSymLocalElfSym(i Sym, es int32) {
        }
 }
 
-// SymPlt returns the plt value for pe symbols.
+// SymPlt returns the PLT offset of symbol s.
 func (l *Loader) SymPlt(s Sym) int32 {
        if v, ok := l.plt[s]; ok {
                return v
@@ -1430,7 +1458,7 @@ func (l *Loader) SymPlt(s Sym) int32 {
        return -1
 }
 
-// SetPlt sets the plt value for pe symbols.
+// SetPlt sets the PLT offset of symbol i.
 func (l *Loader) SetPlt(i Sym, v int32) {
        if i >= Sym(len(l.objSyms)) || i == 0 {
                panic("bad symbol for SetPlt")
@@ -1442,7 +1470,7 @@ func (l *Loader) SetPlt(i Sym, v int32) {
        }
 }
 
-// SymGot returns the got value for pe symbols.
+// SymGot returns the GOT offset of symbol s.
 func (l *Loader) SymGot(s Sym) int32 {
        if v, ok := l.got[s]; ok {
                return v
@@ -1450,7 +1478,7 @@ func (l *Loader) SymGot(s Sym) int32 {
        return -1
 }
 
-// SetGot sets the got value for pe symbols.
+// SetGot sets the GOT offset of symbol i.
 func (l *Loader) SetGot(i Sym, v int32) {
        if i >= Sym(len(l.objSyms)) || i == 0 {
                panic("bad symbol for SetGot")
@@ -1483,7 +1511,7 @@ func (l *Loader) SetSymDynid(i Sym, val int32) {
        }
 }
 
-// DynIdSyms returns the set of symbols for which dynID is set to an
+// DynidSyms returns the set of symbols for which dynID is set to an
 // interesting (non-default) value. This is expected to be a fairly
 // small set.
 func (l *Loader) DynidSyms() []Sym {
@@ -1501,27 +1529,7 @@ func (l *Loader) DynidSyms() []Sym {
 // approach would be to check for gotype during preload and copy the
 // results in to a map (might want to try this at some point and see
 // if it helps speed things up).
-func (l *Loader) SymGoType(i Sym) Sym {
-       var r *oReader
-       var auxs []goobj.Aux
-       if l.IsExternal(i) {
-               pp := l.getPayload(i)
-               r = l.objs[pp.objidx].r
-               auxs = pp.auxs
-       } else {
-               var li uint32
-               r, li = l.toLocal(i)
-               auxs = r.Auxs(li)
-       }
-       for j := range auxs {
-               a := &auxs[j]
-               switch a.Type() {
-               case goobj.AuxGotype:
-                       return l.resolve(r, a.Sym())
-               }
-       }
-       return 0
-}
+func (l *Loader) SymGoType(i Sym) Sym { return l.aux1(i, goobj.AuxGotype) }
 
 // SymUnit returns the compilation unit for a given symbol (which will
 // typically be nil for external or linker-manufactured symbols).
@@ -1542,7 +1550,7 @@ func (l *Loader) SymUnit(i Sym) *sym.CompilationUnit {
 // regular compiler-generated Go symbols), but in the case of
 // building with "-linkshared" (when a symbol is read from a
 // shared library), will hold the library name.
-// NOTE: this correspondes to sym.Symbol.File field.
+// NOTE: this corresponds to sym.Symbol.File field.
 func (l *Loader) SymPkg(i Sym) string {
        if f, ok := l.symPkg[i]; ok {
                return f
@@ -1570,13 +1578,15 @@ func (l *Loader) SetSymPkg(i Sym, pkg string) {
        l.symPkg[i] = pkg
 }
 
-// SymLocalentry returns the "local entry" value for the specified
-// symbol.
+// SymLocalentry returns an offset in bytes of the "local entry" of a symbol.
+//
+// On PPC64, a value of 1 indicates the symbol does not use or preserve a TOC
+// pointer in R2, nor does it have a distinct local entry.
 func (l *Loader) SymLocalentry(i Sym) uint8 {
        return l.localentry[i]
 }
 
-// SetSymLocalentry sets the "local entry" attribute for a symbol.
+// SetSymLocalentry sets the "local entry" offset attribute for a symbol.
 func (l *Loader) SetSymLocalentry(i Sym, value uint8) {
        // reject bad symbols
        if i >= Sym(len(l.objSyms)) || i == 0 {
@@ -1610,6 +1620,39 @@ func (l *Loader) Aux(i Sym, j int) Aux {
        return Aux{r.Aux(li, j), r, l}
 }
 
+// WasmImportSym returns the auxiliary WebAssembly import symbol associated with
+// a given function symbol. The aux sym only exists for Go function stubs that
+// have been annotated with the //go:wasmimport directive.  The aux sym
+// contains the information necessary for the linker to add a WebAssembly
+// import statement.
+// (https://webassembly.github.io/spec/core/syntax/modules.html#imports)
+func (l *Loader) WasmImportSym(fnSymIdx Sym) (Sym, bool) {
+       if l.SymType(fnSymIdx) != sym.STEXT {
+               log.Fatalf("error: non-function sym %d/%s t=%s passed to WasmImportSym", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
+       }
+       r, li := l.toLocal(fnSymIdx)
+       auxs := r.Auxs(li)
+       for i := range auxs {
+               a := &auxs[i]
+               switch a.Type() {
+               case goobj.AuxWasmImport:
+                       return l.resolve(r, a.Sym()), true
+               }
+       }
+
+       return 0, false
+}
+
+// SEHUnwindSym returns the auxiliary SEH unwind symbol associated with
+// a given function symbol.
+func (l *Loader) SEHUnwindSym(fnSymIdx Sym) Sym {
+       if l.SymType(fnSymIdx) != sym.STEXT {
+               log.Fatalf("error: non-function sym %d/%s t=%s passed to SEHUnwindSym", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
+       }
+
+       return l.aux1(fnSymIdx, goobj.AuxSehUnwindInfo)
+}
+
 // GetFuncDwarfAuxSyms collects and returns the auxiliary DWARF
 // symbols associated with a given function symbol.  Prior to the
 // introduction of the loader, this was done purely using name
@@ -1619,13 +1662,8 @@ func (l *Loader) GetFuncDwarfAuxSyms(fnSymIdx Sym) (auxDwarfInfo, auxDwarfLoc, a
        if l.SymType(fnSymIdx) != sym.STEXT {
                log.Fatalf("error: non-function sym %d/%s t=%s passed to GetFuncDwarfAuxSyms", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
        }
-       if l.IsExternal(fnSymIdx) {
-               // Current expectation is that any external function will
-               // not have auxsyms.
-               return
-       }
-       r, li := l.toLocal(fnSymIdx)
-       auxs := r.Auxs(li)
+       r, auxs := l.auxs(fnSymIdx)
+
        for i := range auxs {
                a := &auxs[i]
                switch a.Type() {
@@ -1654,6 +1692,15 @@ func (l *Loader) GetFuncDwarfAuxSyms(fnSymIdx Sym) (auxDwarfInfo, auxDwarfLoc, a
        return
 }
 
+func (l *Loader) GetVarDwarfAuxSym(i Sym) Sym {
+       aux := l.aux1(i, goobj.AuxDwarfInfo)
+       if aux != 0 && l.SymType(aux) != sym.SDWARFVAR {
+               fmt.Println(l.SymName(i), l.SymType(i), l.SymType(aux), sym.SDWARFVAR)
+               panic("aux dwarf info sym with wrong type")
+       }
+       return aux
+}
+
 // AddInteriorSym sets up 'interior' as an interior symbol of
 // container/payload symbol 'container'. An interior symbol does not
 // itself have data, but gives a name to a subrange of the data in its
@@ -1703,19 +1750,24 @@ func (l *Loader) AddInteriorSym(container Sym, interior Sym) {
        l.outer[interior] = container
 }
 
-// OuterSym gets the outer symbol for host object loaded symbols.
+// OuterSym gets the outer/container symbol.
 func (l *Loader) OuterSym(i Sym) Sym {
-       // FIXME: add check for isExternal?
        return l.outer[i]
 }
 
 // SubSym gets the subsymbol for host object loaded symbols.
 func (l *Loader) SubSym(i Sym) Sym {
-       // NB: note -- no check for l.isExternal(), since I am pretty sure
-       // that later phases in the linker set subsym for "type." syms
        return l.sub[i]
 }
 
+// growOuter grows the slice used to store outer symbol.
+func (l *Loader) growOuter(reqLen int) {
+       curLen := len(l.outer)
+       if reqLen > curLen {
+               l.outer = append(l.outer, make([]Sym, reqLen-curLen)...)
+       }
+}
+
 // SetCarrierSym declares that 'c' is the carrier or container symbol
 // for 's'. Carrier symbols are used in the linker to as a container
 // for a collection of sub-symbols where the content of the
@@ -1725,7 +1777,7 @@ func (l *Loader) SubSym(i Sym) Sym {
 // emits named string symbols (type SGOSTRING) when compiling a
 // package; after being deduplicated, these symbols are collected into
 // a single unit by assigning them a new carrier symbol named
-// "go.string.*" (which appears in the final symbol table for the
+// "go:string.*" (which appears in the final symbol table for the
 // output load module).
 func (l *Loader) SetCarrierSym(s Sym, c Sym) {
        if c == 0 {
@@ -1794,6 +1846,11 @@ func (l *Loader) SortSub(s Sym) Sym {
        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() {
@@ -1803,6 +1860,7 @@ func (l *Loader) growAttrBitmaps(reqLen int) {
                l.attrLocal = growBitmap(reqLen, l.attrLocal)
                l.attrNotInSymbolTable = growBitmap(reqLen, l.attrNotInSymbolTable)
                l.attrUsedInIface = growBitmap(reqLen, l.attrUsedInIface)
+               l.attrSpecial = growBitmap(reqLen, l.attrSpecial)
        }
        l.growExtAttrBitmaps()
 }
@@ -1815,6 +1873,7 @@ func (l *Loader) growExtAttrBitmaps() {
                l.attrDuplicateOK = growBitmap(extReqLen, l.attrDuplicateOK)
                l.attrShared = growBitmap(extReqLen, l.attrShared)
                l.attrExternal = growBitmap(extReqLen, l.attrExternal)
+               l.generatedSyms = growBitmap(extReqLen, l.generatedSyms)
        }
 }
 
@@ -1823,10 +1882,9 @@ 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 {
        if relocs.l.isExtReader(relocs.r) {
-               pp := relocs.l.payloads[relocs.li]
-               return Reloc{&relocs.rs[j], relocs.r, relocs.l, pp.reltypes[j]}
+               return Reloc{&relocs.rs[j], relocs.r, relocs.l}
        }
-       return Reloc{&relocs.rs[j], relocs.r, relocs.l, 0}
+       return Reloc{&relocs.rs[j], relocs.r, relocs.l}
 }
 
 // Relocs returns a Relocs object for the given global sym.
@@ -1838,7 +1896,7 @@ func (l *Loader) Relocs(i Sym) Relocs {
        return l.relocs(r, li)
 }
 
-// Relocs returns a Relocs object given a local sym index and reader.
+// relocs returns a Relocs object given a local sym index and reader.
 func (l *Loader) relocs(r *oReader, li uint32) Relocs {
        var rs []goobj.Reloc
        if l.isExtReader(r) {
@@ -1855,12 +1913,98 @@ func (l *Loader) relocs(r *oReader, li uint32) Relocs {
        }
 }
 
+func (l *Loader) auxs(i Sym) (*oReader, []goobj.Aux) {
+       if l.IsExternal(i) {
+               pp := l.getPayload(i)
+               return l.objs[pp.objidx].r, pp.auxs
+       } else {
+               r, li := l.toLocal(i)
+               return r, r.Auxs(li)
+       }
+}
+
+// Returns a specific aux symbol of type t for symbol i.
+func (l *Loader) aux1(i Sym, t uint8) Sym {
+       r, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               if a.Type() == t {
+                       return l.resolve(r, a.Sym())
+               }
+       }
+       return 0
+}
+
+func (l *Loader) Pcsp(i Sym) Sym { return l.aux1(i, goobj.AuxPcsp) }
+
+// Returns all aux symbols of per-PC data for symbol i.
+// tmp is a scratch space for the pcdata slice.
+func (l *Loader) PcdataAuxs(i Sym, tmp []Sym) (pcsp, pcfile, pcline, pcinline Sym, pcdata []Sym) {
+       pcdata = tmp[:0]
+       r, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               switch a.Type() {
+               case goobj.AuxPcsp:
+                       pcsp = l.resolve(r, a.Sym())
+               case goobj.AuxPcline:
+                       pcline = l.resolve(r, a.Sym())
+               case goobj.AuxPcfile:
+                       pcfile = l.resolve(r, a.Sym())
+               case goobj.AuxPcinline:
+                       pcinline = l.resolve(r, a.Sym())
+               case goobj.AuxPcdata:
+                       pcdata = append(pcdata, l.resolve(r, a.Sym()))
+               }
+       }
+       return
+}
+
+// Returns the number of pcdata for symbol i.
+func (l *Loader) NumPcdata(i Sym) int {
+       n := 0
+       _, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               if a.Type() == goobj.AuxPcdata {
+                       n++
+               }
+       }
+       return n
+}
+
+// Returns all funcdata symbols of symbol i.
+// tmp is a scratch space.
+func (l *Loader) Funcdata(i Sym, tmp []Sym) []Sym {
+       fd := tmp[:0]
+       r, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               if a.Type() == goobj.AuxFuncdata {
+                       fd = append(fd, l.resolve(r, a.Sym()))
+               }
+       }
+       return fd
+}
+
+// Returns the number of funcdata for symbol i.
+func (l *Loader) NumFuncdata(i Sym) int {
+       n := 0
+       _, auxs := l.auxs(i)
+       for j := range auxs {
+               a := &auxs[j]
+               if a.Type() == goobj.AuxFuncdata {
+                       n++
+               }
+       }
+       return n
+}
+
 // FuncInfo provides hooks to access goobj.FuncInfo in the objects.
 type FuncInfo struct {
        l       *Loader
        r       *oReader
        data    []byte
-       auxs    []goobj.Aux
        lengths goobj.FuncInfoLengths
 }
 
@@ -1874,23 +2018,16 @@ func (fi *FuncInfo) Locals() int {
        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() []byte {
-       pcsp, end := (*goobj.FuncInfo)(nil).ReadPcsp(fi.data)
-       return fi.r.BytesAt(fi.r.PcdataBase()+pcsp, int(end-pcsp))
+func (fi *FuncInfo) FuncID() abi.FuncID {
+       return (*goobj.FuncInfo)(nil).ReadFuncID(fi.data)
 }
 
-func (fi *FuncInfo) Pcfile() []byte {
-       pcf, end := (*goobj.FuncInfo)(nil).ReadPcfile(fi.data)
-       return fi.r.BytesAt(fi.r.PcdataBase()+pcf, int(end-pcf))
+func (fi *FuncInfo) FuncFlag() abi.FuncFlag {
+       return (*goobj.FuncInfo)(nil).ReadFuncFlag(fi.data)
 }
 
-func (fi *FuncInfo) Pcline() []byte {
-       pcln, end := (*goobj.FuncInfo)(nil).ReadPcline(fi.data)
-       return fi.r.BytesAt(fi.r.PcdataBase()+pcln, int(end-pcln))
+func (fi *FuncInfo) StartLine() int32 {
+       return (*goobj.FuncInfo)(nil).ReadStartLine(fi.data)
 }
 
 // Preload has to be called prior to invoking the various methods
@@ -1899,61 +2036,6 @@ func (fi *FuncInfo) Preload() {
        fi.lengths = (*goobj.FuncInfo)(nil).ReadFuncInfoLengths(fi.data)
 }
 
-func (fi *FuncInfo) Pcinline() []byte {
-       if !fi.lengths.Initialized {
-               panic("need to call Preload first")
-       }
-       pcinl, end := (*goobj.FuncInfo)(nil).ReadPcinline(fi.data, fi.lengths.PcdataOff)
-       return fi.r.BytesAt(fi.r.PcdataBase()+pcinl, int(end-pcinl))
-}
-
-func (fi *FuncInfo) NumPcdata() uint32 {
-       if !fi.lengths.Initialized {
-               panic("need to call Preload first")
-       }
-       return fi.lengths.NumPcdata
-}
-
-func (fi *FuncInfo) Pcdata(k int) []byte {
-       if !fi.lengths.Initialized {
-               panic("need to call Preload first")
-       }
-       pcdat, end := (*goobj.FuncInfo)(nil).ReadPcdata(fi.data, fi.lengths.PcdataOff, uint32(k))
-       return fi.r.BytesAt(fi.r.PcdataBase()+pcdat, int(end-pcdat))
-}
-
-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")
@@ -1968,6 +2050,13 @@ func (fi *FuncInfo) File(k int) goobj.CUFileIndex {
        return (*goobj.FuncInfo)(nil).ReadFile(fi.data, fi.lengths.FileOff, uint32(k))
 }
 
+// TopFrame returns true if the function associated with this FuncInfo
+// is an entry point, meaning that unwinders should stop when they hit
+// this function.
+func (fi *FuncInfo) TopFrame() bool {
+       return (fi.FuncFlag() & abi.FuncFlagTopFrame) != 0
+}
+
 type InlTreeNode struct {
        Parent   int32
        File     goobj.CUFileIndex
@@ -1998,32 +2087,20 @@ func (fi *FuncInfo) InlTree(k int) InlTreeNode {
 }
 
 func (l *Loader) FuncInfo(i Sym) FuncInfo {
-       var r *oReader
-       var auxs []goobj.Aux
-       if l.IsExternal(i) {
-               pp := l.getPayload(i)
-               if pp.objidx == 0 {
-                       return FuncInfo{}
-               }
-               r = l.objs[pp.objidx].r
-               auxs = pp.auxs
-       } else {
-               var li uint32
-               r, li = l.toLocal(i)
-               auxs = r.Auxs(li)
-       }
+       r, auxs := l.auxs(i)
        for j := range auxs {
                a := &auxs[j]
                if a.Type() == goobj.AuxFuncInfo {
                        b := r.Data(a.Sym().SymIdx)
-                       return FuncInfo{l, r, b, auxs, goobj.FuncInfoLengths{}}
+                       return FuncInfo{l, r, b, goobj.FuncInfoLengths{}}
                }
        }
        return FuncInfo{}
 }
 
-// Preload a package: add autolibs, add defined package symbols to the symbol table.
-// Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
+// Preload a package: adds autolib.
+// Does not add defined package or non-packaged symbols to the symbol table.
+// These are done in LoadSyms.
 // Does not read symbol data.
 // Returns the fingerprint of the object.
 func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj.FingerprintType {
@@ -2046,7 +2123,6 @@ func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, u
                Reader:       r,
                unit:         unit,
                version:      localSymVersion,
-               flags:        r.Flags(),
                pkgprefix:    pkgprefix,
                syms:         make([]Sym, ndef+nhashed64def+nhasheddef+r.NNonpkgdef()+r.NNonpkgref()),
                ndef:         ndef,
@@ -2055,6 +2131,10 @@ func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, u
                objidx:       uint32(len(l.objs)),
        }
 
+       if r.Unlinkable() {
+               log.Fatalf("link: unlinkable object (from package %s) - compiler requires -p flag", lib.Pkg)
+       }
+
        // Autolib
        lib.Autolib = append(lib.Autolib, r.Autolib()...)
 
@@ -2066,11 +2146,9 @@ func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, u
        }
 
        l.addObj(lib.Pkg, or)
-       st := loadState{l: l}
-       st.preloadSyms(or, pkgDef)
 
        // The caller expects us consuming all the data
-       f.MustSeek(length, os.SEEK_CUR)
+       f.MustSeek(length, io.SeekCurrent)
 
        return r.Fingerprint()
 }
@@ -2096,16 +2174,6 @@ func (st *loadState) preloadSyms(r *oReader, kind int) {
        case hashedDef:
                start = uint32(r.ndef + r.nhashed64def)
                end = uint32(r.ndef + r.nhashed64def + r.nhasheddef)
-               if l.hasUnknownPkgPath {
-                       // The content hash depends on symbol name expansion. If any package is
-                       // built without fully expanded names, the content hash is unreliable.
-                       // Treat them as named symbols.
-                       // This is rare.
-                       // (We don't need to do this for hashed64Def case, as there the hash
-                       // function is simply the identity function, which doesn't depend on
-                       // name expansion.)
-                       kind = nonPkgDef
-               }
        case nonPkgDef:
                start = uint32(r.ndef + r.nhashed64def + r.nhasheddef)
                end = uint32(r.ndef + r.nhashed64def + r.nhasheddef + r.NNonpkgdef())
@@ -2113,7 +2181,6 @@ func (st *loadState) preloadSyms(r *oReader, kind int) {
                panic("preloadSyms: bad kind")
        }
        l.growAttrBitmaps(len(l.objSyms) + int(end-start))
-       needNameExpansion := r.NeedNameExpansion()
        loadingRuntimePkg := r.unit.Lib.Pkg == "runtime"
        for i := start; i < end; i++ {
                osym := r.Sym(i)
@@ -2121,16 +2188,10 @@ func (st *loadState) preloadSyms(r *oReader, kind int) {
                var v int
                if kind != hashed64Def && kind != hashedDef { // we don't need the name, etc. for hashed symbols
                        name = osym.Name(r.Reader)
-                       if needNameExpansion {
-                               name = strings.Replace(name, "\"\".", r.pkgprefix, -1)
-                       }
                        v = abiToVer(osym.ABI(), r.version)
                }
                gi := st.addSym(name, v, r, i, kind, osym)
                r.syms[i] = gi
-               if osym.TopFrame() {
-                       l.SetAttrTopFrame(gi, true)
-               }
                if osym.Local() {
                        l.SetAttrLocal(gi, true)
                }
@@ -2138,8 +2199,8 @@ func (st *loadState) preloadSyms(r *oReader, kind int) {
                        l.SetAttrUsedInIface(gi, true)
                }
                if strings.HasPrefix(name, "runtime.") ||
-                       (loadingRuntimePkg && strings.HasPrefix(name, "type.")) {
-                       if bi := goobj.BuiltinIdx(name, v); bi != -1 {
+                       (loadingRuntimePkg && strings.HasPrefix(name, "type:")) {
+                       if bi := goobj.BuiltinIdx(name, int(osym.ABI())); bi != -1 {
                                // This is a definition of a builtin symbol. Record where it is.
                                l.builtinSyms[bi] = gi
                        }
@@ -2150,18 +2211,31 @@ func (st *loadState) preloadSyms(r *oReader, kind int) {
        }
 }
 
-// Add hashed (content-addressable) symbols, non-package symbols, and
+// Add syms, hashed (content-addressable) symbols, non-package symbols, and
 // references to external symbols (which are always named).
-func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
-       l.npkgsyms = l.NSym()
-       // Preallocate some space (a few hundreds KB) for some symbols.
-       // As of Go 1.15, linking cmd/compile has ~8000 hashed64 symbols and
-       // ~13000 hashed symbols.
+func (l *Loader) LoadSyms(arch *sys.Arch) {
+       // Allocate space for symbols, making a guess as to how much space we need.
+       // This function was determined empirically by looking at the cmd/compile on
+       // Darwin, and picking factors for hashed and hashed64 syms.
+       var symSize, hashedSize, hashed64Size int
+       for _, o := range l.objs[goObjStart:] {
+               symSize += o.r.ndef + o.r.nhasheddef/2 + o.r.nhashed64def/2 + o.r.NNonpkgdef()
+               hashedSize += o.r.nhasheddef / 2
+               hashed64Size += o.r.nhashed64def / 2
+       }
+       // Index 0 is invalid for symbols.
+       l.objSyms = make([]objSym, 1, symSize)
+
        st := loadState{
                l:            l,
-               hashed64Syms: make(map[uint64]symAndSize, 10000),
-               hashedSyms:   make(map[goobj.HashType]symAndSize, 15000),
+               hashed64Syms: make(map[uint64]symAndSize, hashed64Size),
+               hashedSyms:   make(map[goobj.HashType]symAndSize, hashedSize),
+       }
+
+       for _, o := range l.objs[goObjStart:] {
+               st.preloadSyms(o.r, pkgDef)
        }
+       l.npkgsyms = l.NSym()
        for _, o := range l.objs[goObjStart:] {
                st.preloadSyms(o.r, hashed64Def)
                st.preloadSyms(o.r, hashedDef)
@@ -2172,18 +2246,15 @@ func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
                loadObjRefs(l, o.r, arch)
        }
        l.values = make([]int64, l.NSym(), l.NSym()+1000) // +1000 make some room for external symbols
+       l.outer = make([]Sym, l.NSym(), l.NSym()+1000)
 }
 
 func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
        // load non-package refs
        ndef := uint32(r.NAlldef())
-       needNameExpansion := r.NeedNameExpansion()
        for i, n := uint32(0), uint32(r.NNonpkgref()); i < n; i++ {
                osym := r.Sym(ndef + i)
                name := osym.Name(r.Reader)
-               if needNameExpansion {
-                       name = strings.Replace(name, "\"\".", r.pkgprefix, -1)
-               }
                v := abiToVer(osym.ABI(), r.version)
                r.syms[ndef+i] = l.LookupOrCreateSym(name, v)
                gi := r.syms[ndef+i]
@@ -2195,6 +2266,18 @@ func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
                }
        }
 
+       // referenced packages
+       npkg := r.NPkg()
+       r.pkg = make([]uint32, npkg)
+       for i := 1; i < npkg; i++ { // PkgIdx 0 is a dummy invalid package
+               pkg := r.Pkg(i)
+               objidx, ok := l.objByPkg[pkg]
+               if !ok {
+                       log.Fatalf("%v: reference to nonexistent package %s", r.unit.Lib, pkg)
+               }
+               r.pkg[i] = objidx
+       }
+
        // load flags of package refs
        for i, n := 0, r.NRefFlags(); i < n; i++ {
                rf := r.RefFlags(i)
@@ -2219,30 +2302,12 @@ func abiToVer(abi uint16, localSymVersion int) int {
        return v
 }
 
-// ResolveABIAlias given a symbol returns the ABI alias target of that
-// symbol. If the sym in question is not an alias, the sym itself is
-// returned.
-func (l *Loader) ResolveABIAlias(s Sym) Sym {
-       if s == 0 {
-               return 0
-       }
-       if l.SymType(s) != sym.SABIALIAS {
-               return s
-       }
-       relocs := l.Relocs(s)
-       target := relocs.At(0).Sym()
-       if l.SymType(target) == sym.SABIALIAS {
-               panic(fmt.Sprintf("ABI alias %s references another ABI alias %s", l.SymName(s), l.SymName(target)))
-       }
-       return target
-}
-
 // TopLevelSym tests a symbol (by name and kind) to determine whether
 // the symbol first class sym (participating in the link) or is an
 // anonymous aux or sub-symbol containing some sub-part or payload of
 // another symbol.
 func (l *Loader) TopLevelSym(s Sym) bool {
-       return topLevelSym(l.RawSymName(s), l.SymType(s))
+       return topLevelSym(l.SymName(s), l.SymType(s))
 }
 
 // topLevelSym tests a symbol name and kind to determine whether
@@ -2277,9 +2342,6 @@ func (l *Loader) cloneToExternal(symIdx Sym) {
        r, li := l.toLocal(symIdx)
        osym := r.Sym(li)
        sname := osym.Name(r.Reader)
-       if r.NeedNameExpansion() {
-               sname = strings.Replace(sname, "\"\".", r.pkgprefix, -1)
-       }
        sver := abiToVer(osym.ABI(), r.version)
        skind := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
 
@@ -2298,13 +2360,11 @@ func (l *Loader) cloneToExternal(symIdx Sym) {
                // Copy relocations
                relocs := l.Relocs(symIdx)
                pp.relocs = make([]goobj.Reloc, relocs.Count())
-               pp.reltypes = make([]objabi.RelocType, relocs.Count())
                for i := range pp.relocs {
                        // Copy the relocs slice.
                        // Convert local reference to global reference.
                        rel := relocs.At(i)
-                       pp.relocs[i].Set(rel.Off(), rel.Siz(), 0, rel.Add(), goobj.SymRef{PkgIdx: 0, SymIdx: uint32(rel.Sym())})
-                       pp.reltypes[i] = rel.Type()
+                       pp.relocs[i].Set(rel.Off(), rel.Siz(), uint16(rel.Type()), rel.Add(), goobj.SymRef{PkgIdx: 0, SymIdx: uint32(rel.Sym())})
                }
 
                // Copy data
@@ -2321,6 +2381,10 @@ func (l *Loader) cloneToExternal(symIdx Sym) {
        // need to access the old symbol content.)
        l.objSyms[symIdx] = objSym{l.extReader.objidx, uint32(pi)}
        l.extReader.syms = append(l.extReader.syms, symIdx)
+
+       // Some attributes were encoded in the object file. Copy them over.
+       l.SetAttrDuplicateOK(symIdx, r.Sym(li).Dupok())
+       l.SetAttrShared(symIdx, r.Shared())
 }
 
 // Copy the payload of symbol src to dst. Both src and dst must be external
@@ -2341,32 +2405,6 @@ func (l *Loader) CopySym(src, dst Sym) {
        // TODO: other attributes?
 }
 
-// CopyAttributes copies over all of the attributes of symbol 'src' to
-// symbol 'dst'.
-func (l *Loader) CopyAttributes(src Sym, dst Sym) {
-       l.SetAttrReachable(dst, l.AttrReachable(src))
-       l.SetAttrOnList(dst, l.AttrOnList(src))
-       l.SetAttrLocal(dst, l.AttrLocal(src))
-       l.SetAttrNotInSymbolTable(dst, l.AttrNotInSymbolTable(src))
-       if l.IsExternal(dst) {
-               l.SetAttrVisibilityHidden(dst, l.AttrVisibilityHidden(src))
-               l.SetAttrDuplicateOK(dst, l.AttrDuplicateOK(src))
-               l.SetAttrShared(dst, l.AttrShared(src))
-               l.SetAttrExternal(dst, l.AttrExternal(src))
-       } else {
-               // Some attributes are modifiable only for external symbols.
-               // In such cases, don't try to transfer over the attribute
-               // from the source even if there is a clash. This comes up
-               // when copying attributes from a dupOK ABI wrapper symbol to
-               // the real target symbol (which may not be marked dupOK).
-       }
-       l.SetAttrTopFrame(dst, l.AttrTopFrame(src))
-       l.SetAttrSpecial(dst, l.AttrSpecial(src))
-       l.SetAttrCgoExportDynamic(dst, l.AttrCgoExportDynamic(src))
-       l.SetAttrCgoExportStatic(dst, l.AttrCgoExportStatic(src))
-       l.SetAttrReadOnly(dst, l.AttrReadOnly(src))
-}
-
 // CreateExtSym creates a new external symbol with the specified name
 // without adding it to any lookup tables, returning a Sym index for it.
 func (l *Loader) CreateExtSym(name string, ver int) Sym {
@@ -2423,26 +2461,30 @@ func (l *Loader) RelocVariant(s Sym, ri int) sym.RelocVariant {
 // space, looking for symbols with relocations targeting undefined
 // references. The linker's loadlib method uses this to determine if
 // there are unresolved references to functions in system libraries
-// (for example, libgcc.a), presumably due to CGO code. Return
-// value is a list of loader.Sym's corresponding to the undefined
-// cross-refs. The "limit" param controls the maximum number of
-// results returned; if "limit" is -1, then all undefs are returned.
-func (l *Loader) UndefinedRelocTargets(limit int) []Sym {
-       result := []Sym{}
+// (for example, libgcc.a), presumably due to CGO code. Return value
+// is a pair of lists of loader.Sym's. First list corresponds to the
+// corresponding to the undefined symbols themselves, the second list
+// is the symbol that is making a reference to the undef. The "limit"
+// param controls the maximum number of results returned; if "limit"
+// is -1, then all undefs are returned.
+func (l *Loader) UndefinedRelocTargets(limit int) ([]Sym, []Sym) {
+       result, fromr := []Sym{}, []Sym{}
+outerloop:
        for si := Sym(1); si < Sym(len(l.objSyms)); si++ {
                relocs := l.Relocs(si)
                for ri := 0; ri < relocs.Count(); ri++ {
                        r := relocs.At(ri)
                        rs := r.Sym()
-                       if rs != 0 && l.SymType(rs) == sym.SXREF && l.RawSymName(rs) != ".got" {
+                       if rs != 0 && l.SymType(rs) == sym.SXREF && l.SymName(rs) != ".got" {
                                result = append(result, rs)
+                               fromr = append(fromr, si)
                                if limit != -1 && len(result) >= limit {
-                                       break
+                                       break outerloop
                                }
                        }
                }
        }
-       return result
+       return result, fromr
 }
 
 // AssignTextSymbolOrder populates the Textp slices within each
@@ -2520,7 +2562,7 @@ func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, exts
                        for i, list := range lists {
                                for _, s := range list {
                                        sym := Sym(s)
-                                       if l.attrReachable.Has(sym) && !assignedToUnit.Has(sym) {
+                                       if !assignedToUnit.Has(sym) {
                                                textp = append(textp, sym)
                                                unit := l.SymUnit(sym)
                                                if unit != nil {
@@ -2560,10 +2602,11 @@ type ErrorReporter struct {
 //
 // Logging an error means that on exit cmd/link will delete any
 // output file and return a non-zero error code.
-//
 func (reporter *ErrorReporter) Errorf(s Sym, format string, args ...interface{}) {
        if s != 0 && reporter.ldr.SymName(s) != "" {
-               format = reporter.ldr.SymName(s) + ": " + format
+               // Note: Replace is needed here because symbol names might have % in them,
+               // due to the use of LinkString for names of instantiating types.
+               format = strings.Replace(reporter.ldr.SymName(s), "%", "%%", -1) + ": " + format
        } else {
                format = fmt.Sprintf("sym %d: %s", s, format)
        }
@@ -2602,11 +2645,15 @@ func (l *Loader) Dump() {
        fmt.Println("Nsyms:", len(l.objSyms))
        fmt.Println("syms")
        for i := Sym(1); i < Sym(len(l.objSyms)); i++ {
-               pi := interface{}("")
+               pi := ""
                if l.IsExternal(i) {
                        pi = fmt.Sprintf("<ext %d>", l.extIndex(i))
                }
-               fmt.Println(i, l.SymName(i), l.SymType(i), pi)
+               sect := ""
+               if l.SymSect(i) != nil {
+                       sect = l.SymSect(i).Name
+               }
+               fmt.Printf("%v %v %v %v %x %v\n", i, l.SymName(i), l.SymType(i), pi, l.SymValue(i), sect)
        }
        fmt.Println("symsByName")
        for name, i := range l.symsByName[0] {