]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: convert pcln linker phase to use loader APIs
authorThan McIntosh <thanm@google.com>
Tue, 7 Apr 2020 21:08:00 +0000 (17:08 -0400)
committerThan McIntosh <thanm@google.com>
Fri, 10 Apr 2020 16:35:02 +0000 (16:35 +0000)
Rework the linker's pcln phase to work with the new loader. As part of
this set of changes the handling of "go.file..." symbols has been
revised somewhat -- previously they were treated as always live in the
loader, and now we no longer do this.

The original plan had been to have the new implementation generate
nameless "inltree" symbols, however the plan now is to keep them
named for now and convert them to nameless in a subsequent patch.

Change-Id: If71c93ff1f146dbb63b6ee2546308acdc94b643c
Reviewed-on: https://go-review.googlesource.com/c/go/+/227759
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/link.go
src/cmd/link/internal/ld/macho.go
src/cmd/link/internal/ld/main.go
src/cmd/link/internal/ld/pcln.go
src/cmd/link/internal/ld/symtab.go
src/cmd/link/internal/loader/loader.go

index e560fea2f1fa69548133f536e41984776726c7c9..ebabc2037831f2f03f029e93c64f36889d7f9ed7 100644 (file)
@@ -2808,6 +2808,10 @@ func (ctxt *Link) loadlibfull() {
 
        // Set special global symbols.
        ctxt.setArchSyms(AfterLoadlibFull)
+
+       // Convert special symbols created by pcln.
+       pclntabFirstFunc = ctxt.loader.Syms[pclntabFirstFunc2]
+       pclntabLastFunc = ctxt.loader.Syms[pclntabLastFunc2]
 }
 
 func (ctxt *Link) dumpsyms() {
index a2ea34ea222c2bee388d452d303bea96259e77af..8695a3a9042912f3d8bb2b2cf5baa3d2d3693518 100644 (file)
@@ -73,7 +73,7 @@ type Link struct {
        Shlibs       []Shlib
        Textp        []*sym.Symbol
        Textp2       []loader.Sym
-       Filesyms     []*sym.Symbol
+       NumFilesyms  int
        Moduledata   *sym.Symbol
        Moduledata2  loader.Sym
 
index 0f36cd0cbe618a51df0f55d54c248d736f3edd79..4429b74d1efbda03b74675f54af28b749f020bcb 100644 (file)
@@ -890,7 +890,7 @@ func machosymtab(ctxt *Link) {
                // symbols like crosscall2 are in pclntab and end up
                // pointing at the host binary, breaking unwinding.
                // See Issue #18190.
-               cexport := !isGoSymbol && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s))
+               cexport := !isGoSymbol && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s.Name))
                if cexport || export || isGoSymbol {
                        symstr.AddUint8('_')
                }
