1
0
mirror of https://github.com/golang/go synced 2024-09-30 05:34:35 -06:00

[dev.link] cmd/link: use pclntabState and eliminate globals

Non functional change.

As runtime.pclntab breaks up, it'll be easier if we can just pass around
the pclntab state. Also, eliminate the globals in pclntab.

Change-Id: I2a5849e8f5f422a336a881e53a261e3997d11c44
Reviewed-on: https://go-review.googlesource.com/c/go/+/242599
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Jeremy Faller 2020-07-14 13:12:58 -04:00
parent 365059e1d1
commit 3067a8dc02
3 changed files with 146 additions and 119 deletions

View File

@ -288,13 +288,14 @@ func Main(arch *sys.Arch, theArch Arch) {
bench.Start("buildinfo")
ctxt.buildinfo()
bench.Start("pclntab")
container := ctxt.pclntab()
containers := ctxt.findContainerSyms()
pclnState := ctxt.pclntab(containers)
bench.Start("findfunctab")
ctxt.findfunctab(container)
ctxt.findfunctab(pclnState, containers)
bench.Start("dwarfGenerateDebugSyms")
dwarfGenerateDebugSyms(ctxt)
bench.Start("symtab")
symGroupType := ctxt.symtab()
symGroupType := ctxt.symtab(pclnState)
bench.Start("dodata")
ctxt.dodata(symGroupType)
bench.Start("address")

View File

@ -19,28 +19,51 @@ import (
"strings"
)
// 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 {
// oldPclnState holds state information used during pclntab generation. Here
// 'ldr' is just a pointer to the context's loader, '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).
//
// NB: This is deprecated, and will be eliminated when pclntab_old is
// eliminated.
type oldPclnState 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 {
// pclntab holds the state needed for pclntab generation.
type pclntab struct {
// The first and last functions found.
firstFunc, lastFunc loader.Sym
// The offset to the filetab.
filetabOffset int32
// runtime.pclntab's symbols
carrier loader.Sym
pclntab loader.Sym
pcheader loader.Sym
findfunctab loader.Sym
// The number of functions + number of TEXT sections - 1. This is such an
// unexpected value because platforms that have more than one TEXT section
// get a dummy function inserted between because the external linker can place
// functions in those areas. We mark those areas as not covered by the Go
// runtime.
//
// On most platforms this is the number of reachable functions.
nfunc int32
}
func makeOldPclnState(ctxt *Link) *oldPclnState {
ldr := ctxt.loader
drs := ldr.Lookup("runtime.deferreturn", sym.SymVerABIInternal)
return pclnState{
container: loader.MakeBitmap(ldr.NSym()),
state := &oldPclnState{
ldr: ldr,
deferReturnSym: drs,
numberedFiles: make(map[loader.Sym]int64),
@ -49,9 +72,42 @@ func makepclnState(ctxt *Link) pclnState {
// return a value slot in filepaths.
filepaths: []string{""},
}
return state
}
func (state *pclnState) ftabaddstring(ftab *loader.SymbolBuilder, s string) int32 {
// makePclntab makes a pclnState object.
func makePclntab(ctxt *Link, container loader.Bitmap) *pclntab {
ldr := ctxt.loader
state := &pclntab{}
// Gather some basic stats and info.
prevSect := ldr.SymSect(ctxt.Textp[0])
for _, s := range ctxt.Textp {
if !emitPcln(ctxt, s, container) {
continue
}
state.nfunc++
if state.firstFunc == 0 {
state.firstFunc = s
}
state.lastFunc = s
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.
state.nfunc++
prevSect = ss
}
}
return state
}
func 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
ftd := ftab.Data()
@ -60,7 +116,7 @@ func (state *pclnState) ftabaddstring(ftab *loader.SymbolBuilder, s string) int3
}
// numberfile assigns a file number to the file if it hasn't been assigned already.
func (state *pclnState) numberfile(file loader.Sym) int64 {
func (state *oldPclnState) numberfile(file loader.Sym) int64 {
if val, ok := state.numberedFiles[file]; ok {
return val
}
@ -72,14 +128,14 @@ func (state *pclnState) numberfile(file loader.Sym) int64 {
return val
}
func (state *pclnState) fileVal(file loader.Sym) int64 {
func (state *oldPclnState) 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) {
func (state *oldPclnState) renumberfiles(ctxt *Link, fi loader.FuncInfo, d *sym.Pcdata) {
// Give files numbers.
nf := fi.NumFile()
for i := uint32(0); i < nf; i++ {
@ -146,7 +202,7 @@ func emitPcln(ctxt *Link, s loader.Sym, container loader.Bitmap) bool {
return !container.Has(s)
}
func (state *pclnState) computeDeferReturn(target *Target, s loader.Sym) uint32 {
func (state *oldPclnState) computeDeferReturn(target *Target, s loader.Sym) uint32 {
deferreturn := uint32(0)
lastWasmAddr := uint32(0)
@ -194,7 +250,7 @@ func (state *pclnState) computeDeferReturn(target *Target, s loader.Sym) uint32
// genInlTreeSym generates the InlTree sym for a function with the
// specified FuncInfo.
func (state *pclnState) genInlTreeSym(fi loader.FuncInfo, arch *sys.Arch) loader.Sym {
func (state *oldPclnState) genInlTreeSym(fi loader.FuncInfo, arch *sys.Arch) loader.Sym {
ldr := state.ldr
its := ldr.CreateExtSym("", 0)
inlTreeSym := ldr.MakeSymbolUpdater(its)
@ -229,16 +285,16 @@ func (state *pclnState) genInlTreeSym(fi loader.FuncInfo, arch *sys.Arch) loader
// generatePCHeader creates the runtime.pcheader symbol, setting it up as a
// generator to fill in its data later.
func generatePCHeader(ctxt *Link, carrier *loader.SymbolBuilder, pclntabSym loader.Sym) {
func (state *pclntab) generatePCHeader(ctxt *Link) {
ldr := ctxt.loader
writeHeader := func(ctxt *Link, s loader.Sym) {
ldr := ctxt.loader
header := ctxt.loader.MakeSymbolUpdater(s)
// Check symbol order.
diff := ldr.SymValue(pclntabSym) - ldr.SymValue(s)
diff := ldr.SymValue(state.pclntab) - ldr.SymValue(s)
if diff <= 0 {
panic(fmt.Sprintf("expected runtime.pcheader(%x) to be placed before runtime.pclntab(%x)", ldr.SymValue(s), ldr.SymValue(pclntabSym)))
panic(fmt.Sprintf("expected runtime.pcheader(%x) to be placed before runtime.pclntab(%x)", ldr.SymValue(s), ldr.SymValue(state.pclntab)))
}
// Write header.
@ -246,30 +302,21 @@ func generatePCHeader(ctxt *Link, carrier *loader.SymbolBuilder, pclntabSym load
header.SetUint32(ctxt.Arch, 0, 0xfffffffa)
header.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC))
header.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize))
off := header.SetUint(ctxt.Arch, 8, uint64(pclntabNfunc))
off := header.SetUint(ctxt.Arch, 8, uint64(state.nfunc))
header.SetUintptr(ctxt.Arch, off, uintptr(diff))
}
size := int64(8 + 2*ctxt.Arch.PtrSize)
s := ctxt.createGeneratorSymbol("runtime.pcheader", 0, sym.SPCLNTAB, size, writeHeader)
ldr.SetAttrReachable(s, true)
ldr.SetCarrierSym(s, carrier.Sym())
state.pcheader = ctxt.createGeneratorSymbol("runtime.pcheader", 0, sym.SPCLNTAB, size, writeHeader)
ldr.SetAttrReachable(state.pcheader, true)
ldr.SetCarrierSym(state.pcheader, state.carrier)
}
// pclntab initializes the pclntab symbol with
// runtime function and file name information.
// These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
var pclntabNfunc int32
var pclntabFiletabOffset int32
var pclntabFirstFunc loader.Sym
var pclntabLastFunc loader.Sym
// pclntab generates the pcln table for the link output. Return value
// is a bitmap indexed by global symbol that marks 'container' text
// symbols, e.g. the set of all symbols X such that Outer(S) = X for
// some other text symbol S.
func (ctxt *Link) pclntab() loader.Bitmap {
// pclntab generates the pcln table for the link output.
func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
// Go 1.2's symtab layout is documented in golang.org/s/go12symtab, but the
// layout and data has changed since that time.
//
@ -291,70 +338,39 @@ func (ctxt *Link) pclntab() loader.Bitmap {
// func structures, function names, pcdata tables.
// filetable
oldState := makeOldPclnState(ctxt)
state := makePclntab(ctxt, container)
ldr := ctxt.loader
carrier := ldr.CreateSymForUpdate("runtime.pclntab", 0)
carrier.SetType(sym.SPCLNTAB)
carrier.SetReachable(true)
state.carrier = ldr.LookupOrCreateSym("runtime.pclntab", 0)
ldr.MakeSymbolUpdater(state.carrier).SetType(sym.SPCLNTAB)
ldr.SetAttrReachable(state.carrier, true)
// runtime.pclntab_old is just a placeholder,and will eventually be deleted.
// It contains the pieces of runtime.pclntab that haven't moved to a more
// ration form.
pclntabSym := ldr.LookupOrCreateSym("runtime.pclntab_old", 0)
generatePCHeader(ctxt, carrier, pclntabSym)
state.pclntab = ldr.LookupOrCreateSym("runtime.pclntab_old", 0)
state.generatePCHeader(ctxt)
funcdataBytes := int64(0)
ldr.SetCarrierSym(pclntabSym, carrier.Sym())
ftab := ldr.MakeSymbolUpdater(pclntabSym)
ldr.SetCarrierSym(state.pclntab, state.carrier)
ftab := ldr.MakeSymbolUpdater(state.pclntab)
ftab.SetType(sym.SPCLNTAB)
ftab.SetReachable(true)
state := makepclnState(ctxt)
// Find container symbols and mark them as such.
for _, s := range ctxt.Textp {
outer := ldr.OuterSym(s)
if outer != 0 {
state.container.Set(outer)
}
}
// Gather some basic stats and info.
var nfunc int32
prevSect := ldr.SymSect(ctxt.Textp[0])
for _, s := range ctxt.Textp {
if !emitPcln(ctxt, s, state.container) {
continue
}
nfunc++
if pclntabFirstFunc == 0 {
pclntabFirstFunc = s
}
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 = ss
}
}
pclntabNfunc = nfunc
ftab.Grow(int64(nfunc)*2*int64(ctxt.Arch.PtrSize) + int64(ctxt.Arch.PtrSize) + 4)
ftab.Grow(int64(state.nfunc)*2*int64(ctxt.Arch.PtrSize) + int64(ctxt.Arch.PtrSize) + 4)
szHint := len(ctxt.Textp) * 2
funcnameoff := make(map[string]int32, szHint)
nameToOffset := func(name string) int32 {
nameoff, ok := funcnameoff[name]
if !ok {
nameoff = state.ftabaddstring(ftab, name)
nameoff = ftabaddstring(ftab, name)
funcnameoff[name] = nameoff
}
return nameoff
}
state.nameToOffset = nameToOffset
oldState.nameToOffset = nameToOffset
pctaboff := make(map[string]uint32, szHint)
writepctab := func(off int32, p []byte) int32 {
@ -392,10 +408,10 @@ func (ctxt *Link) pclntab() loader.Bitmap {
funcdata := []loader.Sym{}
funcdataoff := []int64{}
nfunc = 0 // repurpose nfunc as a running index
var nfunc int32
prevFunc := ctxt.Textp[0]
for _, s := range ctxt.Textp {
if !emitPcln(ctxt, s, state.container) {
if !emitPcln(ctxt, s, container) {
continue
}
@ -489,20 +505,20 @@ func (ctxt *Link) pclntab() loader.Bitmap {
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args))
// deferreturn
deferreturn := state.computeDeferReturn(&ctxt.Target, s)
deferreturn := oldState.computeDeferReturn(&ctxt.Target, s)
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), deferreturn))
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)
oldState.renumberfiles(ctxt, fi, &pcfile)
if false {
// Sanity check the new numbering
it := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
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))
if it.Value < 1 || it.Value > int32(len(oldState.numberedFiles)) {
ctxt.Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.Value, len(oldState.numberedFiles))
errorexit()
}
}
@ -510,7 +526,7 @@ func (ctxt *Link) pclntab() loader.Bitmap {
}
if fi.Valid() && fi.NumInlTree() > 0 {
its := state.genInlTreeSym(fi, ctxt.Arch)
its := oldState.genInlTreeSym(fi, ctxt.Arch)
funcdata[objabi.FUNCDATA_InlTree] = its
pcdata[objabi.PCDATA_InlTreeIndex] = sym.Pcdata{P: fi.Pcinline()}
}
@ -567,36 +583,34 @@ func (ctxt *Link) pclntab() loader.Bitmap {
nfunc++
}
last := ctxt.Textp[len(ctxt.Textp)-1]
pclntabLastFunc = last
// Final entry of table is just end pc.
setAddr(ftab, ctxt.Arch, int64(nfunc)*2*int64(ctxt.Arch.PtrSize), last, ldr.SymSize(last))
setAddr(ftab, ctxt.Arch, int64(nfunc)*2*int64(ctxt.Arch.PtrSize), state.lastFunc, ldr.SymSize(state.lastFunc))
// Start file table.
dSize := len(ftab.Data())
start := int32(dSize)
start += int32(-dSize) & (int32(ctxt.Arch.PtrSize) - 1)
pclntabFiletabOffset = start
state.filetabOffset = start
ftab.SetUint32(ctxt.Arch, int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint32(start))
nf := len(state.numberedFiles)
nf := len(oldState.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]
path := oldState.filepaths[i]
val := int64(i)
ftab.SetUint32(ctxt.Arch, int64(start)+val*4, uint32(state.ftabaddstring(ftab, path)))
ftab.SetUint32(ctxt.Arch, int64(start)+val*4, uint32(ftabaddstring(ftab, path)))
}
ftab.SetSize(int64(len(ftab.Data())))
ctxt.NumFilesyms = len(state.numberedFiles)
ctxt.NumFilesyms = len(oldState.numberedFiles)
if ctxt.Debugvlog != 0 {
ctxt.Logf("pclntab=%d bytes, funcdata total %d bytes\n", ftab.Size(), funcdataBytes)
}
return state.container
return state
}
func gorootFinal() string {
@ -624,9 +638,7 @@ const (
// findfunctab generates a lookup table to quickly find the containing
// function for a pc. See src/runtime/symtab.go:findfunc for details.
// 'container' is a bitmap indexed by global symbol holding whether
// a given text symbols is a container (outer sym).
func (ctxt *Link) findfunctab(container loader.Bitmap) {
func (ctxt *Link) findfunctab(state *pclntab, container loader.Bitmap) {
ldr := ctxt.loader
// find min and max address
@ -705,7 +717,22 @@ func (ctxt *Link) findfunctab(container loader.Bitmap) {
}
}
s := ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SRODATA, size, writeFindFuncTab)
ldr.SetAttrReachable(s, true)
ldr.SetAttrLocal(s, true)
state.findfunctab = ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SRODATA, size, writeFindFuncTab)
ldr.SetAttrReachable(state.findfunctab, true)
ldr.SetAttrLocal(state.findfunctab, true)
}
// findContainerSyms returns a bitmap, indexed by symbol number, where there's
// a 1 for every container symbol.
func (ctxt *Link) findContainerSyms() loader.Bitmap {
ldr := ctxt.loader
container := loader.MakeBitmap(ldr.NSym())
// Find container symbols and mark them as such.
for _, s := range ctxt.Textp {
outer := ldr.OuterSym(s)
if outer != 0 {
container.Set(outer)
}
}
return container
}

View File

@ -401,7 +401,7 @@ func textsectionmap(ctxt *Link) (loader.Sym, uint32) {
return t.Sym(), uint32(n)
}
func (ctxt *Link) symtab() []sym.SymKind {
func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
ldr := ctxt.loader
if !ctxt.IsAIX() {
@ -608,25 +608,24 @@ func (ctxt *Link) symtab() []sym.SymKind {
// This code uses several global variables that are set by pcln.go:pclntab.
moduledata := ldr.MakeSymbolUpdater(ctxt.Moduledata)
// The pcHeader
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.pcheader", 0))
moduledata.AddAddr(ctxt.Arch, pcln.pcheader)
// The pclntab slice
pclntab := ldr.Lookup("runtime.pclntab_old", 0)
moduledata.AddAddr(ctxt.Arch, pclntab)
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pclntab)))
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pclntab)))
moduledata.AddAddr(ctxt.Arch, pcln.pclntab)
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.pclntab)))
moduledata.AddUint(ctxt.Arch, uint64(ldr.SymSize(pcln.pclntab)))
// The ftab slice
moduledata.AddAddr(ctxt.Arch, pclntab)
moduledata.AddUint(ctxt.Arch, uint64(pclntabNfunc+1))
moduledata.AddUint(ctxt.Arch, uint64(pclntabNfunc+1))
moduledata.AddAddr(ctxt.Arch, pcln.pclntab)
moduledata.AddUint(ctxt.Arch, uint64(pcln.nfunc+1))
moduledata.AddUint(ctxt.Arch, uint64(pcln.nfunc+1))
// The filetab slice
moduledata.AddAddrPlus(ctxt.Arch, pclntab, int64(pclntabFiletabOffset))
moduledata.AddAddrPlus(ctxt.Arch, pcln.pclntab, int64(pcln.filetabOffset))
moduledata.AddUint(ctxt.Arch, uint64(ctxt.NumFilesyms)+1)
moduledata.AddUint(ctxt.Arch, uint64(ctxt.NumFilesyms)+1)
// findfunctab
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.findfunctab", 0))
moduledata.AddAddr(ctxt.Arch, pcln.findfunctab)
// minpc, maxpc
moduledata.AddAddr(ctxt.Arch, pclntabFirstFunc)
moduledata.AddAddrPlus(ctxt.Arch, pclntabLastFunc, ldr.SymSize(pclntabLastFunc))
moduledata.AddAddr(ctxt.Arch, pcln.firstFunc)
moduledata.AddAddrPlus(ctxt.Arch, pcln.lastFunc, ldr.SymSize(pcln.lastFunc))
// pointers to specific parts of the module
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.text", 0))
moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etext", 0))