-
Notifications
You must be signed in to change notification settings - Fork 18k
cmd/link: add support for automatically generating .note.gnu.build-id #41004
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I hacked a little bit on this by just running sha1 on the output buffer we have in the linker. It gives me a stable sha1 sum and I think(?) it should be good enough? Should we stamp the same build id if we use the diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index a1ae7eab57..3f9f115282 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -10,6 +10,7 @@ import (
"cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
+ "crypto/sha1"
"debug/elf"
"encoding/binary"
"encoding/hex"
@@ -825,6 +826,11 @@ func elfgobuildid(sh *ElfShdr, startva uint64, resoff uint64) int {
return elfnote(sh, startva, resoff, n)
}
+func elfproducebuildinfo(out *OutBuf) {
+ id := sha1.Sum(out.Data())
+ buildinfo = id[:]
+}
+
func elfwritebuildinfo(out *OutBuf) int {
sh := elfwritenotehdr(out, ".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG)
if sh == nil {
@@ -1396,9 +1402,7 @@ func (ctxt *Link) doelf() {
if ctxt.IsFreebsd() {
shstrtab.Addstring(".note.tag")
}
- if len(buildinfo) > 0 {
- shstrtab.Addstring(".note.gnu.build-id")
- }
+ shstrtab.Addstring(".note.gnu.build-id")
if *flagBuildid != "" {
shstrtab.Addstring(".note.go.buildid")
}
@@ -1911,6 +1915,9 @@ func asmbElf(ctxt *Link) {
phsh(pnotei, sh)
}
+ if len(buildinfo) == 0 {
+ elfproducebuildinfo(ctxt.Out)
+ }
if len(buildinfo) > 0 {
sh := elfshname(".note.gnu.build-id")
resoff -= int64(elfbuildinfo(sh, uint64(startva), uint64(resoff)))
@@ -2285,9 +2292,7 @@ elfobj:
if ctxt.HeadType == objabi.Hfreebsd {
a += int64(elfwritefreebsdsig(ctxt.Out))
}
- if len(buildinfo) > 0 {
- a += int64(elfwritebuildinfo(ctxt.Out))
- }
+ a += int64(elfwritebuildinfo(ctxt.Out))
if *flagBuildid != "" {
a += int64(elfwritegobuildid(ctxt.Out))
} |
@bcmills sorry for the ping here. But has there been any discussions on how to solve this? Would a Generally this would help debug packages on Linux distros and debuggers like |
We already have a Go build ID. We can just write that out as the GNU build ID as well. I think the only question is whether we should always do it. The GNU linker only does it upon request, but on many Linux systems the compiler is configured to request it by default (by passing a |
Most (all?) debuggers expect the value for basic functionality and I struggle to see why we would stamp go build id and not the GNU build id along with it? The only issue is that the GNU build ID needs to either be a md5 or sha1, so I don't think we can pass the Go build id as-is? Having this as a build option for distributions is non-trivial as it's still hard to override the command line arguments passed to the compiler. |
To the best of my knowledge the GNU build ID does not have to be an MD5 or SHA1. Those are just common implementations of it. It can be any random relatively unique string. |
For example, for the gold linker the default value (if you just specify |
Linux's |
FWIW, Linux perf expects the GNU build ID to be 20 bytes or less (https://elixir.bootlin.com/linux/v6.2/source/lib/buildid.c#L30). I'm not sure if this is specified or a convention, but the Go build ID is significantly longer (83 bytes). |
Truncating larger hashes seems to be okay: https://reviews.llvm.org/D121531 |
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 biuld 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 "actionid" that can be passed to `-B` that causes the linker to automatically derive the build ID from the Go build ID's action ID, which is derived from all build inputs. This should thus both be deterministic while the value also changes whenever the build inputs change, which is the desired behaviour for the GNU build ID. Furthermore, given that the `-B` flag currently requires a "0x" prefix for all values passed to it, using "actionid" as value is a backwards compatible change. Fixes golang#41004
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 biuld 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 "actionid" that can be passed to `-B` that causes the linker to automatically derive the build ID from the Go build ID's action ID, which is derived from all build inputs. This should thus both be deterministic while the value also changes whenever the build inputs change, which is the desired behaviour for the GNU build ID. Furthermore, given that the `-B` flag currently requires a "0x" prefix for all values passed to it, using "actionid" as value is a backwards compatible change. Fixes golang#41004
Change https://go.dev/cl/511475 mentions this issue: |
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 biuld 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. Derive the GNU build ID automatically from the Go build ID whenever the latter has been provided. Given that the Go build ID is intended to be deterministic, the resulting GNU build ID should be deterministic as well, which is the desired behaviour. Users can continue to override the derived GNU build ID by passing a custom value via the `-B` switch. Fixes golang#41004
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 biuld 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 golang#41004
@pks-t any reason why the option can't be enabled by default? Now that things are deterministic it should be do-able. This would also make it simpler to have proper debug packages for downstreams then trying to pass the option through the Go flags/option shenanigans. |
@Foxboron Yes, please see the discussion at https://go-review.googlesource.com/c/go/+/511475/comment/9d039b0f_102db253/. |
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 golang#41004
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 golang#41004
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 golang#41004
I was looking forward to using this to get a Go compiler with a build ID, so I tried using it to build Go. Unfortunately that fails:
Any chance this could be made to work? |
@znkr Making this work for the Go compiler itself is more complicated than the current iteration. This was discussed at https://go-review.googlesource.com/c/go/+/511475/1..9/src/cmd/link/internal/ld/elf.go#b819, where the agreement was to push this out to another iteration. |
I see, thanks for the clarification. Is there an issue I can follow for the next iteration? |
I see, thanks for the clarification. Is there an issue I can follow for the next iteration?
Not yet to the best of my knowledge, so please feel free to create one.
|
Filed #63934 just now. Sorry for the delay |
Change https://go.dev/cl/547515 mentions this issue: |
Updates #41004. For #61422. Change-Id: I5ab60d8e9d30986233d7adec400ef059bbe4c1a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/547515 Reviewed-by: Than McIntosh <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
Updates golang#41004. For golang#61422. Change-Id: I5ab60d8e9d30986233d7adec400ef059bbe4c1a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/547515 Reviewed-by: Than McIntosh <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
@pks-t I tried to understand why this wasn't enabled by default from the discussion/commit message, but I didn't really get it. |
Change https://go.dev/cl/618600 mentions this issue: |
Change https://go.dev/cl/618601 mentions this issue: |
This is similar to CL 618597, but for GNU build ID on ELF. This makes it possible to enable "-B gobuildid" by default on ELF. Updates #41004. For #63934. Change-Id: I4e663a27a2f7824bce994c783fe6d9ce8d1a395a Reviewed-on: https://go-review.googlesource.com/c/go/+/618600 Reviewed-by: Than McIntosh <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
On ELF, default to "-B gobuildid", so it generates GNU build ID based on Go buildid by default. Updates #41004. Fixes #63934. Fixes #68652. Change-Id: I5619dfaa4eeb6575c52922ae1de3430b46e31db6 Reviewed-on: https://go-review.googlesource.com/c/go/+/618601 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
Change https://go.dev/cl/621639 mentions this issue: |
On Solaris the default (non-GNU) C linker doesn't support the --build-id flag (and I'm not aware of any alternative). So check that the linker supports the flag before passing it. Updates #41004, #63934. Cq-Include-Trybots: luci.golang.try:gotip-solaris-amd64 Change-Id: I4379e5bf6eb495154d663ac4ed802ecb11fcf91c Reviewed-on: https://go-review.googlesource.com/c/go/+/621639 Reviewed-by: Ian Lance Taylor <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I want the ability to automatically generate a
.note.gnu.build-id
section in Go binaries. The linker currently supports a flag to get one from the outside:-B
, but this is supposed to be a CRC that is calculated by the linker rather than something that can reliably be set from the outside as a linker flag.This is used by delve and other debuggers to find split debug symbols.
What did you expect to see?
I want a flag like the binutils linker has
-Wl,-build-id
that adds an automatically generated.note.gnu.build-id
section.What did you see instead?
There is only a flag to set it from the outside, but it is meant to be a CRC calculated by the linker to be used reliably to differentiate different debug symbols.
The text was updated successfully, but these errors were encountered: