From 7556948ebf1c1d739c2fa3b06a0b9bc10e4f150d Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Wed, 29 Apr 2015 22:58:52 +1200 Subject: [PATCH] cmd/internal/ld: put the list of packages built into a shared library into an ELF note Change-Id: I611f7dec2109dc7e2f090ced0a1dca3d4b577134 Reviewed-on: https://go-review.googlesource.com/9520 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor --- src/cmd/internal/ld/elf.go | 49 +++++++++++++++++++++++++++++++++---- src/cmd/internal/ld/lib.go | 9 +++++++ src/cmd/internal/ld/pobj.go | 4 +++ 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/cmd/internal/ld/elf.go b/src/cmd/internal/ld/elf.go index cb4a73a338..01be55e16d 100644 --- a/src/cmd/internal/ld/elf.go +++ b/src/cmd/internal/ld/elf.go @@ -1039,11 +1039,13 @@ func elfwriteinterp() int { return int(sh.size) } -func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int { +func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int, alloc bool) int { n := 3*4 + uint64(sz) + resoff%4 sh.type_ = SHT_NOTE - sh.flags = SHF_ALLOC + if alloc { + sh.flags = SHF_ALLOC + } sh.addralign = 4 sh.addr = startva + resoff - n sh.off = resoff - n @@ -1077,7 +1079,7 @@ var ELF_NOTE_NETBSD_NAME = []byte("NetBSD\x00") func elfnetbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int { n := int(Rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + Rnd(ELF_NOTE_NETBSD_DESCSZ, 4)) - return elfnote(sh, startva, resoff, n) + return elfnote(sh, startva, resoff, n, true) } func elfwritenetbsdsig() int { @@ -1109,7 +1111,7 @@ var ELF_NOTE_OPENBSD_NAME = []byte("OpenBSD\x00") func elfopenbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int { n := ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ - return elfnote(sh, startva, resoff, n) + return elfnote(sh, startva, resoff, n, true) } func elfwriteopenbsdsig() int { @@ -1180,7 +1182,7 @@ var ELF_NOTE_BUILDINFO_NAME = []byte("GNU\x00") func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int { n := int(ELF_NOTE_BUILDINFO_NAMESZ + Rnd(int64(len(buildinfo)), 4)) - return elfnote(sh, startva, resoff, n) + return elfnote(sh, startva, resoff, n, true) } func elfwritebuildinfo() int { @@ -1197,6 +1199,32 @@ func elfwritebuildinfo() int { return int(sh.size) } +// Go package list note +const ( + ELF_NOTE_GOPKGLIST_TAG = 1 +) + +var ELF_NOTE_GO_NAME = []byte("GO\x00\x00") + +func elfgopkgnote(sh *ElfShdr, startva uint64, resoff uint64) int { + n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(pkglistfornote)), 4)) + return elfnote(sh, startva, resoff, n, false) +} + +func elfwritegopkgnote() int { + sh := elfwritenotehdr(".note.go.pkg-list", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(pkglistfornote)), ELF_NOTE_GOPKGLIST_TAG) + if sh == nil { + return 0 + } + + Cwrite(ELF_NOTE_GO_NAME) + Cwrite(pkglistfornote) + var zero = make([]byte, 4) + Cwrite(zero[:int(Rnd(int64(len(pkglistfornote)), 4)-int64(len(pkglistfornote)))]) + + return int(sh.size) +} + var elfverneed int type Elfaux struct { @@ -1604,6 +1632,9 @@ func doelf() { if len(buildinfo) > 0 { Addstring(shstrtab, ".note.gnu.build-id") } + if Buildmode == BuildmodeShared { + Addstring(shstrtab, ".note.go.pkg-list") + } Addstring(shstrtab, ".elfdata") Addstring(shstrtab, ".rodata") Addstring(shstrtab, ".typelink") @@ -1888,6 +1919,11 @@ func Asmbelf(symo int64) { eh.phoff = 0 eh.phentsize = 0 + + if Buildmode == BuildmodeShared { + sh := elfshname(".note.go.pkg-list") + resoff -= int64(elfgopkgnote(sh, uint64(startva), uint64(resoff))) + } goto elfobj } @@ -2296,6 +2332,9 @@ elfobj: a += int64(elfwritebuildinfo()) } } + if Buildmode == BuildmodeShared { + a += int64(elfwritegopkgnote()) + } if a > ELFRESERVE { Diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE) diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go index 44389c9fa8..75a88541b0 100644 --- a/src/cmd/internal/ld/lib.go +++ b/src/cmd/internal/ld/lib.go @@ -516,6 +516,15 @@ func loadlib() { if Ctxt.Library[i].Shlib != "" { ldshlibsyms(Ctxt.Library[i].Shlib) } else { + // Because the linker always looks for runtime/cgo when + // -buildmode=shared is passed, the go tool never passes + // runtime/cgo on the command line. But runtime/cgo needs + // to end up in the package list if it is being built into + // the shared libarary. + if Buildmode == BuildmodeShared { + pkglistfornote = append(pkglistfornote, "runtime/cgo"...) + pkglistfornote = append(pkglistfornote, '\n') + } objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg) } } diff --git a/src/cmd/internal/ld/pobj.go b/src/cmd/internal/ld/pobj.go index dbfe8a044a..9b3e115183 100644 --- a/src/cmd/internal/ld/pobj.go +++ b/src/cmd/internal/ld/pobj.go @@ -38,6 +38,8 @@ import ( "strings" ) +var pkglistfornote []byte + // Reading object files. func Ldmain() { @@ -196,6 +198,8 @@ func Ldmain() { } else { pkgpath, file = parts[0], parts[1] } + pkglistfornote = append(pkglistfornote, pkgpath...) + pkglistfornote = append(pkglistfornote, '\n') addlibpath(Ctxt, "command line", "command line", file, pkgpath, "") } } else { -- 2.50.0