2019-09-17 16:14:37 -04:00
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
2019-10-14 10:06:37 -04:00
package loader
2019-09-17 16:14:37 -04:00
import (
2019-09-30 11:43:41 -04:00
"bytes"
2019-09-17 16:14:37 -04:00
"cmd/internal/bio"
2019-09-30 11:43:41 -04:00
"cmd/internal/dwarf"
2019-09-17 16:14:37 -04:00
"cmd/internal/goobj2"
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/sym"
"fmt"
"log"
"os"
"sort"
"strconv"
"strings"
)
var _ = fmt . Print
2019-10-09 09:04:16 -04:00
// Sym encapsulates a global symbol index, used to identify a specific
// Go symbol. The 0-valued Sym is corresponds to an invalid symbol.
type Sym int
2019-10-11 08:56:19 -04:00
// Relocs encapsulates the set of relocations on a given symbol; an
// instance of this type is returned by the Loader Relocs() method.
type Relocs struct {
Count int // number of relocs
li int // local index of symbol whose relocs we're examining
r * oReader // object reader for containing package
l * Loader // loader
2019-10-16 15:44:04 -04:00
ext * sym . Symbol // external symbol if not nil
2019-10-11 08:56:19 -04:00
}
// Reloc contains the payload for a specific relocation.
// TODO: replace this with sym.Reloc, once we change the
// relocation target from "*sym.Symbol" to "loader.Sym" in sym.Reloc.
type Reloc struct {
Off int32 // offset to rewrite
Size uint8 // number of bytes to rewrite: 0, 1, 2, or 4
Type objabi . RelocType // the relocation type
Add int64 // addend
Sym Sym // global index of symbol the reloc addresses
}
2019-09-30 11:43:41 -04:00
// oReader is a wrapper type of obj.Reader, along with some
// extra information.
// TODO: rename to objReader once the old one is gone?
type oReader struct {
* goobj2 . Reader
unit * sym . CompilationUnit
2019-10-16 08:54:58 -04:00
version int // version of static symbol
flags uint32 // read from object file
2019-09-30 11:43:41 -04:00
pkgprefix string
}
2019-09-17 16:14:37 -04:00
type objIdx struct {
2019-09-30 11:43:41 -04:00
r * oReader
2019-10-09 09:04:16 -04:00
i Sym // start index
2019-09-17 16:14:37 -04:00
}
type nameVer struct {
name string
v int
}
2019-09-28 22:42:35 -04:00
type bitmap [ ] uint32
// set the i-th bit.
func ( bm bitmap ) Set ( i Sym ) {
n , r := uint ( i ) / 32 , uint ( i ) % 32
bm [ n ] |= 1 << r
}
// whether the i-th bit is set.
func ( bm bitmap ) Has ( i Sym ) bool {
n , r := uint ( i ) / 32 , uint ( i ) % 32
return bm [ n ] & ( 1 << r ) != 0
}
func makeBitmap ( n int ) bitmap {
return make ( bitmap , ( n + 31 ) / 32 )
}
2019-09-17 16:14:37 -04:00
// A Loader loads new object files and resolves indexed symbol references.
type Loader struct {
2019-09-28 22:42:35 -04:00
start map [ * oReader ] Sym // map from object file to its start index
objs [ ] objIdx // sorted by start index (i.e. objIdx.i)
max Sym // current max index
extStart Sym // from this index on, the symbols are externally defined
2019-10-04 22:05:41 -04:00
extSyms [ ] nameVer // externally defined symbols
2019-09-17 16:14:37 -04:00
2019-10-09 09:04:16 -04:00
symsByName map [ nameVer ] Sym // map symbol name to index
2019-10-08 15:35:36 -04:00
overwrite map [ Sym ] Sym // overwrite[i]=j if symbol j overwrites symbol i
2019-09-17 16:14:37 -04:00
2019-09-30 11:43:41 -04:00
objByPkg map [ string ] * oReader // map package path to its Go object reader
2019-09-17 16:14:37 -04:00
Syms [ ] * sym . Symbol // indexed symbols. XXX we still make sym.Symbol for now.
2019-09-28 22:42:35 -04:00
Reachable bitmap // bitmap of reachable symbols, indexed by global index
2019-09-17 16:14:37 -04:00
}
func NewLoader ( ) * Loader {
return & Loader {
2019-10-09 09:04:16 -04:00
start : make ( map [ * oReader ] Sym ) ,
2019-09-17 16:14:37 -04:00
objs : [ ] objIdx { { nil , 0 } } ,
2019-10-09 09:04:16 -04:00
symsByName : make ( map [ nameVer ] Sym ) ,
2019-09-30 11:43:41 -04:00
objByPkg : make ( map [ string ] * oReader ) ,
2019-10-08 15:35:36 -04:00
overwrite : make ( map [ Sym ] Sym ) ,
2019-09-17 16:14:37 -04:00
}
}
// Return the start index in the global index space for a given object file.
2019-10-14 10:06:37 -04:00
func ( l * Loader ) startIndex ( r * oReader ) Sym {
2019-09-17 16:14:37 -04:00
return l . start [ r ]
}
// Add object file r, return the start index.
2019-10-14 10:06:37 -04:00
func ( l * Loader ) addObj ( pkg string , r * oReader ) Sym {
2019-09-17 16:14:37 -04:00
if _ , ok := l . start [ r ] ; ok {
panic ( "already added" )
}
2019-10-09 15:37:46 -04:00
pkg = objabi . PathToPrefix ( pkg ) // the object file contains escaped package path
2019-09-30 11:43:41 -04:00
if _ , ok := l . objByPkg [ pkg ] ; ! ok {
l . objByPkg [ pkg ] = r
}
2019-09-17 16:14:37 -04:00
n := r . NSym ( ) + r . NNonpkgdef ( )
i := l . max + 1
l . start [ r ] = i
l . objs = append ( l . objs , objIdx { r , i } )
2019-10-09 09:04:16 -04:00
l . max += Sym ( n )
2019-09-17 16:14:37 -04:00
return i
}
// Add a symbol with a given index, return if it is added.
2019-10-08 15:35:36 -04:00
func ( l * Loader ) AddSym ( name string , ver int , i Sym , r * oReader , dupok bool , typ sym . SymKind ) bool {
2019-09-28 22:42:35 -04:00
if l . extStart != 0 {
panic ( "AddSym called after AddExtSym is called" )
}
2019-09-17 16:14:37 -04:00
nv := nameVer { name , ver }
2019-10-08 15:35:36 -04:00
if oldi , ok := l . symsByName [ nv ] ; ok {
if dupok {
return false
}
2019-10-14 10:06:37 -04:00
overwrite := r . DataSize ( int ( i - l . startIndex ( r ) ) ) != 0
2019-10-08 15:35:36 -04:00
if overwrite {
// new symbol overwrites old symbol.
2019-10-14 10:06:37 -04:00
oldr , li := l . toLocal ( oldi )
2019-10-08 15:35:36 -04:00
oldsym := goobj2 . Sym { }
oldsym . Read ( oldr . Reader , oldr . SymOff ( li ) )
oldtyp := sym . AbiSymKindToSymKind [ objabi . SymKind ( oldsym . Type ) ]
2019-10-14 11:17:18 -04:00
if ! oldsym . Dupok ( ) && ! ( ( oldtyp == sym . SDATA || oldtyp == sym . SNOPTRDATA || oldtyp == sym . SBSS || oldtyp == sym . SNOPTRBSS ) && oldr . DataSize ( li ) == 0 ) { // only allow overwriting 0-sized data symbol
2019-10-08 15:35:36 -04:00
log . Fatalf ( "duplicated definition of symbol " + name )
}
l . overwrite [ oldi ] = i
} else {
// old symbol overwrites new symbol.
if typ != sym . SDATA && typ != sym . SNOPTRDATA && typ != sym . SBSS && typ != sym . SNOPTRBSS { // only allow overwriting data symbol
log . Fatalf ( "duplicated definition of symbol " + name )
}
l . overwrite [ i ] = oldi
2019-09-17 16:14:37 -04:00
return false
}
}
l . symsByName [ nv ] = i
return true
}
// Add an external symbol (without index). Return the index of newly added
// symbol, or 0 if not added.
2019-10-09 09:04:16 -04:00
func ( l * Loader ) AddExtSym ( name string , ver int ) Sym {
2019-09-17 16:14:37 -04:00
nv := nameVer { name , ver }
if _ , ok := l . symsByName [ nv ] ; ok {
return 0
}
i := l . max + 1
l . symsByName [ nv ] = i
l . max ++
2019-09-28 22:42:35 -04:00
if l . extStart == 0 {
l . extStart = i
}
2019-10-04 22:05:41 -04:00
l . extSyms = append ( l . extSyms , nv )
2019-10-16 15:44:04 -04:00
l . growSyms ( int ( i ) )
2019-09-17 16:14:37 -04:00
return i
}
2019-10-16 15:44:04 -04:00
// Returns whether i is an external symbol.
func ( l * Loader ) isExternal ( i Sym ) bool {
return l . extStart != 0 && i >= l . extStart
}
// Ensure Syms slice als enough space.
func ( l * Loader ) growSyms ( i int ) {
n := len ( l . Syms )
if n > i {
return
}
l . Syms = append ( l . Syms , make ( [ ] * sym . Symbol , i + 1 - n ) ... )
}
2019-09-17 16:14:37 -04:00
// Convert a local index to a global index.
2019-10-14 10:06:37 -04:00
func ( l * Loader ) toGlobal ( r * oReader , i int ) Sym {
g := l . startIndex ( r ) + Sym ( i )
2019-10-08 15:35:36 -04:00
if ov , ok := l . overwrite [ g ] ; ok {
return ov
}
return g
2019-09-17 16:14:37 -04:00
}
2019-09-30 11:43:41 -04:00
// Convert a global index to a local index.
2019-10-14 10:06:37 -04:00
func ( l * Loader ) toLocal ( i Sym ) ( * oReader , int ) {
2019-10-08 15:35:36 -04:00
if ov , ok := l . overwrite [ i ] ; ok {
i = ov
}
2019-10-16 15:44:04 -04:00
if l . isExternal ( i ) {
2019-09-28 22:42:35 -04:00
return nil , int ( i - l . extStart )
2019-09-17 16:14:37 -04:00
}
2019-09-28 22:42:35 -04:00
// Search for the local object holding index i.
// Below k is the first one that has its start index > i,
// so k-1 is the one we want.
k := sort . Search ( len ( l . objs ) , func ( k int ) bool {
return l . objs [ k ] . i > i
} )
return l . objs [ k - 1 ] . r , int ( i - l . objs [ k - 1 ] . i )
2019-09-17 16:14:37 -04:00
}
2019-09-30 11:43:41 -04:00
// Resolve a local symbol reference. Return global index.
2019-10-14 10:06:37 -04:00
func ( l * Loader ) resolve ( r * oReader , s goobj2 . SymRef ) Sym {
2019-09-30 11:43:41 -04:00
var rr * oReader
switch p := s . PkgIdx ; p {
case goobj2 . PkgIdxInvalid :
if s . SymIdx != 0 {
panic ( "bad sym ref" )
}
return 0
case goobj2 . PkgIdxNone :
// Resolve by name
i := int ( s . SymIdx ) + r . NSym ( )
osym := goobj2 . Sym { }
osym . Read ( r . Reader , r . SymOff ( i ) )
name := strings . Replace ( osym . Name , "\"\"." , r . pkgprefix , - 1 )
v := abiToVer ( osym . ABI , r . version )
nv := nameVer { name , v }
return l . symsByName [ nv ]
case goobj2 . PkgIdxBuiltin :
panic ( "PkgIdxBuiltin not used" )
case goobj2 . PkgIdxSelf :
rr = r
default :
pkg := r . Pkg ( int ( p ) )
2019-10-09 15:37:46 -04:00
var ok bool
rr , ok = l . objByPkg [ pkg ]
if ! ok {
log . Fatalf ( "reference of nonexisted package %s, from %v" , pkg , r . unit . Lib )
}
2019-09-30 11:43:41 -04:00
}
2019-10-14 10:06:37 -04:00
return l . toGlobal ( rr , int ( s . SymIdx ) )
2019-09-30 11:43:41 -04:00
}
2019-09-17 16:14:37 -04:00
// 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.
2019-10-09 09:04:16 -04:00
func ( l * Loader ) Lookup ( name string , ver int ) Sym {
2019-09-17 16:14:37 -04:00
nv := nameVer { name , ver }
return l . symsByName [ nv ]
}
2019-10-16 15:44:04 -04:00
// Returns whether i is a dup of another symbol, and i is not
// "primary", i.e. Lookup i by name will not return i.
func ( l * Loader ) IsDup ( i Sym ) bool {
if _ , ok := l . overwrite [ i ] ; ok {
return true
}
if l . isExternal ( i ) {
return false
}
r , li := l . toLocal ( i )
osym := goobj2 . Sym { }
osym . Read ( r . Reader , r . SymOff ( li ) )
if ! osym . Dupok ( ) {
return false
}
if osym . Name == "" {
return false
}
name := strings . Replace ( osym . Name , "\"\"." , r . pkgprefix , - 1 )
ver := abiToVer ( osym . ABI , r . version )
return l . symsByName [ nameVer { name , ver } ] != i
}
2019-09-28 22:42:35 -04:00
// Number of total symbols.
func ( l * Loader ) NSym ( ) int {
return int ( l . max + 1 )
}
2019-10-16 15:44:04 -04:00
// Number of defined Go symbols.
func ( l * Loader ) NDef ( ) int {
return int ( l . extStart )
}
2019-09-28 22:42:35 -04:00
// Returns the raw (unpatched) name of the i-th symbol.
func ( l * Loader ) RawSymName ( i Sym ) string {
2019-10-16 15:44:04 -04:00
if l . isExternal ( i ) {
if s := l . Syms [ i ] ; s != nil {
return s . Name
}
2019-09-28 22:42:35 -04:00
return ""
}
2019-10-14 10:06:37 -04:00
r , li := l . toLocal ( i )
2019-09-28 22:42:35 -04:00
osym := goobj2 . Sym { }
osym . Read ( r . Reader , r . SymOff ( li ) )
return osym . Name
}
// Returns the (patched) name of the i-th symbol.
func ( l * Loader ) SymName ( i Sym ) string {
2019-10-16 15:44:04 -04:00
if l . isExternal ( i ) {
if s := l . Syms [ i ] ; s != nil {
return s . Name // external name should already be patched?
}
2019-09-28 22:42:35 -04:00
return ""
}
2019-10-14 10:06:37 -04:00
r , li := l . toLocal ( i )
2019-09-28 22:42:35 -04:00
osym := goobj2 . Sym { }
osym . Read ( r . Reader , r . SymOff ( li ) )
return strings . Replace ( osym . Name , "\"\"." , r . pkgprefix , - 1 )
}
// Returns the type of the i-th symbol.
func ( l * Loader ) SymType ( i Sym ) sym . SymKind {
2019-10-16 15:44:04 -04:00
if l . isExternal ( i ) {
if s := l . Syms [ i ] ; s != nil {
return s . Type
}
2019-09-28 22:42:35 -04:00
return 0
}
2019-10-14 10:06:37 -04:00
r , li := l . toLocal ( i )
2019-09-28 22:42:35 -04:00
osym := goobj2 . Sym { }
osym . Read ( r . Reader , r . SymOff ( li ) )
return sym . AbiSymKindToSymKind [ objabi . SymKind ( osym . Type ) ]
}
2019-10-08 18:21:22 -04:00
// Returns the attributes of the i-th symbol.
func ( l * Loader ) SymAttr ( i Sym ) uint8 {
2019-10-16 15:44:04 -04:00
if l . isExternal ( i ) {
// TODO: do something? External symbols have different representation of attributes. For now, ReflectMethod is the only thing matters and it cannot be set by external symbol.
2019-10-08 18:21:22 -04:00
return 0
}
2019-10-14 10:06:37 -04:00
r , li := l . toLocal ( i )
2019-10-08 18:21:22 -04:00
osym := goobj2 . Sym { }
osym . Read ( r . Reader , r . SymOff ( li ) )
return osym . Flag
}
// Returns whether the i-th symbol has ReflectMethod attribute set.
func ( l * Loader ) IsReflectMethod ( i Sym ) bool {
return l . SymAttr ( i ) & goobj2 . SymFlagReflectMethod != 0
}
2019-10-16 09:13:59 -04:00
// Returns whether this is a Go type symbol.
func ( l * Loader ) IsGoType ( i Sym ) bool {
return l . SymAttr ( i ) & goobj2 . SymFlagGoType != 0
}
2019-10-04 15:08:58 -04:00
// Returns the symbol content of the i-th symbol. i is global index.
func ( l * Loader ) Data ( i Sym ) [ ] byte {
2019-10-16 15:44:04 -04:00
if l . isExternal ( i ) {
if s := l . Syms [ i ] ; s != nil {
return s . P
}
2019-10-04 15:08:58 -04:00
return nil
}
2019-10-14 10:06:37 -04:00
r , li := l . toLocal ( i )
2019-10-04 15:08:58 -04:00
return r . Data ( li )
}
2019-09-28 22:42:35 -04:00
// Returns the number of aux symbols given a global index.
func ( l * Loader ) NAux ( i Sym ) int {
2019-10-16 15:44:04 -04:00
if l . isExternal ( i ) {
2019-09-28 22:42:35 -04:00
return 0
}
2019-10-14 10:06:37 -04:00
r , li := l . toLocal ( i )
2019-09-28 22:42:35 -04:00
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 {
2019-10-16 15:44:04 -04:00
if l . isExternal ( i ) {
2019-10-04 15:08:58 -04:00
return 0
}
2019-10-14 10:06:37 -04:00
r , li := l . toLocal ( i )
2019-09-28 22:42:35 -04:00
a := goobj2 . Aux { }
a . Read ( r . Reader , r . AuxOff ( li , j ) )
2019-10-14 10:06:37 -04:00
return l . resolve ( r , a . Sym )
2019-09-28 22:42:35 -04:00
}
// Initialize Reachable bitmap for running deadcode pass.
func ( l * Loader ) InitReachable ( ) {
l . Reachable = makeBitmap ( l . NSym ( ) )
}
2019-10-11 08:56:19 -04:00
// At method returns the j-th reloc for a global symbol.
func ( relocs * Relocs ) At ( j int ) Reloc {
2019-10-16 15:44:04 -04:00
if relocs . ext != nil {
rel := & relocs . ext . 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 ) ) ,
}
}
2019-10-11 08:56:19 -04:00
rel := goobj2 . Reloc { }
rel . Read ( relocs . r . Reader , relocs . r . RelocOff ( relocs . li , j ) )
2019-10-14 10:06:37 -04:00
target := relocs . l . resolve ( relocs . r , rel . Sym )
2019-10-11 08:56:19 -04:00
return Reloc {
Off : rel . Off ,
Size : rel . Siz ,
Type : objabi . RelocType ( rel . Type ) ,
Add : rel . Add ,
Sym : target ,
}
}
// Relocs returns a Relocs object for the given global sym.
func ( l * Loader ) Relocs ( i Sym ) Relocs {
2019-10-16 15:44:04 -04:00
if l . isExternal ( i ) {
if s := l . Syms [ i ] ; s != nil {
return Relocs { Count : len ( s . R ) , l : l , ext : s }
}
2019-10-11 08:56:19 -04:00
return Relocs { }
}
2019-10-14 10:06:37 -04:00
r , li := l . toLocal ( i )
2019-10-11 08:56:19 -04:00
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 ,
}
}
2019-09-17 16:14:37 -04:00
// Preload a package: add autolibs, add symbols to the symbol table.
// Does not read symbol data yet.
2019-10-14 10:06:37 -04:00
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 ) {
2019-09-27 14:49:44 -04:00
roObject , readonly , err := f . Slice ( uint64 ( length ) )
if err != nil {
log . Fatal ( "cannot read object file:" , err )
}
r := goobj2 . NewReaderFromBytes ( roObject , readonly )
2019-09-17 16:14:37 -04:00
if r == nil {
panic ( "cannot read object file" )
}
localSymVersion := syms . IncVersion ( )
pkgprefix := objabi . PathToPrefix ( lib . Pkg ) + "."
2019-10-16 08:54:58 -04:00
or := & oReader { r , unit , localSymVersion , r . Flags ( ) , pkgprefix }
2019-09-17 16:14:37 -04:00
// Autolib
2019-10-09 10:22:02 -04:00
lib . ImportStrings = append ( lib . ImportStrings , r . Autolib ( ) ... )
2019-09-17 16:14:37 -04:00
2019-09-30 11:43:41 -04:00
// DWARF file table
nfile := r . NDwarfFile ( )
unit . DWARFFileTable = make ( [ ] string , nfile )
for i := range unit . DWARFFileTable {
unit . DWARFFileTable [ i ] = r . DwarfFile ( i )
}
2019-10-14 10:06:37 -04:00
istart := l . addObj ( lib . Pkg , or )
2019-09-17 16:14:37 -04:00
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 )
2019-10-14 11:17:18 -04:00
dupok := osym . Dupok ( )
2019-10-08 15:35:36 -04:00
l . AddSym ( name , v , istart + Sym ( i ) , or , dupok , sym . AbiSymKindToSymKind [ objabi . SymKind ( osym . Type ) ] )
2019-09-17 16:14:37 -04:00
}
// 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.
2019-10-14 10:06:37 -04:00
func ( l * Loader ) LoadRefs ( arch * sys . Arch , syms * sym . Symbols ) {
2019-09-30 11:43:41 -04:00
for _ , o := range l . objs [ 1 : ] {
loadObjRefs ( l , o . r , arch , syms )
}
}
func loadObjRefs ( l * Loader , r * oReader , arch * sys . Arch , syms * sym . Symbols ) {
2019-09-17 16:14:37 -04:00
ndef := r . NSym ( ) + r . NNonpkgdef ( )
for i , n := 0 , r . NNonpkgref ( ) ; i < n ; i ++ {
osym := goobj2 . Sym { }
2019-09-30 11:43:41 -04:00
osym . Read ( r . Reader , r . SymOff ( ndef + i ) )
2019-10-04 22:05:41 -04:00
name := strings . Replace ( osym . Name , "\"\"." , r . pkgprefix , - 1 )
2019-09-30 11:43:41 -04:00
v := abiToVer ( osym . ABI , r . version )
2019-10-04 22:05:41 -04:00
l . AddExtSym ( name , v )
2019-09-17 16:14:37 -04:00
}
}
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 )
}
}
}
2019-10-04 22:05:41 -04:00
// Load full contents.
2019-10-14 10:06:37 -04:00
func ( l * Loader ) LoadFull ( arch * sys . Arch , syms * sym . Symbols ) {
2019-10-04 22:05:41 -04:00
// create all Symbols first.
2019-10-16 15:44:04 -04:00
l . growSyms ( l . NSym ( ) )
2019-10-04 22:05:41 -04:00
for _ , o := range l . objs [ 1 : ] {
loadObjSyms ( l , syms , o . r )
}
// external symbols
for i := l . extStart ; i <= l . max ; i ++ {
2019-10-16 15:44:04 -04:00
if s := l . Syms [ i ] ; s != nil {
s . Attr . Set ( sym . AttrReachable , l . Reachable . Has ( i ) )
continue // already loaded from external object
}
2019-10-04 22:05:41 -04:00
nv := l . extSyms [ i - l . extStart ]
2019-10-07 21:10:41 -04:00
if l . Reachable . Has ( i ) || strings . HasPrefix ( nv . name , "gofile.." ) { // XXX file symbols are used but not marked
2019-10-04 22:05:41 -04:00
s := syms . Newsym ( nv . name , nv . v )
preprocess ( arch , s )
2019-10-07 21:10:41 -04:00
s . Attr . Set ( sym . AttrReachable , l . Reachable . Has ( i ) )
2019-10-04 22:05:41 -04:00
l . Syms [ i ] = s
}
}
// load contents of defined symbols
2019-09-30 11:43:41 -04:00
for _ , o := range l . objs [ 1 : ] {
2019-10-04 22:05:41 -04:00
loadObjFull ( l , o . r )
2019-09-30 11:43:41 -04:00
}
}
2019-09-17 16:14:37 -04:00
2019-10-04 22:05:41 -04:00
func loadObjSyms ( l * Loader , syms * sym . Symbols , r * oReader ) {
2019-09-30 11:43:41 -04:00
lib := r . unit . Lib
2019-10-14 10:06:37 -04:00
istart := l . startIndex ( r )
2019-09-17 16:14:37 -04:00
for i , n := 0 , r . NSym ( ) + r . NNonpkgdef ( ) ; i < n ; i ++ {
osym := goobj2 . Sym { }
2019-09-30 11:43:41 -04:00
osym . Read ( r . Reader , r . SymOff ( i ) )
2019-10-04 22:05:41 -04:00
name := strings . Replace ( osym . Name , "\"\"." , r . pkgprefix , - 1 )
if name == "" {
continue
2019-09-17 16:14:37 -04:00
}
2019-10-04 22:05:41 -04:00
ver := abiToVer ( osym . ABI , r . version )
if l . symsByName [ nameVer { name , ver } ] != istart + Sym ( i ) {
2019-10-11 13:58:43 -04:00
continue
2019-09-17 16:14:37 -04:00
}
2019-09-24 17:31:12 -04:00
t := sym . AbiSymKindToSymKind [ objabi . SymKind ( osym . Type ) ]
if t == sym . SXREF {
log . Fatalf ( "bad sxref" )
}
if t == 0 {
2019-10-04 22:05:41 -04:00
log . Fatalf ( "missing type for %s in %s" , name , lib )
2019-09-24 17:31:12 -04:00
}
2019-10-07 21:10:41 -04:00
if ! l . Reachable . Has ( istart + Sym ( i ) ) && ! ( t == sym . SRODATA && strings . HasPrefix ( name , "type." ) ) && name != "runtime.addmoduledata" && name != "runtime.lastmoduledatap" {
2019-09-28 22:42:35 -04:00
// No need to load unreachable symbols.
2019-10-07 21:10:41 -04:00
// XXX some type symbol's content may be needed in DWARF code, but they are not marked.
2019-10-04 22:05:41 -04:00
// XXX reference to runtime.addmoduledata may be generated later by the linker in plugin mode.
2019-09-28 22:42:35 -04:00
continue
}
2019-10-04 22:05:41 -04:00
s := syms . Newsym ( name , ver )
if s . Type != 0 && s . Type != sym . SXREF {
fmt . Println ( "symbol already processed:" , lib , i , s )
panic ( "symbol already processed" )
}
2019-09-24 17:31:12 -04:00
if t == sym . SBSS && ( s . Type == sym . SRODATA || s . Type == sym . SNOPTRBSS ) {
t = s . Type
}
s . Type = t
2019-09-30 11:43:41 -04:00
s . Unit = r . unit
2019-10-04 22:05:41 -04:00
s . Attr . Set ( sym . AttrReachable , l . Reachable . Has ( istart + Sym ( i ) ) )
l . Syms [ istart + Sym ( i ) ] = s
}
}
func loadObjFull ( l * Loader , r * oReader ) {
lib := r . unit . Lib
2019-10-14 10:06:37 -04:00
istart := l . startIndex ( r )
2019-10-04 22:05:41 -04:00
resolveSymRef := func ( s goobj2 . SymRef ) * sym . Symbol {
2019-10-14 10:06:37 -04:00
i := l . resolve ( r , s )
2019-10-04 22:05:41 -04:00
return l . Syms [ i ]
}
pcdataBase := r . PcdataBase ( )
for i , n := 0 , r . NSym ( ) + r . NNonpkgdef ( ) ; i < n ; i ++ {
osym := goobj2 . Sym { }
osym . Read ( r . Reader , r . SymOff ( i ) )
name := strings . Replace ( osym . Name , "\"\"." , r . pkgprefix , - 1 )
2019-10-11 17:43:32 -04:00
if name == "" {
continue
}
ver := abiToVer ( osym . ABI , r . version )
2019-10-14 11:17:18 -04:00
dupok := osym . Dupok ( )
2019-10-11 17:43:32 -04:00
if dupsym := l . symsByName [ nameVer { name , ver } ] ; dupsym != istart + Sym ( i ) {
if dupok && l . Reachable . Has ( dupsym ) {
// A dupok symbol is resolved to another package. We still need
// to record its presence in the current package, as the trampoline
// pass expects packages are laid out in dependency order.
s := l . Syms [ dupsym ]
if s . Type == sym . STEXT {
lib . DupTextSyms = append ( lib . DupTextSyms , s )
}
}
continue
}
s := l . Syms [ istart + Sym ( i ) ]
if s == nil {
continue
}
2019-10-04 22:05:41 -04:00
if s . Name != name { // Sanity check. We can remove it in the final version.
fmt . Println ( "name mismatch:" , lib , i , s . Name , name )
panic ( "name mismatch" )
}
2019-10-14 11:17:18 -04:00
local := osym . Local ( )
makeTypelink := osym . Typelink ( )
2019-10-04 22:05:41 -04:00
size := osym . Siz
// Symbol data
s . P = r . Data ( i )
s . Attr . Set ( sym . AttrReadOnly , r . ReadOnly ( ) )
2019-09-17 16:14:37 -04:00
2019-10-11 08:56:19 -04:00
// Relocs
relocs := l . relocs ( r , i )
s . R = make ( [ ] sym . Reloc , relocs . Count )
2019-09-17 16:14:37 -04:00
for j := range s . R {
2019-10-11 08:56:19 -04:00
r := relocs . At ( j )
rs := r . Sym
sz := r . Size
rt := r . Type
2019-09-28 22:42:35 -04:00
if rt == objabi . R_METHODOFF {
if l . Reachable . Has ( rs ) {
rt = objabi . R_ADDROFF
} else {
sz = 0
rs = 0
}
}
if rt == objabi . R_WEAKADDROFF && ! l . Reachable . Has ( rs ) {
rs = 0
sz = 0
}
if rs != 0 && l . SymType ( rs ) == sym . SABIALIAS {
2019-10-11 08:56:19 -04:00
rsrelocs := l . Relocs ( rs )
rs = rsrelocs . At ( 0 ) . Sym
2019-09-28 22:42:35 -04:00
}
2019-09-17 16:14:37 -04:00
s . R [ j ] = sym . Reloc {
2019-10-11 08:56:19 -04:00
Off : r . Off ,
2019-09-28 22:42:35 -04:00
Siz : sz ,
Type : rt ,
2019-10-11 08:56:19 -04:00
Add : r . Add ,
2019-09-28 22:42:35 -04:00
Sym : l . Syms [ rs ] ,
2019-09-17 16:14:37 -04:00
}
}
2019-10-04 22:05:41 -04:00
// Aux symbol info
isym := - 1
2019-09-17 16:14:37 -04:00
naux := r . NAux ( i )
for j := 0 ; j < naux ; j ++ {
a := goobj2 . Aux { }
2019-09-30 11:43:41 -04:00
a . Read ( r . Reader , r . AuxOff ( i , j ) )
2019-09-17 16:14:37 -04:00
switch a . Type {
case goobj2 . AuxGotype :
typ := resolveSymRef ( a . Sym )
if typ != nil {
s . Gotype = typ
}
2019-09-24 17:31:12 -04:00
case goobj2 . AuxFuncdata :
pc := s . FuncInfo
if pc == nil {
pc = & sym . FuncInfo { Funcdata : make ( [ ] * sym . Symbol , 0 , 4 ) }
s . FuncInfo = pc
}
pc . Funcdata = append ( pc . Funcdata , resolveSymRef ( a . Sym ) )
2019-09-17 16:14:37 -04:00
case goobj2 . AuxFuncInfo :
if a . Sym . PkgIdx != goobj2 . PkgIdxSelf {
panic ( "funcinfo symbol not defined in current package" )
}
isym = int ( a . Sym . SymIdx )
2019-10-07 21:10:41 -04:00
case goobj2 . AuxDwarfInfo , goobj2 . AuxDwarfLoc , goobj2 . AuxDwarfRanges , goobj2 . AuxDwarfLines :
// ignored for now
2019-09-17 16:14:37 -04:00
default :
panic ( "unknown aux type" )
}
}
2019-10-04 22:05:41 -04:00
s . File = r . pkgprefix [ : len ( r . pkgprefix ) - 1 ]
2019-09-17 16:14:37 -04:00
if dupok {
s . Attr |= sym . AttrDuplicateOK
}
if s . Size < int64 ( size ) {
s . Size = int64 ( size )
}
s . Attr . Set ( sym . AttrLocal , local )
s . Attr . Set ( sym . AttrMakeTypelink , makeTypelink )
2019-09-30 11:43:41 -04:00
if s . Type == sym . SDWARFINFO {
// For DWARF symbols, replace `"".` to actual package prefix
// in the symbol content.
// TODO: maybe we should do this in the compiler and get rid
// of this.
patchDWARFName ( s , r )
}
2019-09-17 16:14:37 -04:00
if s . Type != sym . STEXT {
continue
}
// FuncInfo
if isym == - 1 {
continue
}
2019-09-30 11:43:41 -04:00
b := r . Data ( isym )
2019-09-17 16:14:37 -04:00
info := goobj2 . FuncInfo { }
info . Read ( b )
if info . NoSplit != 0 {
s . Attr |= sym . AttrNoSplit
}
2019-10-14 11:17:18 -04:00
if osym . ReflectMethod ( ) {
2019-09-17 16:14:37 -04:00
s . Attr |= sym . AttrReflectMethod
}
2019-10-16 08:54:58 -04:00
if r . Flags ( ) & goobj2 . ObjFlagShared != 0 {
2019-09-17 16:14:37 -04:00
s . Attr |= sym . AttrShared
}
2019-10-14 11:17:18 -04:00
if osym . TopFrame ( ) {
2019-09-17 16:14:37 -04:00
s . Attr |= sym . AttrTopFrame
}
info . Pcdata = append ( info . Pcdata , info . PcdataEnd ) // for the ease of knowing where it ends
2019-09-24 17:31:12 -04:00
pc := s . FuncInfo
if pc == nil {
pc = & sym . FuncInfo { }
s . FuncInfo = pc
}
pc . Args = int32 ( info . Args )
pc . Locals = int32 ( info . Locals )
pc . Pcdata = make ( [ ] sym . Pcdata , len ( info . Pcdata ) - 1 ) // -1 as we appended one above
pc . Funcdataoff = make ( [ ] int64 , len ( info . Funcdataoff ) )
pc . File = make ( [ ] * sym . Symbol , len ( info . File ) )
2019-10-08 17:22:20 -04:00
pc . InlTree = make ( [ ] sym . InlinedCall , len ( info . InlTree ) )
2019-09-17 16:14:37 -04:00
pc . Pcsp . P = r . BytesAt ( pcdataBase + info . Pcsp , int ( info . Pcfile - info . Pcsp ) )
pc . Pcfile . P = r . BytesAt ( pcdataBase + info . Pcfile , int ( info . Pcline - info . Pcfile ) )
pc . Pcline . P = r . BytesAt ( pcdataBase + info . Pcline , int ( info . Pcinline - info . Pcline ) )
pc . Pcinline . P = r . BytesAt ( pcdataBase + info . Pcinline , int ( info . Pcdata [ 0 ] - info . Pcinline ) )
for k := range pc . Pcdata {
pc . Pcdata [ k ] . P = r . BytesAt ( pcdataBase + info . Pcdata [ k ] , int ( info . Pcdata [ k + 1 ] - info . Pcdata [ k ] ) )
}
2019-09-24 17:31:12 -04:00
for k := range pc . Funcdataoff {
2019-09-17 16:14:37 -04:00
pc . Funcdataoff [ k ] = int64 ( info . Funcdataoff [ k ] )
}
for k := range pc . File {
pc . File [ k ] = resolveSymRef ( info . File [ k ] )
}
2019-10-08 17:22:20 -04:00
for k := range pc . InlTree {
inl := & info . InlTree [ k ]
pc . InlTree [ k ] = sym . InlinedCall {
Parent : inl . Parent ,
File : resolveSymRef ( inl . File ) ,
Line : inl . Line ,
2019-10-14 10:06:37 -04:00
Func : l . SymName ( l . resolve ( r , inl . Func ) ) ,
2019-10-08 17:22:20 -04:00
ParentPC : inl . ParentPC ,
}
}
2019-10-04 22:05:41 -04:00
if ! dupok {
if s . Attr . OnList ( ) {
log . Fatalf ( "symbol %s listed multiple times" , s . Name )
}
s . Attr . Set ( sym . AttrOnList , true )
lib . Textp = append ( lib . Textp , s )
} else {
// there may ba a dup in another package
// put into a temp list and add to text later
lib . DupTextSyms = append ( lib . DupTextSyms , s )
}
2019-09-17 16:14:37 -04:00
}
}
2019-09-30 11:43:41 -04:00
2019-10-14 10:06:37 -04:00
var emptyPkg = [ ] byte ( ` "". ` )
2019-09-30 11:43:41 -04:00
func patchDWARFName ( s * sym . Symbol , r * oReader ) {
// This is kind of ugly. Really the package name should not
// even be included here.
if s . Size < 1 || s . P [ 0 ] != dwarf . DW_ABRV_FUNCTION {
return
}
e := bytes . IndexByte ( s . P , 0 )
if e == - 1 {
return
}
p := bytes . Index ( s . P [ : e ] , emptyPkg )
if p == - 1 {
return
}
pkgprefix := [ ] byte ( r . pkgprefix )
patched := bytes . Replace ( s . P [ : e ] , emptyPkg , pkgprefix , - 1 )
s . P = append ( patched , s . P [ e : ] ... )
s . Attr . Set ( sym . AttrReadOnly , false )
delta := int64 ( len ( s . P ) ) - s . Size
s . Size = int64 ( len ( s . P ) )
for i := range s . R {
r := & s . R [ i ]
if r . Off > int32 ( e ) {
r . Off += int32 ( delta )
}
}
}
2019-10-16 15:44:04 -04:00
// For debugging.
func ( l * Loader ) Dump ( ) {
fmt . Println ( "objs" )
for _ , obj := range l . objs {
if obj . r != nil {
fmt . Println ( obj . i , obj . r . unit . Lib )
}
}
fmt . Println ( "syms" )
for i , s := range l . Syms {
if i == 0 {
continue
}
if s != nil {
fmt . Println ( i , s , s . Type )
} else {
fmt . Println ( i , l . SymName ( Sym ( i ) ) , "<not loaded>" )
}
}
fmt . Println ( "overwrite:" , l . overwrite )
fmt . Println ( "symsByName" )
for nv , i := range l . symsByName {
fmt . Println ( i , nv . name , nv . v )
}
}