mirror of
https://github.com/golang/go.git
synced 2026-04-04 10:20:00 +09:00
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>
This commit is contained in:
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user