From f69dbb6dfa8af7a32a47070d71b82fc4ed4b9d2a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 1 Feb 2023 12:15:08 -0500 Subject: [PATCH] [release-branch.go1.19] cmd/link: keep go.buildinfo even with --gc-sections If you use an external linker with --gc-sections, nothing refers to .go.buildinfo, so the section is deleted, which in turns makes 'go version' fail on the binary. It is important for vulnerability scanning and the like to be able to run 'go version' on any binary. Fix this by inserting a reference to .go.buildinfo from the rodata section, which will not be GC'ed. Fixes #58222. Fixes #58223. Change-Id: I1e13e9464acaf2f5cc5e0b70476fa52b43651123 Reviewed-on: https://go-review.googlesource.com/c/go/+/464435 Run-TryBot: Russ Cox Reviewed-by: Cherry Mui Reviewed-by: Than McIntosh Auto-Submit: Russ Cox TryBot-Result: Gopher Robot Reviewed-on: https://go-review.googlesource.com/c/go/+/464795 --- .../testdata/script/version_gc_sections.txt | 24 +++++++++++++++++++ src/cmd/link/internal/ld/data.go | 13 +++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/version_gc_sections.txt diff --git a/src/cmd/go/testdata/script/version_gc_sections.txt b/src/cmd/go/testdata/script/version_gc_sections.txt new file mode 100644 index 0000000000..6dabd96162 --- /dev/null +++ b/src/cmd/go/testdata/script/version_gc_sections.txt @@ -0,0 +1,24 @@ +# This test checks that external linking with --gc-sections does not strip version information. + +[short] skip +[!cgo] skip +[aix] skip # no --gc-sections +[darwin] skip # no --gc-sections + +go build -ldflags='-linkmode=external -extldflags=-Wl,--gc-sections' +go version hello$GOEXE +! stdout 'not a Go executable' +! stderr 'not a Go executable' + +-- go.mod -- +module hello +-- hello.go -- +package main + +/* +*/ +import "C" + +func main() { + println("hello") +} diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index cb2afeaa9a..e1a211a16e 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1601,6 +1601,9 @@ func (ctxt *Link) dodata(symGroupType []sym.SymKind) { func (state *dodataState) allocateDataSectionForSym(seg *sym.Segment, s loader.Sym, rwx int) *sym.Section { ldr := state.ctxt.loader sname := ldr.SymName(s) + if sname == "go.buildinfo" { // clumsy hack for Go 1.19 builders + sname = ".go.buildinfo" + } sect := addsection(ldr, state.ctxt.Arch, seg, sname, rwx) sect.Align = symalign(ldr, s) state.datsize = Rnd(state.datsize, int64(sect.Align)) @@ -2177,7 +2180,7 @@ func (ctxt *Link) buildinfo() { // Write the buildinfo symbol, which go version looks for. // The code reading this data is in package debug/buildinfo. ldr := ctxt.loader - s := ldr.CreateSymForUpdate(".go.buildinfo", 0) + s := ldr.CreateSymForUpdate("go.buildinfo", 0) s.SetType(sym.SBUILDINFO) s.SetAlign(16) // The \xff is invalid UTF-8, meant to make it less likely @@ -2199,6 +2202,14 @@ func (ctxt *Link) buildinfo() { } s.SetData(data) s.SetSize(int64(len(data))) + + // Add reference to go:buildinfo from the rodata section, + // so that external linking with -Wl,--gc-sections does not + // delete the build info. + sr := ldr.CreateSymForUpdate("go.buildinfo.ref", 0) + sr.SetType(sym.SRODATA) + sr.SetAlign(int32(ctxt.Arch.PtrSize)) + sr.AddAddr(ctxt.Arch, s.Sym()) } // appendString appends s to data, prefixed by its varint-encoded length. -- 2.50.0