//
// Because of timing in the linker, generating this table takes two passes.
// The first pass is executed early in the link, and it creates any needed
-// relocations to lay out the data. The pieces that need relocations are:
-// 1) the PC->func table.
-// 2) The funcdata.
-// (1) is handled in writePCToFunc. (2) is handled in writeFuncdata.
-//
+// relocations to lay out the data. The piece that needs relocations is
+// the PC->func table, handled in writePCToFunc.
// After relocations, once we know where to write things in the output buffer,
// we execute the second pass, which is actually writing the data.
func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
// Write the data.
writePCToFunc(ctxt, sb, funcs, startLocations, setAddr, (*loader.SymbolBuilder).SetUint)
writeFuncs(ctxt, sb, funcs, inlSyms, startLocations, cuOffsets, nameOffsets)
- state.writeFuncData(ctxt, sb, funcs, inlSyms, startLocations, setAddr, (*loader.SymbolBuilder).SetUint)
}
state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, writePcln)
}
setUintNOP := func(*loader.SymbolBuilder, *sys.Arch, int64, uint64) int64 { return 0 }
writePCToFunc(ctxt, sb, funcs, startLocations, setAddr, setUintNOP)
- if !useSymValue {
- // Generate relocations for funcdata when externally linking.
- state.writeFuncData(ctxt, sb, funcs, inlSyms, startLocations, setAddr, setUintNOP)
- sb.SortRelocs()
- }
}
// funcData returns the funcdata and offsets for the FuncInfo.
if numFuncData > 0 { // Func data is aligned.
size = Rnd(size, int64(ctxt.Arch.PtrSize))
}
- size += int64(numFuncData * ctxt.Arch.PtrSize)
+ size += int64(numFuncData * 4)
}
}
setAddr(sb, ctxt.Arch, int64(funcIndex)*2*int64(ctxt.Arch.PtrSize), prevFunc, ldr.SymSize(prevFunc))
}
-// writeFuncData writes the funcdata tables.
-//
-// This function executes a callback for each funcdata needed in
-// runtime.functab. It should be called once for internally linked static
-// binaries, or twice (once to generate the needed relocations) for other
-// build modes.
-//
-// Note the output of this function is interwoven with writeFuncs, but this is
-// a separate function, because it's needed in different passes in
-// generateFunctab.
-func (state *pclntab) writeFuncData(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations []uint32, setAddr pclnSetAddr, setUint pclnSetUint) {
- ldr := ctxt.loader
- funcdata := []loader.Sym{}
- for i, s := range funcs {
- fi := ldr.FuncInfo(s)
- if !fi.Valid() {
- continue
- }
- fi.Preload()
-
- // funcdata, must be pointer-aligned and we're only int32-aligned.
- // Missing funcdata will be 0 (nil pointer).
- funcdata = funcData(ldr, s, fi, inlSyms[s], funcdata)
- if len(funcdata) > 0 {
- off := int64(startLocations[i] + funcSize + numPCData(ldr, s, fi)*4)
- off = Rnd(off, int64(ctxt.Arch.PtrSize))
- for j := range funcdata {
- dataoff := off + int64(ctxt.Arch.PtrSize*j)
- if funcdata[j] == 0 {
- setUint(sb, ctxt.Arch, dataoff, 0)
- continue
- }
- // TODO: Does this need deduping?
- setAddr(sb, ctxt.Arch, dataoff, funcdata[j], 0)
- }
- }
- }
-}
-
// writeFuncs writes the func structures and pcdata to runtime.functab.
func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
ldr := ctxt.loader
deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
+ gofunc := ldr.Lookup("go.func.*", 0)
+ gofuncrel := ldr.Lookup("go.funcrel.*", 0)
textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
funcdata := []loader.Sym{}
var pcsp, pcfile, pcline, pcinline loader.Sym
sb.SetUint32(ctxt.Arch, int64(off+objabi.PCDATA_InlTreeIndex*4), uint32(ldr.SymValue(pcinline)))
}
}
+
+ // Write funcdata refs as offsets from go.func.* and go.funcrel.*.
+ funcdata = funcData(ldr, s, fi, inlSyms[s], funcdata)
+ // funcdata must be pointer-aligned and we're only int32-aligned.
+ // Missing funcdata will be ^0. See runtime/symtab.go:funcdata.
+ off = uint32(startLocations[i] + funcSize + numPCData(ldr, s, fi)*4)
+ off = uint32(Rnd(int64(off), int64(ctxt.Arch.PtrSize)))
+ for j := range funcdata {
+ dataoff := off + uint32(4*j)
+ fdsym := funcdata[j]
+ if fdsym == 0 {
+ sb.SetUint32(ctxt.Arch, int64(dataoff), ^uint32(0)) // ^0 is a sentinel for "no value"
+ continue
+ }
+
+ outer := ldr.OuterSym(fdsym)
+ if outer == 0 {
+ panic(fmt.Sprintf("no carrier sym for symbol %s (funcdata %s#%d)", ldr.SymName(fdsym), ldr.SymName(s), j))
+ }
+ rel := uint32(ldr.SymValue(fdsym) - ldr.SymValue(outer))
+ // Record gofunc vs gofuncrel in bottom bit. See runtime/symtab.go:funcdata.
+ // TODO: The only symbols that in gofuncrel are .stkobj symbols.
+ // Remove those relocations, and simplify this.
+ rel <<= 1
+ switch outer {
+ case gofunc:
+ case gofuncrel:
+ rel |= 1
+ default:
+ panic(fmt.Sprintf("expected symbol %s (funcdata %s#%d) to be placed in go.func.* or go.funcrel.*, got %s (%d)",
+ ldr.SymName(fdsym), ldr.SymName(s), j, ldr.SymName(outer), outer))
+ }
+ sb.SetUint32(ctxt.Arch, int64(dataoff), rel)
+ }
}
}