aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2023-02-01 12:15:08 -0500
committerGopher Robot <gobot@golang.org>2023-02-10 17:19:20 +0000
commitfbba58a0a4f5ff4f3aa4cfa0d494b6d2fefd068a (patch)
tree12d62d1a6a0d68bb6f80ee5bfe78cfcb7106baba
parent9987cb6cf34cc893887ad2ecc9d832ee3c69c255 (diff)
downloadgo-fbba58a0a4f5ff4f3aa4cfa0d494b6d2fefd068a.tar.gz
go-fbba58a0a4f5ff4f3aa4cfa0d494b6d2fefd068a.zip
[release-branch.go1.20] 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 #58224. Change-Id: I1e13e9464acaf2f5cc5e0b70476fa52b43651123 Reviewed-on: https://go-review.googlesource.com/c/go/+/464435 Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Than McIntosh <thanm@google.com> Auto-Submit: Russ Cox <rsc@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-on: https://go-review.googlesource.com/c/go/+/464796
-rw-r--r--src/cmd/go/testdata/script/version_gc_sections.txt24
-rw-r--r--src/cmd/link/internal/ld/data.go13
2 files changed, 36 insertions, 1 deletions
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..4bda23ba95
--- /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
+[GOOS:aix] skip # no --gc-sections
+[GOOS: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 94f8fc32d6..925e554b1d 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -1669,6 +1669,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 strings.HasPrefix(sname, "go:") {
+ sname = ".go." + sname[len("go:"):]
+ }
sect := addsection(ldr, state.ctxt.Arch, seg, sname, rwx)
sect.Align = symalign(ldr, s)
state.datsize = Rnd(state.datsize, int64(sect.Align))
@@ -2254,7 +2257,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
@@ -2276,6 +2279,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.