mirror of
https://github.com/golang/go
synced 2024-11-27 02:41:23 -07:00
cmd/internal/ld, runtime: abort on shared library ABI mismatch
This: 1) Defines the ABI hash of a package (as the SHA1 of the __.PKGDEF) 2) Defines the ABI hash of a shared library (sort the packages by import path, concatenate the hashes of the packages and SHA1 that) 3) When building a shared library, compute the above value and define a global symbol that points to a go string that has the hash as its value. 4) When linking against a shared library, read the abi hash from the library and put both the value seen at link time and a reference to the global symbol into the moduledata. 5) During runtime initialization, check that the hash seen at link time still matches the hash the global symbol points to. Change-Id: Iaa54c783790e6dde3057a2feadc35473d49614a5 Reviewed-on: https://go-review.googlesource.com/8773 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
This commit is contained in:
parent
be0cb9224b
commit
77fc03f4cd
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
export GOPATH="$(pwd)"
|
|
||||||
|
|
||||||
die () {
|
die () {
|
||||||
echo $@
|
echo $@
|
||||||
@ -23,8 +22,14 @@ rootdir="$(dirname $(go list -f '{{.Target}}' runtime))"
|
|||||||
template="${rootdir}_XXXXXXXX_dynlink"
|
template="${rootdir}_XXXXXXXX_dynlink"
|
||||||
std_install_dir=$(mktemp -d "$template")
|
std_install_dir=$(mktemp -d "$template")
|
||||||
|
|
||||||
|
scratch_dir=$(mktemp -d)
|
||||||
|
cp -a . $scratch_dir
|
||||||
|
opwd="$(pwd)"
|
||||||
|
cd $scratch_dir
|
||||||
|
export GOPATH="$(pwd)"
|
||||||
|
|
||||||
cleanup () {
|
cleanup () {
|
||||||
rm -rf $std_install_dir ./bin/ ./pkg/
|
rm -rf $std_install_dir $scratch_dir
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
@ -109,3 +114,24 @@ will_check_rebuilt $rootdir/libdep.so $rootdir/dep.a
|
|||||||
go install -installsuffix="$mysuffix" -linkshared exe
|
go install -installsuffix="$mysuffix" -linkshared exe
|
||||||
assert_not_rebuilt $rootdir/dep.a
|
assert_not_rebuilt $rootdir/dep.a
|
||||||
assert_rebuilt $rootdir/libdep.so
|
assert_rebuilt $rootdir/libdep.so
|
||||||
|
|
||||||
|
# If we make an ABI-breaking change to dep and rebuild libp.so but not exe, exe will
|
||||||
|
# abort with a complaint on startup.
|
||||||
|
# This assumes adding an exported function breaks ABI, which is not true in some
|
||||||
|
# senses but suffices for the narrow definition of ABI compatiblity the toolchain
|
||||||
|
# uses today.
|
||||||
|
echo "func ABIBreak() {}" >> src/dep/dep.go
|
||||||
|
go install -installsuffix="$mysuffix" -buildmode=shared -linkshared dep
|
||||||
|
output="$(./bin/exe 2>&1)" && die "exe succeeded after ABI break" || true
|
||||||
|
msg="abi mismatch detected between the executable and libdep.so"
|
||||||
|
{ echo "$output" | grep -q "$msg"; } || die "exe did not fail with expected message"
|
||||||
|
|
||||||
|
# Rebuilding exe makes it work again.
|
||||||
|
go install -installsuffix="$mysuffix" -linkshared exe
|
||||||
|
./bin/exe || die "exe failed after rebuild"
|
||||||
|
|
||||||
|
# If we make a change which does not break ABI (such as adding an
|
||||||
|
# unexported function) and rebuild libdep.so, exe still works.
|
||||||
|
echo "func noABIBreak() {}" >> src/dep/dep.go
|
||||||
|
go install -installsuffix="$mysuffix" -buildmode=shared -linkshared dep
|
||||||
|
./bin/exe || die "exe failed after non-ABI breaking change"
|
||||||
|
@ -963,6 +963,22 @@ func Addstring(s *LSym, str string) int64 {
|
|||||||
return int64(r)
|
return int64(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addgostring adds str, as a Go string value, to s. symname is the name of the
|
||||||
|
// symbol used to define the string data and must be unique per linked object.
|
||||||
|
func addgostring(s *LSym, symname, str string) {
|
||||||
|
sym := Linklookup(Ctxt, symname, 0)
|
||||||
|
if sym.Type != obj.Sxxx {
|
||||||
|
Diag("duplicate symname in addgostring: %s", symname)
|
||||||
|
}
|
||||||
|
sym.Reachable = true
|
||||||
|
sym.Local = true
|
||||||
|
sym.Type = obj.SRODATA
|
||||||
|
sym.Size = int64(len(str))
|
||||||
|
sym.P = []byte(str)
|
||||||
|
Addaddr(Ctxt, s, sym)
|
||||||
|
adduint(Ctxt, s, uint64(len(str)))
|
||||||
|
}
|
||||||
|
|
||||||
func addinitarrdata(s *LSym) {
|
func addinitarrdata(s *LSym) {
|
||||||
p := s.Name + ".ptr"
|
p := s.Name + ".ptr"
|
||||||
sp := Linklookup(Ctxt, p, 0)
|
sp := Linklookup(Ctxt, p, 0)
|
||||||
|
@ -109,8 +109,8 @@ func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg strin
|
|||||||
fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlibnamefile: %s\n", obj.Cputime(), srcref, objref, file, pkg, shlibnamefile)
|
fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlibnamefile: %s\n", obj.Cputime(), srcref, objref, file, pkg, shlibnamefile)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxt.Library = append(ctxt.Library, Library{})
|
ctxt.Library = append(ctxt.Library, &Library{})
|
||||||
l := &ctxt.Library[len(ctxt.Library)-1]
|
l := ctxt.Library[len(ctxt.Library)-1]
|
||||||
l.Objref = objref
|
l.Objref = objref
|
||||||
l.Srcref = srcref
|
l.Srcref = srcref
|
||||||
l.File = file
|
l.File = file
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
|
"crypto/sha1"
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -474,7 +475,7 @@ func loadlib() {
|
|||||||
if Ctxt.Library[i].Shlib != "" {
|
if Ctxt.Library[i].Shlib != "" {
|
||||||
ldshlibsyms(Ctxt.Library[i].Shlib)
|
ldshlibsyms(Ctxt.Library[i].Shlib)
|
||||||
} else {
|
} else {
|
||||||
objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
|
objfile(Ctxt.Library[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,7 +521,7 @@ func loadlib() {
|
|||||||
if DynlinkingGo() {
|
if DynlinkingGo() {
|
||||||
Exitf("cannot implicitly include runtime/cgo in a shared library")
|
Exitf("cannot implicitly include runtime/cgo in a shared library")
|
||||||
}
|
}
|
||||||
objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
|
objfile(Ctxt.Library[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -631,18 +632,18 @@ func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 {
|
|||||||
return int64(arsize) + SAR_HDR
|
return int64(arsize) + SAR_HDR
|
||||||
}
|
}
|
||||||
|
|
||||||
func objfile(file string, pkg string) {
|
func objfile(lib *Library) {
|
||||||
pkg = pathtoprefix(pkg)
|
pkg := pathtoprefix(lib.Pkg)
|
||||||
|
|
||||||
if Debug['v'] > 1 {
|
if Debug['v'] > 1 {
|
||||||
fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), file, pkg)
|
fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg)
|
||||||
}
|
}
|
||||||
Bso.Flush()
|
Bso.Flush()
|
||||||
var err error
|
var err error
|
||||||
var f *obj.Biobuf
|
var f *obj.Biobuf
|
||||||
f, err = obj.Bopenr(file)
|
f, err = obj.Bopenr(lib.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Exitf("cannot open file %s: %v", file, err)
|
Exitf("cannot open file %s: %v", lib.File, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
magbuf := make([]byte, len(ARMAG))
|
magbuf := make([]byte, len(ARMAG))
|
||||||
@ -651,7 +652,7 @@ func objfile(file string, pkg string) {
|
|||||||
l := obj.Bseek(f, 0, 2)
|
l := obj.Bseek(f, 0, 2)
|
||||||
|
|
||||||
obj.Bseek(f, 0, 0)
|
obj.Bseek(f, 0, 0)
|
||||||
ldobj(f, pkg, l, file, file, FileObj)
|
ldobj(f, pkg, l, lib.File, lib.File, FileObj)
|
||||||
obj.Bterm(f)
|
obj.Bterm(f)
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -664,7 +665,7 @@ func objfile(file string, pkg string) {
|
|||||||
l := nextar(f, off, &arhdr)
|
l := nextar(f, off, &arhdr)
|
||||||
var pname string
|
var pname string
|
||||||
if l <= 0 {
|
if l <= 0 {
|
||||||
Diag("%s: short read on archive file symbol header", file)
|
Diag("%s: short read on archive file symbol header", lib.File)
|
||||||
goto out
|
goto out
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,20 +673,29 @@ func objfile(file string, pkg string) {
|
|||||||
off += l
|
off += l
|
||||||
l = nextar(f, off, &arhdr)
|
l = nextar(f, off, &arhdr)
|
||||||
if l <= 0 {
|
if l <= 0 {
|
||||||
Diag("%s: short read on archive file symbol header", file)
|
Diag("%s: short read on archive file symbol header", lib.File)
|
||||||
goto out
|
goto out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(arhdr.name, pkgname) {
|
if !strings.HasPrefix(arhdr.name, pkgname) {
|
||||||
Diag("%s: cannot find package header", file)
|
Diag("%s: cannot find package header", lib.File)
|
||||||
goto out
|
goto out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if Buildmode == BuildmodeShared {
|
||||||
|
before := obj.Boffset(f)
|
||||||
|
pkgdefBytes := make([]byte, atolwhex(arhdr.size))
|
||||||
|
obj.Bread(f, pkgdefBytes)
|
||||||
|
hash := sha1.Sum(pkgdefBytes)
|
||||||
|
lib.hash = hash[:]
|
||||||
|
obj.Bseek(f, before, 0)
|
||||||
|
}
|
||||||
|
|
||||||
off += l
|
off += l
|
||||||
|
|
||||||
if Debug['u'] != 0 {
|
if Debug['u'] != 0 {
|
||||||
ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef)
|
ldpkg(f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -706,14 +716,14 @@ func objfile(file string, pkg string) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if l < 0 {
|
if l < 0 {
|
||||||
Exitf("%s: malformed archive", file)
|
Exitf("%s: malformed archive", lib.File)
|
||||||
}
|
}
|
||||||
|
|
||||||
off += l
|
off += l
|
||||||
|
|
||||||
pname = fmt.Sprintf("%s(%s)", file, arhdr.name)
|
pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
|
||||||
l = atolwhex(arhdr.size)
|
l = atolwhex(arhdr.size)
|
||||||
ldobj(f, pkg, l, pname, file, ArchiveObj)
|
ldobj(f, pkg, l, pname, lib.File, ArchiveObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -974,7 +984,7 @@ func hostlink() {
|
|||||||
|
|
||||||
if Linkshared {
|
if Linkshared {
|
||||||
for _, shlib := range Ctxt.Shlibs {
|
for _, shlib := range Ctxt.Shlibs {
|
||||||
dir, base := filepath.Split(shlib)
|
dir, base := filepath.Split(shlib.Path)
|
||||||
argv = append(argv, "-L"+dir)
|
argv = append(argv, "-L"+dir)
|
||||||
if !rpath.set {
|
if !rpath.set {
|
||||||
argv = append(argv, "-Wl,-rpath="+dir)
|
argv = append(argv, "-Wl,-rpath="+dir)
|
||||||
@ -1120,6 +1130,19 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when
|
|||||||
ldobjfile(Ctxt, f, pkg, eof-obj.Boffset(f), pn)
|
ldobjfile(Ctxt, f, pkg, eof-obj.Boffset(f), pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
n, err := sect.ReadAt(data, int64(sym.Value-sect.Offset))
|
||||||
|
if uint64(n) != sym.Size {
|
||||||
|
Diag("reading contents of %s: %v", sym.Name, err)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
func ldshlibsyms(shlib string) {
|
func ldshlibsyms(shlib string) {
|
||||||
found := false
|
found := false
|
||||||
libpath := ""
|
libpath := ""
|
||||||
@ -1134,8 +1157,8 @@ func ldshlibsyms(shlib string) {
|
|||||||
Diag("cannot find shared library: %s", shlib)
|
Diag("cannot find shared library: %s", shlib)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, processedname := range Ctxt.Shlibs {
|
for _, processedlib := range Ctxt.Shlibs {
|
||||||
if processedname == libpath {
|
if processedlib.Path == libpath {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1167,6 +1190,7 @@ func ldshlibsyms(shlib string) {
|
|||||||
// table removed.
|
// table removed.
|
||||||
gcmasks := make(map[uint64][]byte)
|
gcmasks := make(map[uint64][]byte)
|
||||||
types := []*LSym{}
|
types := []*LSym{}
|
||||||
|
var hash []byte
|
||||||
for _, s := range syms {
|
for _, s := range syms {
|
||||||
if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION {
|
if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION {
|
||||||
continue
|
continue
|
||||||
@ -1178,15 +1202,10 @@ func ldshlibsyms(shlib string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(s.Name, "runtime.gcbits.0x") {
|
if strings.HasPrefix(s.Name, "runtime.gcbits.0x") {
|
||||||
data := make([]byte, s.Size)
|
gcmasks[s.Value] = readelfsymboldata(f, &s)
|
||||||
sect := f.Sections[s.Section]
|
}
|
||||||
if sect.Type == elf.SHT_PROGBITS {
|
if s.Name == "go.link.abihashbytes" {
|
||||||
n, err := sect.ReadAt(data, int64(s.Value-sect.Offset))
|
hash = readelfsymboldata(f, &s)
|
||||||
if uint64(n) != s.Size {
|
|
||||||
Diag("Error reading contents of %s: %v", s.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gcmasks[s.Value] = data
|
|
||||||
}
|
}
|
||||||
if elf.ST_BIND(s.Info) != elf.STB_GLOBAL {
|
if elf.ST_BIND(s.Info) != elf.STB_GLOBAL {
|
||||||
continue
|
continue
|
||||||
@ -1201,14 +1220,8 @@ func ldshlibsyms(shlib string) {
|
|||||||
lsym.ElfType = elf.ST_TYPE(s.Info)
|
lsym.ElfType = elf.ST_TYPE(s.Info)
|
||||||
lsym.File = libpath
|
lsym.File = libpath
|
||||||
if strings.HasPrefix(lsym.Name, "type.") {
|
if strings.HasPrefix(lsym.Name, "type.") {
|
||||||
data := make([]byte, s.Size)
|
if f.Sections[s.Section].Type == elf.SHT_PROGBITS {
|
||||||
sect := f.Sections[s.Section]
|
lsym.P = readelfsymboldata(f, &s)
|
||||||
if sect.Type == elf.SHT_PROGBITS {
|
|
||||||
n, err := sect.ReadAt(data, int64(s.Value-sect.Offset))
|
|
||||||
if uint64(n) != s.Size {
|
|
||||||
Diag("Error reading contents of %s: %v", s.Name, err)
|
|
||||||
}
|
|
||||||
lsym.P = data
|
|
||||||
}
|
}
|
||||||
if !strings.HasPrefix(lsym.Name, "type..") {
|
if !strings.HasPrefix(lsym.Name, "type..") {
|
||||||
types = append(types, lsym)
|
types = append(types, lsym)
|
||||||
@ -1255,7 +1268,7 @@ func ldshlibsyms(shlib string) {
|
|||||||
Ctxt.Etextp = last
|
Ctxt.Etextp = last
|
||||||
}
|
}
|
||||||
|
|
||||||
Ctxt.Shlibs = append(Ctxt.Shlibs, libpath)
|
Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash})
|
||||||
}
|
}
|
||||||
|
|
||||||
func mywhatsys() {
|
func mywhatsys() {
|
||||||
|
@ -106,6 +106,11 @@ type Auto struct {
|
|||||||
Gotype *LSym
|
Gotype *LSym
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Shlib struct {
|
||||||
|
Path string
|
||||||
|
Hash []byte
|
||||||
|
}
|
||||||
|
|
||||||
type Link struct {
|
type Link struct {
|
||||||
Thechar int32
|
Thechar int32
|
||||||
Thestring string
|
Thestring string
|
||||||
@ -122,8 +127,8 @@ type Link struct {
|
|||||||
Nsymbol int32
|
Nsymbol int32
|
||||||
Tlsg *LSym
|
Tlsg *LSym
|
||||||
Libdir []string
|
Libdir []string
|
||||||
Library []Library
|
Library []*Library
|
||||||
Shlibs []string
|
Shlibs []Shlib
|
||||||
Tlsoffset int
|
Tlsoffset int
|
||||||
Diag func(string, ...interface{})
|
Diag func(string, ...interface{})
|
||||||
Cursym *LSym
|
Cursym *LSym
|
||||||
@ -149,6 +154,7 @@ type Library struct {
|
|||||||
File string
|
File string
|
||||||
Pkg string
|
Pkg string
|
||||||
Shlib string
|
Shlib string
|
||||||
|
hash []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type Pcln struct {
|
type Pcln struct {
|
||||||
|
@ -32,6 +32,10 @@ package ld
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
|
"crypto/sha1"
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -294,6 +298,20 @@ func Vputl(v uint64) {
|
|||||||
Lputl(uint32(v >> 32))
|
Lputl(uint32(v >> 32))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type byPkg []*Library
|
||||||
|
|
||||||
|
func (libs byPkg) Len() int {
|
||||||
|
return len(libs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (libs byPkg) Less(a, b int) bool {
|
||||||
|
return libs[a].Pkg < libs[b].Pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (libs byPkg) Swap(a, b int) {
|
||||||
|
libs[a], libs[b] = libs[b], libs[a]
|
||||||
|
}
|
||||||
|
|
||||||
func symtab() {
|
func symtab() {
|
||||||
dosymtype()
|
dosymtype()
|
||||||
|
|
||||||
@ -410,6 +428,19 @@ 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)))
|
||||||
|
}
|
||||||
|
|
||||||
// Information about the layout of the executable image for the
|
// Information about the layout of the executable image for the
|
||||||
// runtime to use. Any changes here must be matched by changes to
|
// runtime to use. Any changes here must be matched by changes to
|
||||||
// the definition of moduledata in runtime/symtab.go.
|
// the definition of moduledata in runtime/symtab.go.
|
||||||
@ -454,6 +485,38 @@ func symtab() {
|
|||||||
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
|
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
|
||||||
adduint(Ctxt, moduledata, uint64(ntypelinks))
|
adduint(Ctxt, moduledata, uint64(ntypelinks))
|
||||||
adduint(Ctxt, moduledata, uint64(ntypelinks))
|
adduint(Ctxt, moduledata, uint64(ntypelinks))
|
||||||
|
if len(Ctxt.Shlibs) > 0 {
|
||||||
|
thismodulename := filepath.Base(outfile)
|
||||||
|
if Buildmode == BuildmodeExe {
|
||||||
|
// When linking an executable, outfile is just "a.out". Make
|
||||||
|
// it something slightly more comprehensible.
|
||||||
|
thismodulename = "the executable"
|
||||||
|
}
|
||||||
|
addgostring(moduledata, "go.link.thismodulename", thismodulename)
|
||||||
|
|
||||||
|
modulehashes := Linklookup(Ctxt, "go.link.abihashes", 0)
|
||||||
|
modulehashes.Reachable = true
|
||||||
|
modulehashes.Local = true
|
||||||
|
modulehashes.Type = obj.SRODATA
|
||||||
|
|
||||||
|
for i, shlib := range Ctxt.Shlibs {
|
||||||
|
// modulehashes[i].modulename
|
||||||
|
modulename := filepath.Base(shlib.Path)
|
||||||
|
addgostring(modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename)
|
||||||
|
|
||||||
|
// modulehashes[i].linktimehash
|
||||||
|
addgostring(modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash))
|
||||||
|
|
||||||
|
// modulehashes[i].runtimehash
|
||||||
|
abihash := Linklookup(Ctxt, "go.link.abihash."+modulename, 0)
|
||||||
|
abihash.Reachable = true
|
||||||
|
Addaddr(Ctxt, modulehashes, abihash)
|
||||||
|
}
|
||||||
|
|
||||||
|
Addaddr(Ctxt, moduledata, modulehashes)
|
||||||
|
adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs)))
|
||||||
|
adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs)))
|
||||||
|
}
|
||||||
// The rest of moduledata is zero initialized.
|
// The rest of moduledata is zero initialized.
|
||||||
// When linking an object that does not contain the runtime we are
|
// When linking an object that does not contain the runtime we are
|
||||||
// creating the moduledata from scratch and it does not have a
|
// creating the moduledata from scratch and it does not have a
|
||||||
|
@ -48,11 +48,24 @@ type moduledata struct {
|
|||||||
|
|
||||||
typelinks []*_type
|
typelinks []*_type
|
||||||
|
|
||||||
|
modulename string
|
||||||
|
modulehashes []modulehash
|
||||||
|
|
||||||
gcdatamask, gcbssmask bitvector
|
gcdatamask, gcbssmask bitvector
|
||||||
|
|
||||||
next *moduledata
|
next *moduledata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For each shared library a module links against, the linker creates an entry in the
|
||||||
|
// moduledata.modulehashes slice containing the name of the module, the abi hash seen
|
||||||
|
// at link time and a pointer to the runtime abi hash. These are checked in
|
||||||
|
// moduledataverify1 below.
|
||||||
|
type modulehash struct {
|
||||||
|
modulename string
|
||||||
|
linktimehash string
|
||||||
|
runtimehash *string
|
||||||
|
}
|
||||||
|
|
||||||
var firstmoduledata moduledata // linker symbol
|
var firstmoduledata moduledata // linker symbol
|
||||||
var lastmoduledatap *moduledata // linker symbol
|
var lastmoduledatap *moduledata // linker symbol
|
||||||
|
|
||||||
@ -117,6 +130,13 @@ func moduledataverify1(datap *moduledata) {
|
|||||||
datap.maxpc != datap.ftab[nftab].entry {
|
datap.maxpc != datap.ftab[nftab].entry {
|
||||||
throw("minpc or maxpc invalid")
|
throw("minpc or maxpc invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, modulehash := range datap.modulehashes {
|
||||||
|
if modulehash.linktimehash != *modulehash.runtimehash {
|
||||||
|
println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
|
||||||
|
throw("abi mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FuncForPC returns a *Func describing the function that contains the
|
// FuncForPC returns a *Func describing the function that contains the
|
||||||
|
Loading…
Reference in New Issue
Block a user