]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: use new sym format in pe loader
authorJeremy Faller <jeremy@golang.org>
Mon, 27 Jan 2020 20:31:41 +0000 (15:31 -0500)
committerJeremy Faller <jeremy@golang.org>
Wed, 5 Feb 2020 20:12:48 +0000 (20:12 +0000)
Change-Id: Ib784b8432ff4355b7ff4068801a0bcfcaf108950
Reviewed-on: https://go-review.googlesource.com/c/go/+/216718
Run-TryBot: Jeremy Faller <jeremy@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/link/internal/ld/ar.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/main.go
src/cmd/link/internal/ld/pe.go
src/cmd/link/internal/loader/loader.go
src/cmd/link/internal/loader/symbolbuilder.go
src/cmd/link/internal/loadpe/ldpe.go

index 9e770e2615964d7226fcfbba8b4e605358dd0598..268f40e92d69267c797ba62809294ee988185ea3 100644 (file)
@@ -104,30 +104,13 @@ func hostArchive(ctxt *Link, name string) {
        any := true
        for any {
                var load []uint64
-               if ctxt.IsELF {
-                       returnAllUndefs := -1
-                       undefs := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
-                       for _, symIdx := range undefs {
-                               name := ctxt.loader.SymName(symIdx)
-                               if off := armap[name]; off != 0 && !loaded[off] {
-                                       load = append(load, off)
-                                       loaded[off] = true
-                               }
-                       }
-               } else {
-                       for _, s := range ctxt.loader.Syms {
-                               if s == nil {
-                                       continue
-                               }
-                               for i := range s.R {
-                                       r := &s.R[i] // Copying sym.Reloc has measurable impact on performance
-                                       if r.Sym != nil && r.Sym.Type == sym.SXREF {
-                                               if off := armap[r.Sym.Name]; off != 0 && !loaded[off] {
-                                                       load = append(load, off)
-                                                       loaded[off] = true
-                                               }
-                                       }
-                               }
+               returnAllUndefs := -1
+               undefs := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
+               for _, symIdx := range undefs {
+                       name := ctxt.loader.SymName(symIdx)
+                       if off := armap[name]; off != 0 && !loaded[off] {
+                               load = append(load, off)
+                               loaded[off] = true
                        }
                }
 
index 1652724a44c0350d636d2dc218dc33bed4bd9330..912d283221cb63068de5522fa2abf62b0bcd01cd 100644 (file)
@@ -1883,10 +1883,10 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
                                Errorf(nil, "%v", err)
                                return
                        }
-                       if rsrc != nil {
+                       if rsrc != 0 {
                                setpersrc(ctxt, rsrc)
                        }
-                       ctxt.Textp = append(ctxt.Textp, textp...)
+                       ctxt.Textp2 = append(ctxt.Textp2, textp...)
                }
                return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
        }
@@ -2812,9 +2812,6 @@ func (ctxt *Link) loadlibfull() {
        ctxt.cgodata = nil
 
        addToTextp(ctxt)
-
-       // Drop the loader.
-       ctxt.loader = nil
 }
 
 func (ctxt *Link) dumpsyms() {
index 9b362ca8b89fadff0935315391d0f3ab5e39319d..e0168fbc561175017bca8f1b31641298fdaa920a 100644 (file)
@@ -98,7 +98,7 @@ var (
 )
 
 func (ctxt *Link) loaderSupport() bool {
-       return ctxt.IsELF || ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix
+       return true //ctxt.IsELF || ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix
 }
 
 // Main is the main entry point for the linker code.
index 4ab346e733a97fe05fa1ecd3fea9fc55d43ce7ad..e20d7da9aabb11aaef2c2545a83067d6a7d9eeff 100644 (file)
@@ -10,6 +10,7 @@ package ld
 import (
        "cmd/internal/objabi"
        "cmd/internal/sys"
+       "cmd/link/internal/loader"
        "cmd/link/internal/sym"
        "debug/pe"
        "encoding/binary"
@@ -282,7 +283,7 @@ type Dll struct {
 }
 
 var (
-       rsrcsym     *sym.Symbol
+       rsrcsym     loader.Sym
        PESECTHEADR int32
        PEFILEHEADR int32
        pe64        int
@@ -1469,27 +1470,30 @@ func (ctxt *Link) dope() {
        initdynexport(ctxt)
 }
 
-func setpersrc(ctxt *Link, sym *sym.Symbol) {
-       if rsrcsym != nil {
-               Errorf(sym, "too many .rsrc sections")
+func setpersrc(ctxt *Link, sym loader.Sym) {
+       if rsrcsym != 0 {
+               Errorf(nil, "too many .rsrc sections")
        }
 
        rsrcsym = sym
 }
 
 func addpersrc(ctxt *Link) {
-       if rsrcsym == nil {
+       if rsrcsym == 0 {
                return
        }
 
-       h := pefile.addSection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
+       data := ctxt.loader.Data(rsrcsym)
+       size := len(data)
+       h := pefile.addSection(".rsrc", size, size)
        h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
        h.checkOffset(ctxt.Out.Offset())
 
        // relocation
-       for ri := range rsrcsym.R {
-               r := &rsrcsym.R[ri]
-               p := rsrcsym.P[r.Off:]
+       relocs := ctxt.loader.Relocs(rsrcsym)
+       for i := 0; i < relocs.Count; i++ {
+               r := relocs.At(i)
+               p := data[r.Off:]
                val := uint32(int64(h.virtualAddress) + r.Add)
 
                // 32-bit little-endian
@@ -1500,8 +1504,8 @@ func addpersrc(ctxt *Link) {
                p[3] = byte(val >> 24)
        }
 
-       ctxt.Out.Write(rsrcsym.P)
-       h.pad(ctxt.Out, uint32(rsrcsym.Size))
+       ctxt.Out.Write(data)
+       h.pad(ctxt.Out, uint32(size))
 
        // update data directory
        pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
index 78e75c0a35ba8a003944a2dad776ede764676282..02a15dc1557c388a79c6faf7a25696250c1fcffe 100644 (file)
@@ -228,6 +228,8 @@ type Loader struct {
        extname    map[Sym]string      // stores Extname symbol attribute
        elfType    map[Sym]elf.SymType // stores elf type symbol property
        symFile    map[Sym]string      // stores file for shlib-derived syms
+       plt        map[Sym]int32       // stores dynimport for pe objects
+       got        map[Sym]int32       // stores got for pe objects
 
        // Used to implement field tracking; created during deadcode if
        // field tracking is enabled. Reachparent[K] contains the index of
@@ -282,6 +284,8 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
                attrReadOnly:         make(map[Sym]bool),
                elfType:              make(map[Sym]elf.SymType),
                symFile:              make(map[Sym]string),
+               plt:                  make(map[Sym]int32),
+               got:                  make(map[Sym]int32),
                attrTopFrame:         make(map[Sym]struct{}),
                attrSpecial:          make(map[Sym]struct{}),
                attrCgoExportDynamic: make(map[Sym]struct{}),
@@ -1154,7 +1158,7 @@ func (l *Loader) SymElfType(i Sym) elf.SymType {
        return elf.STT_NOTYPE
 }
 
-// SetSymElfType sets the  elf type attribute for a symbol.
+// SetSymElfType sets the elf type attribute for a symbol.
 func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
        // reject bad symbols
        if i > l.max || i == 0 {
@@ -1167,6 +1171,30 @@ func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
        }
 }
 
+// SetPlt sets the plt value for pe symbols.
+func (l *Loader) SetPlt(i Sym, v int32) {
+       if i > l.max || i == 0 {
+               panic("bad symbol for SetPlt")
+       }
+       if v == 0 {
+               delete(l.plt, i)
+       } else {
+               l.plt[i] = v
+       }
+}
+
+// SetGot sets the got value for pe symbols.
+func (l *Loader) SetGot(i Sym, v int32) {
+       if i > l.max || i == 0 {
+               panic("bad symbol for SetPlt")
+       }
+       if v == 0 {
+               delete(l.got, i)
+       } else {
+               l.got[i] = v
+       }
+}
+
 // SymGoType returns the 'Gotype' property for a given symbol (set by
 // the Go compiler for variable symbols). This version relies on
 // reading aux symbols for the target sym -- it could be that a faster
@@ -2078,6 +2106,14 @@ func (l *Loader) migrateAttributes(src Sym, dst *sym.Symbol) {
        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)
+       }
 }
 
 // CreateExtSym creates a new external symbol with the specified name
index e34bc989558cf28b71330930174e6cc32f481ba4..b6299610709ea24748a69f8db76b4a8e6a45427a 100644 (file)
@@ -88,6 +88,8 @@ func (sb *SymbolBuilder) SetLocalentry(value uint8)  { sb.l.SetSymLocalentry(sb.
 func (sb *SymbolBuilder) SetExtname(value string)    { sb.l.SetSymExtname(sb.symIdx, value) }
 func (sb *SymbolBuilder) SetDynimplib(value string)  { sb.l.SetSymDynimplib(sb.symIdx, value) }
 func (sb *SymbolBuilder) SetDynimpvers(value string) { sb.l.SetSymDynimpvers(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetPlt(value int32)         { sb.l.SetPlt(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetGot(value int32)         { sb.l.SetGot(sb.symIdx, value) }
 
 func (sb *SymbolBuilder) AddBytes(data []byte) {
        sb.setReachable()
index 7924d16b7c7087c333e80f28fb742bd9651a1fb6..807e4e903812a8289504ef3598f6f102aa3b3d08 100644 (file)
@@ -145,14 +145,24 @@ func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
        return n, nil
 }
 
+// makeUpdater creates a loader.SymbolBuilder if one hasn't been created previously.
+// We use this to lazily make SymbolBuilders as we don't always need a builder, and creating them for all symbols might be an error.
+func makeUpdater(l *loader.Loader, bld *loader.SymbolBuilder, s loader.Sym) *loader.SymbolBuilder {
+       if bld != nil {
+               return bld
+       }
+       bld, _ = l.MakeSymbolUpdater(s)
+       return bld
+}
+
 // Load loads the PE file pn from input.
 // Symbols are written into syms, and a slice of the text symbols is returned.
 // If an .rsrc section is found, its symbol is returned as rsrc.
-func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
-       lookup := func(name string, version int) *sym.Symbol {
-               return l.LookupOrCreate(name, version)
+func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, rsrc loader.Sym, err error) {
+       lookup := func(name string, version int) (*loader.SymbolBuilder, loader.Sym) {
+               return l.MakeSymbolUpdater(l.LookupOrCreateSym(name, version))
        }
-       sectsyms := make(map[*pe.Section]*sym.Symbol)
+       sectsyms := make(map[*pe.Section]loader.Sym)
        sectdata := make(map[*pe.Section][]byte)
 
        // Some input files are archives containing multiple of
@@ -164,7 +174,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
        // TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details)
        f, err := pe.NewFile(sr)
        if err != nil {
-               return nil, nil, err
+               return nil, 0, err
        }
        defer f.Close()
 
@@ -183,34 +193,34 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
                }
 
                name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
-               s := lookup(name, localSymVersion)
+               bld, s := lookup(name, localSymVersion)
 
                switch sect.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
                case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
-                       s.Type = sym.SRODATA
+                       bld.SetType(sym.SRODATA)
 
                case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
-                       s.Type = sym.SNOPTRBSS
+                       bld.SetType(sym.SNOPTRBSS)
 
                case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
-                       s.Type = sym.SNOPTRDATA
+                       bld.SetType(sym.SNOPTRDATA)
 
                case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
-                       s.Type = sym.STEXT
+                       bld.SetType(sym.STEXT)
 
                default:
-                       return nil, nil, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
+                       return nil, 0, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
                }
 
-               if s.Type != sym.SNOPTRBSS {
+               if bld.Type() != sym.SNOPTRBSS {
                        data, err := sect.Data()
                        if err != nil {
-                               return nil, nil, err
+                               return nil, 0, err
                        }
                        sectdata[sect] = data
-                       s.P = data
+                       bld.SetData(data)
                }
-               s.Size = int64(sect.Size)
+               bld.SetSize(int64(sect.Size))
                sectsyms[sect] = s
                if sect.Name == ".rsrc" {
                        rsrc = s
@@ -234,35 +244,35 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
                        continue
                }
 
-               rs := make([]sym.Reloc, rsect.NumberOfRelocations)
+               rs := make([]loader.Reloc, rsect.NumberOfRelocations)
                for j, r := range rsect.Relocs {
                        rp := &rs[j]
                        if int(r.SymbolTableIndex) >= len(f.COFFSymbols) {
-                               return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
+                               return nil, 0, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
                        }
                        pesym := &f.COFFSymbols[r.SymbolTableIndex]
-                       gosym, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
+                       _, gosym, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion)
                        if err != nil {
-                               return nil, nil, err
+                               return nil, 0, err
                        }
-                       if gosym == nil {
+                       if gosym == 0 {
                                name, err := pesym.FullName(f.StringTable)
                                if err != nil {
                                        name = string(pesym.Name[:])
                                }
-                               return nil, nil, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
+                               return nil, 0, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
                        }
 
                        rp.Sym = gosym
-                       rp.Siz = 4
+                       rp.Size = 4
                        rp.Off = int32(r.VirtualAddress)
                        switch arch.Family {
                        default:
-                               return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
+                               return nil, 0, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
                        case sys.I386, sys.AMD64:
                                switch r.Type {
                                default:
-                                       return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
+                                       return nil, 0, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
 
                                case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
                                        IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
@@ -278,7 +288,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
                                        rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
 
                                case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
-                                       rp.Siz = 8
+                                       rp.Size = 8
 
                                        rp.Type = objabi.R_ADDR
 
@@ -289,7 +299,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
                        case sys.ARM:
                                switch r.Type {
                                default:
-                                       return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
+                                       return nil, 0, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
 
                                case IMAGE_REL_ARM_SECREL:
                                        rp.Type = objabi.R_PCREL
@@ -316,11 +326,10 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
                        }
                }
 
-               sort.Sort(sym.RelocByOff(rs[:rsect.NumberOfRelocations]))
+               sort.Sort(loader.RelocByOff(rs[:rsect.NumberOfRelocations]))
 
-               s := sectsyms[rsect]
-               s.R = rs
-               s.R = s.R[:rsect.NumberOfRelocations]
+               bld, _ := l.MakeSymbolUpdater(sectsyms[rsect])
+               bld.SetRelocs(rs[:rsect.NumberOfRelocations])
        }
 
        // enter sub-symbols into symbol table.
@@ -331,7 +340,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
 
                name, err := pesym.FullName(f.StringTable)
                if err != nil {
-                       return nil, nil, err
+                       return nil, 0, err
                }
                if name == "" {
                        continue
@@ -353,54 +362,56 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
                        }
                }
 
-               s, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
+               bld, s, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion)
                if err != nil {
-                       return nil, nil, err
+                       return nil, 0, err
                }
 
                if pesym.SectionNumber == 0 { // extern
-                       if s.Type == sym.SDYNIMPORT {
-                               s.SetPlt(-2) // flag for dynimport in PE object files.
+                       if l.SymType(s) == sym.SDYNIMPORT {
+                               bld = makeUpdater(l, bld, s)
+                               bld.SetPlt(-2) // flag for dynimport in PE object files.
                        }
-                       if s.Type == sym.SXREF && pesym.Value > 0 { // global data
-                               s.Type = sym.SNOPTRDATA
-                               s.Size = int64(pesym.Value)
+                       if l.SymType(s) == sym.SXREF && pesym.Value > 0 { // global data
+                               bld = makeUpdater(l, bld, s)
+                               bld.SetType(sym.SNOPTRDATA)
+                               bld.SetSize(int64(pesym.Value))
                        }
 
                        continue
                } else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) {
                        sect = f.Sections[pesym.SectionNumber-1]
                        if _, found := sectsyms[sect]; !found {
-                               return nil, nil, fmt.Errorf("%s: %v: missing sect.sym", pn, s)
+                               return nil, 0, fmt.Errorf("%s: %v: missing sect.sym", pn, s)
                        }
                } else {
-                       return nil, nil, fmt.Errorf("%s: %v: sectnum < 0!", pn, s)
+                       return nil, 0, fmt.Errorf("%s: %v: sectnum < 0!", pn, s)
                }
 
                if sect == nil {
-                       return nil, rsrc, nil
+                       return nil, 0, nil
                }
 
-               if s.Outer != nil {
-                       if s.Attr.DuplicateOK() {
+               if l.OuterSym(s) != 0 {
+                       if l.AttrDuplicateOK(s) {
                                continue
                        }
-                       return nil, nil, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sectsyms[sect].Name)
+                       outerName := l.SymName(l.OuterSym(s))
+                       sectName := l.SymName(sectsyms[sect])
+                       return nil, 0, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, l.SymName(s), outerName, sectName)
                }
 
+               bld = makeUpdater(l, bld, s)
                sectsym := sectsyms[sect]
-               s.Sub = sectsym.Sub
-               sectsym.Sub = s
-               s.Type = sectsym.Type
-               s.Attr |= sym.AttrSubSymbol
-               s.Value = int64(pesym.Value)
-               s.Size = 4
-               s.Outer = sectsym
-               if sectsym.Type == sym.STEXT {
-                       if s.Attr.External() && !s.Attr.DuplicateOK() {
-                               return nil, nil, fmt.Errorf("%s: duplicate symbol definition", s.Name)
+               bld.SetType(l.SymType(sectsym))
+               l.PrependSub(sectsym, s)
+               bld.SetValue(int64(pesym.Value))
+               bld.SetSize(4)
+               if l.SymType(sectsym) == sym.STEXT {
+                       if bld.External() && !bld.DuplicateOK() {
+                               return nil, 0, fmt.Errorf("%s: duplicate symbol definition", l.SymName(s))
                        }
-                       s.Attr |= sym.AttrExternal
+                       bld.SetExternal(true)
                }
        }
 
@@ -408,23 +419,16 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
        // This keeps textp in increasing address order.
        for _, sect := range f.Sections {
                s := sectsyms[sect]
-               if s == nil {
+               if s == 0 {
                        continue
                }
-               if s.Sub != nil {
-                       s.Sub = sym.SortSub(s.Sub)
-               }
-               if s.Type == sym.STEXT {
-                       if s.Attr.OnList() {
-                               return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
-                       }
-                       s.Attr |= sym.AttrOnList
-                       textp = append(textp, s)
-                       for s = s.Sub; s != nil; s = s.Sub {
-                               if s.Attr.OnList() {
-                                       return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
+               l.SortSub(s)
+               if l.SymType(s) == sym.STEXT {
+                       for ; s != 0; s = l.SubSym(s) {
+                               if l.AttrOnList(s) {
+                                       return nil, 0, fmt.Errorf("symbol %s listed multiple times", l.SymName(s))
                                }
-                               s.Attr |= sym.AttrOnList
+                               l.SetAttrOnList(s, true)
                                textp = append(textp, s)
                        }
                }
@@ -437,14 +441,14 @@ func issect(s *pe.COFFSymbol) bool {
        return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.'
 }
 
-func readpesym(arch *sys.Arch, lookup func(string, int) *sym.Symbol, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]*sym.Symbol, localSymVersion int) (*sym.Symbol, error) {
+func readpesym(l *loader.Loader, arch *sys.Arch, lookup func(string, int) loader.Sym, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]loader.Sym, localSymVersion int) (*loader.SymbolBuilder, loader.Sym, error) {
        symname, err := pesym.FullName(f.StringTable)
        if err != nil {
-               return nil, err
+               return nil, 0, err
        }
        var name string
        if issect(pesym) {
-               name = sectsyms[f.Sections[pesym.SectionNumber-1]].Name
+               name = l.SymName(sectsyms[f.Sections[pesym.SectionNumber-1]])
        } else {
                name = symname
                switch arch.Family {
@@ -475,10 +479,11 @@ func readpesym(arch *sys.Arch, lookup func(string, int) *sym.Symbol, f *pe.File,
                name = name[:i]
        }
 
-       var s *sym.Symbol
+       var s loader.Sym
+       var bld *loader.SymbolBuilder
        switch pesym.Type {
        default:
-               return nil, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type)
+               return nil, 0, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type)
 
        case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
                switch pesym.StorageClass {
@@ -487,19 +492,22 @@ func readpesym(arch *sys.Arch, lookup func(string, int) *sym.Symbol, f *pe.File,
 
                case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
                        s = lookup(name, localSymVersion)
-                       s.Attr |= sym.AttrDuplicateOK
+                       bld = makeUpdater(l, bld, s)
+                       bld.SetDuplicateOK(true)
 
                default:
-                       return nil, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass)
+                       return nil, 0, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass)
                }
        }
 
-       if s != nil && s.Type == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) {
-               s.Type = sym.SXREF
+       if s != 0 && l.SymType(s) == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) {
+               bld = makeUpdater(l, bld, s)
+               bld.SetType(sym.SXREF)
        }
        if strings.HasPrefix(symname, "__imp_") {
-               s.SetGot(-2) // flag for __imp_
+               bld = makeUpdater(l, bld, s)
+               bld.SetGot(-2) // flag for __imp_
        }
 
-       return s, nil
+       return bld, s, nil
 }