]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: add -buildid flag to write Go build ID to ELF output, same as cmd/compile
authorRuss Cox <rsc@golang.org>
Thu, 4 Jun 2015 18:31:05 +0000 (14:31 -0400)
committerRuss Cox <rsc@golang.org>
Fri, 5 Jun 2015 04:02:26 +0000 (04:02 +0000)
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 <iant@golang.org>
src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/ld/pobj.go

index 7854ce429ff1859aed9ece745c5c8dad97152bae..785b1cbd2ddfb1052c917e24c9a5978322517e2d 100644 (file)
@@ -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 {
index ed8e30e9ffd27a688ece8a4656bc7a38d6d1bc58..b3252c181b93a8866fd41b9baf660d176e1c77fe 100644 (file)
@@ -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'])