-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
cmd/go is apparently unable to read the Go build ID from ELF binaries created by /usr/bin/gold on Ubuntu 17.04, which is:
$ gold -v
GNU gold (GNU Binutils for Ubuntu 2.28) 1.14
$
If I build with external linking with and without gold, I get different binaries, both of which seem to have a valid .note.go.buildid section:
$ go build -ldflags=-linkmode=external -o /tmp/hello.default ~/go/test/helloworld.go
$ go build "-ldflags=-linkmode=external -extldflags=-fuse-ld=gold" -o /tmp/hello.gold ~/go/test/helloworld.go
$ objdump -s -j .note.go.buildid /tmp/hello.default
/tmp/hello.default: file format elf64-x86-64
Contents of section .note.go.buildid:
400320 04000000 28000000 04000000 476f0000 ....(.......Go..
400330 61633839 33303162 66323264 39643237 ac89301bf22d9d27
400340 64626331 35393532 32306538 31333466 dbc1595220e8134f
400350 34643230 31656132 4d201ea2
$ objdump -s -j .note.go.buildid /tmp/hello.gold
/tmp/hello.gold: file format elf64-x86-64
Contents of section .note.go.buildid:
4002c0 04000000 28000000 04000000 476f0000 ....(.......Go..
4002d0 61633839 33303162 66323264 39643237 ac89301bf22d9d27
4002e0 64626331 35393532 32306538 31333466 dbc1595220e8134f
4002f0 34643230 31656132 4d201ea2
$ readelf -S /tmp/hello.default | grep -C 3 note.go.buildid
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.ABI-tag NOTE 00000000004002fc 000002fc
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.go.buildid NOTE 0000000000400320 00000320
0000000000000038 0000000000000000 A 0 0 32
[ 4] .note.gnu.build-i NOTE 0000000000400358 00000358
0000000000000024 0000000000000000 A 0 0 4
$ readelf -S /tmp/hello.gold | grep -C 3 note.go.buildid
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.ABI-tag NOTE 000000000040028c 0000028c
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.go.buildid NOTE 00000000004002c0 000002c0
0000000000000038 0000000000000000 A 0 0 32
[ 4] .note.gnu.build-i NOTE 00000000004002f8 000002f8
0000000000000024 0000000000000000 A 0 0 4
$
The sections are in a different order using gold but things look OK. In particular the sections themselves seem to have exactly the same bytes in either build.
But while normally go test -run NoteReading cmd/go passes, if I change it to use gold, it fails:
$ git diff
diff --git a/src/cmd/go/note_test.go b/src/cmd/go/note_test.go
index 2ee013faf3..87c31cea88 100644
--- a/src/cmd/go/note_test.go
+++ b/src/cmd/go/note_test.go
@@ -53,7 +53,7 @@ func testNoteReading(t *testing.T) {
t.Skipf("skipping - external linking not supported")
}
- tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello.exe"), tg.path("hello.go"))
+ tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external -extldflags=-fuse-ld=gold", "-o", tg.path("hello.exe"), tg.path("hello.go"))
id, err = main.ReadBuildIDFromBinary(tg.path("hello.exe"))
if err != nil {
t.Fatalf("reading build ID from hello binary (linkmode=external): %v", err)
$ go test -run=NoteReading cmd/go
--- FAIL: TestNoteReading (0.27s)
go_test.go:260: running testgo [build -ldflags -buildid=TestNoteReading-Build-ID -o /tmp/gotest563847269/hello.exe /tmp/gotest563847269/hello.go]
go_test.go:260: running testgo [build -ldflags -buildid=TestNoteReading-Build-ID -linkmode=external -extldflags=-fuse-ld=gold -o /tmp/gotest563847269/hello.exe /tmp/gotest563847269/hello.go]
note_test.go:62: buildID in hello binary = "", want "TestNoteReading-Build-ID" (linkmode=external)
--- FAIL: TestNoteReading2K (0.27s)
go_test.go:260: running testgo [build -ldflags -buildid=TestNoteReading-Build-ID -o /tmp/gotest844349056/hello.exe /tmp/gotest844349056/hello.go]
go_test.go:260: running testgo [build -ldflags -buildid=TestNoteReading-Build-ID -linkmode=external -extldflags=-fuse-ld=gold -o /tmp/gotest844349056/hello.exe /tmp/gotest844349056/hello.go]
note_test.go:62: buildID in hello binary = "", want "TestNoteReading-Build-ID" (linkmode=external)
FAIL
FAIL cmd/go 2.469s
$
This makes Go using gold do spurious rebuilds of binaries, because they appear out of date but are not.
I discovered this by compiling gccgo from source, which installed a new gcc into /usr/local/bin, and I'd (apparently mistakenly) configured with --with-ld=/usr/bin/gold. I will rebuild without that, but we should probably understand what is going on here.
I remember that in the past we've had problems with Ubuntu shipping ancient buggy versions of gold. I wondered if that might be the case here, but objdump and readelf are happy with the binary, so the go command probably should be made to be happy too.