diff options
| author | qmuntal <quimmuntal@gmail.com> | 2026-02-10 14:21:15 +0100 |
|---|---|---|
| committer | Quim Muntal <quimmuntal@gmail.com> | 2026-03-06 12:53:54 -0800 |
| commit | bbed50aaa3033c9be6a5268268a7faf226be9de0 (patch) | |
| tree | 335144950658578925c8236d8e5dca77b46738b6 /src/cmd/link | |
| parent | de5c138eef88685442dc71e36dd98d66b885a605 (diff) | |
| download | go-bbed50aaa3033c9be6a5268268a7faf226be9de0.tar.xz | |
cmd/link: sort .pdata by function start address
Loosely based on CL 678795.
The PE/COFF spec requires RUNTIME_FUNCTION entries in the .pdata
section to be ordered by their function start address. Previously
the linker emitted them in symbol order.
An unsorted table triggers the MSVC linker error:
fatal error LNK1223: invalid or corrupt file: file contains invalid
.pdata contributions
Fixes #65116.
Change-Id: I589cb4e6787a9edb34400b56e60fe23065b59162
Reviewed-on: https://go-review.googlesource.com/c/go/+/743820
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/cmd/link')
| -rw-r--r-- | src/cmd/link/internal/ld/data.go | 5 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/pe.go | 1 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/seh.go | 35 |
3 files changed, 32 insertions, 9 deletions
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 43c3cd38db..89df83cfeb 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -2777,6 +2777,11 @@ func (ctxt *Link) textaddress() { ldr.SetSymValue(etext, int64(va)) ldr.SetSymValue(text, int64(Segtext.Sections[0].Vaddr)) } + if ctxt.IsWindows() { + // .pdata entries should be sorted by address, so process them now + // that we have final addresses for the text symbols. + collectSEH(ctxt) + } } // assigns address for a text symbol, returns (possibly new) section, its number, and the address. diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index b49da42c4c..8184a32f83 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -1635,7 +1635,6 @@ func addPEBaseReloc(ctxt *Link) { func (ctxt *Link) dope() { initdynimport(ctxt) initdynexport(ctxt) - writeSEH(ctxt) } func setpersrc(ctxt *Link, syms []loader.Sym) { diff --git a/src/cmd/link/internal/ld/seh.go b/src/cmd/link/internal/ld/seh.go index 9f0f747c04..2bee6d4cf7 100644 --- a/src/cmd/link/internal/ld/seh.go +++ b/src/cmd/link/internal/ld/seh.go @@ -8,6 +8,8 @@ import ( "cmd/internal/sys" "cmd/link/internal/loader" "cmd/link/internal/sym" + "cmp" + "slices" ) var sehp struct { @@ -15,14 +17,16 @@ var sehp struct { xdata []sym.LoaderSym } -func writeSEH(ctxt *Link) { +// collectSEH collects the SEH unwind information for all functions and organizes +// it into .pdata and .xdata sections. +func collectSEH(ctxt *Link) { switch ctxt.Arch.Family { case sys.AMD64: - writeSEHAMD64(ctxt) + collectSEHAMD64(ctxt) } } -func writeSEHAMD64(ctxt *Link) { +func collectSEHAMD64(ctxt *Link) { ldr := ctxt.loader mkSecSym := func(name string, kind sym.SymKind) *loader.SymbolBuilder { s := ldr.CreateSymForUpdate(name, 0) @@ -39,6 +43,11 @@ func writeSEHAMD64(ctxt *Link) { // an RVA, so it is possible, and binary-size wise, // to deduplicate .xdata entries. uwcache := make(map[string]int64) // aux symbol name --> .xdata offset + type pdataEntry struct { + start sym.LoaderSym + xdataOff int64 + } + var entries []pdataEntry for _, s := range ctxt.Textp { if fi := ldr.FuncInfo(s); !fi.Valid() { continue @@ -66,12 +75,22 @@ func writeSEHAMD64(ctxt *Link) { } } + entries = append(entries, pdataEntry{start: s, xdataOff: off}) + } + slices.SortFunc(entries, func(a, b pdataEntry) int { + return cmp.Compare(ldr.SymAddr(a.start), ldr.SymAddr(b.start)) + }) + for _, ent := range entries { // Reference: // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-runtime_function - pdata.AddPEImageRelativeAddrPlus(ctxt.Arch, s, 0) - pdata.AddPEImageRelativeAddrPlus(ctxt.Arch, s, ldr.SymSize(s)) - pdata.AddPEImageRelativeAddrPlus(ctxt.Arch, xdata.Sym(), off) + pdata.AddPEImageRelativeAddrPlus(ctxt.Arch, ent.start, 0) // function start address + pdata.AddPEImageRelativeAddrPlus(ctxt.Arch, ent.start, ldr.SymSize(ent.start)) // function end address + pdata.AddPEImageRelativeAddrPlus(ctxt.Arch, xdata.Sym(), ent.xdataOff) // xdata symbol offset + } + if pdata.Size() > 0 { + sehp.pdata = append(sehp.pdata, pdata.Sym()) + } + if xdata.Size() > 0 { + sehp.xdata = append(sehp.xdata, xdata.Sym()) } - sehp.pdata = append(sehp.pdata, pdata.Sym()) - sehp.xdata = append(sehp.xdata, xdata.Sym()) } |
