From: Russ Cox Date: Thu, 4 Jun 2015 18:31:05 +0000 (-0400) Subject: cmd/link: add -buildid flag to write Go build ID to ELF output, same as cmd/compile X-Git-Tag: go1.5beta1~354 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ac1f48e2f6ac7cad2fbe072de8d4fbf50c5d8e67;p=gostls13.git 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/10706 Reviewed-by: Ian Lance Taylor --- diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 7854ce429f..785b1cbd2d 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1189,6 +1189,11 @@ func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int { 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 { sh := elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG) if sh == nil { @@ -1203,11 +1208,26 @@ func elfwritebuildinfo() int { 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 const ( ELF_NOTE_GOPKGLIST_TAG = 1 ELF_NOTE_GOABIHASH_TAG = 2 ELF_NOTE_GODEPS_TAG = 3 + ELF_NOTE_GOBUILDID_TAG = 4 ) var ELF_NOTE_GO_NAME = []byte("Go\x00\x00") @@ -1663,6 +1683,9 @@ func doelf() { if len(buildinfo) > 0 { Addstring(shstrtab, ".note.gnu.build-id") } + if buildid != "" { + Addstring(shstrtab, ".note.go.buildid") + } Addstring(shstrtab, ".elfdata") Addstring(shstrtab, ".rodata") Addstring(shstrtab, ".typelink") @@ -1702,6 +1725,10 @@ func doelf() { Addstring(shstrtab, ".note.go.pkg-list") Addstring(shstrtab, ".note.go.deps") } + + if buildid != "" { + Addstring(shstrtab, ".note.go.buildid") + } } hasinitarr := Linkshared @@ -1914,6 +1941,10 @@ func doelf() { } 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. @@ -1988,6 +2019,13 @@ func Asmbelf(symo int64) { sh = elfshname(".note.go.deps") sh.type_ = SHT_NOTE } + + if buildid != "" { + sh := elfshname(".note.go.buildid") + sh.type_ = SHT_NOTE + sh.flags = SHF_ALLOC + } + goto elfobj } @@ -2084,6 +2122,16 @@ func Asmbelf(symo int64) { 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. elfphload(&Segtext) @@ -2395,6 +2443,9 @@ elfobj: if len(buildinfo) > 0 { a += int64(elfwritebuildinfo()) } + if buildid != "" { + a += int64(elfwritegobuildid()) + } } if a > elfreserve { diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go index ed8e30e9ff..b3252c181b 100644 --- a/src/cmd/link/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -38,9 +38,10 @@ import ( "strings" ) -var pkglistfornote []byte - -// Reading object files. +var ( + pkglistfornote []byte + buildid string +) func Ldmain() { Ctxt = linknew(Thelinkarch) @@ -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.Flagcount("Z", "clear stack frame on entry", &Debug['Z']) 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`") obj.Flagcount("c", "dump call graph", &Debug['c']) obj.Flagcount("d", "disable dynamic executable", &Debug['d'])