aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/loader/loader.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/internal/loader/loader.go')
-rw-r--r--src/cmd/link/internal/loader/loader.go309
1 files changed, 229 insertions, 80 deletions
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 987feeb284..2abd0e60e1 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -58,7 +58,7 @@ type Reloc2 struct {
// External reloc types may not fit into a uint8 which the Go object file uses.
// Store it here, instead of in the byte of goobj2.Reloc2.
- // For Go symbols this will always be 0.
+ // For Go symbols this will always be zero.
// goobj2.Reloc2.Type() + typ is always the right type, for both Go and external
// symbols.
typ objabi.RelocType
@@ -73,6 +73,10 @@ func (rel Reloc2) SetType(t objabi.RelocType) {
panic("SetType: type doesn't fit into Reloc2")
}
rel.Reloc.SetType(uint8(t))
+ if rel.typ != 0 {
+ // should use SymbolBuilder.SetRelocType
+ panic("wrong method to set reloc type")
+ }
}
// Aux2 holds a "handle" to access an aux symbol record from an
@@ -143,6 +147,16 @@ func (bm Bitmap) Has(i Sym) bool {
func (bm Bitmap) Len() int {
return len(bm) * 32
}
+
+// return the number of bits set.
+func (bm Bitmap) Count() int {
+ s := 0
+ for _, x := range bm {
+ s += bits.OnesCount32(x)
+ }
+ return s
+}
+
func MakeBitmap(n int) Bitmap {
return make(Bitmap, (n+31)/32)
}
@@ -202,6 +216,8 @@ type Loader struct {
sects []*sym.Section // sections
symSects []uint16 // symbol's section, index to sects array
+ outdata [][]byte // symbol's data in the output buffer
+
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
objByPkg map[string]*oReader // map package path to its Go object reader
@@ -241,15 +257,17 @@ type Loader struct {
align map[Sym]int32 // stores alignment for symbols
- dynimplib map[Sym]string // stores Dynimplib symbol attribute
- dynimpvers map[Sym]string // stores Dynimpvers symbol attribute
- localentry map[Sym]uint8 // stores Localentry symbol attribute
- extname map[Sym]string // stores Extname symbol attribute
- elfType map[Sym]elf.SymType // stores elf type symbol property
- symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms
- plt map[Sym]int32 // stores dynimport for pe objects
- got map[Sym]int32 // stores got for pe objects
- dynid map[Sym]int32 // stores Dynid for symbol
+ dynimplib map[Sym]string // stores Dynimplib symbol attribute
+ dynimpvers map[Sym]string // stores Dynimpvers symbol attribute
+ localentry map[Sym]uint8 // stores Localentry symbol attribute
+ extname map[Sym]string // stores Extname symbol attribute
+ elfType map[Sym]elf.SymType // stores elf type symbol property
+ elfSym map[Sym]int32 // stores elf sym symbol property
+ localElfSym map[Sym]int32 // stores "local" elf sym symbol property
+ symPkg map[Sym]string // stores package for symbol, or library for shlib-derived syms
+ plt map[Sym]int32 // stores dynimport for pe objects
+ got map[Sym]int32 // stores got for pe objects
+ dynid map[Sym]int32 // stores Dynid for symbol
relocVariant map[relocId]sym.RelocVariant // stores variant relocs
@@ -266,6 +284,8 @@ type Loader struct {
elfsetstring elfsetstringFunc
+ errorReporter *ErrorReporter
+
SymLookup func(name string, ver int) *sym.Symbol
}
@@ -297,9 +317,9 @@ const (
FlagStrictDups = 1 << iota
)
-func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
+func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
nbuiltin := goobj2.NBuiltin()
- return &Loader{
+ ldr := &Loader{
start: make(map[*oReader]Sym),
objs: []objIdx{{}}, // reserve index 0 for nil symbol
objSyms: []objSym{{}}, // reserve index 0 for nil symbol
@@ -315,6 +335,8 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
extname: make(map[Sym]string),
attrReadOnly: make(map[Sym]bool),
elfType: make(map[Sym]elf.SymType),
+ elfSym: make(map[Sym]int32),
+ localElfSym: make(map[Sym]int32),
symPkg: make(map[Sym]string),
plt: make(map[Sym]int32),
got: make(map[Sym]int32),
@@ -328,8 +350,11 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
builtinSyms: make([]Sym, nbuiltin),
flags: flags,
elfsetstring: elfsetstring,
+ errorReporter: reporter,
sects: []*sym.Section{nil}, // reserve index 0 for nil section
}
+ reporter.ldr = ldr
+ return ldr
}
// Add object file r, return the start index.
@@ -616,6 +641,11 @@ func (l *Loader) NDef() int {
return int(l.extStart)
}
+// Number of reachable symbols.
+func (l *Loader) NReachableSym() int {
+ return l.attrReachable.Count()
+}
+
// Returns the raw (unpatched) name of the i-th symbol.
func (l *Loader) RawSymName(i Sym) string {
if l.IsExternal(i) {
@@ -732,6 +762,14 @@ func (l *Loader) SetAttrLocal(i Sym, v bool) {
}
}
+// SymAddr checks that a symbol is reachable, and returns its value.
+func (l *Loader) SymAddr(i Sym) int64 {
+ if !l.AttrReachable(i) {
+ panic("unreachable symbol in symaddr")
+ }
+ return l.values[i]
+}
+
// AttrNotInSymbolTable returns true for symbols that should not be
// added to the symbol table of the final generated load module.
func (l *Loader) AttrNotInSymbolTable(i Sym) bool {
@@ -1026,6 +1064,11 @@ func (l *Loader) SetSymValue(i Sym, val int64) {
l.values[i] = val
}
+// AddToSymValue adds to the value of the i-th symbol. i is the global index.
+func (l *Loader) AddToSymValue(i Sym, val int64) {
+ l.values[i] += val
+}
+
// Returns the symbol content of the i-th symbol. i is global index.
func (l *Loader) Data(i Sym) []byte {
if l.IsExternal(i) {
@@ -1039,6 +1082,32 @@ func (l *Loader) Data(i Sym) []byte {
return r.Data(li)
}
+// Returns the data of the i-th symbol in the output buffer.
+func (l *Loader) OutData(i Sym) []byte {
+ if int(i) < len(l.outdata) && l.outdata[i] != nil {
+ return l.outdata[i]
+ }
+ return l.Data(i)
+}
+
+// SetOutData sets the position of the data of the i-th symbol in the output buffer.
+// i is global index.
+func (l *Loader) SetOutData(i Sym, data []byte) {
+ if l.IsExternal(i) {
+ pp := l.getPayload(i)
+ if pp != nil {
+ pp.data = data
+ return
+ }
+ }
+ l.outdata[i] = data
+}
+
+// InitOutData initializes the slice used to store symbol output data.
+func (l *Loader) InitOutData() {
+ l.outdata = make([][]byte, l.extStart)
+}
+
// SymAlign returns the alignment for a symbol.
func (l *Loader) SymAlign(i Sym) int32 {
// If an alignment has been recorded, return that.
@@ -1075,6 +1144,12 @@ func (l *Loader) SetSymAlign(i Sym, align int32) {
// SymValue returns the section of the i-th symbol. i is global index.
func (l *Loader) SymSect(i Sym) *sym.Section {
+ if int(i) >= len(l.symSects) {
+ // symSects is extended lazily -- it the sym in question is
+ // outside the range of the existing slice, then we assume its
+ // section has not yet been set.
+ return nil
+ }
return l.sects[l.symSects[i]]
}
@@ -1192,6 +1267,42 @@ func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
}
}
+// SymElfSym returns the ELF symbol index for a given loader
+// symbol, assigned during ELF symtab generation.
+func (l *Loader) SymElfSym(i Sym) int32 {
+ return l.elfSym[i]
+}
+
+// SetSymElfSym sets the elf symbol index for a symbol.
+func (l *Loader) SetSymElfSym(i Sym, es int32) {
+ if i == 0 {
+ panic("bad sym index")
+ }
+ if es == 0 {
+ delete(l.elfSym, i)
+ } else {
+ l.elfSym[i] = es
+ }
+}
+
+// SymLocalElfSym returns the "local" ELF symbol index for a given loader
+// symbol, assigned during ELF symtab generation.
+func (l *Loader) SymLocalElfSym(i Sym) int32 {
+ return l.localElfSym[i]
+}
+
+// SetSymLocalElfSym sets the "local" elf symbol index for a symbol.
+func (l *Loader) SetSymLocalElfSym(i Sym, es int32) {
+ if i == 0 {
+ panic("bad sym index")
+ }
+ if es == 0 {
+ delete(l.localElfSym, i)
+ } else {
+ l.localElfSym[i] = es
+ }
+}
+
// SymPlt returns the plt value for pe symbols.
func (l *Loader) SymPlt(s Sym) int32 {
if v, ok := l.plt[s]; ok {
@@ -1253,6 +1364,18 @@ func (l *Loader) SetSymDynid(i Sym, val int32) {
}
}
+// DynIdSyms returns the set of symbols for which dynID is set to an
+// interesting (non-default) value. This is expected to be a fairly
+// small set.
+func (l *Loader) DynidSyms() []Sym {
+ sl := make([]Sym, 0, len(l.dynid))
+ for s := range l.dynid {
+ sl = append(sl, s)
+ }
+ sort.Slice(sl, func(i, j int) bool { return sl[i] < sl[j] })
+ return sl
+}
+
// SymGoType returns the 'Gotype' property for a given symbol (set by
// the Go compiler for variable symbols). This version relies on
// reading aux symbols for the target sym -- it could be that a faster
@@ -1734,7 +1857,8 @@ func (l *Loader) FuncInfo(i Sym) 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.
// Does not read symbol data.
-func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, flags int) {
+// Returns the fingerprint of the object.
+func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj2.FingerprintType {
roObject, readonly, err := f.Slice(uint64(length))
if err != nil {
log.Fatal("cannot read object file:", err)
@@ -1753,7 +1877,7 @@ func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, uni
or := &oReader{r, unit, localSymVersion, r.Flags(), pkgprefix, make([]Sym, ndef+nnonpkgdef+r.NNonpkgref()), ndef, uint32(len(l.objs))}
// Autolib
- lib.ImportStrings = append(lib.ImportStrings, r.Autolib()...)
+ lib.Autolib = append(lib.Autolib, r.Autolib()...)
// DWARF file table
nfile := r.NDwarfFile()
@@ -1767,6 +1891,8 @@ func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, uni
// The caller expects us consuming all the data
f.MustSeek(length, os.SEEK_CUR)
+
+ return r.Fingerprint()
}
// Preload symbols of given kind from an object.
@@ -1890,7 +2016,7 @@ func (l *Loader) preprocess(arch *sys.Arch, s Sym, name string) {
}
// Load full contents.
-func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
+func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
// create all Symbols first.
l.growSyms(l.NSym())
l.growSects(l.NSym())
@@ -1923,7 +2049,9 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
}
// allocate a single large slab of relocations for all live symbols
- l.relocBatch = make([]sym.Reloc, nr)
+ if needReloc {
+ l.relocBatch = make([]sym.Reloc, nr)
+ }
// convert payload-based external symbols into sym.Symbol-based
for _, i := range toConvert {
@@ -1934,21 +2062,15 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
s.Version = int16(pp.ver)
s.Type = pp.kind
s.Size = pp.size
- if pp.gotype != 0 {
- s.Gotype = l.Syms[pp.gotype]
- }
- if f, ok := l.symPkg[i]; ok {
- s.File = f
- } else if pp.objidx != 0 {
- s.File = l.objs[pp.objidx].r.unit.Lib.Pkg
- }
// Copy relocations
- batch := l.relocBatch
- s.R = batch[:len(pp.relocs):len(pp.relocs)]
- l.relocBatch = batch[len(pp.relocs):]
- relocs := l.Relocs(i)
- l.convertRelocations(i, &relocs, s, false)
+ if needReloc {
+ batch := l.relocBatch
+ s.R = batch[:len(pp.relocs):len(pp.relocs)]
+ l.relocBatch = batch[len(pp.relocs):]
+ relocs := l.Relocs(i)
+ l.convertRelocations(i, &relocs, s, false)
+ }
// Copy data
s.P = pp.data
@@ -1959,7 +2081,7 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
// load contents of defined symbols
for _, o := range l.objs[1:] {
- loadObjFull(l, o.r)
+ loadObjFull(l, o.r, needReloc)
}
// Note: resolution of ABI aliases is now also handled in
@@ -2103,22 +2225,7 @@ func (l *Loader) PropagateLoaderChangesToSymbols(toconvert []Sym, anonVerReplace
relfix = true
}
- // For 'new' symbols, copy other content (such as Gotype,
- // sym file, relocations, etc).
- if isnew {
- if gt := l.SymGoType(cand); gt != 0 {
- s.Gotype = l.Syms[gt]
- }
- if f, ok := l.symPkg[cand]; ok {
- s.File = f
- } else {
- r, _ := l.toLocal(cand)
- if r != nil && r != l.extReader {
- s.File = l.SymPkg(cand)
- }
- }
- }
-
+ // For 'new' symbols, copy other content.
if relfix {
relocfixup = append(relocfixup, cand)
}
@@ -2165,7 +2272,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
if s == nil {
continue
}
- syms.Allsym = append(syms.Allsym, s) // XXX still add to Allsym for now, as there are code looping through Allsym
if s.Version < 0 {
s.Version = int16(anonVerReplacement)
}
@@ -2179,7 +2285,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
}
s := l.allocSym(name, ver)
l.installSym(i, s)
- syms.Allsym = append(syms.Allsym, s) // XXX see above
return s
}
syms.Lookup = l.SymLookup
@@ -2191,7 +2296,6 @@ func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
i := l.newExtSym(name, ver)
s := l.allocSym(name, ver)
l.installSym(i, s)
- syms.Allsym = append(syms.Allsym, s) // XXX see above
return s
}
}
@@ -2221,6 +2325,7 @@ func (l *Loader) installSym(i Sym, s *sym.Symbol) {
panic("sym already present in installSym")
}
l.Syms[i] = s
+ s.SymIdx = sym.LoaderSym(i)
}
// addNewSym adds a new sym.Symbol to the i-th index in the list of symbols.
@@ -2234,12 +2339,35 @@ func (l *Loader) addNewSym(i Sym, name string, ver int, unit *sym.CompilationUni
t = s.Type
}
s.Type = t
- s.Unit = unit
l.growSyms(int(i))
l.installSym(i, s)
return s
}
+// TopLevelSym tests a symbol (by name and kind) to determine whether
+// the symbol first class sym (participating in the link) or is an
+// anonymous aux or sub-symbol containing some sub-part or payload of
+// another symbol.
+func (l *Loader) TopLevelSym(s Sym) bool {
+ return topLevelSym(l.RawSymName(s), l.SymType(s))
+}
+
+// topLevelSym tests a symbol name and kind to determine whether
+// the symbol first class sym (participating in the link) or is an
+// anonymous aux or sub-symbol containing some sub-part or payload of
+// another symbol.
+func topLevelSym(sname string, skind sym.SymKind) bool {
+ if sname != "" {
+ return true
+ }
+ switch skind {
+ case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES, sym.SGOFUNC:
+ return true
+ default:
+ return false
+ }
+}
+
// loadObjSyms creates sym.Symbol objects for the live Syms in the
// object corresponding to object reader "r". Return value is the
// number of sym.Reloc entries required for all the new symbols.
@@ -2253,16 +2381,11 @@ func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
osym := r.Sym(i)
name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
t := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())]
- // NB: for the test below, we can skip most anonymous symbols
- // since they will never be turned into sym.Symbols (eg:
- // funcdata). DWARF symbols are an exception however -- we
- // want to include all reachable but nameless DWARF symbols.
- if name == "" {
- switch t {
- case sym.SDWARFINFO, sym.SDWARFRANGE, sym.SDWARFLOC, sym.SDWARFLINES:
- default:
- continue
- }
+
+ // Skip non-dwarf anonymous symbols (e.g. funcdata),
+ // since they will never be turned into sym.Symbols.
+ if !topLevelSym(name, t) {
+ continue
}
ver := abiToVer(osym.ABI(), r.version)
if t == sym.SXREF {
@@ -2479,12 +2602,7 @@ func (l *Loader) CreateStaticSym(name string) Sym {
return l.newExtSym(name, l.anonVersion)
}
-func loadObjFull(l *Loader, r *oReader) {
- resolveSymRef := func(s goobj2.SymRef) *sym.Symbol {
- i := l.resolve(r, s)
- return l.Syms[i]
- }
-
+func loadObjFull(l *Loader, r *oReader, needReloc bool) {
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
// A symbol may be a dup or overwritten. In this case, its
// content will actually be provided by a different object
@@ -2506,27 +2624,23 @@ func loadObjFull(l *Loader, r *oReader) {
size := osym.Siz()
// Symbol data
- s.P = r.Data(i)
- s.Attr.Set(sym.AttrReadOnly, r.ReadOnly())
+ s.P = l.OutData(gi)
// Relocs
- relocs := l.relocs(r, i)
- batch := l.relocBatch
- s.R = batch[:relocs.Count():relocs.Count()]
- l.relocBatch = batch[relocs.Count():]
- l.convertRelocations(gi, &relocs, s, false)
+ if needReloc {
+ relocs := l.relocs(r, i)
+ batch := l.relocBatch
+ s.R = batch[:relocs.Count():relocs.Count()]
+ l.relocBatch = batch[relocs.Count():]
+ l.convertRelocations(gi, &relocs, s, false)
+ }
// Aux symbol info
auxs := r.Auxs(i)
for j := range auxs {
a := &auxs[j]
switch a.Type() {
- case goobj2.AuxGotype:
- typ := resolveSymRef(a.Sym())
- if typ != nil {
- s.Gotype = typ
- }
- case goobj2.AuxFuncInfo, goobj2.AuxFuncdata:
+ case goobj2.AuxFuncInfo, goobj2.AuxFuncdata, goobj2.AuxGotype:
// already handled
case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines:
// ignored for now
@@ -2535,7 +2649,6 @@ func loadObjFull(l *Loader, r *oReader) {
}
}
- s.File = r.pkgprefix[:len(r.pkgprefix)-1]
if s.Size < int64(size) {
s.Size = int64(size)
}
@@ -2744,6 +2857,42 @@ func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, exts
return textp2
}
+// ErrorReporter is a helper class for reporting errors.
+type ErrorReporter struct {
+ ldr *Loader
+ AfterErrorAction func()
+}
+
+// Errorf method logs an error message.
+//
+// After each error, the error actions function will be invoked; this
+// will either terminate the link immediately (if -h option given)
+// or it will keep a count and exit if more than 20 errors have been printed.
+//
+// Logging an error means that on exit cmd/link will delete any
+// output file and return a non-zero error code.
+//
+func (reporter *ErrorReporter) Errorf(s Sym, format string, args ...interface{}) {
+ if s != 0 && reporter.ldr.SymName(s) != "" {
+ format = reporter.ldr.SymName(s) + ": " + format
+ } else {
+ format = fmt.Sprintf("sym %d: %s", s, format)
+ }
+ format += "\n"
+ fmt.Fprintf(os.Stderr, format, args...)
+ reporter.AfterErrorAction()
+}
+
+// GetErrorReporter returns the loader's associated error reporter.
+func (l *Loader) GetErrorReporter() *ErrorReporter {
+ return l.errorReporter
+}
+
+// Errorf method logs an error message. See ErrorReporter.Errorf for details.
+func (l *Loader) Errorf(s Sym, format string, args ...interface{}) {
+ l.errorReporter.Errorf(s, format, args...)
+}
+
// For debugging.
func (l *Loader) Dump() {
fmt.Println("objs")