mirror of
https://github.com/golang/go.git
synced 2026-01-29 15:12:08 +03:00
cmd/link: fix AIX builds after recent linker changes
This updates XCOFF-specific code for the recent addition of funcdata to pclntab. Because XCOFF puts separate symbols into separate csects, each with their own alignment, it's important to tell the external linker the expected alignment of each part of pclntab. Otherwise the offsets within pclntab may change as the external linker aligns symbols. This CL sets the correct alignment for each pclntab child symbol, and sets pclntab's alignment to the max of that of its children. Tested on the GCC compile farm. Fixes #76486 Change-Id: I77d8a90c4b4b79d80ca11ede8d9a2aa9cc89f53f Reviewed-on: https://go-review.googlesource.com/c/go/+/725603 Auto-Submit: Ian Lance Taylor <iant@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
committed by
Gopher Robot
parent
f2d96272cb
commit
276cc4d3db
@@ -55,13 +55,20 @@ type pclntab struct {
|
||||
|
||||
// addGeneratedSym adds a generator symbol to pclntab, returning the new Sym.
|
||||
// It is the caller's responsibility to save the symbol in state.
|
||||
func (state *pclntab) addGeneratedSym(ctxt *Link, name string, size int64, f generatorFunc) loader.Sym {
|
||||
func (state *pclntab) addGeneratedSym(ctxt *Link, name string, size int64, align int32, f generatorFunc) loader.Sym {
|
||||
size = Rnd(size, int64(ctxt.Arch.PtrSize))
|
||||
state.size += size
|
||||
s := ctxt.createGeneratorSymbol(name, 0, sym.SPCLNTAB, size, f)
|
||||
ctxt.loader.SetAttrReachable(s, true)
|
||||
ctxt.loader.SetCarrierSym(s, state.carrier)
|
||||
ctxt.loader.SetAttrNotInSymbolTable(s, true)
|
||||
ldr := ctxt.loader
|
||||
ldr.SetSymAlign(s, align)
|
||||
ldr.SetAttrReachable(s, true)
|
||||
ldr.SetCarrierSym(s, state.carrier)
|
||||
ldr.SetAttrNotInSymbolTable(s, true)
|
||||
|
||||
if align > ldr.SymAlign(state.carrier) {
|
||||
ldr.SetSymAlign(state.carrier, align)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -277,7 +284,7 @@ func (state *pclntab) generatePCHeader(ctxt *Link) {
|
||||
}
|
||||
}
|
||||
|
||||
state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader)
|
||||
state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, int32(ctxt.Arch.PtrSize), writeHeader)
|
||||
}
|
||||
|
||||
// walkFuncs iterates over the funcs, calling a function for each unique
|
||||
@@ -326,7 +333,7 @@ func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[lo
|
||||
size += int64(len(ctxt.loader.SymName(s)) + 1) // NULL terminate
|
||||
})
|
||||
|
||||
state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab)
|
||||
state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, 1, writeFuncNameTab)
|
||||
return nameOffsets
|
||||
}
|
||||
|
||||
@@ -442,7 +449,7 @@ func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.Compilat
|
||||
}
|
||||
}
|
||||
}
|
||||
state.cutab = state.addGeneratedSym(ctxt, "runtime.cutab", int64(totalEntries*4), writeCutab)
|
||||
state.cutab = state.addGeneratedSym(ctxt, "runtime.cutab", int64(totalEntries*4), 4, writeCutab)
|
||||
|
||||
// Write filetab.
|
||||
writeFiletab := func(ctxt *Link, s loader.Sym) {
|
||||
@@ -454,7 +461,7 @@ func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.Compilat
|
||||
}
|
||||
}
|
||||
state.nfiles = uint32(len(fileOffsets))
|
||||
state.filetab = state.addGeneratedSym(ctxt, "runtime.filetab", fileSize, writeFiletab)
|
||||
state.filetab = state.addGeneratedSym(ctxt, "runtime.filetab", fileSize, 1, writeFiletab)
|
||||
|
||||
return cuOffsets
|
||||
}
|
||||
@@ -518,7 +525,7 @@ func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
|
||||
}
|
||||
}
|
||||
|
||||
state.pctab = state.addGeneratedSym(ctxt, "runtime.pctab", size, writePctab)
|
||||
state.pctab = state.addGeneratedSym(ctxt, "runtime.pctab", size, 1, writePctab)
|
||||
}
|
||||
|
||||
// generateFuncdata writes out the funcdata information.
|
||||
@@ -647,7 +654,7 @@ func (state *pclntab) generateFuncdata(ctxt *Link, funcs []loader.Sym, inlsyms m
|
||||
}
|
||||
}
|
||||
|
||||
state.funcdata = state.addGeneratedSym(ctxt, "go:func.*", size, writeFuncData)
|
||||
state.funcdata = state.addGeneratedSym(ctxt, "go:func.*", size, maxAlign, writeFuncData)
|
||||
|
||||
// Because the funcdata previously was not in pclntab,
|
||||
// we need to keep the visible symbol so that tools can find it.
|
||||
@@ -703,7 +710,7 @@ func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms ma
|
||||
writePCToFunc(ctxt, sb, funcs, startLocations)
|
||||
writeFuncs(ctxt, sb, funcs, inlSyms, startLocations, cuOffsets, nameOffsets)
|
||||
}
|
||||
state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, writePcln)
|
||||
state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, 4, writePcln)
|
||||
}
|
||||
|
||||
// funcData returns the funcdata and offsets for the FuncInfo.
|
||||
@@ -967,6 +974,10 @@ func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
|
||||
ldr.SetAttrReachable(state.carrier, true)
|
||||
setCarrierSym(sym.SPCLNTAB, state.carrier)
|
||||
|
||||
// Aign pclntab to at least a pointer boundary,
|
||||
// for pcHeader. This may be raised further by subsymbols.
|
||||
ldr.SetSymAlign(state.carrier, int32(ctxt.Arch.PtrSize))
|
||||
|
||||
state.generatePCHeader(ctxt)
|
||||
nameOffsets := state.generateFuncnametab(ctxt, funcs)
|
||||
cuOffsets := state.generateFilenameTabs(ctxt, compUnits, funcs)
|
||||
@@ -1076,6 +1087,7 @@ func (ctxt *Link) findfunctab(state *pclntab, container loader.Bitmap) {
|
||||
}
|
||||
|
||||
state.findfunctab = ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SPCLNTAB, size, writeFindFuncTab)
|
||||
ldr.SetSymAlign(state.findfunctab, 4)
|
||||
ldr.SetAttrReachable(state.findfunctab, true)
|
||||
ldr.SetAttrLocal(state.findfunctab, true)
|
||||
}
|
||||
|
||||
@@ -672,6 +672,7 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
|
||||
addRef("runtime.rodata")
|
||||
addRef("runtime.erodata")
|
||||
addRef("runtime.epclntab")
|
||||
addRef("go:func.*")
|
||||
// As we use relative addressing for text symbols in functab, it is
|
||||
// important that the offsets we computed stay unchanged by the external
|
||||
// linker, i.e. all symbols in Textp should not be removed.
|
||||
|
||||
@@ -603,14 +603,20 @@ func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
|
||||
outerSymSize["go:string.*"] = size
|
||||
case sym.SGOFUNC:
|
||||
if !ctxt.DynlinkingGo() {
|
||||
outerSymSize["go:func.*"] = size
|
||||
outerSymSize["go:funcdesc"] = size
|
||||
}
|
||||
case sym.SGOFUNCRELRO:
|
||||
outerSymSize["go:funcrel.*"] = size
|
||||
outerSymSize["go:funcdescrel"] = size
|
||||
case sym.SGCBITS:
|
||||
outerSymSize["runtime.gcbits.*"] = size
|
||||
case sym.SPCLNTAB:
|
||||
outerSymSize["runtime.pclntab"] = size
|
||||
// go:func.* size must be removed from pclntab,
|
||||
// as it's a real symbol. Same for runtime.findfunctab.
|
||||
fsize := ldr.SymSize(ldr.Lookup("go:func.*", 0))
|
||||
fft := ldr.Lookup("runtime.findfunctab", 0)
|
||||
fsize = Rnd(fsize, int64(symalign(ldr, fft)))
|
||||
tsize := ldr.SymSize(fft)
|
||||
outerSymSize["runtime.pclntab"] = size - (fsize + tsize)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1960,33 +1960,55 @@ func TestFuncdataPlacement(t *testing.T) {
|
||||
case xf != nil:
|
||||
defer xf.Close()
|
||||
|
||||
var moddataSym, gofuncSym, pclntabSym, epclntabSym *xcoff.Symbol
|
||||
for _, sym := range xf.Symbols {
|
||||
switch sym.Name {
|
||||
case moddataSymName:
|
||||
moddataAddr = sym.Value
|
||||
moddataSym = sym
|
||||
case gofuncSymName:
|
||||
gofuncAddr = sym.Value
|
||||
gofuncSym = sym
|
||||
case "runtime.pclntab":
|
||||
pclntabSym = sym
|
||||
case "runtime.epclntab":
|
||||
epclntabSym = sym
|
||||
}
|
||||
}
|
||||
|
||||
for _, sec := range xf.Sections {
|
||||
if sec.Name == ".go.pclntab" {
|
||||
data, err := sec.Data()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pclntab = data
|
||||
pclntabAddr = sec.VirtualAddress
|
||||
pclntabEnd = sec.VirtualAddress + sec.Size
|
||||
}
|
||||
if moddataAddr >= sec.VirtualAddress && moddataAddr < sec.VirtualAddress+sec.Size {
|
||||
data, err := sec.Data()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
moddataBytes = data[moddataAddr-sec.VirtualAddress:]
|
||||
}
|
||||
if moddataSym == nil {
|
||||
t.Fatalf("could not find symbol %s", moddataSymName)
|
||||
}
|
||||
if gofuncSym == nil {
|
||||
t.Fatalf("could not find symbol %s", gofuncSymName)
|
||||
}
|
||||
if pclntabSym == nil {
|
||||
t.Fatal("could not find symbol runtime.pclntab")
|
||||
}
|
||||
if epclntabSym == nil {
|
||||
t.Fatal("could not find symbol runtime.epclntab")
|
||||
}
|
||||
|
||||
sec := xf.Sections[moddataSym.SectionNumber-1]
|
||||
data, err := sec.Data()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
moddataBytes = data[moddataSym.Value:]
|
||||
moddataAddr = uint64(sec.VirtualAddress + moddataSym.Value)
|
||||
|
||||
sec = xf.Sections[gofuncSym.SectionNumber-1]
|
||||
gofuncAddr = uint64(sec.VirtualAddress + gofuncSym.Value)
|
||||
|
||||
if pclntabSym.SectionNumber != epclntabSym.SectionNumber {
|
||||
t.Fatalf("runtime.pclntab section %d != runtime.epclntab section %d", pclntabSym.SectionNumber, epclntabSym.SectionNumber)
|
||||
}
|
||||
sec = xf.Sections[pclntabSym.SectionNumber-1]
|
||||
data, err = sec.Data()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pclntab = data[pclntabSym.Value:epclntabSym.Value]
|
||||
pclntabAddr = uint64(sec.VirtualAddress + pclntabSym.Value)
|
||||
pclntabEnd = uint64(sec.VirtualAddress + epclntabSym.Value)
|
||||
|
||||
default:
|
||||
panic("can't happen")
|
||||
@@ -2183,31 +2205,16 @@ func TestModuledataPlacement(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
case pf != nil:
|
||||
defer pf.Close()
|
||||
|
||||
// On Windows all the Go specific sections seem to
|
||||
// get stuffed into a few Windows sections,
|
||||
// so there is nothing to test here.
|
||||
|
||||
case xf != nil:
|
||||
defer xf.Close()
|
||||
|
||||
for _, sym := range xf.Symbols {
|
||||
if sym.Name == moddataSymName {
|
||||
if sym.SectionNumber == 0 {
|
||||
t.Errorf("moduledata not in a section")
|
||||
} else {
|
||||
sec := xf.Sections[sym.SectionNumber-1]
|
||||
if sec.Name != ".go.module" {
|
||||
t.Errorf("moduledata in section %s, not .go.module", sec.Name)
|
||||
}
|
||||
if sym.Value != sec.VirtualAddress {
|
||||
t.Errorf("moduledata address %#x != section start address %#x", sym.Value, sec.VirtualAddress)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case pf != nil, xf != nil:
|
||||
if pf != nil {
|
||||
defer pf.Close()
|
||||
}
|
||||
if xf != nil {
|
||||
defer xf.Close()
|
||||
}
|
||||
|
||||
// On Windows and AIX all the Go specific sections
|
||||
// get stuffed into a few sections,
|
||||
// so there is nothing to test here.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,11 +118,6 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
|
||||
"runtime.noptrdata": "D",
|
||||
}
|
||||
|
||||
if runtime.GOOS == "aix" && iscgo {
|
||||
// pclntab is moved to .data section on AIX.
|
||||
runtimeSyms["runtime.epclntab"] = "D"
|
||||
}
|
||||
|
||||
out, err = testenv.Command(t, testenv.Executable(t), exe).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("go tool nm: %v\n%s", err, string(out))
|
||||
|
||||
Reference in New Issue
Block a user