Commit ac1f48e2 authored by Russ Cox's avatar Russ Cox

cmd/link: add -buildid flag to write Go build ID to ELF output, same as cmd/compile

Other binary formats to follow.

Using our own note instead of the GNU build ID note because
we are not the GNU project, and I can't guarantee that the semantics
of our note and the semantics of the GNU note will match forever.
(Also they don't match today.)

For #11048.

Change-Id: Iec7e5a2e49d52b6d3a51b0aface2de7c77a45491
Reviewed-on: https://go-review.googlesource.com/10706Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent a2c50ece
...@@ -1189,6 +1189,11 @@ func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int { ...@@ -1189,6 +1189,11 @@ func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int {
return elfnote(sh, startva, resoff, n, true) return elfnote(sh, startva, resoff, n, true)
} }
func elfgobuildid(sh *ElfShdr, startva uint64, resoff uint64) int {
n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(buildid)), 4))
return elfnote(sh, startva, resoff, n, true)
}
func elfwritebuildinfo() int { func elfwritebuildinfo() int {
sh := elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG) sh := elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG)
if sh == nil { if sh == nil {
...@@ -1203,11 +1208,26 @@ func elfwritebuildinfo() int { ...@@ -1203,11 +1208,26 @@ func elfwritebuildinfo() int {
return int(sh.size) return int(sh.size)
} }
func elfwritegobuildid() int {
sh := elfwritenotehdr(".note.go.buildid", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(buildid)), ELF_NOTE_GOBUILDID_TAG)
if sh == nil {
return 0
}
Cwrite(ELF_NOTE_GO_NAME)
Cwrite([]byte(buildid))
var zero = make([]byte, 4)
Cwrite(zero[:int(Rnd(int64(len(buildid)), 4)-int64(len(buildid)))])
return int(sh.size)
}
// Go specific notes // Go specific notes
const ( const (
ELF_NOTE_GOPKGLIST_TAG = 1 ELF_NOTE_GOPKGLIST_TAG = 1
ELF_NOTE_GOABIHASH_TAG = 2 ELF_NOTE_GOABIHASH_TAG = 2
ELF_NOTE_GODEPS_TAG = 3 ELF_NOTE_GODEPS_TAG = 3
ELF_NOTE_GOBUILDID_TAG = 4
) )
var ELF_NOTE_GO_NAME = []byte("Go\x00\x00") var ELF_NOTE_GO_NAME = []byte("Go\x00\x00")
...@@ -1663,6 +1683,9 @@ func doelf() { ...@@ -1663,6 +1683,9 @@ func doelf() {
if len(buildinfo) > 0 { if len(buildinfo) > 0 {
Addstring(shstrtab, ".note.gnu.build-id") Addstring(shstrtab, ".note.gnu.build-id")
} }
if buildid != "" {
Addstring(shstrtab, ".note.go.buildid")
}
Addstring(shstrtab, ".elfdata") Addstring(shstrtab, ".elfdata")
Addstring(shstrtab, ".rodata") Addstring(shstrtab, ".rodata")
Addstring(shstrtab, ".typelink") Addstring(shstrtab, ".typelink")
...@@ -1702,6 +1725,10 @@ func doelf() { ...@@ -1702,6 +1725,10 @@ func doelf() {
Addstring(shstrtab, ".note.go.pkg-list") Addstring(shstrtab, ".note.go.pkg-list")
Addstring(shstrtab, ".note.go.deps") Addstring(shstrtab, ".note.go.deps")
} }
if buildid != "" {
Addstring(shstrtab, ".note.go.buildid")
}
} }
hasinitarr := Linkshared hasinitarr := Linkshared
...@@ -1914,6 +1941,10 @@ func doelf() { ...@@ -1914,6 +1941,10 @@ func doelf() {
} }
addgonote(".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n"))) addgonote(".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n")))
} }
if Linkmode == LinkExternal && buildid != "" {
addgonote(".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(buildid))
}
} }
// Do not write DT_NULL. elfdynhash will finish it. // Do not write DT_NULL. elfdynhash will finish it.
...@@ -1988,6 +2019,13 @@ func Asmbelf(symo int64) { ...@@ -1988,6 +2019,13 @@ func Asmbelf(symo int64) {
sh = elfshname(".note.go.deps") sh = elfshname(".note.go.deps")
sh.type_ = SHT_NOTE sh.type_ = SHT_NOTE
} }
if buildid != "" {
sh := elfshname(".note.go.buildid")
sh.type_ = SHT_NOTE
sh.flags = SHF_ALLOC
}
goto elfobj goto elfobj
} }
...@@ -2084,6 +2122,16 @@ func Asmbelf(symo int64) { ...@@ -2084,6 +2122,16 @@ func Asmbelf(symo int64) {
phsh(pnote, sh) phsh(pnote, sh)
} }
if buildid != "" {
sh := elfshname(".note.go.buildid")
resoff -= int64(elfgobuildid(sh, uint64(startva), uint64(resoff)))
pnote := newElfPhdr()
pnote.type_ = PT_NOTE
pnote.flags = PF_R
phsh(pnote, sh)
}
// Additions to the reserved area must be above this line. // Additions to the reserved area must be above this line.
elfphload(&Segtext) elfphload(&Segtext)
...@@ -2395,6 +2443,9 @@ elfobj: ...@@ -2395,6 +2443,9 @@ elfobj:
if len(buildinfo) > 0 { if len(buildinfo) > 0 {
a += int64(elfwritebuildinfo()) a += int64(elfwritebuildinfo())
} }
if buildid != "" {
a += int64(elfwritegobuildid())
}
} }
if a > elfreserve { if a > elfreserve {
......
...@@ -38,9 +38,10 @@ import ( ...@@ -38,9 +38,10 @@ import (
"strings" "strings"
) )
var pkglistfornote []byte var (
pkglistfornote []byte
// Reading object files. buildid string
)
func Ldmain() { func Ldmain() {
Ctxt = linknew(Thelinkarch) Ctxt = linknew(Thelinkarch)
...@@ -104,6 +105,7 @@ func Ldmain() { ...@@ -104,6 +105,7 @@ func Ldmain() {
obj.Flagfn1("X", "set the value of a string variable; the next two arguments are its name and value", addstrdata1) obj.Flagfn1("X", "set the value of a string variable; the next two arguments are its name and value", addstrdata1)
obj.Flagcount("Z", "clear stack frame on entry", &Debug['Z']) obj.Flagcount("Z", "clear stack frame on entry", &Debug['Z'])
obj.Flagcount("a", "disassemble output", &Debug['a']) obj.Flagcount("a", "disassemble output", &Debug['a'])
obj.Flagstr("buildid", "record `id` as Go toolchain build id", &buildid)
flag.Var(&Buildmode, "buildmode", "set build `mode`") flag.Var(&Buildmode, "buildmode", "set build `mode`")
obj.Flagcount("c", "dump call graph", &Debug['c']) obj.Flagcount("c", "dump call graph", &Debug['c'])
obj.Flagcount("d", "disable dynamic executable", &Debug['d']) obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment