diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 7506bf17a3..b041174cfe 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -552,11 +552,8 @@ type pclnSetUint func(*loader.SymbolBuilder, *sys.Arch, int64, uint64) int64 // // 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) { @@ -592,7 +589,6 @@ func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms ma // 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) @@ -616,11 +612,6 @@ func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms ma } 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. @@ -675,7 +666,7 @@ func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64 if numFuncData > 0 { // Func data is aligned. size = Rnd(size, int64(ctxt.Arch.PtrSize)) } - size += int64(numFuncData * ctxt.Arch.PtrSize) + size += int64(numFuncData * 4) } } @@ -715,49 +706,12 @@ func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, sta 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 @@ -844,6 +798,40 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym 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) + } } } diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 7fddc59bb5..c582e4908d 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -676,6 +676,12 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind { moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcbss", 0)) moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.types", 0)) moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etypes", 0)) + moduledata.AddAddr(ctxt.Arch, ldr.Lookup("go.func.*", 0)) + if gofuncrel := ldr.Lookup("go.funcrel.*", 0); gofuncrel != 0 { + moduledata.AddAddr(ctxt.Arch, gofuncrel) + } else { + moduledata.AddUint(ctxt.Arch, 0) + } if ctxt.IsAIX() && ctxt.IsExternal() { // Add R_XCOFFREF relocation to prevent ld's garbage collection of diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 14591602a3..8f7b439dc5 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -427,6 +427,7 @@ type moduledata struct { noptrbss, enoptrbss uintptr end, gcdata, gcbss uintptr types, etypes uintptr + gofunc, gofuncrel uintptr // go.func.*, go.funcrel.* textsectmap []textsect typelinks []int32 // offsets from types @@ -1073,6 +1074,8 @@ func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) { return pcvalue(f, pcdatastart(f, table), targetpc, nil, true) } +// funcdata returns a pointer to the ith funcdata for f. +// funcdata should be kept in sync with cmd/link:writeFuncs. func funcdata(f funcInfo, i uint8) unsafe.Pointer { if i < 0 || i >= f.nfuncdata { return nil @@ -1084,7 +1087,16 @@ func funcdata(f funcInfo, i uint8) unsafe.Pointer { } p = add(p, 4) } - return *(*unsafe.Pointer)(add(p, uintptr(i)*goarch.PtrSize)) + p = add(p, uintptr(i)*4) + off := *(*uint32)(p) + if off == ^uint32(0) { + return nil + } + base := f.datap.gofunc + if off&1 != 0 { + base = f.datap.gofuncrel + } + return unsafe.Pointer(base + uintptr(off>>1)) } // step advances to the next pc, value pair in the encoded table.