Newer
Older
// AttrContainer returns true for symbols that are listed as a
// sub-symbol of some other outer symbol. The sub/outer mechanism is
// used when loading host objects (sections from the host object
// become regular linker symbols and symbols go on the Sub list of
// their section) and for constructing the global offset table when
// internally linking a dynamic executable.
func (l *Loader) AttrContainer(i Sym) bool {
// we don't explicitly store this attribute any more -- return
// a value based on the sub-symbol setting.
return l.SubSym(i) != 0
}
// Note that we don't have SetAttrSubSymbol' or 'SetAttrContainer' methods
// in the loader; clients should just use methods like PrependSub
// to establish these relationships
// Returns whether the i-th symbol has ReflectMethod attribute set.
func (l *Loader) IsReflectMethod(i Sym) bool {
return l.SymAttr(i)&goobj2.SymFlagReflectMethod != 0
}
// Returns whether this is a Go type symbol.
func (l *Loader) IsGoType(i Sym) bool {
return l.SymAttr(i)&goobj2.SymFlagGoType != 0
}
// Returns whether this is a "go.itablink.*" symbol.
func (l *Loader) IsItabLink(i Sym) bool {
if _, ok := l.itablink[i]; ok {
return true
}
return false
}
// growValues grows the slice used to store symbol values.
func (l *Loader) growValues(reqLen int) {
curLen := len(l.values)
if reqLen > curLen {
l.values = append(l.values, make([]int64, reqLen+1-curLen)...)
}
}
// SymValue returns the value of the i-th symbol. i is global index.
func (l *Loader) SymValue(i Sym) int64 {
return l.values[i]
}
// SetSymValue sets the value of the i-th symbol. i is global index.
func (l *Loader) SetSymValue(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) {
if s := l.Syms[i]; s != nil {
return s.P
}
Than McIntosh
committed
pp := l.getPayload(i)
if pp != nil {
return pp.data
}
return nil
}
r, li := l.toLocal(i)
return r.Data(li)
}
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
// SymAlign returns the alignment for a symbol.
func (l *Loader) SymAlign(i Sym) int32 {
// If an alignment has been recorded, return that.
if align, ok := l.align[i]; ok {
return align
}
// TODO: would it make sense to return an arch-specific
// alignment depending on section type? E.g. STEXT => 32,
// SDATA => 1, etc?
return 0
}
// SetSymAlign sets the alignment for a symbol.
func (l *Loader) SetSymAlign(i Sym, align int32) {
// reject bad synbols
if i > l.max || i == 0 {
panic("bad symbol index in SetSymAlign")
}
// Reject nonsense alignments.
// TODO: do we need this?
if align < 0 {
panic("bad alignment value")
}
if align == 0 {
delete(l.align, i)
} else {
// Alignment should be a power of 2.
if bits.OnesCount32(uint32(align)) != 1 {
panic("bad alignment value")
}
l.align[i] = align
}
}
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
// SymDynImplib returns the "dynimplib" attribute for the specified
// symbol, making up a portion of the info for a symbol specified
// on a "cgo_import_dynamic" compiler directive.
func (l *Loader) SymDynimplib(i Sym) string {
return l.dynimplib[i]
}
// SetSymDynimplib sets the "dynimplib" attribute for a symbol.
func (l *Loader) SetSymDynimplib(i Sym, value string) {
// reject bad symbols
if i > l.max || i == 0 {
panic("bad symbol index in SetDynimplib")
}
if value == "" {
delete(l.dynimplib, i)
} else {
l.dynimplib[i] = value
}
}
// SymDynimpvers returns the "dynimpvers" attribute for the specified
// symbol, making up a portion of the info for a symbol specified
// on a "cgo_import_dynamic" compiler directive.
func (l *Loader) SymDynimpvers(i Sym) string {
return l.dynimpvers[i]
}
// SetSymDynimpvers sets the "dynimpvers" attribute for a symbol.
func (l *Loader) SetSymDynimpvers(i Sym, value string) {
// reject bad symbols
if i > l.max || i == 0 {
panic("bad symbol index in SetDynimpvers")
}
if value == "" {
delete(l.dynimpvers, i)
} else {
l.dynimpvers[i] = value
}
}
// SymExtname returns the "extname" value for the specified
// symbol.
func (l *Loader) SymExtname(i Sym) string {
return l.extname[i]
}
// SetSymExtname sets the "extname" attribute for a symbol.
func (l *Loader) SetSymExtname(i Sym, value string) {
// reject bad symbols
if i > l.max || i == 0 {
panic("bad symbol index in SetExtname")
}
if value == "" {
delete(l.extname, i)
} else {
l.extname[i] = value
}
}
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
// SymElfType returns the previously recorded ELF type for a symbol
// (used only for symbols read from shared libraries by ldshlibsyms).
// It is not set for symbols defined by the packages being linked or
// by symbols read by ldelf (and so is left as elf.STT_NOTYPE).
func (l *Loader) SymElfType(i Sym) elf.SymType {
if et, ok := l.elfType[i]; ok {
return et
}
return elf.STT_NOTYPE
}
// SetSymElfType sets the elf type attribute for a symbol.
func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
// reject bad symbols
if i > l.max || i == 0 {
panic("bad symbol index in SetSymElfType")
}
if et == elf.STT_NOTYPE {
delete(l.elfType, i)
} else {
l.elfType[i] = et
}
}
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
// SymFile returns the file for a symbol, which is normally the
// package the symbol came from (for regular compiler-generated Go
// symbols), but in the case of building with "-linkshared" (when a
// symbol is read from a a shared library), will hold the library
// name.
func (l *Loader) SymFile(i Sym) string {
if l.IsExternal(i) {
if l.Syms[i] != nil {
return l.Syms[i].File
}
if f, ok := l.symFile[i]; ok {
return f
}
pp := l.getPayload(i)
if pp.objidx != 0 {
r := l.objs[pp.objidx].r
return r.unit.Lib.File
}
return ""
}
r, _ := l.toLocal(i)
return r.unit.Lib.File
}
// SetSymFile sets the file attribute for a symbol. This is
// needed mainly for external symbols, specifically those imported
// from shared libraries.
func (l *Loader) SetSymFile(i Sym, file string) {
// reject bad symbols
if i > l.max || i == 0 {
panic("bad symbol index in SetSymFile")
}
if !l.IsExternal(i) {
panic("can't set file for non-external sym")
}
if l.Syms[i] != nil {
l.Syms[i].File = file
return
}
l.symFile[i] = file
}
// SymLocalentry returns the "local entry" value for the specified
// symbol.
func (l *Loader) SymLocalentry(i Sym) uint8 {
return l.localentry[i]
}
// SetSymExtname sets the "extname" attribute for a symbol.
func (l *Loader) SetSymLocalentry(i Sym, value uint8) {
// reject bad symbols
if i > l.max || i == 0 {
panic("bad symbol index in SetExtname")
}
if value == 0 {
delete(l.localentry, i)
} else {
l.localentry[i] = value
}
}
// Returns the number of aux symbols given a global index.
func (l *Loader) NAux(i Sym) int {
if l.IsExternal(i) {
r, li := l.toLocal(i)
return r.NAux(li)
}
// Returns the referred symbol of the j-th aux symbol of the i-th
// symbol.
func (l *Loader) AuxSym(i Sym, j int) Sym {
if l.IsExternal(i) {
return 0
}
r, li := l.toLocal(i)
a := goobj2.Aux{}
a.Read(r.Reader, r.AuxOff(li, j))
return l.resolve(r, a.Sym)
// ReadAuxSyms reads the aux symbol ids for the specified symbol into the
// slice passed as a parameter. If the slice capacity is not large enough, a new
// larger slice will be allocated. Final slice is returned.
func (l *Loader) ReadAuxSyms(symIdx Sym, dst []Sym) []Sym {
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
return dst[:0]
}
naux := l.NAux(symIdx)
if naux == 0 {
return dst[:0]
}
if cap(dst) < naux {
dst = make([]Sym, naux)
}
dst = dst[:0]
r, li := l.toLocal(symIdx)
for i := 0; i < naux; i++ {
a := goobj2.Aux{}
a.Read(r.Reader, r.AuxOff(li, i))
dst = append(dst, l.resolve(r, a.Sym))
}
return dst
}
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
// PrependSub prepends 'sub' onto the sub list for outer symbol 'outer'.
// Will panic if 'sub' already has an outer sym or sub sym.
// FIXME: should this be instead a method on SymbolBuilder?
func (l *Loader) PrependSub(outer Sym, sub Sym) {
if l.Syms[outer] != nil {
panic("not implemented for sym.Symbol based syms")
}
// NB: this presupposes that an outer sym can't be a sub symbol of
// some other outer-outer sym (I'm assuming this is true, but I
// haven't tested exhaustively).
if l.OuterSym(outer) != 0 {
panic("outer has outer itself")
}
if l.SubSym(sub) != 0 {
panic("sub set for subsym")
}
if l.OuterSym(sub) != 0 {
panic("outer already set for subsym")
}
l.sub[sub] = l.sub[outer]
l.sub[outer] = sub
l.outer[sub] = outer
}
// OuterSym gets the outer symbol for host object loaded symbols.
func (l *Loader) OuterSym(i Sym) Sym {
sym := l.Syms[i]
if sym != nil && sym.Outer != nil {
outer := sym.Outer
return l.Lookup(outer.Name, int(outer.Version))
}
// FIXME: add check for isExternal?
return l.outer[i]
// SubSym gets the subsymbol for host object loaded symbols.
func (l *Loader) SubSym(i Sym) Sym {
sym := l.Syms[i]
if sym != nil && sym.Sub != nil {
sub := sym.Sub
return l.Lookup(sub.Name, int(sub.Version))
}
// NB: note -- no check for l.isExternal(), since I am pretty sure
// that later phases in the linker set subsym for "type." syms
return l.sub[i]
// Initialize Reachable bitmap and its siblings for running deadcode pass.
func (l *Loader) InitReachable() {
l.growAttrBitmaps(l.NSym() + 1)
Than McIntosh
committed
}
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
type symWithVal struct {
s Sym
v int64
}
type bySymValue []symWithVal
func (s bySymValue) Len() int { return len(s) }
func (s bySymValue) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s bySymValue) Less(i, j int) bool { return s[i].v < s[j].v }
// SortSub walks through the sub-symbols for 's' and sorts them
// in place by increasing value. Return value is the new
// sub symbol for the specified outer symbol.
func (l *Loader) SortSub(s Sym) Sym {
if s == 0 || l.sub[s] == 0 {
return s
}
// Sort symbols using a slice first. Use a stable sort on the off
// chance that there's more than once symbol with the same value,
// so as to preserve reproducible builds.
sl := []symWithVal{}
for ss := l.sub[s]; ss != 0; ss = l.sub[ss] {
sl = append(sl, symWithVal{s: ss, v: l.SymValue(ss)})
}
sort.Stable(bySymValue(sl))
// Then apply any changes needed to the sub map.
ns := Sym(0)
for i := len(sl) - 1; i >= 0; i-- {
s := sl[i].s
l.sub[s] = ns
ns = s
}
// Update sub for outer symbol, then return
l.sub[s] = sl[0].s
return sl[0].s
}
// Insure that reachable bitmap and its siblings have enough size.
func (l *Loader) growAttrBitmaps(reqLen int) {
if reqLen > l.attrReachable.len() {
// These are indexed by global symbol
l.attrReachable = growBitmap(reqLen, l.attrReachable)
l.attrOnList = growBitmap(reqLen, l.attrOnList)
l.attrLocal = growBitmap(reqLen, l.attrLocal)
}
// These are indexed by external symbol offset (e.g. i - l.extStart)
if l.extStart == 0 {
return
}
extReqLen := reqLen - int(l.extStart)
if extReqLen > l.attrVisibilityHidden.len() {
l.attrVisibilityHidden = growBitmap(extReqLen, l.attrVisibilityHidden)
l.attrDuplicateOK = growBitmap(extReqLen, l.attrDuplicateOK)
l.attrShared = growBitmap(extReqLen, l.attrShared)
l.attrExternal = growBitmap(extReqLen, l.attrExternal)
Than McIntosh
committed
}
// At method returns the j-th reloc for a global symbol.
func (relocs *Relocs) At(j int) Reloc {
Than McIntosh
committed
if s := relocs.l.Syms[relocs.extIdx]; s != nil {
rel := s.R[j]
return Reloc{
Off: rel.Off,
Size: rel.Siz,
Type: rel.Type,
Add: rel.Add,
Sym: relocs.l.Lookup(rel.Sym.Name, int(rel.Sym.Version)),
}
}
Than McIntosh
committed
if relocs.extIdx != 0 {
pp := relocs.l.getPayload(relocs.extIdx)
return pp.relocs[j]
}
rel := goobj2.Reloc{}
rel.Read(relocs.r.Reader, relocs.r.RelocOff(relocs.li, j))
target := relocs.l.resolve(relocs.r, rel.Sym)
return Reloc{
Off: rel.Off,
Size: rel.Siz,
Type: objabi.RelocType(rel.Type),
Add: rel.Add,
Sym: target,
}
}
// ReadAll method reads all relocations for a symbol into the
// specified slice. If the slice capacity is not large enough, a new
// larger slice will be allocated. Final slice is returned.
func (relocs *Relocs) ReadAll(dst []Reloc) []Reloc {
if relocs.Count == 0 {
return dst[:0]
}
if cap(dst) < relocs.Count {
dst = make([]Reloc, relocs.Count)
}
dst = dst[:0]
Than McIntosh
committed
if s := relocs.l.Syms[relocs.extIdx]; s != nil {
for i := 0; i < relocs.Count; i++ {
Than McIntosh
committed
erel := &s.R[i]
rel := Reloc{
Off: erel.Off,
Size: erel.Siz,
Type: erel.Type,
Add: erel.Add,
Sym: relocs.l.Lookup(erel.Sym.Name, int(erel.Sym.Version)),
}
dst = append(dst, rel)
}
return dst
}
Than McIntosh
committed
if relocs.extIdx != 0 {
pp := relocs.l.getPayload(relocs.extIdx)
dst = append(dst, pp.relocs...)
return dst
}
off := relocs.r.RelocOff(relocs.li, 0)
for i := 0; i < relocs.Count; i++ {
rel := goobj2.Reloc{}
rel.Read(relocs.r.Reader, off)
off += uint32(rel.Size())
target := relocs.l.resolve(relocs.r, rel.Sym)
dst = append(dst, Reloc{
Off: rel.Off,
Size: rel.Siz,
Type: objabi.RelocType(rel.Type),
Add: rel.Add,
Sym: target,
})
}
return dst
}
// Relocs returns a Relocs object for the given global sym.
func (l *Loader) Relocs(i Sym) Relocs {
if l.IsExternal(i) {
if s := l.Syms[i]; s != nil {
Than McIntosh
committed
return Relocs{Count: len(s.R), l: l, extIdx: i}
}
pp := l.getPayload(i)
if pp != nil {
return Relocs{Count: len(pp.relocs), l: l, extIdx: i}
return Relocs{}
}
r, li := l.toLocal(i)
Than McIntosh
committed
if r == nil {
panic(fmt.Sprintf("trying to get oreader for invalid sym %d\n\n", i))
}
return l.relocs(r, li)
}
// Relocs returns a Relocs object given a local sym index and reader.
func (l *Loader) relocs(r *oReader, li int) Relocs {
return Relocs{
Count: r.NReloc(li),
li: li,
r: r,
l: l,
}
}
// RelocByOff implements sort.Interface for sorting relocations by offset.
type RelocByOff []Reloc
func (x RelocByOff) Len() int { return len(x) }
func (x RelocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x RelocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
// Preload a package: add autolibs, add symbols to the symbol table.
// Does not read symbol data yet.
func (l *Loader) Preload(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) {
roObject, readonly, err := f.Slice(uint64(length))
if err != nil {
log.Fatal("cannot read object file:", err)
}
r := goobj2.NewReaderFromBytes(roObject, readonly)
if r == nil {
panic("cannot read object file")
}
localSymVersion := syms.IncVersion()
pkgprefix := objabi.PathToPrefix(lib.Pkg) + "."
or := &oReader{r, unit, localSymVersion, r.Flags(), pkgprefix, nil}
Cherry Zhang
committed
lib.ImportStrings = append(lib.ImportStrings, r.Autolib()...)
Cherry Zhang
committed
// DWARF file table
nfile := r.NDwarfFile()
unit.DWARFFileTable = make([]string, nfile)
for i := range unit.DWARFFileTable {
unit.DWARFFileTable[i] = r.DwarfFile(i)
}
istart := l.addObj(lib.Pkg, or)
ndef := r.NSym()
nnonpkgdef := r.NNonpkgdef()
for i, n := 0, ndef+nnonpkgdef; i < n; i++ {
osym := goobj2.Sym{}
osym.Read(r, r.SymOff(i))
name := strings.Replace(osym.Name, "\"\".", pkgprefix, -1)
if name == "" {
continue // don't add unnamed aux symbol
}
v := abiToVer(osym.ABI, localSymVersion)
dupok := osym.Dupok()
added := l.AddSym(name, v, istart+Sym(i), or, dupok, sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)])
if added && strings.HasPrefix(name, "go.itablink.") {
l.itablink[istart+Sym(i)] = struct{}{}
}
if added && strings.HasPrefix(name, "runtime.") {
if bi := goobj2.BuiltinIdx(name, v); bi != -1 {
// This is a definition of a builtin symbol. Record where it is.
l.builtinSyms[bi] = istart + Sym(i)
}
}
}
// The caller expects us consuming all the data
f.MustSeek(length, os.SEEK_CUR)
}
// Make sure referenced symbols are added. Most of them should already be added.
// This should only be needed for referenced external symbols.
func (l *Loader) LoadRefs(arch *sys.Arch, syms *sym.Symbols) {
Cherry Zhang
committed
for _, o := range l.objs[1:] {
loadObjRefs(l, o.r, arch, syms)
}
}
func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch, syms *sym.Symbols) {
ndef := r.NSym() + r.NNonpkgdef()
for i, n := 0, r.NNonpkgref(); i < n; i++ {
osym := goobj2.Sym{}
Cherry Zhang
committed
osym.Read(r.Reader, r.SymOff(ndef+i))
name := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
Cherry Zhang
committed
v := abiToVer(osym.ABI, r.version)
l.AddExtSym(name, v)
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
}
}
func abiToVer(abi uint16, localSymVersion int) int {
var v int
if abi == goobj2.SymABIstatic {
// Static
v = localSymVersion
} else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {
// Note that data symbols are "ABI0", which maps to version 0.
v = abiver
} else {
log.Fatalf("invalid symbol ABI: %d", abi)
}
return v
}
func preprocess(arch *sys.Arch, s *sym.Symbol) {
if s.Name != "" && s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
x, err := strconv.ParseUint(s.Name[5:], 16, 64)
if err != nil {
log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
}
s.Type = sym.SRODATA
s.Attr |= sym.AttrLocal
switch s.Name[:5] {
case "$f32.":
if uint64(uint32(x)) != x {
log.Panicf("$-symbol %s too large: %d", s.Name, x)
}
s.AddUint32(arch, uint32(x))
case "$f64.", "$i64.":
s.AddUint64(arch, x)
default:
log.Panicf("unrecognized $-symbol: %s", s.Name)
}
}
}
// Load full contents.
func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols) {
// create all Symbols first.
l.growSyms(l.NSym())
nr := 0 // total number of sym.Reloc's we'll need
for _, o := range l.objs[1:] {
nr += loadObjSyms(l, syms, o.r)
}
// Make a first pass through the external symbols, making
// sure that each external symbol has a non-nil entry in
// l.Syms (note that relocations and symbol content will
// be copied in a later loop).
toConvert := make([]Sym, 0, l.max-l.extStart+1)
for i := l.extStart; i <= l.max; i++ {
if s := l.Syms[i]; s != nil {
s.Attr.Set(sym.AttrReachable, l.attrReachable.has(i))
continue
}
if i != l.getOverwrite(i) {
continue
}
sname := l.RawSymName(i)
if !l.attrReachable.has(i) && !strings.HasPrefix(sname, "gofile..") { // XXX file symbols are used but not marked
continue
}
pp := l.getPayload(i)
nr += len(pp.relocs)
// create and install the sym.Symbol here so that l.Syms will
// be fully populated when we do relocation processing and
// outer/sub processing below. Note that once we do this,
// we'll need to get at the payload for a symbol with direct
// reference to l.payloads[] as opposed to calling l.getPayload().
s := l.allocSym(sname, 0)
l.installSym(i, s)
toConvert = append(toConvert, i)
}
// allocate a single large slab of relocations for all live symbols
l.relocBatch = make([]sym.Reloc, nr)
// convert payload-based external symbols into sym.Symbol-based
for _, i := range toConvert {
// Copy kind/size/value etc.
pp := &l.payloads[i-l.extStart]
s := l.Syms[i]
s.Version = int16(pp.ver)
s.Type = pp.kind
s.Size = pp.size
s.Value = l.SymValue(i)
if pp.gotype != 0 {
s.Gotype = l.Syms[pp.gotype]
}
s.Value = l.values[i]
if f, ok := l.symFile[i]; ok {
s.File = f
} else if pp.objidx != 0 {
s.File = l.objs[pp.objidx].r.unit.Lib.File
}
// Copy relocations
batch := l.relocBatch
s.R = batch[:len(pp.relocs):len(pp.relocs)]
l.relocBatch = batch[len(pp.relocs):]
l.convertRelocations(pp.relocs, s)
// Copy data
s.P = pp.data
// Transfer over attributes.
l.migrateAttributes(i, s)
// Preprocess symbol. May set 'AttrLocal'.
preprocess(arch, s)
}
// load contents of defined symbols
Cherry Zhang
committed
for _, o := range l.objs[1:] {
loadObjFull(l, o.r)
Cherry Zhang
committed
}
// Note: resolution of ABI aliases is now also handled in
// loader.convertRelocations, so once the host object loaders move
// completely to loader.Sym, we can remove the code below.
// Resolve ABI aliases for external symbols. This is only
// needed for internal cgo linking.
// (The old code does this in deadcode, but deadcode2 doesn't
// do this.)
for i := l.extStart; i <= l.max; i++ {
if s := l.Syms[i]; s != nil && s.Attr.Reachable() {
for ri := range s.R {
r := &s.R[ri]
if r.Sym != nil && r.Sym.Type == sym.SABIALIAS {
r.Sym = r.Sym.R[0].Sym
}
}
}
}
Cherry Zhang
committed
}
// ExtractSymbols grabs the symbols out of the loader for work that hasn't been
// ported to the new symbol type.
func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
// Nil out overwritten symbols.
// Overwritten Go symbols aren't a problem (as they're lazy loaded), but
// symbols loaded from host object loaders are fully loaded, and we might
// have multiple symbols with the same name. This loop nils them out.
for oldI := range l.overwrite {
l.Syms[oldI] = nil
}
// Add symbols to the ctxt.Syms lookup table. This explicitly skips things
// created via loader.Create (marked with versions less than zero), since
// if we tried to add these we'd wind up with collisions. We do, however,
// add these symbols to the list of global symbols so that other future
// steps (like pclntab generation) can find these symbols if neceassary.
// Along the way, update the version from the negative anon version to
// something larger than sym.SymVerStatic (needed so that
// sym.symbol.IsFileLocal() works properly).
anonVerReplacement := syms.IncVersion()
for _, s := range l.Syms {
if s == nil {
continue
}
if s.Name != "" && s.Version >= 0 {
} else {
syms.Allsym = append(syms.Allsym, s)
if s.Version < 0 {
s.Version = int16(anonVerReplacement)
}
}
}
// allocSym allocates a new symbol backing.
func (l *Loader) allocSym(name string, version int) *sym.Symbol {
batch := l.symBatch
if len(batch) == 0 {
batch = make([]sym.Symbol, 1000)
}
s := &batch[0]
l.symBatch = batch[1:]
s.Dynid = -1
s.Name = name
s.Version = int16(version)
return s
}
Than McIntosh
committed
// installSym sets the underlying sym.Symbol for the specified sym index.
func (l *Loader) installSym(i Sym, s *sym.Symbol) {
if s == nil {
panic("installSym nil symbol")
}
if l.Syms[i] != nil {
panic("sym already present in installSym")
Than McIntosh
committed
}
l.Syms[i] = s
}
// addNewSym adds a new sym.Symbol to the i-th index in the list of symbols.
func (l *Loader) addNewSym(i Sym, name string, ver int, unit *sym.CompilationUnit, t sym.SymKind) *sym.Symbol {
s := l.allocSym(name, ver)
if s.Type != 0 && s.Type != sym.SXREF {
fmt.Println("symbol already processed:", unit.Lib, i, s)
panic("symbol already processed")
}
if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
t = s.Type
}
s.Type = t
s.Unit = unit
l.growSyms(int(i))
Than McIntosh
committed
l.installSym(i, s)
return s
}
// 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.
func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
istart := l.startIndex(r)
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
// If it's been previously loaded in host object loading, we don't need to do it again.
if s := l.Syms[istart+Sym(i)]; s != nil {
// Mark symbol as reachable as it wasn't marked as such before.
s.Attr.Set(sym.AttrReachable, l.attrReachable.has(istart+Sym(i)))
nr += r.NReloc(i)
continue
}
osym := goobj2.Sym{}
Cherry Zhang
committed
osym.Read(r.Reader, r.SymOff(i))
name := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
if name == "" {
continue
ver := abiToVer(osym.ABI, r.version)
if osym.ABI != goobj2.SymABIstatic && l.symsByName[ver][name] != istart+Sym(i) {
continue
t := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
if t == sym.SXREF {
log.Fatalf("bad sxref")
}
if t == 0 {
log.Fatalf("missing type for %s in %s", name, r.unit.Lib)
if !l.attrReachable.has(istart+Sym(i)) && !(t == sym.SRODATA && strings.HasPrefix(name, "type.")) && name != "runtime.addmoduledata" && name != "runtime.lastmoduledatap" {
// No need to load unreachable symbols.
// XXX some type symbol's content may be needed in DWARF code, but they are not marked.
// XXX reference to runtime.addmoduledata may be generated later by the linker in plugin mode.
s := l.addNewSym(istart+Sym(i), name, ver, r.unit, t)
l.migrateAttributes(istart+Sym(i), s)
nr += r.NReloc(i)
return nr
}
// funcInfoSym records the sym.Symbol for a function, along with a copy
// of the corresponding goobj2.Sym and the index of its FuncInfo aux sym.
// We use this to delay populating FuncInfo until we can batch-allocate
// slices for their sub-objects.
type funcInfoSym struct {
s *sym.Symbol // sym.Symbol for a live function
osym goobj2.Sym // object file symbol data for that function
isym int // global symbol index of FuncInfo aux sym for func
}
// funcAllocInfo records totals/counts for all functions in an objfile;
// used to help with bulk allocation of sym.Symbol sub-objects.
type funcAllocInfo struct {
symPtr uint32 // number of *sym.Symbol's needed in file slices
inlCall uint32 // number of sym.InlinedCall's needed in inltree slices
pcData uint32 // number of sym.Pcdata's needed in pdata slices
fdOff uint32 // number of int64's needed in all Funcdataoff slices
}
// loadSymbol loads a single symbol by name.
// NB: This function does NOT set the symbol as reachable.
func (l *Loader) loadSymbol(name string, version int) *sym.Symbol {
global := l.Lookup(name, version)
// If we're already loaded, bail.
if global != 0 && int(global) < len(l.Syms) && l.Syms[global] != nil {
return l.Syms[global]
}
// Read the symbol.
r, i := l.toLocal(global)
istart := l.startIndex(r)
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(int(i)))
if l.symsByName[version][name] != istart+Sym(i) {
return nil
}
return l.addNewSym(istart+Sym(i), name, version, r.unit, sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)])
// LookupOrCreate looks up a symbol by name, and creates one if not found.
// Either way, it will also create a sym.Symbol for it, if not already.
// This should only be called when interacting with parts of the linker
// that still works on sym.Symbols (i.e. internal cgo linking, for now).
func (l *Loader) LookupOrCreate(name string, version int) *sym.Symbol {
i := l.Lookup(name, version)
if i != 0 {
// symbol exists
if int(i) < len(l.Syms) && l.Syms[i] != nil {
}
if l.IsExternal(i) {
panic("Can't load an external symbol.")
}
return l.loadSymbol(name, version)
}
i = l.AddExtSym(name, version)
s := l.allocSym(name, version)
l.Syms[i] = s
return s
}
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
// cloneToExternal takes the existing object file symbol (symIdx)
// and creates a new external symbol that is a clone with respect
// to name, version, type, relocations, etc. The idea here is that
// if the linker decides it wants to update the contents of a
// symbol originally discovered as part of an object file, it's
// easier to do this if we make the updates to a new and similarly
// named external copy of that symbol.
func (l *Loader) cloneToExternal(symIdx Sym) Sym {
if l.IsExternal(symIdx) {
panic("sym is already external, no need for clone")
}
// Read the particulars from object.
osym := goobj2.Sym{}
r, li := l.toLocal(symIdx)
osym.Read(r.Reader, r.SymOff(li))
sname := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
sver := abiToVer(osym.ABI, r.version)
skind := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
// Create new symbol, update version and kind.
ns := l.newExtSym(sname, sver)
pp := &l.payloads[ns-l.extStart]
pp.kind = skind
pp.ver = sver
pp.size = int64(osym.Siz)
pp.objidx = uint32(l.ocache)
// If this is a def, then copy the guts. We expect this case
// to be very rare (one case it may come up is with -X).
if li < (r.NSym() + r.NNonpkgdef()) {
// Copy relocations
relocs := l.Relocs(symIdx)
pp.relocs = relocs.ReadAll(nil)
// Copy data
pp.data = r.Data(li)
// Copy read-only attr
if r.ReadOnly() {
l.attrReadOnly[ns] = true
}
}
// If we're overriding a data symbol, collect the associated
// Gotype, so as to propagate it to the new symbol.
naux := r.NAux(li)
for j := 0; j < naux; j++ {
a := goobj2.Aux{}
a.Read(r.Reader, r.AuxOff(li, j))
switch a.Type {
case goobj2.AuxGotype:
pp.gotype = l.resolve(r, a.Sym)
default:
log.Fatalf("internal error: cloneToExternal applied to %s symbol %s with non-gotype aux data %d", skind.String(), sname, a.Type)
}
}
// Fix up the lookup tables if the symbol in question was
// present in the lookup tables. At the moment it only makes
// sense to do this sort of clone/update for symbols that are
// in the symbol table (as opposed to anonymous symbols);
// issue an error if we can't look up the original symbol.
if sver >= sym.SymVerStatic {
s, ok := l.extStaticSyms[nameVer{sname, sver}]
if !ok || s != symIdx {
panic("lookup failed for clone of non-external static symbol")
}
l.extStaticSyms[nameVer{sname, sver}] = ns
} else {
s, ok := l.symsByName[sver][sname]
if !ok || s != symIdx {