index 1985f41ff134f997868595289950224590ebc498..48f89c96d4dfed1b4c1b2c725b3d6aef3ad78d2f 100644 (file)
@@ -294,10 +294,10 @@ func Main(arch *sys.Arch, theArch Arch) {
        ctxt.typelink()
        bench.Start("buildinfo")
        ctxt.buildinfo()
-       bench.Start("loadlibfull")
-       ctxt.loadlibfull() // XXX do it here for now
        bench.Start("pclntab")
        ctxt.pclntab()
+       bench.Start("loadlibfull")
+       ctxt.loadlibfull() // XXX do it here for now
        bench.Start("findfunctab")
        ctxt.findfunctab()
        bench.Start("symtab")
index 3e8135c959c7d0f6e527028c58eaeb0bccf2d661..d6bba56eeeed601ffa21c72862748cf84c9dd1aa 100644 (file)
@@ -9,6 +9,7 @@ import (
        "cmd/internal/objabi"
        "cmd/internal/src"
        "cmd/internal/sys"
+       "cmd/link/internal/loader"
        "cmd/link/internal/sym"
        "encoding/binary"
        "fmt"
@@ -18,28 +19,71 @@ import (
        "strings"
 )
 
-func ftabaddstring(ftab *sym.Symbol, s string) int32 {
-       start := len(ftab.P)
+// pclnState holds state information used during pclntab generation.
+// Here 'ldr' is just a pointer to the context's loader, 'container'
+// is a bitmap holding whether a given symbol index is an outer or
+// container symbol, 'deferReturnSym' is the index for the symbol
+// "runtime.deferreturn", 'nameToOffset' is a helper function for
+// capturing function names, 'numberedFiles' records the file number
+// assigned to a given file symbol, 'filepaths' is a slice of
+// expanded paths (indexed by file number).
+type pclnState struct {
+       ldr            *loader.Loader
+       container      loader.Bitmap
+       deferReturnSym loader.Sym
+       nameToOffset   func(name string) int32
+       numberedFiles  map[loader.Sym]int64
+       filepaths      []string
+}
+
+func makepclnState(ctxt *Link) pclnState {
+       ldr := ctxt.loader
+       drs := ldr.Lookup("runtime.deferreturn", sym.SymVerABIInternal)
+       return pclnState{
+               container:      loader.MakeBitmap(ldr.NSym()),
+               ldr:            ldr,
+               deferReturnSym: drs,
+               numberedFiles:  make(map[loader.Sym]int64),
+               // NB: initial entry in filepaths below is to reserve the zero value,
+               // so that when we do a map lookup in numberedFiles fails, it will not
+               // return a value slot in filepaths.
+               filepaths: []string{""},
+       }
+}
+
+func (state *pclnState) ftabaddstring(ftab *loader.SymbolBuilder, s string) int32 {
+       start := len(ftab.Data())
        ftab.Grow(int64(start + len(s) + 1)) // make room for s plus trailing NUL
-       copy(ftab.P[start:], s)
+       ftd := ftab.Data()
+       copy(ftd[start:], s)
        return int32(start)
 }
 
 // numberfile assigns a file number to the file if it hasn't been assigned already.
-func numberfile(ctxt *Link, file *sym.Symbol) {
-       if file.Type != sym.SFILEPATH {
-               ctxt.Filesyms = append(ctxt.Filesyms, file)
-               file.Value = int64(len(ctxt.Filesyms))
-               file.Type = sym.SFILEPATH
-               path := file.Name[len(src.FileSymPrefix):]
-               file.Name = expandGoroot(path)
+func (state *pclnState) numberfile(file loader.Sym) int64 {
+       if val, ok := state.numberedFiles[file]; ok {
+               return val
        }
+       sn := state.ldr.SymName(file)
+       path := sn[len(src.FileSymPrefix):]
+       val := int64(len(state.filepaths))
+       state.numberedFiles[file] = val
+       state.filepaths = append(state.filepaths, expandGoroot(path))
+       return val
 }
 
-func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
+func (state *pclnState) fileVal(file loader.Sym) int64 {
+       if val, ok := state.numberedFiles[file]; ok {
+               return val
+       }
+       panic("should have been numbered first")
+}
+
+func (state *pclnState) renumberfiles(ctxt *Link, fi loader.FuncInfo, d *sym.Pcdata) {
        // Give files numbers.
-       for _, f := range files {
-               numberfile(ctxt, f)
+       nf := fi.NumFile()
+       for i := uint32(0); i < nf; i++ {
+               state.numberfile(fi.File(int(i)))
        }
 
        buf := make([]byte, binary.MaxVarintLen32)
@@ -54,10 +98,10 @@ func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
                if oldval == -1 {
                        val = -1
                } else {
-                       if oldval < 0 || oldval >= int32(len(files)) {
+                       if oldval < 0 || oldval >= int32(nf) {
                                log.Fatalf("bad pcdata %d", oldval)
                        }
-                       val = int32(files[oldval].Value)
+                       val = int32(state.fileVal(fi.File(int(oldval))))
                }
 
                dv := val - newval
@@ -80,23 +124,33 @@ func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
        *d = out
 }
 
-// onlycsymbol reports whether this is a symbol that is referenced by C code.
-func onlycsymbol(s *sym.Symbol) bool {
-       switch s.Name {
+// onlycsymbol looks at a symbol's name to report whether this is a
+// symbol that is referenced by C code
+func onlycsymbol(sname string) bool {
+       switch sname {
        case "_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2":
                return true
        }
-       if strings.HasPrefix(s.Name, "_cgoexp_") {
+       if strings.HasPrefix(sname, "_cgoexp_") {
                return true
        }
        return false
 }
 
+func (state *pclnState) emitPcln(ctxt *Link, s loader.Sym) bool {
+       if ctxt.BuildMode == BuildModePlugin && ctxt.HeadType == objabi.Hdarwin && onlycsymbol(state.ldr.SymName(s)) {
+               return false
+       }
+       // We want to generate func table entries only for the "lowest
+       // level" symbols, not containers of subsymbols.
+       return !state.container.Has(s)
+}
+
 func emitPcln(ctxt *Link, s *sym.Symbol) bool {
        if s == nil {
                return true
        }
-       if ctxt.BuildMode == BuildModePlugin && ctxt.HeadType == objabi.Hdarwin && onlycsymbol(s) {
+       if ctxt.BuildMode == BuildModePlugin && ctxt.HeadType == objabi.Hdarwin && onlycsymbol(s.Name) {
                return false
        }
        // We want to generate func table entries only for the "lowest level" symbols,
@@ -104,23 +158,108 @@ func emitPcln(ctxt *Link, s *sym.Symbol) bool {
        return !s.Attr.Container()
 }
 
+func (state *pclnState) computeDeferReturn(target *Target, s loader.Sym) uint32 {
+       deferreturn := uint32(0)
+       lastWasmAddr := uint32(0)
+
+       relocs := state.ldr.Relocs(s)
+       for ri := 0; ri < relocs.Count(); ri++ {
+               r := relocs.At2(ri)
+               if target.IsWasm() && r.Type() == objabi.R_ADDR {
+                       // Wasm does not have a live variable set at the deferreturn
+                       // call itself. Instead it has one identified by the
+                       // resumption point immediately preceding the deferreturn.
+                       // The wasm code has a R_ADDR relocation which is used to
+                       // set the resumption point to PC_B.
+                       lastWasmAddr = uint32(r.Add())
+               }
+               if r.Type().IsDirectCall() && r.Sym() == state.deferReturnSym {
+                       if target.IsWasm() {
+                               deferreturn = lastWasmAddr - 1
+                       } else {
+                               // Note: the relocation target is in the call instruction, but
+                               // is not necessarily the whole instruction (for instance, on
+                               // x86 the relocation applies to bytes [1:5] of the 5 byte call
+                               // instruction).
+                               deferreturn = uint32(r.Off())
+                               switch target.Arch.Family {
+                               case sys.AMD64, sys.I386:
+                                       deferreturn--
+                               case sys.PPC64, sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64:
+                                       // no change
+                               case sys.RISCV64:
+                                       // TODO(jsing): The JALR instruction is marked with
+                                       // R_CALLRISCV, whereas the actual reloc is currently
+                                       // one instruction earlier starting with the AUIPC.
+                                       deferreturn -= 4
+                               case sys.S390X:
+                                       deferreturn -= 2
+                               default:
+                                       panic(fmt.Sprint("Unhandled architecture:", target.Arch.Family))
+                               }
+                       }
+                       break // only need one
+               }
+       }
+       return deferreturn
+}
+
+// genInlTreeSym generates the InlTree sym for the a given function symbol
+// with name 'sn'.
+func (state *pclnState) genInlTreeSym(sn string, fi loader.FuncInfo, arch *sys.Arch) loader.Sym {
+       itsName := "inltree." + sn
+       ldr := state.ldr
+       if ldr.Lookup(itsName, 0) != 0 {
+               panic("should not exist yet")
+       }
+       its := ldr.LookupOrCreateSym(itsName, 0)
+       inlTreeSym := ldr.MakeSymbolUpdater(its)
+       inlTreeSym.SetType(sym.SRODATA)
+       ldr.SetAttrReachable(its, true)
+       ninl := fi.NumInlTree()
+       for i := 0; i < int(ninl); i++ {
+               call := fi.InlTree(i)
+               // Usually, call.File is already numbered since the file
+               // shows up in the Pcfile table. However, two inlined calls
+               // might overlap exactly so that only the innermost file
+               // appears in the Pcfile table. In that case, this assigns
+               // the outer file a number.
+               val := state.numberfile(call.File)
+               fn := ldr.SymName(call.Func)
+               nameoff := state.nameToOffset(fn)
+
+               inlTreeSym.SetUint16(arch, int64(i*20+0), uint16(call.Parent))
+               inlTreeSym.SetUint8(arch, int64(i*20+2), uint8(objabi.GetFuncID(fn, "")))
+               // byte 3 is unused
+               inlTreeSym.SetUint32(arch, int64(i*20+4), uint32(val))
+               inlTreeSym.SetUint32(arch, int64(i*20+8), uint32(call.Line))
+               inlTreeSym.SetUint32(arch, int64(i*20+12), uint32(nameoff))
+               inlTreeSym.SetUint32(arch, int64(i*20+16), uint32(call.ParentPC))
+       }
+       return its
+}
+
 // pclntab initializes the pclntab symbol with
 // runtime function and file name information.
 
-var pclntabZpcln sym.FuncInfo
-
 // These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
 var pclntabNfunc int32
 var pclntabFiletabOffset int32
 var pclntabPclntabOffset int32
 var pclntabFirstFunc *sym.Symbol
 var pclntabLastFunc *sym.Symbol
+var pclntabFirstFunc2 loader.Sym
+var pclntabLastFunc2 loader.Sym
 
 func (ctxt *Link) pclntab() {
        funcdataBytes := int64(0)
-       ftab := ctxt.Syms.Lookup("runtime.pclntab", 0)
-       ftab.Type = sym.SPCLNTAB
-       ftab.Attr |= sym.AttrReachable
+       ldr := ctxt.loader
+       ftabsym := ldr.LookupOrCreateSym("runtime.pclntab", 0)
+       ftab := ldr.MakeSymbolUpdater(ftabsym)
+       ftab.SetType(sym.SPCLNTAB)
+       ldr.SetAttrReachable(ftabsym, true)
+
+       state := makepclnState(ctxt)
 
        // See golang.org/s/go12symtab for the format. Briefly:
        //      8-byte header
@@ -130,30 +269,33 @@ func (ctxt *Link) pclntab() {
        //      offset to file table [4 bytes]
 
        // Find container symbols and mark them as such.
-       for _, s := range ctxt.Textp {
-               if s.Outer != nil {
-                       s.Outer.Attr |= sym.AttrContainer
+       for _, s := range ctxt.Textp2 {
+               outer := ldr.OuterSym(s)
+               if outer != 0 {
+                       state.container.Set(outer)
                }
        }
 
        // Gather some basic stats and info.
        var nfunc int32
-       prevSect := ctxt.Textp[0].Sect
-       for _, s := range ctxt.Textp {
-               if !emitPcln(ctxt, s) {
+       prevSect := ldr.SymSect(ctxt.Textp2[0])
+       for _, s := range ctxt.Textp2 {
+               if !state.emitPcln(ctxt, s) {
                        continue
                }
                nfunc++
-               if pclntabFirstFunc == nil {
-                       pclntabFirstFunc = s
+               if pclntabFirstFunc2 == 0 {
+                       pclntabFirstFunc2 = s
                }
-               if s.Sect != prevSect {
-                       // With multiple text sections, the external linker may insert functions
-                       // between the sections, which are not known by Go. This leaves holes in
-                       // the PC range covered by the func table. We need to generate an entry
-                       // to mark the hole.
+               ss := ldr.SymSect(s)
+               if ss != prevSect {
+                       // With multiple text sections, the external linker may
+                       // insert functions between the sections, which are not
+                       // known by Go. This leaves holes in the PC range covered
+                       // by the func table. We need to generate an entry to mark
+                       // the hole.
                        nfunc++
-                       prevSect = s.Sect
+                       prevSect = ss
                }
        }
 
@@ -165,22 +307,24 @@ func (ctxt *Link) pclntab() {
        ftab.SetUint(ctxt.Arch, 8, uint64(nfunc))
        pclntabPclntabOffset = int32(8 + ctxt.Arch.PtrSize)
 
-       funcnameoff := make(map[string]int32)
+       szHint := len(ctxt.Textp2) * 2
+       funcnameoff := make(map[string]int32, szHint)
        nameToOffset := func(name string) int32 {
                nameoff, ok := funcnameoff[name]
                if !ok {
-                       nameoff = ftabaddstring(ftab, name)
+                       nameoff = state.ftabaddstring(ftab, name)
                        funcnameoff[name] = nameoff
                }
                return nameoff
        }
+       state.nameToOffset = nameToOffset
 
-       pctaboff := make(map[string]uint32)
+       pctaboff := make(map[string]uint32, szHint)
        writepctab := func(off int32, p []byte) int32 {
                start, ok := pctaboff[string(p)]
                if !ok {
                        if len(p) > 0 {
-                               start = uint32(len(ftab.P))
+                               start = uint32(len(ftab.Data()))
                                ftab.AddBytes(p)
                        }
                        pctaboff[string(p)] = start
@@ -189,52 +333,82 @@ func (ctxt *Link) pclntab() {
                return newoff
        }
 
+       pcsp := sym.Pcdata{}
+       pcfile := sym.Pcdata{}
+       pcline := sym.Pcdata{}
+       pcdata := []sym.Pcdata{}
+       funcdata := []loader.Sym{}
+       funcdataoff := []int64{}
+
        nfunc = 0 // repurpose nfunc as a running index
-       prevFunc := ctxt.Textp[0]
-       for _, s := range ctxt.Textp {
-               if !emitPcln(ctxt, s) {
+       prevFunc := ctxt.Textp2[0]
+       for _, s := range ctxt.Textp2 {
+               if !state.emitPcln(ctxt, s) {
                        continue
                }
 
-               if s.Sect != prevFunc.Sect {
-                       // With multiple text sections, there may be a hole here in the address
-                       // space (see the comment above). We use an invalid funcoff value to
-                       // mark the hole.
-                       // See also runtime/symtab.go:findfunc
-                       ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), prevFunc, prevFunc.Size)
+               thisSect := ldr.SymSect(s)
+               prevSect := ldr.SymSect(prevFunc)
+               if thisSect != prevSect {
+                       // With multiple text sections, there may be a hole here
+                       // in the address space (see the comment above). We use an
+                       // invalid funcoff value to mark the hole. See also
+                       // runtime/symtab.go:findfunc
+                       prevFuncSize := int64(ldr.SymSize(prevFunc))
+                       ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), prevFunc, prevFuncSize)
                        ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), ^uint64(0))
                        nfunc++
                }
                prevFunc = s
 
-               pcln := s.FuncInfo
-               if pcln == nil {
-                       pcln = &pclntabZpcln
+               pcsp.P = pcsp.P[:0]
+               pcline.P = pcline.P[:0]
+               pcfile.P = pcfile.P[:0]
+               pcdata = pcdata[:0]
+               funcdataoff = funcdataoff[:0]
+               funcdata = funcdata[:0]
+               fi := ldr.FuncInfo(s)
+               if fi.Valid() {
+                       fi.Preload()
+                       npc := fi.NumPcdata()
+                       for i := uint32(0); i < npc; i++ {
+                               pcdata = append(pcdata, sym.Pcdata{P: fi.Pcdata(int(i))})
+                       }
+                       nfd := fi.NumFuncdataoff()
+                       for i := uint32(0); i < nfd; i++ {
+                               funcdataoff = append(funcdataoff, fi.Funcdataoff(int(i)))
+                       }
+                       funcdata = fi.Funcdata(s, funcdata)
                }
 
-               if len(pcln.InlTree) > 0 {
-                       if len(pcln.Pcdata) <= objabi.PCDATA_InlTreeIndex {
+               if fi.Valid() && fi.NumInlTree() > 0 {
+
+                       if len(pcdata) <= objabi.PCDATA_InlTreeIndex {
                                // Create inlining pcdata table.
-                               pcdata := make([]sym.Pcdata, objabi.PCDATA_InlTreeIndex+1)
-                               copy(pcdata, pcln.Pcdata)
-                               pcln.Pcdata = pcdata
+                               newpcdata := make([]sym.Pcdata, objabi.PCDATA_InlTreeIndex+1)
+                               copy(newpcdata, pcdata)
+                               pcdata = newpcdata
                        }
 
-                       if len(pcln.Funcdataoff) <= objabi.FUNCDATA_InlTree {
+                       if len(funcdataoff) <= objabi.FUNCDATA_InlTree {
                                // Create inline tree funcdata.
-                               funcdata := make([]*sym.Symbol, objabi.FUNCDATA_InlTree+1)
-                               funcdataoff := make([]int64, objabi.FUNCDATA_InlTree+1)
-                               copy(funcdata, pcln.Funcdata)
-                               copy(funcdataoff, pcln.Funcdataoff)
-                               pcln.Funcdata = funcdata
-                               pcln.Funcdataoff = funcdataoff
+                               newfuncdata := make([]loader.Sym, objabi.FUNCDATA_InlTree+1)
+                               newfuncdataoff := make([]int64, objabi.FUNCDATA_InlTree+1)
+                               copy(newfuncdata, funcdata)
+                               copy(newfuncdataoff, funcdataoff)
+                               funcdata = newfuncdata
+                               funcdataoff = newfuncdataoff
                        }
                }
 
-               funcstart := int32(len(ftab.P))
-               funcstart += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1) // align to ptrsize
+               dSize := len(ftab.Data())
+               funcstart := int32(dSize)
+               funcstart += int32(-dSize) & (int32(ctxt.Arch.PtrSize) - 1) // align to ptrsize
 
-               ftab.SetAddr(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), s)
+               // NB: for the static binary internal-link case, we could just
+               // emit the symbol value instead of creating a relocation here
+               // (might speed things up for that case).
+               ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), s, 0)
                ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint64(funcstart))
 
                // Write runtime._func. Keep in sync with ../../../../runtime/runtime2.go:/_func
@@ -243,122 +417,68 @@ func (ctxt *Link) pclntab() {
                // fixed size of struct, checked below
                off := funcstart
 
-               end := funcstart + int32(ctxt.Arch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(ctxt.Arch.PtrSize)
-               if len(pcln.Funcdata) > 0 && (end&int32(ctxt.Arch.PtrSize-1) != 0) {
+               end := funcstart + int32(ctxt.Arch.PtrSize) + 3*4 + 5*4 + int32(len(pcdata))*4 + int32(len(funcdata))*int32(ctxt.Arch.PtrSize)
+               if len(funcdata) > 0 && (end&int32(ctxt.Arch.PtrSize-1) != 0) {
                        end += 4
                }
                ftab.Grow(int64(end))
 
                // entry uintptr
-               off = int32(ftab.SetAddr(ctxt.Arch, int64(off), s))
+               off = int32(ftab.SetAddrPlus(ctxt.Arch, int64(off), s, 0))
 
                // name int32
-               nameoff := nameToOffset(s.Name)
+               sn := ldr.SymName(s)
+               nameoff := nameToOffset(sn)
                off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(nameoff)))
 
                // args int32
                // TODO: Move into funcinfo.
                args := uint32(0)
-               if s.FuncInfo != nil {
-                       args = uint32(s.FuncInfo.Args)
+               if fi.Valid() {
+                       args = uint32(fi.Args())
                }
                off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args))
 
                // deferreturn
-               deferreturn := uint32(0)
-               lastWasmAddr := uint32(0)
-               for _, r := range s.R {
-                       if ctxt.Arch.Family == sys.Wasm && r.Type == objabi.R_ADDR {
-                               // Wasm does not have a live variable set at the deferreturn
-                               // call itself. Instead it has one identified by the
-                               // resumption point immediately preceding the deferreturn.
-                               // The wasm code has a R_ADDR relocation which is used to
-                               // set the resumption point to PC_B.
-                               lastWasmAddr = uint32(r.Add)
-                       }
-                       if r.Type.IsDirectCall() && r.Sym != nil && r.Sym.Name == "runtime.deferreturn" {
-                               if ctxt.Arch.Family == sys.Wasm {
-                                       deferreturn = lastWasmAddr - 1
-                               } else {
-                                       // Note: the relocation target is in the call instruction, but
-                                       // is not necessarily the whole instruction (for instance, on
-                                       // x86 the relocation applies to bytes [1:5] of the 5 byte call
-                                       // instruction).
-                                       deferreturn = uint32(r.Off)
-                                       switch ctxt.Arch.Family {
-                                       case sys.AMD64, sys.I386:
-                                               deferreturn--
-                                       case sys.PPC64, sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64:
-                                               // no change
-                                       case sys.RISCV64:
-                                               // TODO(jsing): The JALR instruction is marked with
-                                               // R_CALLRISCV, whereas the actual reloc is currently
-                                               // one instruction earlier starting with the AUIPC.
-                                               deferreturn -= 4
-                                       case sys.S390X:
-                                               deferreturn -= 2
-                                       default:
-                                               panic(fmt.Sprint("Unhandled architecture:", ctxt.Arch.Family))
-                                       }
-                               }
-                               break // only need one
-                       }
-               }
+               deferreturn := state.computeDeferReturn(&ctxt.Target, s)
                off = int32(ftab.SetUint32(ctxt.Arch, int64(off), deferreturn))
 
-               if pcln != &pclntabZpcln {
-                       renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
+               if fi.Valid() {
+                       pcsp = sym.Pcdata{P: fi.Pcsp()}
+                       pcfile = sym.Pcdata{P: fi.Pcfile()}
+                       pcline = sym.Pcdata{P: fi.Pcline()}
+                       state.renumberfiles(ctxt, fi, &pcfile)
                        if false {
                                // Sanity check the new numbering
                                it := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
-                               for it.Init(pcln.Pcfile.P); !it.Done; it.Next() {
-                                       if it.Value < 1 || it.Value > int32(len(ctxt.Filesyms)) {
-                                               Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.Value, len(ctxt.Filesyms))
+                               for it.Init(pcfile.P); !it.Done; it.Next() {
+                                       if it.Value < 1 || it.Value > int32(len(state.numberedFiles)) {
+                                               ctxt.Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.Value, len(state.numberedFiles))
                                                errorexit()
                                        }
                                }
                        }
                }
 
-               if len(pcln.InlTree) > 0 {
-                       inlTreeSym := ctxt.Syms.Lookup("inltree."+s.Name, 0)
-                       inlTreeSym.Type = sym.SRODATA
-                       inlTreeSym.Attr |= sym.AttrReachable | sym.AttrDuplicateOK
-
-                       for i, call := range pcln.InlTree {
-                               // Usually, call.File is already numbered since the file
-                               // shows up in the Pcfile table. However, two inlined calls
-                               // might overlap exactly so that only the innermost file
-                               // appears in the Pcfile table. In that case, this assigns
-                               // the outer file a number.
-                               numberfile(ctxt, call.File)
-                               nameoff := nameToOffset(call.Func)
-
-                               inlTreeSym.SetUint16(ctxt.Arch, int64(i*20+0), uint16(call.Parent))
-                               inlTreeSym.SetUint8(ctxt.Arch, int64(i*20+2), uint8(objabi.GetFuncID(call.Func, "")))
-                               // byte 3 is unused
-                               inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+4), uint32(call.File.Value))
-                               inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+8), uint32(call.Line))
-                               inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+12), uint32(nameoff))
-                               inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+16), uint32(call.ParentPC))
-                       }
-
-                       pcln.Funcdata[objabi.FUNCDATA_InlTree] = inlTreeSym
-                       pcln.Pcdata[objabi.PCDATA_InlTreeIndex] = pcln.Pcinline
+               if fi.Valid() && fi.NumInlTree() > 0 {
+                       its := state.genInlTreeSym(sn, fi, ctxt.Arch)
+                       funcdata[objabi.FUNCDATA_InlTree] = its
+                       pcdata[objabi.PCDATA_InlTreeIndex] = sym.Pcdata{P: fi.Pcinline()}
                }
 
                // pcdata
-               off = writepctab(off, pcln.Pcsp.P)
-               off = writepctab(off, pcln.Pcfile.P)
-               off = writepctab(off, pcln.Pcline.P)
-               off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(len(pcln.Pcdata))))
+               off = writepctab(off, pcsp.P)
+               off = writepctab(off, pcfile.P)
+               off = writepctab(off, pcline.P)
+               off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(len(pcdata))))
 
                // funcID uint8
                var file string
-               if s.FuncInfo != nil && len(s.FuncInfo.File) > 0 {
-                       file = s.FuncInfo.File[0].Name
+               if fi.Valid() && fi.NumFile() > 0 {
+                       filesymname := ldr.SymName(fi.File(0))
+                       file = filesymname[len(src.FileSymPrefix):]
                }
-               funcID := objabi.GetFuncID(s.Name, file)
+               funcID := objabi.GetFuncID(sn, file)
 
                off = int32(ftab.SetUint8(ctxt.Arch, int64(off), uint8(funcID)))
 
@@ -366,61 +486,65 @@ func (ctxt *Link) pclntab() {
                off += 2
 
                // nfuncdata must be the final entry.
-               off = int32(ftab.SetUint8(ctxt.Arch, int64(off), uint8(len(pcln.Funcdata))))
-               for i := range pcln.Pcdata {
-                       off = writepctab(off, pcln.Pcdata[i].P)
+               off = int32(ftab.SetUint8(ctxt.Arch, int64(off), uint8(len(funcdata))))
+               for i := range pcdata {
+                       off = writepctab(off, pcdata[i].P)
                }
 
                // funcdata, must be pointer-aligned and we're only int32-aligned.
                // Missing funcdata will be 0 (nil pointer).
-               if len(pcln.Funcdata) > 0 {
+               if len(funcdata) > 0 {
                        if off&int32(ctxt.Arch.PtrSize-1) != 0 {
                                off += 4
                        }
-                       for i := range pcln.Funcdata {
+                       for i := range funcdata {
                                dataoff := int64(off) + int64(ctxt.Arch.PtrSize)*int64(i)
-                               if pcln.Funcdata[i] == nil {
-                                       ftab.SetUint(ctxt.Arch, dataoff, uint64(pcln.Funcdataoff[i]))
+                               if funcdata[i] == 0 {
+                                       ftab.SetUint(ctxt.Arch, dataoff, uint64(funcdataoff[i]))
                                        continue
                                }
                                // TODO: Dedup.
-                               funcdataBytes += pcln.Funcdata[i].Size
-                               ftab.SetAddrPlus(ctxt.Arch, dataoff, pcln.Funcdata[i], pcln.Funcdataoff[i])
+                               funcdataBytes += int64(len(ldr.Data(funcdata[i])))
+                               ftab.SetAddrPlus(ctxt.Arch, dataoff, funcdata[i], funcdataoff[i])
                        }
-                       off += int32(len(pcln.Funcdata)) * int32(ctxt.Arch.PtrSize)
+                       off += int32(len(funcdata)) * int32(ctxt.Arch.PtrSize)
                }
 
                if off != end {
-                       Errorf(s, "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), ctxt.Arch.PtrSize)
+                       ctxt.Errorf(s, "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcdata), len(funcdata), ctxt.Arch.PtrSize)
                        errorexit()
                }
 
                nfunc++
        }
 
-       last := ctxt.Textp[len(ctxt.Textp)-1]
-       pclntabLastFunc = last
+       last := ctxt.Textp2[len(ctxt.Textp2)-1]
+       pclntabLastFunc2 = last
        // Final entry of table is just end pc.
-       ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), last, last.Size)
+       ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), last, ldr.SymSize(last))
 
        // Start file table.
-       start := int32(len(ftab.P))
-
-       start += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1)
+       dSize := len(ftab.Data())
+       start := int32(dSize)
+       start += int32(-dSize) & (int32(ctxt.Arch.PtrSize) - 1)
        pclntabFiletabOffset = start
        ftab.SetUint32(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint32(start))
 
-       ftab.Grow(int64(start) + (int64(len(ctxt.Filesyms))+1)*4)
-       ftab.SetUint32(ctxt.Arch, int64(start), uint32(len(ctxt.Filesyms)+1))
-       for i := len(ctxt.Filesyms) - 1; i >= 0; i-- {
-               s := ctxt.Filesyms[i]
-               ftab.SetUint32(ctxt.Arch, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name)))
+       nf := len(state.numberedFiles)
+       ftab.Grow(int64(start) + int64((nf+1)*4))
+       ftab.SetUint32(ctxt.Arch, int64(start), uint32(nf+1))
+       for i := nf; i > 0; i-- {
+               path := state.filepaths[i]
+               val := int64(i)
+               ftab.SetUint32(ctxt.Arch, int64(start)+val*4, uint32(state.ftabaddstring(ftab, path)))
        }
 
-       ftab.Size = int64(len(ftab.P))
+       ftab.SetSize(int64(len(ftab.Data())))
+
+       ctxt.NumFilesyms = len(state.numberedFiles)
 
        if ctxt.Debugvlog != 0 {
-               ctxt.Logf("pclntab=%d bytes, funcdata total %d bytes\n", ftab.Size, funcdataBytes)
+               ctxt.Logf("pclntab=%d bytes, funcdata total %d bytes\n", ftab.Size(), funcdataBytes)
        }
 }
 
index 97cbb5616e508553e3ba1d9ea3479fad5896dfed..290bf5edaa56ec37b0c22a7f2233057b216cf4ed 100644 (file)
@@ -554,8 +554,8 @@ func (ctxt *Link) symtab() {
        moduledata.AddUint(ctxt.Arch, uint64(pclntabNfunc+1))
        // The filetab slice
        moduledata.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabFiletabOffset))
-       moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Filesyms))+1)
-       moduledata.AddUint(ctxt.Arch, uint64(len(ctxt.Filesyms))+1)
+       moduledata.AddUint(ctxt.Arch, uint64(ctxt.NumFilesyms)+1)
+       moduledata.AddUint(ctxt.Arch, uint64(ctxt.NumFilesyms)+1)
        // findfunctab
        moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.findfunctab", 0))
        // minpc, maxpc
index 390eb1af24325b0d86876f99874620c169b56f83..6e814c1e6421fe498cd14b2115596de16dd68691 100644 (file)
@@ -1861,7 +1861,7 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
        toConvert := make([]Sym, 0, len(l.payloads))
        for _, i := range l.extReader.syms {
                sname := l.RawSymName(i)
-               if !l.attrReachable.Has(i) && !strings.HasPrefix(sname, "gofile..") { // XXX file symbols are used but not marked
+               if !l.attrReachable.Has(i) {
                        continue
                }
                pp := l.getPayload(i)