diff options
Diffstat (limited to 'src/cmd/link/internal/loader/loader.go')
| -rw-r--r-- | src/cmd/link/internal/loader/loader.go | 309 |
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") |
