mirror of
https://github.com/golang/go
synced 2024-11-18 18:04:46 -07:00
cmd/link: allow deriving GNU build ID from Go build ID ID
While it is possible to embed a GNU build ID into the linked executable by passing `-B 0xBUILDID` to the linker, the build ID will need to be precomputed by the build system somehow. This makes it unnecessarily complex to generate a deterministic build ID as it either requires the build system to hash all inputs manually or to build the binary twice, once to compute its hash and once with the GNU build ID derived from that hash. Despite being complex, it is also inefficient as it requires the build system to duplicate some of the work that the Go linker already performs anyway. Introduce a new argument "gobuildid" that can be passed to `-B` that causes the linker to automatically derive the GNU build ID from the Go build ID. Given that the Go build ID is deterministically computed from all of its inputs, the resulting GNU build ID should be deterministic in the same way, which is the desired behaviour. Furthermore, given that the `-B` flag currently requires a "0x" prefix for all values passed to it, using "gobuildid" as value is a backwards compatible change. An alternative would be to unconditionally calculate the GNU build ID unless otherwise specified. This would require some larger rework though because building the Go toolchain would not converge anymore due the GNU build ID changing on every stage, which in turn would cause the Go build ID to change as well. Fixes #41004
This commit is contained in:
parent
a278550c40
commit
5483305a85
@ -18,6 +18,8 @@ Flags:
|
||||
-B note
|
||||
Add an ELF_NT_GNU_BUILD_ID note when using ELF.
|
||||
The value should start with 0x and be an even number of hex digits.
|
||||
Alternatively, you can pass "gobuildid" in order to derive the
|
||||
GNU build ID from the Go build ID.
|
||||
-E entry
|
||||
Set entry symbol name.
|
||||
-H type
|
||||
|
@ -7,6 +7,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/buildid"
|
||||
"cmd/internal/notsha256"
|
||||
"cmd/link/internal/ld"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"internal/platform"
|
||||
@ -199,6 +203,39 @@ func TestMinusRSymsWithSameName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGNUBuildIDDerivedFromGoBuildID(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
goFile := filepath.Join(t.TempDir(), "notes.go")
|
||||
if err := os.WriteFile(goFile, []byte(goSource), 0444); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
outFile := filepath.Join(t.TempDir(), "notes.exe")
|
||||
goTool := testenv.GoToolPath(t)
|
||||
|
||||
cmd := testenv.Command(t, goTool, "build", "-o", outFile, "-ldflags", "-buildid 0x1234 -B gobuildid", goFile)
|
||||
cmd.Dir = t.TempDir()
|
||||
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedGoBuildID := notsha256.Sum256([]byte("0x1234"))
|
||||
|
||||
gnuBuildID, err := buildid.ReadELFNote(outFile, string(ld.ELF_NOTE_BUILDINFO_NAME), ld.ELF_NOTE_BUILDINFO_TAG)
|
||||
if err != nil || gnuBuildID == nil {
|
||||
t.Fatalf("can't read GNU build ID")
|
||||
}
|
||||
|
||||
if !bytes.Equal(gnuBuildID, expectedGoBuildID[:20]) {
|
||||
t.Fatalf("build id not matching")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeNoteSections(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
expected := 1
|
||||
|
@ -806,6 +806,18 @@ func elfwritefreebsdsig(out *OutBuf) int {
|
||||
}
|
||||
|
||||
func addbuildinfo(val string) {
|
||||
if val == "gobuildid" {
|
||||
buildID := *flagBuildid
|
||||
if buildID == "" {
|
||||
Exitf("-B gobuildid requires a Go build ID supplied via -buildid")
|
||||
}
|
||||
|
||||
hashedBuildID := notsha256.Sum256([]byte(buildID))
|
||||
buildinfo = hashedBuildID[:20]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(val, "0x") {
|
||||
Exitf("-B argument must start with 0x: %s", val)
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ func Main(arch *sys.Arch, theArch Arch) {
|
||||
flag.Var(&ctxt.LinkMode, "linkmode", "set link `mode`")
|
||||
flag.Var(&ctxt.BuildMode, "buildmode", "set build `mode`")
|
||||
flag.BoolVar(&ctxt.compressDWARF, "compressdwarf", true, "compress DWARF if possible")
|
||||
objabi.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
|
||||
objabi.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF; use \"gobuildid\" to generate it from the Go build ID", addbuildinfo)
|
||||
objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) })
|
||||
objabi.AddVersionFlag() // -V
|
||||
objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
|
||||
|
Loading…
Reference in New Issue
Block a user