mirror of
https://github.com/golang/go
synced 2024-11-26 22:21:27 -07:00
cmd/link/internal/ld: put abi hash into a note
This makes for a more stable API for tools (including cmd/link itself) to extract the abi hash from a shared library and makes it possible at all for a library that has had the local symbol table removed. The existing note-writing code only supports writing notes into the very start of the object file so they are easy to find in core dumps. This doesn't apply to the "go" notes and means that all notes have to fit into a fixed size budget. That's annoying now we have more notes (and the next CL will add another one) so this does a little bit of work to make adding notes that do not have to go at the start of the file easier and moves the writing of the package list note over to that mechanism, which lets me revert a hack that increased the size budget mentioned above for -buildmode=shared builds. Change-Id: I6077a68d395c8a2bc43dec8506e73c71ef77d9b9 Reviewed-on: https://go-review.googlesource.com/10375 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
9262e2183b
commit
65518032b9
@ -8,10 +8,12 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
@ -176,6 +178,89 @@ func TestShlibnameFiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Is a given offset into the file contained in a loaded segment?
|
||||
func isOffsetLoaded(f *elf.File, offset uint64) bool {
|
||||
for _, prog := range f.Progs {
|
||||
if prog.Type == elf.PT_LOAD {
|
||||
if prog.Off <= offset && offset < prog.Off+prog.Filesz {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func rnd(v int32, r int32) int32 {
|
||||
if r <= 0 {
|
||||
return v
|
||||
}
|
||||
v += r - 1
|
||||
c := v % r
|
||||
if c < 0 {
|
||||
c += r
|
||||
}
|
||||
v -= c
|
||||
return v
|
||||
}
|
||||
|
||||
func readwithpad(r io.Reader, sz int32) ([]byte, error) {
|
||||
data := make([]byte, rnd(sz, 4))
|
||||
_, err := io.ReadFull(r, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data = data[:sz]
|
||||
return data, nil
|
||||
}
|
||||
|
||||
type note struct {
|
||||
name string
|
||||
tag int32
|
||||
desc string
|
||||
section *elf.Section
|
||||
}
|
||||
|
||||
// Read all notes from f. As ELF section names are not supposed to be special, one
|
||||
// looks for a particular note by scanning all SHT_NOTE sections looking for a note
|
||||
// with a particular "name" and "tag".
|
||||
func readNotes(f *elf.File) ([]*note, error) {
|
||||
var notes []*note
|
||||
for _, sect := range f.Sections {
|
||||
if sect.Type != elf.SHT_NOTE {
|
||||
continue
|
||||
}
|
||||
r := sect.Open()
|
||||
for {
|
||||
var namesize, descsize, tag int32
|
||||
err := binary.Read(r, f.ByteOrder, &namesize)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, fmt.Errorf("read namesize failed:", err)
|
||||
}
|
||||
err = binary.Read(r, f.ByteOrder, &descsize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read descsize failed:", err)
|
||||
}
|
||||
err = binary.Read(r, f.ByteOrder, &tag)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read type failed:", err)
|
||||
}
|
||||
name, err := readwithpad(r, namesize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read name failed:", err)
|
||||
}
|
||||
desc, err := readwithpad(r, descsize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read desc failed:", err)
|
||||
}
|
||||
notes = append(notes, ¬e{name: string(name), tag: tag, desc: string(desc), section: sect})
|
||||
}
|
||||
}
|
||||
return notes, nil
|
||||
}
|
||||
|
||||
func dynStrings(path string, flag elf.DynTag) []string {
|
||||
f, err := elf.Open(path)
|
||||
defer f.Close()
|
||||
@ -233,6 +318,97 @@ func TestGOPathShlib(t *testing.T) {
|
||||
run(t, "executable linked to GOPATH library", "./bin/exe")
|
||||
}
|
||||
|
||||
// The shared library contains a note listing the packages it contains in a section
|
||||
// that is not mapped into memory.
|
||||
func testPkgListNote(t *testing.T, f *elf.File, note *note) {
|
||||
if note.section.Flags != 0 {
|
||||
t.Errorf("package list section has flags %v", note.section.Flags)
|
||||
}
|
||||
if isOffsetLoaded(f, note.section.Offset) {
|
||||
t.Errorf("package list section contained in PT_LOAD segment")
|
||||
}
|
||||
if note.desc != "dep\n" {
|
||||
t.Errorf("incorrect package list %q", note.desc)
|
||||
}
|
||||
}
|
||||
|
||||
// The shared library contains a note containing the ABI hash that is mapped into
|
||||
// memory and there is a local symbol called go.link.abihashbytes that points 16
|
||||
// bytes into it.
|
||||
func testABIHashNote(t *testing.T, f *elf.File, note *note) {
|
||||
if note.section.Flags != elf.SHF_ALLOC {
|
||||
t.Errorf("abi hash section has flags %v", note.section.Flags)
|
||||
}
|
||||
if !isOffsetLoaded(f, note.section.Offset) {
|
||||
t.Errorf("abihash section not contained in PT_LOAD segment")
|
||||
}
|
||||
var hashbytes elf.Symbol
|
||||
symbols, err := f.Symbols()
|
||||
if err != nil {
|
||||
t.Errorf("error reading symbols %v", err)
|
||||
return
|
||||
}
|
||||
for _, sym := range symbols {
|
||||
if sym.Name == "go.link.abihashbytes" {
|
||||
hashbytes = sym
|
||||
}
|
||||
}
|
||||
if hashbytes.Name == "" {
|
||||
t.Errorf("no symbol called go.link.abihashbytes")
|
||||
return
|
||||
}
|
||||
if elf.ST_BIND(hashbytes.Info) != elf.STB_LOCAL {
|
||||
t.Errorf("%s has incorrect binding %v", hashbytes.Name, elf.ST_BIND(hashbytes.Info))
|
||||
}
|
||||
if f.Sections[hashbytes.Section] != note.section {
|
||||
t.Errorf("%s has incorrect section %v", hashbytes.Name, f.Sections[hashbytes.Section].Name)
|
||||
}
|
||||
if hashbytes.Value-note.section.Addr != 16 {
|
||||
t.Errorf("%s has incorrect offset into section %d", hashbytes.Name, hashbytes.Value-note.section.Addr)
|
||||
}
|
||||
}
|
||||
|
||||
// The shared library contains notes with defined contents; see above.
|
||||
func TestNotes(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
|
||||
f, err := elf.Open(filepath.Join(gopathInstallDir, "libdep.so"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
notes, err := readNotes(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pkgListNoteFound := false
|
||||
abiHashNoteFound := false
|
||||
for _, note := range notes {
|
||||
if note.name != "GO\x00\x00" {
|
||||
continue
|
||||
}
|
||||
switch note.tag {
|
||||
case 1: // ELF_NOTE_GOPKGLIST_TAG
|
||||
if pkgListNoteFound {
|
||||
t.Error("multiple package list notes")
|
||||
}
|
||||
testPkgListNote(t, f, note)
|
||||
pkgListNoteFound = true
|
||||
case 2: // ELF_NOTE_GOABIHASH_TAG
|
||||
if abiHashNoteFound {
|
||||
t.Error("multiple abi hash notes")
|
||||
}
|
||||
testABIHashNote(t, f, note)
|
||||
abiHashNoteFound = true
|
||||
}
|
||||
}
|
||||
if !pkgListNoteFound {
|
||||
t.Error("package list note not found")
|
||||
}
|
||||
if !abiHashNoteFound {
|
||||
t.Error("abi hash note not found")
|
||||
}
|
||||
}
|
||||
|
||||
// Testing rebuilding of shared libraries when they are stale is a bit more
|
||||
// complicated that it seems like it should be. First, we make everything "old": but
|
||||
// only a few seconds old, or it might be older than 6g (or the runtime source) and
|
||||
|
@ -168,14 +168,6 @@ func archinit() {
|
||||
ld.Elfinit()
|
||||
|
||||
ld.HEADR = ld.ELFRESERVE
|
||||
if ld.Buildmode == ld.BuildmodeShared {
|
||||
// When building a shared library we write a package list
|
||||
// note that can get quite large. The external linker will
|
||||
// re-layout all the sections anyway, so making this larger
|
||||
// just wastes a little space in the intermediate object
|
||||
// file, not the final shared library.
|
||||
ld.HEADR *= 3
|
||||
}
|
||||
if ld.INITTEXT == -1 {
|
||||
ld.INITTEXT = (1 << 22) + int64(ld.HEADR)
|
||||
}
|
||||
|
@ -1688,6 +1688,13 @@ func address() {
|
||||
}
|
||||
}
|
||||
|
||||
if Buildmode == BuildmodeShared {
|
||||
s := Linklookup(Ctxt, "go.link.abihashbytes", 0)
|
||||
sectSym := Linklookup(Ctxt, ".note.go.abihash", 0)
|
||||
s.Sect = sectSym.Sect
|
||||
s.Value = int64(sectSym.Sect.Vaddr + 16)
|
||||
}
|
||||
|
||||
xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
|
||||
xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
|
||||
xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr))
|
||||
|
@ -6,8 +6,10 @@ package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
/*
|
||||
@ -1199,32 +1201,14 @@ func elfwritebuildinfo() int {
|
||||
return int(sh.size)
|
||||
}
|
||||
|
||||
// Go package list note
|
||||
// Go specific notes
|
||||
const (
|
||||
ELF_NOTE_GOPKGLIST_TAG = 1
|
||||
ELF_NOTE_GOABIHASH_TAG = 2
|
||||
)
|
||||
|
||||
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 {
|
||||
@ -1455,6 +1439,24 @@ func elfshalloc(sect *Section) *ElfShdr {
|
||||
|
||||
func elfshbits(sect *Section) *ElfShdr {
|
||||
sh := elfshalloc(sect)
|
||||
// If this section has already been set up as a note, we assume type_ and
|
||||
// flags are already correct, but the other fields still need filling in.
|
||||
if sh.type_ == SHT_NOTE {
|
||||
if Linkmode != LinkExternal {
|
||||
// TODO(mwhudson): the approach here will work OK when
|
||||
// linking internally for notes that we want to be included
|
||||
// in a loadable segment (e.g. the abihash note) but not for
|
||||
// notes that we do not want to be mapped (e.g. the package
|
||||
// list note). The real fix is probably to define new values
|
||||
// for LSym.Type corresponding to mapped and unmapped notes
|
||||
// and handle them in dodata().
|
||||
Diag("sh.type_ == SHT_NOTE in elfshbits when linking internally")
|
||||
}
|
||||
sh.addralign = uint64(sect.Align)
|
||||
sh.size = sect.Length
|
||||
sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
|
||||
return sh
|
||||
}
|
||||
if sh.type_ > 0 {
|
||||
return sh
|
||||
}
|
||||
@ -1490,13 +1492,16 @@ func elfshbits(sect *Section) *ElfShdr {
|
||||
|
||||
func elfshreloc(sect *Section) *ElfShdr {
|
||||
// If main section is SHT_NOBITS, nothing to relocate.
|
||||
// Also nothing to relocate in .shstrtab.
|
||||
// Also nothing to relocate in .shstrtab or notes.
|
||||
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
|
||||
return nil
|
||||
}
|
||||
if sect.Name == ".shstrtab" || sect.Name == ".tbss" {
|
||||
return nil
|
||||
}
|
||||
if sect.Elfsect.type_ == SHT_NOTE {
|
||||
return nil
|
||||
}
|
||||
|
||||
var prefix string
|
||||
var typ int
|
||||
@ -1596,6 +1601,29 @@ func Elfemitreloc() {
|
||||
}
|
||||
}
|
||||
|
||||
func addgonote(sectionName string, tag uint32, desc []byte) {
|
||||
s := Linklookup(Ctxt, sectionName, 0)
|
||||
s.Reachable = true
|
||||
s.Type = obj.SELFROSECT
|
||||
// namesz
|
||||
Adduint32(Ctxt, s, uint32(len(ELF_NOTE_GO_NAME)))
|
||||
// descsz
|
||||
Adduint32(Ctxt, s, uint32(len(desc)))
|
||||
// tag
|
||||
Adduint32(Ctxt, s, tag)
|
||||
// name + padding
|
||||
s.P = append(s.P, ELF_NOTE_GO_NAME...)
|
||||
for len(s.P)%4 != 0 {
|
||||
s.P = append(s.P, 0)
|
||||
}
|
||||
// desc + padding
|
||||
s.P = append(s.P, desc...)
|
||||
for len(s.P)%4 != 0 {
|
||||
s.P = append(s.P, 0)
|
||||
}
|
||||
s.Size = int64(len(s.P))
|
||||
}
|
||||
|
||||
func doelf() {
|
||||
if !Iself {
|
||||
return
|
||||
@ -1632,9 +1660,6 @@ 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")
|
||||
@ -1668,6 +1693,11 @@ func doelf() {
|
||||
|
||||
// add a .note.GNU-stack section to mark the stack as non-executable
|
||||
Addstring(shstrtab, ".note.GNU-stack")
|
||||
|
||||
if Buildmode == BuildmodeShared {
|
||||
Addstring(shstrtab, ".note.go.abihash")
|
||||
Addstring(shstrtab, ".note.go.pkg-list")
|
||||
}
|
||||
}
|
||||
|
||||
hasinitarr := Linkshared
|
||||
@ -1856,6 +1886,25 @@ func doelf() {
|
||||
// size of .rel(a).plt section.
|
||||
Elfwritedynent(s, DT_DEBUG, 0)
|
||||
}
|
||||
|
||||
if Buildmode == BuildmodeShared {
|
||||
// The go.link.abihashbytes symbol will be pointed at the appropriate
|
||||
// part of the .note.go.abihash section in data.go:func address().
|
||||
s := Linklookup(Ctxt, "go.link.abihashbytes", 0)
|
||||
s.Local = true
|
||||
s.Type = obj.SRODATA
|
||||
s.Special = 1
|
||||
s.Reachable = true
|
||||
s.Size = int64(sha1.Size)
|
||||
|
||||
sort.Sort(byPkg(Ctxt.Library))
|
||||
h := sha1.New()
|
||||
for _, l := range Ctxt.Library {
|
||||
h.Write(l.hash)
|
||||
}
|
||||
addgonote(".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{}))
|
||||
addgonote(".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, []byte(pkglistfornote))
|
||||
}
|
||||
}
|
||||
|
||||
// Do not write DT_NULL. elfdynhash will finish it.
|
||||
@ -1922,15 +1971,11 @@ func Asmbelf(symo int64) {
|
||||
eh.phentsize = 0
|
||||
|
||||
if Buildmode == BuildmodeShared {
|
||||
// The package list note we make space for here can get quite
|
||||
// large. The external linker will re-layout all the sections
|
||||
// anyway, so making this larger just wastes a little space
|
||||
// in the intermediate object file, not the final shared
|
||||
// library.
|
||||
elfreserve *= 3
|
||||
resoff = elfreserve
|
||||
sh := elfshname(".note.go.pkg-list")
|
||||
resoff -= int64(elfgopkgnote(sh, uint64(startva), uint64(resoff)))
|
||||
sh.type_ = SHT_NOTE
|
||||
sh = elfshname(".note.go.abihash")
|
||||
sh.type_ = SHT_NOTE
|
||||
sh.flags = SHF_ALLOC
|
||||
}
|
||||
goto elfobj
|
||||
}
|
||||
@ -2340,9 +2385,6 @@ elfobj:
|
||||
a += int64(elfwritebuildinfo())
|
||||
}
|
||||
}
|
||||
if Buildmode == BuildmodeShared {
|
||||
a += int64(elfwritegopkgnote())
|
||||
}
|
||||
|
||||
if a > elfreserve {
|
||||
Diag("ELFRESERVE too small: %d > %d", a, elfreserve)
|
||||
|
@ -36,6 +36,7 @@ import (
|
||||
"cmd/internal/obj"
|
||||
"crypto/sha1"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -1154,8 +1155,8 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when
|
||||
func readelfsymboldata(f *elf.File, sym *elf.Symbol) []byte {
|
||||
data := make([]byte, sym.Size)
|
||||
sect := f.Sections[sym.Section]
|
||||
if sect.Type != elf.SHT_PROGBITS {
|
||||
Diag("reading %s from non-PROGBITS section", sym.Name)
|
||||
if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
|
||||
Diag("reading %s from non-data section", sym.Name)
|
||||
}
|
||||
n, err := sect.ReadAt(data, int64(sym.Value-sect.Offset))
|
||||
if uint64(n) != sym.Size {
|
||||
@ -1164,6 +1165,55 @@ func readelfsymboldata(f *elf.File, sym *elf.Symbol) []byte {
|
||||
return data
|
||||
}
|
||||
|
||||
func readwithpad(r io.Reader, sz int32) ([]byte, error) {
|
||||
data := make([]byte, Rnd(int64(sz), 4))
|
||||
_, err := io.ReadFull(r, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data = data[:sz]
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
|
||||
for _, sect := range f.Sections {
|
||||
if sect.Type != elf.SHT_NOTE {
|
||||
continue
|
||||
}
|
||||
r := sect.Open()
|
||||
for {
|
||||
var namesize, descsize, noteType int32
|
||||
err := binary.Read(r, f.ByteOrder, &namesize)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, fmt.Errorf("read namesize failed:", err)
|
||||
}
|
||||
err = binary.Read(r, f.ByteOrder, &descsize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read descsize failed:", err)
|
||||
}
|
||||
err = binary.Read(r, f.ByteOrder, ¬eType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read type failed:", err)
|
||||
}
|
||||
noteName, err := readwithpad(r, namesize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read name failed:", err)
|
||||
}
|
||||
desc, err := readwithpad(r, descsize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read desc failed:", err)
|
||||
}
|
||||
if string(name) == string(noteName) && typ == noteType {
|
||||
return desc, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func ldshlibsyms(shlib string) {
|
||||
found := false
|
||||
libpath := ""
|
||||
@ -1194,6 +1244,13 @@ func ldshlibsyms(shlib string) {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
|
||||
if err != nil {
|
||||
Diag("cannot read ABI hash from shared library %s: %v", libpath, err)
|
||||
return
|
||||
}
|
||||
|
||||
syms, err := f.Symbols()
|
||||
if err != nil {
|
||||
Diag("cannot read symbols from shared library: %s", libpath)
|
||||
@ -1211,7 +1268,6 @@ func ldshlibsyms(shlib string) {
|
||||
// table removed.
|
||||
gcmasks := make(map[uint64][]byte)
|
||||
types := []*LSym{}
|
||||
var hash []byte
|
||||
for _, s := range syms {
|
||||
if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION {
|
||||
continue
|
||||
@ -1225,9 +1281,6 @@ func ldshlibsyms(shlib string) {
|
||||
if strings.HasPrefix(s.Name, "runtime.gcbits.") {
|
||||
gcmasks[s.Value] = readelfsymboldata(f, &s)
|
||||
}
|
||||
if s.Name == "go.link.abihashbytes" {
|
||||
hash = readelfsymboldata(f, &s)
|
||||
}
|
||||
if elf.ST_BIND(s.Info) != elf.STB_GLOBAL {
|
||||
continue
|
||||
}
|
||||
|
@ -32,10 +32,8 @@ package ld
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -429,16 +427,12 @@ func symtab() {
|
||||
}
|
||||
|
||||
if Buildmode == BuildmodeShared {
|
||||
sort.Sort(byPkg(Ctxt.Library))
|
||||
h := sha1.New()
|
||||
for _, l := range Ctxt.Library {
|
||||
h.Write(l.hash)
|
||||
}
|
||||
abihashgostr := Linklookup(Ctxt, "go.link.abihash."+filepath.Base(outfile), 0)
|
||||
abihashgostr.Reachable = true
|
||||
abihashgostr.Type = obj.SRODATA
|
||||
var hashbytes []byte
|
||||
addgostring(abihashgostr, "go.link.abihashbytes", string(h.Sum(hashbytes)))
|
||||
hashsym := Linklookup(Ctxt, "go.link.abihashbytes", 0)
|
||||
Addaddr(Ctxt, abihashgostr, hashsym)
|
||||
adduint(Ctxt, abihashgostr, uint64(hashsym.Size))
|
||||
}
|
||||
|
||||
// Information about the layout of the executable image for the
|
||||
|
Loading…
Reference in New Issue
Block a user