]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: fix AIX builds after recent linker changes
authorIan Lance Taylor <iant@golang.org>
Tue, 2 Dec 2025 00:25:56 +0000 (16:25 -0800)
committerGopher Robot <gobot@golang.org>
Mon, 8 Dec 2025 22:37:09 +0000 (14:37 -0800)
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>
src/cmd/link/internal/ld/pcln.go
src/cmd/link/internal/ld/symtab.go
src/cmd/link/internal/ld/xcoff.go
src/cmd/link/link_test.go
src/cmd/nm/nm_test.go

index 1eb7112e64415548401cab844d5bb27986cb3a06..08c4d4db830949cbf83d812adaf92d4ca39fa33e 100644 (file)
@@ -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)
 }
index f9bc7007eda0bbb730423bb6a0ce9e1dd70ef366..dd2d74895ad60cd79667554a90b6999a0c7bf468 100644 (file)
@@ -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.
index 77ae1236c9c0105a147b0a6fabe9e63ff9ec59ad..5f01eb2507dd5e9db15d79d84fa0c3007f2250bb 100644 (file)
@@ -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)
        }
 }
 
index 0c4cde0399fbd5457b1410735bee06163b1ee04a..bc7504e5b1c39a536a0e5bcf95689b0b015929cc 100644 (file)
@@ -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
-                       }
-               }
        }
 }
index f740a3f738a86665d8fad12c661a825250209e9e..424ac72e228db81ba583df66ee023aaf34af240c 100644 (file)
@@ -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))