From: Ian Lance Taylor Date: Tue, 2 Dec 2025 00:25:56 +0000 (-0800) Subject: cmd/link: fix AIX builds after recent linker changes X-Git-Tag: go1.26rc1~1^2~48 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=276cc4d3dbbf413be008113e6c88ffb3df2de4d6;p=gostls13.git 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 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase --- diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 1eb7112e64..08c4d4db83 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -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) } diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index f9bc7007ed..dd2d74895a 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -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. diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go index 77ae1236c9..5f01eb2507 100644 --- a/src/cmd/link/internal/ld/xcoff.go +++ b/src/cmd/link/internal/ld/xcoff.go @@ -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) } } diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 0c4cde0399..bc7504e5b1 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -1960,34 +1960,56 @@ 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() + case pf != nil, xf != nil: + if pf != nil { + defer pf.Close() + } + if xf != nil { + defer xf.Close() + } - // On Windows all the Go specific sections seem to - // get stuffed into a few Windows sections, + // On Windows and AIX all the Go specific sections + // get stuffed into a few 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 - } - } } } diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index f740a3f738..424ac72e22 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -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))