mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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
7 changed files with 186 additions and 42 deletions
|
|
@ -34,6 +34,7 @@ import (
|
|||
"bufio"
|
||||
"bytes"
|
||||
"cmd/internal/obj"
|
||||
"crypto/sha1"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -474,7 +475,7 @@ func loadlib() {
|
|||
if Ctxt.Library[i].Shlib != "" {
|
||||
ldshlibsyms(Ctxt.Library[i].Shlib)
|
||||
} else {
|
||||
objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
|
||||
objfile(Ctxt.Library[i])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -520,7 +521,7 @@ func loadlib() {
|
|||
if DynlinkingGo() {
|
||||
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
|
||||
}
|
||||
|
||||
func objfile(file string, pkg string) {
|
||||
pkg = pathtoprefix(pkg)
|
||||
func objfile(lib *Library) {
|
||||
pkg := pathtoprefix(lib.Pkg)
|
||||
|
||||
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()
|
||||
var err error
|
||||
var f *obj.Biobuf
|
||||
f, err = obj.Bopenr(file)
|
||||
f, err = obj.Bopenr(lib.File)
|
||||
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))
|
||||
|
|
@ -651,7 +652,7 @@ func objfile(file string, pkg string) {
|
|||
l := obj.Bseek(f, 0, 2)
|
||||
|
||||
obj.Bseek(f, 0, 0)
|
||||
ldobj(f, pkg, l, file, file, FileObj)
|
||||
ldobj(f, pkg, l, lib.File, lib.File, FileObj)
|
||||
obj.Bterm(f)
|
||||
|
||||
return
|
||||
|
|
@ -664,7 +665,7 @@ func objfile(file string, pkg string) {
|
|||
l := nextar(f, off, &arhdr)
|
||||
var pname string
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -672,20 +673,29 @@ func objfile(file string, pkg string) {
|
|||
off += l
|
||||
l = nextar(f, off, &arhdr)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(arhdr.name, pkgname) {
|
||||
Diag("%s: cannot find package header", file)
|
||||
Diag("%s: cannot find package header", lib.File)
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
if l < 0 {
|
||||
Exitf("%s: malformed archive", file)
|
||||
Exitf("%s: malformed archive", lib.File)
|
||||
}
|
||||
|
||||
off += l
|
||||
|
||||
pname = fmt.Sprintf("%s(%s)", file, arhdr.name)
|
||||
pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
|
||||
l = atolwhex(arhdr.size)
|
||||
ldobj(f, pkg, l, pname, file, ArchiveObj)
|
||||
ldobj(f, pkg, l, pname, lib.File, ArchiveObj)
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -974,7 +984,7 @@ func hostlink() {
|
|||
|
||||
if Linkshared {
|
||||
for _, shlib := range Ctxt.Shlibs {
|
||||
dir, base := filepath.Split(shlib)
|
||||
dir, base := filepath.Split(shlib.Path)
|
||||
argv = append(argv, "-L"+dir)
|
||||
if !rpath.set {
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
found := false
|
||||
libpath := ""
|
||||
|
|
@ -1134,8 +1157,8 @@ func ldshlibsyms(shlib string) {
|
|||
Diag("cannot find shared library: %s", shlib)
|
||||
return
|
||||
}
|
||||
for _, processedname := range Ctxt.Shlibs {
|
||||
if processedname == libpath {
|
||||
for _, processedlib := range Ctxt.Shlibs {
|
||||
if processedlib.Path == libpath {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -1167,6 +1190,7 @@ 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
|
||||
|
|
@ -1178,15 +1202,10 @@ func ldshlibsyms(shlib string) {
|
|||
continue
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "runtime.gcbits.0x") {
|
||||
data := make([]byte, s.Size)
|
||||
sect := f.Sections[s.Section]
|
||||
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)
|
||||
}
|
||||
}
|
||||
gcmasks[s.Value] = data
|
||||
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
|
||||
|
|
@ -1201,14 +1220,8 @@ func ldshlibsyms(shlib string) {
|
|||
lsym.ElfType = elf.ST_TYPE(s.Info)
|
||||
lsym.File = libpath
|
||||
if strings.HasPrefix(lsym.Name, "type.") {
|
||||
data := make([]byte, s.Size)
|
||||
sect := f.Sections[s.Section]
|
||||
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 f.Sections[s.Section].Type == elf.SHT_PROGBITS {
|
||||
lsym.P = readelfsymboldata(f, &s)
|
||||
}
|
||||
if !strings.HasPrefix(lsym.Name, "type..") {
|
||||
types = append(types, lsym)
|
||||
|
|
@ -1255,7 +1268,7 @@ func ldshlibsyms(shlib string) {
|
|||
Ctxt.Etextp = last
|
||||
}
|
||||
|
||||
Ctxt.Shlibs = append(Ctxt.Shlibs, libpath)
|
||||
Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash})
|
||||
}
|
||||
|
||||
func mywhatsys() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue