aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorqmuntal <quimmuntal@gmail.com>2026-02-10 14:21:15 +0100
committerQuim Muntal <quimmuntal@gmail.com>2026-03-06 12:53:54 -0800
commitbbed50aaa3033c9be6a5268268a7faf226be9de0 (patch)
tree335144950658578925c8236d8e5dca77b46738b6 /src/cmd
parentde5c138eef88685442dc71e36dd98d66b885a605 (diff)
downloadgo-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')
-rw-r--r--src/cmd/cgo/internal/test/seh_internal_windows_test.go16
-rw-r--r--src/cmd/cgo/internal/test/seh_windows_test.go2
-rw-r--r--src/cmd/link/internal/ld/data.go5
-rw-r--r--src/cmd/link/internal/ld/pe.go1
-rw-r--r--src/cmd/link/internal/ld/seh.go35
5 files changed, 33 insertions, 26 deletions
diff --git a/src/cmd/cgo/internal/test/seh_internal_windows_test.go b/src/cmd/cgo/internal/test/seh_internal_windows_test.go
deleted file mode 100644
index 708ffdc6f6..0000000000
--- a/src/cmd/cgo/internal/test/seh_internal_windows_test.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2024 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build cgo && windows && internal
-
-package cgotest
-
-import (
- "internal/testenv"
- "testing"
-)
-
-func TestCallbackCallersSEH(t *testing.T) {
- testenv.SkipFlaky(t, 65116)
-}
diff --git a/src/cmd/cgo/internal/test/seh_windows_test.go b/src/cmd/cgo/internal/test/seh_windows_test.go
index 4a8d5bbd4d..7bbed5b04e 100644
--- a/src/cmd/cgo/internal/test/seh_windows_test.go
+++ b/src/cmd/cgo/internal/test/seh_windows_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build cgo && windows && !internal
+//go:build cgo && windows
package cgotest
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())
}