aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/loader
diff options
context:
space:
mode:
authorKatie Hockman <katie@golang.org>2020-12-14 10:03:05 -0500
committerKatie Hockman <katie@golang.org>2020-12-14 10:06:13 -0500
commit0345ede87ee12698988973884cfc0fd3d499dffd (patch)
tree7123cff141ee5661208d2f5f437b8f5252ac7f6a /src/cmd/link/internal/loader
parent4651d6b267818b0e0d128a5443289717c4bb8cbc (diff)
parent0a02371b0576964e81c3b40d328db9a3ef3b031b (diff)
downloadgo-0345ede87ee12698988973884cfc0fd3d499dffd.tar.xz
[dev.fuzz] all: merge master into dev.fuzz
Change-Id: I5d8c8329ccc9d747bd81ade6b1cb7cb8ae2e94b2
Diffstat (limited to 'src/cmd/link/internal/loader')
-rw-r--r--src/cmd/link/internal/loader/loader.go161
-rw-r--r--src/cmd/link/internal/loader/symbolbuilder.go27
2 files changed, 133 insertions, 55 deletions
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 8fd10b0848..971cc432ff 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -63,6 +63,7 @@ type Reloc struct {
func (rel Reloc) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc.Type()) + rel.typ }
func (rel Reloc) Sym() Sym { return rel.l.resolve(rel.r, rel.Reloc.Sym()) }
func (rel Reloc) SetSym(s Sym) { rel.Reloc.SetSym(goobj.SymRef{PkgIdx: 0, SymIdx: uint32(s)}) }
+func (rel Reloc) IsMarker() bool { return rel.Siz() == 0 }
func (rel Reloc) SetType(t objabi.RelocType) {
if t != objabi.RelocType(uint8(t)) {
@@ -93,11 +94,12 @@ type oReader struct {
version int // version of static symbol
flags uint32 // read from object file
pkgprefix string
- syms []Sym // Sym's global index, indexed by local index
- ndef int // cache goobj.Reader.NSym()
- nhashed64def int // cache goobj.Reader.NHashed64Def()
- nhasheddef int // cache goobj.Reader.NHashedDef()
- objidx uint32 // index of this reader in the objs slice
+ syms []Sym // Sym's global index, indexed by local index
+ pkg []uint32 // indices of referenced package by PkgIdx (index into loader.objs array)
+ ndef int // cache goobj.Reader.NSym()
+ nhashed64def int // cache goobj.Reader.NHashed64Def()
+ nhasheddef int // cache goobj.Reader.NHashedDef()
+ objidx uint32 // index of this reader in the objs slice
}
// Total number of defined symbols (package symbols, hashed symbols, and
@@ -219,7 +221,7 @@ type Loader struct {
deferReturnTramp map[Sym]bool // whether the symbol is a trampoline of a deferreturn call
- objByPkg map[string]*oReader // map package path to its Go object reader
+ objByPkg map[string]uint32 // map package path to the index of its Go object reader
anonVersion int // most recently assigned ext static sym pseudo-version
@@ -328,10 +330,10 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorRepor
ldr := &Loader{
start: make(map[*oReader]Sym),
objs: []objIdx{{}, {extReader, 0}}, // reserve index 0 for nil symbol, 1 for external symbols
- objSyms: make([]objSym, 1, 100000), // reserve index 0 for nil symbol
+ objSyms: make([]objSym, 1, 1), // This will get overwritten later.
extReader: extReader,
symsByName: [2]map[string]Sym{make(map[string]Sym, 80000), make(map[string]Sym, 50000)}, // preallocate ~2MB for ABI0 and ~1MB for ABI1 symbols
- objByPkg: make(map[string]*oReader),
+ objByPkg: make(map[string]uint32),
outer: make(map[Sym]Sym),
sub: make(map[Sym]Sym),
dynimplib: make(map[Sym]string),
@@ -370,7 +372,7 @@ func (l *Loader) addObj(pkg string, r *oReader) Sym {
}
pkg = objabi.PathToPrefix(pkg) // the object file contains escaped package path
if _, ok := l.objByPkg[pkg]; !ok {
- l.objByPkg[pkg] = r
+ l.objByPkg[pkg] = r.objidx
}
i := Sym(len(l.objSyms))
l.start[r] = i
@@ -631,20 +633,42 @@ func (l *Loader) resolve(r *oReader, s goobj.SymRef) Sym {
i := int(s.SymIdx) + r.ndef + r.nhashed64def + r.nhasheddef
return r.syms[i]
case goobj.PkgIdxBuiltin:
- return l.builtinSyms[s.SymIdx]
+ if bi := l.builtinSyms[s.SymIdx]; bi != 0 {
+ return bi
+ }
+ l.reportMissingBuiltin(int(s.SymIdx), r.unit.Lib.Pkg)
+ return 0
case goobj.PkgIdxSelf:
rr = r
default:
- pkg := r.Pkg(int(p))
- var ok bool
- rr, ok = l.objByPkg[pkg]
- if !ok {
- log.Fatalf("reference of nonexisted package %s, from %v", pkg, r.unit.Lib)
- }
+ rr = l.objs[r.pkg[p]].r
}
return l.toGlobal(rr, s.SymIdx)
}
+// reportMissingBuiltin issues an error in the case where we have a
+// relocation against a runtime builtin whose definition is not found
+// when the runtime package is built. The canonical example is
+// "runtime.racefuncenter" -- currently if you do something like
+//
+// go build -gcflags=-race myprogram.go
+//
+// the compiler will insert calls to the builtin runtime.racefuncenter,
+// but the version of the runtime used for linkage won't actually contain
+// definitions of that symbol. See issue #42396 for details.
+//
+// As currently implemented, this is a fatal error. This has drawbacks
+// in that if there are multiple missing builtins, the error will only
+// cite the first one. On the plus side, terminating the link here has
+// advantages in that we won't run the risk of panics or crashes later
+// on in the linker due to R_CALL relocations with 0-valued target
+// symbols.
+func (l *Loader) reportMissingBuiltin(bsym int, reflib string) {
+ bname, _ := goobj.BuiltinName(bsym)
+ log.Fatalf("reference to undefined builtin %q from package %q",
+ bname, reflib)
+}
+
// Look up a symbol by name, return global index, or 0 if not found.
// This is more like Syms.ROLookup than Lookup -- it doesn't create
// new symbol.
@@ -1794,6 +1818,11 @@ func (l *Loader) SortSub(s Sym) Sym {
return sl[0].s
}
+// SortSyms sorts a list of symbols by their value.
+func (l *Loader) SortSyms(ss []Sym) {
+ sort.SliceStable(ss, func(i, j int) bool { return l.SymValue(ss[i]) < l.SymValue(ss[j]) })
+}
+
// Insure that reachable bitmap and its siblings have enough size.
func (l *Loader) growAttrBitmaps(reqLen int) {
if reqLen > l.attrReachable.Len() {
@@ -1878,19 +1907,24 @@ func (fi *FuncInfo) FuncID() objabi.FuncID {
return objabi.FuncID((*goobj.FuncInfo)(nil).ReadFuncID(fi.data))
}
-func (fi *FuncInfo) Pcsp() []byte {
- pcsp, end := (*goobj.FuncInfo)(nil).ReadPcsp(fi.data)
- return fi.r.BytesAt(fi.r.PcdataBase()+pcsp, int(end-pcsp))
+func (fi *FuncInfo) Pcsp() Sym {
+ sym := (*goobj.FuncInfo)(nil).ReadPcsp(fi.data)
+ return fi.l.resolve(fi.r, sym)
}
-func (fi *FuncInfo) Pcfile() []byte {
- pcf, end := (*goobj.FuncInfo)(nil).ReadPcfile(fi.data)
- return fi.r.BytesAt(fi.r.PcdataBase()+pcf, int(end-pcf))
+func (fi *FuncInfo) Pcfile() Sym {
+ sym := (*goobj.FuncInfo)(nil).ReadPcfile(fi.data)
+ return fi.l.resolve(fi.r, sym)
}
-func (fi *FuncInfo) Pcline() []byte {
- pcln, end := (*goobj.FuncInfo)(nil).ReadPcline(fi.data)
- return fi.r.BytesAt(fi.r.PcdataBase()+pcln, int(end-pcln))
+func (fi *FuncInfo) Pcline() Sym {
+ sym := (*goobj.FuncInfo)(nil).ReadPcline(fi.data)
+ return fi.l.resolve(fi.r, sym)
+}
+
+func (fi *FuncInfo) Pcinline() Sym {
+ sym := (*goobj.FuncInfo)(nil).ReadPcinline(fi.data)
+ return fi.l.resolve(fi.r, sym)
}
// Preload has to be called prior to invoking the various methods
@@ -1899,27 +1933,16 @@ func (fi *FuncInfo) Preload() {
fi.lengths = (*goobj.FuncInfo)(nil).ReadFuncInfoLengths(fi.data)
}
-func (fi *FuncInfo) Pcinline() []byte {
- if !fi.lengths.Initialized {
- panic("need to call Preload first")
- }
- pcinl, end := (*goobj.FuncInfo)(nil).ReadPcinline(fi.data, fi.lengths.PcdataOff)
- return fi.r.BytesAt(fi.r.PcdataBase()+pcinl, int(end-pcinl))
-}
-
-func (fi *FuncInfo) NumPcdata() uint32 {
+func (fi *FuncInfo) Pcdata() []Sym {
if !fi.lengths.Initialized {
panic("need to call Preload first")
}
- return fi.lengths.NumPcdata
-}
-
-func (fi *FuncInfo) Pcdata(k int) []byte {
- if !fi.lengths.Initialized {
- panic("need to call Preload first")
+ syms := (*goobj.FuncInfo)(nil).ReadPcdata(fi.data)
+ ret := make([]Sym, len(syms))
+ for i := range ret {
+ ret[i] = fi.l.resolve(fi.r, syms[i])
}
- pcdat, end := (*goobj.FuncInfo)(nil).ReadPcdata(fi.data, fi.lengths.PcdataOff, uint32(k))
- return fi.r.BytesAt(fi.r.PcdataBase()+pcdat, int(end-pcdat))
+ return ret
}
func (fi *FuncInfo) NumFuncdataoff() uint32 {
@@ -2022,8 +2045,9 @@ func (l *Loader) FuncInfo(i Sym) FuncInfo {
return FuncInfo{}
}
-// Preload a package: add autolibs, add defined package symbols to the symbol table.
-// Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
+// Preload a package: adds autolib.
+// Does not add defined package or non-packaged symbols to the symbol table.
+// These are done in LoadSyms.
// Does not read symbol data.
// Returns the fingerprint of the object.
func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj.FingerprintType {
@@ -2066,8 +2090,6 @@ func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, u
}
l.addObj(lib.Pkg, or)
- st := loadState{l: l}
- st.preloadSyms(or, pkgDef)
// The caller expects us consuming all the data
f.MustSeek(length, os.SEEK_CUR)
@@ -2150,17 +2172,30 @@ func (st *loadState) preloadSyms(r *oReader, kind int) {
}
}
-// Add hashed (content-addressable) symbols, non-package symbols, and
+// Add syms, hashed (content-addressable) symbols, non-package symbols, and
// references to external symbols (which are always named).
-func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
+func (l *Loader) LoadSyms(arch *sys.Arch) {
+ // Allocate space for symbols, making a guess as to how much space we need.
+ // This function was determined empirically by looking at the cmd/compile on
+ // Darwin, and picking factors for hashed and hashed64 syms.
+ var symSize, hashedSize, hashed64Size int
+ for _, o := range l.objs[goObjStart:] {
+ symSize += o.r.ndef + o.r.nhasheddef/2 + o.r.nhashed64def/2 + o.r.NNonpkgdef()
+ hashedSize += o.r.nhasheddef / 2
+ hashed64Size += o.r.nhashed64def / 2
+ }
+ // Index 0 is invalid for symbols.
+ l.objSyms = make([]objSym, 1, symSize)
+
l.npkgsyms = l.NSym()
- // Preallocate some space (a few hundreds KB) for some symbols.
- // As of Go 1.15, linking cmd/compile has ~8000 hashed64 symbols and
- // ~13000 hashed symbols.
st := loadState{
l: l,
- hashed64Syms: make(map[uint64]symAndSize, 10000),
- hashedSyms: make(map[goobj.HashType]symAndSize, 15000),
+ hashed64Syms: make(map[uint64]symAndSize, hashed64Size),
+ hashedSyms: make(map[goobj.HashType]symAndSize, hashedSize),
+ }
+
+ for _, o := range l.objs[goObjStart:] {
+ st.preloadSyms(o.r, pkgDef)
}
for _, o := range l.objs[goObjStart:] {
st.preloadSyms(o.r, hashed64Def)
@@ -2195,6 +2230,18 @@ func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
}
}
+ // referenced packages
+ npkg := r.NPkg()
+ r.pkg = make([]uint32, npkg)
+ for i := 1; i < npkg; i++ { // PkgIdx 0 is a dummy invalid package
+ pkg := r.Pkg(i)
+ objidx, ok := l.objByPkg[pkg]
+ if !ok {
+ log.Fatalf("reference of nonexisted package %s, from %v", pkg, r.unit.Lib)
+ }
+ r.pkg[i] = objidx
+ }
+
// load flags of package refs
for i, n := 0, r.NRefFlags(); i < n; i++ {
rf := r.RefFlags(i)
@@ -2602,11 +2649,15 @@ func (l *Loader) Dump() {
fmt.Println("Nsyms:", len(l.objSyms))
fmt.Println("syms")
for i := Sym(1); i < Sym(len(l.objSyms)); i++ {
- pi := interface{}("")
+ pi := ""
if l.IsExternal(i) {
pi = fmt.Sprintf("<ext %d>", l.extIndex(i))
}
- fmt.Println(i, l.SymName(i), l.SymType(i), pi)
+ sect := ""
+ if l.SymSect(i) != nil {
+ sect = l.SymSect(i).Name
+ }
+ fmt.Printf("%v %v %v %v %x %v\n", i, l.SymName(i), l.SymType(i), pi, l.SymValue(i), sect)
}
fmt.Println("symsByName")
for name, i := range l.symsByName[0] {
diff --git a/src/cmd/link/internal/loader/symbolbuilder.go b/src/cmd/link/internal/loader/symbolbuilder.go
index e14d89a927..5d37da8ac6 100644
--- a/src/cmd/link/internal/loader/symbolbuilder.go
+++ b/src/cmd/link/internal/loader/symbolbuilder.go
@@ -336,6 +336,15 @@ func (sb *SymbolBuilder) Addstring(str string) int64 {
return r
}
+func (sb *SymbolBuilder) SetBytesAt(off int64, b []byte) int64 {
+ datLen := int64(len(b))
+ if off+datLen > int64(len(sb.data)) {
+ panic("attempt to write past end of buffer")
+ }
+ copy(sb.data[off:off+datLen], b)
+ return off + datLen
+}
+
func (sb *SymbolBuilder) addSymRef(tgt Sym, add int64, typ objabi.RelocType, rsize int) int64 {
if sb.kind == 0 {
sb.kind = sym.SDATA
@@ -411,3 +420,21 @@ func (sb *SymbolBuilder) MakeWritable() {
sb.l.SetAttrReadOnly(sb.symIdx, false)
}
}
+
+func (sb *SymbolBuilder) AddUleb(v uint64) {
+ if v < 128 { // common case: 1 byte
+ sb.AddUint8(uint8(v))
+ return
+ }
+ for {
+ c := uint8(v & 0x7f)
+ v >>= 7
+ if v != 0 {
+ c |= 0x80
+ }
+ sb.AddUint8(c)
+ if c&0x80 == 0 {
+ break
+ }
+ }
+}