]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.20] cmd/link: keep go.buildinfo even with --gc-sections
authorRuss Cox <rsc@golang.org>
Wed, 1 Feb 2023 17:15:08 +0000 (12:15 -0500)
committerGopher Robot <gobot@golang.org>
Fri, 10 Feb 2023 17:19:20 +0000 (17:19 +0000)
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

src/cmd/go/testdata/script/version_gc_sections.txt [new file with mode: 0644]
src/cmd/link/internal/ld/data.go

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 (file)
index 0000000..4bda23b
--- /dev/null
@@ -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")
+}
index 94f8fc32d6e2d61bedc2ffd1571efc9dbe4e7ff9..925e554b1d9db14e41c36c96a2312ef9591d182b 100644 (file)
@@ -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.