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"
2019-12-11 14:24:19 -05:00
"math/bits"
2019-09-17 16:14:37 -04:00
"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
2019-12-11 13:39:39 -05:00
extIdx Sym // index of external symbol we're examining or 0
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-10-24 11:59:49 -04:00
rcache [ ] Sym // cache mapping local PkgNone symbol to resolved Sym
2019-09-30 11:43:41 -04:00
}
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-10-30 10:14:33 -04:00
e Sym // end 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.
2019-12-11 14:05:14 -05:00
func ( bm bitmap ) set ( i Sym ) {
2019-09-28 22:42:35 -04:00
n , r := uint ( i ) / 32 , uint ( i ) % 32
bm [ n ] |= 1 << r
}
2019-12-11 14:05:14 -05:00
// unset the i-th bit.
func ( bm bitmap ) unset ( i Sym ) {
n , r := uint ( i ) / 32 , uint ( i ) % 32
bm [ n ] &^= ( 1 << r )
}
2019-09-28 22:42:35 -04:00
// whether the i-th bit is set.
2019-12-11 14:05:14 -05:00
func ( bm bitmap ) has ( i Sym ) bool {
2019-09-28 22:42:35 -04:00
n , r := uint ( i ) / 32 , uint ( i ) % 32
return bm [ n ] & ( 1 << r ) != 0
}
2019-12-11 13:39:39 -05:00
// return current length of bitmap in bits.
func ( bm bitmap ) len ( ) int {
return len ( bm ) * 32
}
2019-09-28 22:42:35 -04:00
func makeBitmap ( n int ) bitmap {
return make ( bitmap , ( n + 31 ) / 32 )
}
2019-12-11 13:39:39 -05:00
// growBitmap insures that the specified bitmap has enough capacity,
// reallocating (doubling the size) if needed.
func growBitmap ( reqLen int , b bitmap ) bitmap {
curLen := b . len ( )
if reqLen > curLen {
2019-12-11 14:05:14 -05:00
b = append ( b , makeBitmap ( reqLen + 1 - curLen ) ... )
2019-12-11 13:39:39 -05:00
}
return b
}
2019-09-17 16:14:37 -04:00
// A Loader loads new object files and resolves indexed symbol references.
2019-12-11 13:39:39 -05:00
//
// Notes on the layout of global symbol index space:
//
// - Go object files are read before host object files; each Go object
// read allocates a new chunk of global index space of size P + NP,
// where P is the number of package defined symbols in the object and
// NP is the number of non-package defined symbols.
//
// - In loader.LoadRefs(), the loader makes a sweep through all of the
// non-package references in each object file and allocates sym indices
// for any symbols that have not yet been defined (start of this space
// is marked by loader.extStart).
//
// - Host object file loading happens; the host object loader does a
// name/version lookup for each symbol it finds; this can wind up
// extending the external symbol index space range. The host object
// loader currently stores symbol payloads in sym.Symbol objects,
// which get handed off to the loader.
//
// - A given external symbol (Sym) either has a sym.Symbol acting as
// its backing store (this will continue to be the case until we
// finish rewriting the host object loader to work entirely with
// loader.Sym) or it has a "payload" backing store (represented by
// extSymPayload). Newly created external symbols (created by
// a call to AddExtSym or equivalent) start out in the "has payload"
// state, and continue until installSym is called for the sym
// index in question.
//
// - At some point (when the wayfront is pushed through all of the
// linker), all external symbols will be payload-based, and we can
// get rid of the loader.Syms array.
//
2019-09-17 16:14:37 -04:00
type Loader struct {
2019-10-18 17:08: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
builtinSyms [ ] Sym // global index of builtin symbols
2019-10-30 10:14:33 -04:00
ocache int // index (into 'objs') of most recent lookup
2019-09-17 16:14:37 -04:00
2019-10-18 12:11:56 -04:00
symsByName [ 2 ] map [ string ] Sym // map symbol name to index, two maps are for ABI0 and ABIInternal
extStaticSyms map [ nameVer ] Sym // externally defined static symbols, keyed by name
overwrite map [ Sym ] Sym // overwrite[i]=j if symbol j overwrites symbol i
2019-09-17 16:14:37 -04:00
2019-12-11 13:39:39 -05:00
payloads [ ] extSymPayload // contents of linker-materialized external syms
2019-12-13 11:51:15 -05:00
values [ ] int64 // symbol values, indexed by global sym index
2019-12-11 13:39:39 -05:00
2019-10-16 09:29:56 -04:00
itablink map [ Sym ] struct { } // itablink[j] defined if j is go.itablink.*
2019-09-30 11:43:41 -04:00
objByPkg map [ string ] * oReader // map package path to its Go object reader
2019-11-27 12:33:35 -05:00
Syms [ ] * sym . Symbol // indexed symbols. XXX we still make sym.Symbol for now.
symBatch [ ] sym . Symbol // batch of symbols.
2019-09-28 22:42:35 -04:00
2019-11-25 14:07:59 -05:00
anonVersion int // most recently assigned ext static sym pseudo-version
2019-12-11 14:05:14 -05:00
// Bitmaps and other side structures used to store data used to store
// symbol flags/attributes; these are to be accessed via the
// corresponding loader "AttrXXX" and "SetAttrXXX" methods. Please
// visit the comments on these methods for more details on the
// semantics / interpretation of the specific flags or attribute.
attrReachable bitmap // reachable symbols, indexed by global index
attrOnList bitmap // "on list" symbols, indexed by global index
attrVisibilityHidden bitmap // hidden symbols, indexed by ext sym index
attrDuplicateOK bitmap // dupOK symbols, indexed by ext sym index
attrShared bitmap // shared symbols, indexed by ext sym index
attrExternal bitmap // external symbols, indexed by ext sym index
2019-12-16 14:14:29 -05:00
attrReadOnly map [ Sym ] bool // readonly data for this sym
2019-12-11 14:05:14 -05:00
attrTopFrame map [ Sym ] struct { } // top frame symbols
attrSpecial map [ Sym ] struct { } // "special" frame symbols
attrCgoExportDynamic map [ Sym ] struct { } // "cgo_export_dynamic" symbols
attrCgoExportStatic map [ Sym ] struct { } // "cgo_export_static" symbols
2019-10-30 12:31:55 -04:00
2019-12-11 14:17:14 -05:00
// Outer and Sub relations for symbols.
// TODO: figure out whether it's more efficient to just have these
// as fields on extSymPayload (note that this won't be a viable
// strategy if somewhere in the linker we set sub/outer for a
// non-external sym).
outer map [ Sym ] Sym
sub map [ Sym ] Sym
2019-12-11 14:24:19 -05:00
align map [ Sym ] int32 // stores alignment for symbols
2019-12-12 08:08:40 -05:00
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
2019-10-30 12:31:55 -04:00
// Used to implement field tracking; created during deadcode if
// field tracking is enabled. Reachparent[K] contains the index of
// the symbol that triggered the marking of symbol K as live.
Reachparent [ ] Sym
2019-10-24 11:27:47 -04:00
relocBatch [ ] sym . Reloc // for bulk allocation of relocations
2019-11-02 00:38:21 -04:00
flags uint32
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
2019-12-11 14:36:17 -05:00
elfsetstring elfsetstringFunc
2019-09-17 16:14:37 -04:00
}
2019-12-11 14:36:17 -05:00
type elfsetstringFunc func ( s * sym . Symbol , str string , off int )
2019-12-11 13:39:39 -05:00
// extSymPayload holds the payload (data + relocations) for linker-synthesized
2019-12-13 11:51:15 -05:00
// external symbols (note that symbol value is stored in a separate slice).
2019-12-11 13:39:39 -05:00
type extSymPayload struct {
name string // TODO: would this be better as offset into str table?
size int64
ver int
kind sym . SymKind
2020-01-06 20:37:50 -05:00
gotype Sym // Gotype (0 if not present)
2019-12-11 13:39:39 -05:00
relocs [ ] Reloc
data [ ] byte
}
2019-11-02 00:38:21 -04:00
const (
// Loader.flags
FlagStrictDups = 1 << iota
)
2019-12-11 14:36:17 -05:00
func NewLoader ( flags uint32 , elfsetstring elfsetstringFunc ) * Loader {
2019-10-18 17:08:35 -04:00
nbuiltin := goobj2 . NBuiltin ( )
2019-09-17 16:14:37 -04:00
return & Loader {
2019-12-18 10:57:15 -05:00
start : make ( map [ * oReader ] Sym ) ,
objs : [ ] objIdx { { nil , 0 , 0 } } ,
symsByName : [ 2 ] map [ string ] Sym { make ( map [ string ] Sym ) , make ( map [ string ] Sym ) } ,
objByPkg : make ( map [ string ] * oReader ) ,
outer : make ( map [ Sym ] Sym ) ,
sub : make ( map [ Sym ] Sym ) ,
align : make ( map [ Sym ] int32 ) ,
dynimplib : make ( map [ Sym ] string ) ,
dynimpvers : make ( map [ Sym ] string ) ,
localentry : make ( map [ Sym ] uint8 ) ,
extname : make ( map [ Sym ] string ) ,
2019-12-16 14:14:29 -05:00
attrReadOnly : make ( map [ Sym ] bool ) ,
2019-12-18 10:57:15 -05:00
attrTopFrame : make ( map [ Sym ] struct { } ) ,
attrSpecial : make ( map [ Sym ] struct { } ) ,
attrCgoExportDynamic : make ( map [ Sym ] struct { } ) ,
attrCgoExportStatic : make ( map [ Sym ] struct { } ) ,
overwrite : make ( map [ Sym ] Sym ) ,
itablink : make ( map [ Sym ] struct { } ) ,
extStaticSyms : make ( map [ nameVer ] Sym ) ,
builtinSyms : make ( [ ] Sym , nbuiltin ) ,
flags : flags ,
2019-12-11 14:36:17 -05:00
elfsetstring : elfsetstring ,
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
2019-10-30 10:14:33 -04:00
l . objs = append ( l . objs , objIdx { r , i , i + Sym ( n ) - 1 } )
2019-10-09 09:04:16 -04:00
l . max += Sym ( n )
2019-12-13 11:51:15 -05:00
l . growValues ( int ( l . max ) )
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-10-18 11:19:32 -04:00
if ver == r . version {
// Static symbol. Add its global index but don't
// add to name lookup table, as it cannot be
// referenced by name.
return true
}
2019-10-18 12:11:56 -04:00
if oldi , ok := l . symsByName [ ver ] [ name ] ; ok {
2019-10-08 15:35:36 -04:00
if dupok {
2019-11-02 00:38:21 -04:00
if l . flags & FlagStrictDups != 0 {
l . checkdup ( name , i , r , oldi )
}
2019-10-08 15:35:36 -04:00
return false
}
2019-10-17 18:42:38 -04:00
oldr , li := l . toLocal ( oldi )
oldsym := goobj2 . Sym { }
oldsym . Read ( oldr . Reader , oldr . SymOff ( li ) )
if oldsym . 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.
oldtyp := sym . AbiSymKindToSymKind [ objabi . SymKind ( oldsym . Type ) ]
2019-10-17 11:06:11 -04:00
if ! oldtyp . IsData ( ) && r . DataSize ( li ) == 0 {
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
}
}
2019-10-18 12:11:56 -04:00
l . symsByName [ ver ] [ name ] = i
2019-09-17 16:14:37 -04:00
return true
}
2019-12-11 13:39:39 -05:00
// newExtSym creates a new external sym with the specified
// name/version.
func ( l * Loader ) newExtSym ( name string , ver int ) Sym {
l . max ++
i := l . max
if l . extStart == 0 {
l . extStart = i
}
l . growSyms ( int ( i ) )
pi := i - l . extStart
l . payloads [ pi ] . name = name
l . payloads [ pi ] . ver = ver
return i
}
2019-09-17 16:14:37 -04:00
// 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-12-11 13:39:39 -05:00
i := l . Lookup ( name , ver )
if i != 0 {
return 0
}
i = l . newExtSym ( name , ver )
static := ver >= sym . SymVerStatic || ver < 0
2019-10-18 12:11:56 -04:00
if static {
2019-12-11 13:39:39 -05:00
l . extStaticSyms [ nameVer { name , ver } ] = i
2019-10-18 12:11:56 -04:00
} else {
2019-12-11 13:39:39 -05:00
l . symsByName [ ver ] [ name ] = i
2019-09-17 16:14:37 -04:00
}
2019-12-11 13:39:39 -05:00
return i
}
// LookupOrCreateSym looks up the symbol with the specified name/version,
// returning its Sym index if found. If the lookup fails, a new external
// Sym will be created, entered into the lookup tables, and returned.
func ( l * Loader ) LookupOrCreateSym ( name string , ver int ) Sym {
i := l . Lookup ( name , ver )
if i != 0 {
return i
}
i = l . newExtSym ( name , ver )
static := ver >= sym . SymVerStatic || ver < 0
2019-10-18 12:11:56 -04:00
if static {
l . extStaticSyms [ nameVer { name , ver } ] = i
} else {
l . symsByName [ ver ] [ name ] = i
}
2019-09-17 16:14:37 -04:00
return i
}
2019-10-17 11:06:11 -04:00
func ( l * Loader ) IsExternal ( i Sym ) bool {
2019-10-16 15:44:04 -04:00
return l . extStart != 0 && i >= l . extStart
}
2019-12-11 13:39:39 -05:00
// getPayload returns a pointer to the extSymPayload struct for an
// external symbol if the symbol has a payload, or nil if the
// data for the sym is being stored in a sym.Symbol. Will panic if
// the symbol in question is bogus (zero or not an external sym).
func ( l * Loader ) getPayload ( i Sym ) * extSymPayload {
if l . extStart == 0 || i < l . extStart {
panic ( fmt . Sprintf ( "bogus symbol index %d in getPayload" , i ) )
}
if l . Syms [ i ] != nil {
return nil
}
pi := i - l . extStart
return & l . payloads [ pi ]
}
2019-12-11 14:36:17 -05:00
func ( ms * extSymPayload ) Grow ( siz int64 ) {
if int64 ( int ( siz ) ) != siz {
log . Fatalf ( "symgrow size %d too long" , siz )
}
if int64 ( len ( ms . data ) ) >= siz {
return
}
if cap ( ms . data ) < int ( siz ) {
cl := len ( ms . data )
ms . data = append ( ms . data , make ( [ ] byte , int ( siz ) + 1 - cl ) ... )
ms . data = ms . data [ 0 : cl ]
}
ms . data = ms . data [ : siz ]
}
2019-12-11 14:05:14 -05:00
// Ensure Syms slice has enough space, as well as growing the
// 'payloads' slice.
2019-10-16 15:44:04 -04:00
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-12-11 13:39:39 -05:00
l . payloads = append ( l . payloads , make ( [ ] extSymPayload , i + 1 - n ) ... )
2019-12-13 11:51:15 -05:00
l . growValues ( int ( i ) + 1 )
2019-12-11 14:05:14 -05:00
l . growAttrBitmaps ( int ( i ) + 1 )
2019-10-16 15:44:04 -04:00
}
2019-12-18 15:14:46 -05:00
// getOverwrite returns the overwrite symbol for 'symIdx', while
// collapsing any chains of overwrites along the way. This is
// apparently needed in cases where we add an overwrite entry X -> Y
// during preload (where both X and Y are non-external symbols), and
// then we add an additional entry to the overwrite map Y -> W in
// cloneToExternal when we encounter the real definition of the symbol
// in a host object file, and we need to build up W's content.
//
// Note: it would be nice to avoid this sort of complexity. One of the
// main reasons we wind up with overwrites has to do with the way the
// compiler handles link-named symbols that are 'defined elsewhere':
// at the moment they wind up as no-package defs. For example, consider
// the variable "runtime.no_pointers_stackmap". This variable is defined
// in an assembly file as RODATA, then in one of the Go files it is
// declared this way:
//
// var no_pointers_stackmap uint64 // defined in assembly
//
// This generates what amounts to a weak definition (in the object
// containing the line of code above), which is then overriden by the
// stronger def from the assembly file. Rather than have things work
// this way, it would be better if in the Go file we emitted a
// no-package ref instead of a no-package def, which would eliminate
// the need for overwrites. Doing this would also require changing the
// semantics of //go:linkname, however; we'd have to insure that in
// the cross-package case there is a go:linkname directive on both
// ends.
func ( l * Loader ) getOverwrite ( symIdx Sym ) Sym {
var seen map [ Sym ] bool
result := symIdx
cur := symIdx
for {
if ov , ok := l . overwrite [ cur ] ; ok {
if seen == nil {
seen = make ( map [ Sym ] bool )
seen [ symIdx ] = true
}
if _ , ok := seen [ ov ] ; ok {
panic ( "cycle in overwrite map" )
} else {
seen [ cur ] = true
}
cur = ov
} else {
break
}
}
if cur != symIdx {
result = cur
cur = symIdx
for {
if ov , ok := l . overwrite [ cur ] ; ok {
l . overwrite [ cur ] = result
cur = ov
} else {
break
}
}
}
return result
}
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-12-18 15:14:46 -05:00
g = l . getOverwrite ( g )
2019-10-08 15:35:36 -04:00
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-17 11:06:11 -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-10-30 10:14:33 -04:00
oc := l . ocache
if oc != 0 && i >= l . objs [ oc ] . i && i <= l . objs [ oc ] . e {
return l . objs [ oc ] . r , int ( i - l . objs [ oc ] . i )
}
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
} )
2019-10-30 10:14:33 -04:00
l . ocache = k - 1
2019-09-28 22:42:35 -04:00
return l . objs [ k - 1 ] . r , int ( i - l . objs [ k - 1 ] . i )
2019-09-17 16:14:37 -04:00
}
2019-10-24 11:59:49 -04:00
// rcacheGet checks for a valid entry for 's' in the readers cache,
// where 's' is a local PkgIdxNone ref or def, or zero if
// the cache is empty or doesn't contain a value for 's'.
func ( or * oReader ) rcacheGet ( symIdx uint32 ) Sym {
if len ( or . rcache ) > 0 {
return or . rcache [ symIdx ]
}
return 0
}
// rcacheSet installs a new entry in the oReader's PkgNone
// resolver cache for the specified PkgIdxNone ref or def,
// allocating a new cache if needed.
func ( or * oReader ) rcacheSet ( symIdx uint32 , gsym Sym ) {
if len ( or . rcache ) == 0 {
or . rcache = make ( [ ] Sym , or . NNonpkgdef ( ) + or . NNonpkgref ( ) )
}
or . rcache [ symIdx ] = gsym
}
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 :
2019-10-24 11:59:49 -04:00
// Check for cached version first
if cached := r . rcacheGet ( s . SymIdx ) ; cached != 0 {
2019-12-18 15:14:46 -05:00
ov := l . getOverwrite ( cached )
if cached != ov {
r . rcacheSet ( s . SymIdx , ov )
return ov
}
2019-10-24 11:59:49 -04:00
}
2019-09-30 11:43:41 -04:00
// 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 )
2019-12-18 15:14:46 -05:00
gsym := l . getOverwrite ( l . Lookup ( name , v ) )
2019-10-24 11:59:49 -04:00
// Add to cache, then return.
r . rcacheSet ( s . SymIdx , gsym )
return gsym
2019-09-30 11:43:41 -04:00
case goobj2 . PkgIdxBuiltin :
2019-10-18 17:08:35 -04:00
return l . builtinSyms [ s . SymIdx ]
2019-09-30 11:43:41 -04:00
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-11-25 14:07:59 -05:00
if ver >= sym . SymVerStatic || ver < 0 {
2019-10-18 12:11:56 -04:00
return l . extStaticSyms [ nameVer { name , ver } ]
}
return l . symsByName [ ver ] [ name ]
2019-09-17 16:14:37 -04:00
}
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
}
2019-10-17 11:06:11 -04:00
if l . IsExternal ( i ) {
2019-10-16 15:44:04 -04:00
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 == "" {
2019-10-18 11:19:32 -04:00
return false // Unnamed aux symbol cannot be dup.
}
if osym . ABI == goobj2 . SymABIstatic {
return false // Static symbol cannot be dup.
2019-10-16 15:44:04 -04:00
}
name := strings . Replace ( osym . Name , "\"\"." , r . pkgprefix , - 1 )
ver := abiToVer ( osym . ABI , r . version )
2019-10-18 12:11:56 -04:00
return l . symsByName [ ver ] [ name ] != i
2019-10-16 15:44:04 -04:00
}
2019-11-02 00:38:21 -04:00
// Check that duplicate symbols have same contents.
func ( l * Loader ) checkdup ( name string , i Sym , r * oReader , dup Sym ) {
li := int ( i - l . startIndex ( r ) )
p := r . Data ( li )
if strings . HasPrefix ( name , "go.info." ) {
p , _ = patchDWARFName1 ( p , r )
}
rdup , ldup := l . toLocal ( dup )
pdup := rdup . Data ( ldup )
if strings . HasPrefix ( name , "go.info." ) {
pdup , _ = patchDWARFName1 ( pdup , rdup )
}
if bytes . Equal ( p , pdup ) {
return
}
reason := "same length but different contents"
if len ( p ) != len ( pdup ) {
reason = fmt . Sprintf ( "new length %d != old length %d" , len ( p ) , len ( pdup ) )
}
fmt . Fprintf ( os . Stderr , "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n" , r . unit . Lib , name , rdup . unit . Lib , reason )
// For the moment, whitelist DWARF subprogram DIEs for
// auto-generated wrapper functions. What seems to happen
// here is that we get different line numbers on formal
// params; I am guessing that the pos is being inherited
// from the spot where the wrapper is needed.
whitelist := strings . HasPrefix ( name , "go.info.go.interface" ) ||
strings . HasPrefix ( name , "go.info.go.builtin" ) ||
strings . HasPrefix ( name , "go.debuglines" )
if ! whitelist {
l . strictDupMsgs ++
}
}
func ( l * Loader ) NStrictDupMsgs ( ) int { return l . strictDupMsgs }
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-17 11:06:11 -04:00
if l . IsExternal ( i ) {
2019-10-16 15:44:04 -04:00
if s := l . Syms [ i ] ; s != nil {
return s . Name
}
2019-12-11 13:39:39 -05:00
pp := l . getPayload ( i )
return pp . name
2019-09-28 22:42:35 -04:00
}
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-17 11:06:11 -04:00
if l . IsExternal ( i ) {
2019-10-16 15:44:04 -04:00
if s := l . Syms [ i ] ; s != nil {
return s . Name // external name should already be patched?
}
2019-12-11 13:39:39 -05:00
pp := l . getPayload ( i )
return pp . name
2019-09-28 22:42:35 -04:00
}
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 )
}
2019-12-26 13:39:04 -05:00
// Returns the version of the i-th symbol.
func ( l * Loader ) SymVersion ( i Sym ) int {
if l . IsExternal ( i ) {
if s := l . Syms [ i ] ; s != nil {
return int ( s . Version )
}
pp := l . getPayload ( i )
return pp . ver
}
r , li := l . toLocal ( i )
osym := goobj2 . Sym { }
osym . Read ( r . Reader , r . SymOff ( li ) )
return int ( abiToVer ( osym . ABI , r . version ) )
}
2019-09-28 22:42:35 -04:00
// Returns the type of the i-th symbol.
func ( l * Loader ) SymType ( i Sym ) sym . SymKind {
2019-10-17 11:06:11 -04:00
if l . IsExternal ( i ) {
2019-10-16 15:44:04 -04:00
if s := l . Syms [ i ] ; s != nil {
return s . Type
}
2019-12-11 13:39:39 -05:00
pp := l . getPayload ( i )
if pp != nil {
return pp . kind
}
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-17 11:06:11 -04:00
if l . IsExternal ( i ) {
2019-10-16 15:44:04 -04:00
// 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
}
2019-12-11 14:05:14 -05:00
// AttrReachable returns true for symbols that are transitively
// referenced from the entry points. Unreachable symbols are not
// written to the output.
func ( l * Loader ) AttrReachable ( i Sym ) bool {
return l . attrReachable . has ( i )
}
// SetAttrReachable sets the reachability property for a symbol (see
// AttrReachable).
func ( l * Loader ) SetAttrReachable ( i Sym , v bool ) {
if v {
l . attrReachable . set ( i )
} else {
l . attrReachable . unset ( i )
}
}
// AttrOnList returns true for symbols that are on some list (such as
// the list of all text symbols, or one of the lists of data symbols)
// and is consulted to avoid bugs where a symbol is put on a list
// twice.
func ( l * Loader ) AttrOnList ( i Sym ) bool {
return l . attrOnList . has ( i )
}
// SetAttrOnList sets the "on list" property for a symbol (see
// AttrOnList).
func ( l * Loader ) SetAttrOnList ( i Sym , v bool ) {
if v {
l . attrOnList . set ( i )
} else {
l . attrOnList . unset ( i )
}
}
// AttrVisibilityHidden symbols returns true for ELF symbols with
// visibility set to STV_HIDDEN. They become local symbols in
// the final executable. Only relevant when internally linking
// on an ELF platform.
func ( l * Loader ) AttrVisibilityHidden ( i Sym ) bool {
if i < l . extStart {
return false
}
return l . attrVisibilityHidden . has ( i - l . extStart )
}
// SetAttrVisibilityHidden sets the "hidden visibility" property for a
// symbol (see AttrVisibilityHidden).
func ( l * Loader ) SetAttrVisibilityHidden ( i Sym , v bool ) {
if i < l . extStart {
panic ( "tried to set visibility attr on non-external symbol" )
}
if v {
l . attrVisibilityHidden . set ( i - l . extStart )
} else {
l . attrVisibilityHidden . unset ( i - l . extStart )
}
}
// AttrDuplicateOK returns true for a symbol that can be present in
// multiple object files.
func ( l * Loader ) AttrDuplicateOK ( i Sym ) bool {
if i < l . extStart {
// TODO: if this path winds up being taken frequently, it
// might make more sense to copy the flag value out of the object
// into a larger bitmap during preload.
r , li := l . toLocal ( i )
osym := goobj2 . Sym { }
osym . Read ( r . Reader , r . SymOff ( li ) )
return osym . Dupok ( )
}
return l . attrDuplicateOK . has ( i - l . extStart )
}
// SetAttrDuplicateOK sets the "duplicate OK" property for an external
// symbol (see AttrDuplicateOK).
func ( l * Loader ) SetAttrDuplicateOK ( i Sym , v bool ) {
if i < l . extStart {
panic ( "tried to set dupok attr on non-external symbol" )
}
if v {
l . attrDuplicateOK . set ( i - l . extStart )
} else {
l . attrDuplicateOK . unset ( i - l . extStart )
}
}
// AttrShared returns true for symbols compiled with the -shared option.
func ( l * Loader ) AttrShared ( i Sym ) bool {
if i < l . extStart {
// TODO: if this path winds up being taken frequently, it
// might make more sense to copy the flag value out of the
// object into a larger bitmap during preload.
r , _ := l . toLocal ( i )
return ( r . Flags ( ) & goobj2 . ObjFlagShared ) != 0
}
return l . attrShared . has ( i - l . extStart )
}
// SetAttrShared sets the "shared" property for an external
// symbol (see AttrShared).
func ( l * Loader ) SetAttrShared ( i Sym , v bool ) {
if i < l . extStart {
panic ( "tried to set shared attr on non-external symbol" )
}
if v {
l . attrShared . set ( i - l . extStart )
} else {
l . attrShared . unset ( i - l . extStart )
}
}
// AttrExternal returns true for function symbols loaded from host
// object files.
func ( l * Loader ) AttrExternal ( i Sym ) bool {
if i < l . extStart {
return false
}
return l . attrExternal . has ( i - l . extStart )
}
// SetAttrExternal sets the "external" property for an host object
// symbol (see AttrExternal).
func ( l * Loader ) SetAttrExternal ( i Sym , v bool ) {
if i < l . extStart {
panic ( "tried to set external attr on non-external symbol" )
}
if v {
l . attrExternal . set ( i - l . extStart )
} else {
l . attrExternal . unset ( i - l . extStart )
}
}
// AttrTopFrame returns true for a function symbol that is an entry
// point, meaning that unwinders should stop when they hit this
// function.
func ( l * Loader ) AttrTopFrame ( i Sym ) bool {
_ , ok := l . attrTopFrame [ i ]
return ok
}
// SetAttrTopFrame sets the "top frame" property for a symbol (see
// AttrTopFrame).
func ( l * Loader ) SetAttrTopFrame ( i Sym , v bool ) {
if v {
l . attrTopFrame [ i ] = struct { } { }
} else {
delete ( l . attrTopFrame , i )
}
}
// AttrSpecial returns true for a symbols that do not have their
// address (i.e. Value) computed by the usual mechanism of
// data.go:dodata() & data.go:address().
func ( l * Loader ) AttrSpecial ( i Sym ) bool {
_ , ok := l . attrSpecial [ i ]
return ok
}
// SetAttrSpecial sets the "special" property for a symbol (see
// AttrSpecial).
func ( l * Loader ) SetAttrSpecial ( i Sym , v bool ) {
if v {
l . attrSpecial [ i ] = struct { } { }
} else {
delete ( l . attrSpecial , i )
}
}
// AttrCgoExportDynamic returns true for a symbol that has been
// specially marked via the "cgo_export_dynamic" compiler directive
// written by cgo (in response to //export directives in the source).
func ( l * Loader ) AttrCgoExportDynamic ( i Sym ) bool {
_ , ok := l . attrCgoExportDynamic [ i ]
return ok
}
// SetAttrCgoExportDynamic sets the "cgo_export_dynamic" for a symbol
// (see AttrCgoExportDynamic).
func ( l * Loader ) SetAttrCgoExportDynamic ( i Sym , v bool ) {
if v {
l . attrCgoExportDynamic [ i ] = struct { } { }
} else {
delete ( l . attrCgoExportDynamic , i )
}
}
// AttrCgoExportStatic returns true for a symbol that has been
// specially marked via the "cgo_export_static" directive
// written by cgo.
func ( l * Loader ) AttrCgoExportStatic ( i Sym ) bool {
_ , ok := l . attrCgoExportStatic [ i ]
return ok
}
// SetAttrCgoExportStatic sets the "cgo_export_dynamic" for a symbol
// (see AttrCgoExportStatic).
func ( l * Loader ) SetAttrCgoExportStatic ( i Sym , v bool ) {
if v {
l . attrCgoExportStatic [ i ] = struct { } { }
} else {
delete ( l . attrCgoExportStatic , i )
}
}
2019-12-16 14:14:29 -05:00
// AttrReadOnly returns true for a symbol whose underlying data
// is stored via a read-only mmap.
func ( l * Loader ) AttrReadOnly ( i Sym ) bool {
if v , ok := l . attrReadOnly [ i ] ; ok {
return v
}
if i >= l . extStart {
return false
}
r , _ := l . toLocal ( i )
return r . ReadOnly ( )
}
// SetAttrReadOnly sets the "cgo_export_dynamic" for a symbol
// (see AttrReadOnly).
func ( l * Loader ) SetAttrReadOnly ( i Sym , v bool ) {
l . attrReadOnly [ i ] = v
}
2019-12-11 14:17:14 -05:00
// AttrSubSymbol 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 ) AttrSubSymbol ( i Sym ) bool {
// we don't explicitly store this attribute any more -- return
// a value based on the sub-symbol setting.
return l . OuterSym ( i ) != 0
}
// 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
2019-10-08 18:21:22 -04:00
// 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-16 09:29:56 -04:00
// 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
}
2019-12-13 11:51:15 -05:00
// 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
}
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-17 11:06:11 -04:00
if l . IsExternal ( i ) {
2019-10-16 15:44:04 -04:00
if s := l . Syms [ i ] ; s != nil {
return s . P
}
2019-12-11 13:39:39 -05:00
pp := l . getPayload ( i )
if pp != nil {
return pp . data
}
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-12-11 14:24:19 -05:00
// 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
}
}
2019-12-12 08:08:40 -05:00
// 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
}
}
// 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
}
}
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-17 11:06:11 -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-17 11:06:11 -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
}
2019-10-25 12:39:20 -04:00
// 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 {
2019-10-31 09:51:20 -04:00
if l . IsExternal ( symIdx ) {
2019-10-25 12:39:20 -04:00
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
}
2019-12-11 14:17:14 -05:00
// 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
}
2019-10-17 11:06:11 -04:00
// 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 ) )
}
2019-12-11 14:17:14 -05:00
// FIXME: add check for isExternal?
return l . outer [ i ]
2019-10-17 11:06:11 -04:00
}
2019-10-29 10:52:20 -04:00
// SubSym gets the subsymbol for host object loaded symbols.
2019-10-17 11:06:11 -04:00
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 ) )
}
2019-12-11 14:17:14 -05:00
// 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 ]
2019-10-17 11:06:11 -04:00
}
2019-12-11 14:05:14 -05:00
// Initialize Reachable bitmap and its siblings for running deadcode pass.
2019-09-28 22:42:35 -04:00
func ( l * Loader ) InitReachable ( ) {
2019-12-11 14:05:14 -05:00
l . growAttrBitmaps ( l . NSym ( ) + 1 )
2019-12-11 13:39:39 -05:00
}
2019-12-12 11:28:07 -05:00
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
}
2019-12-11 14:05:14 -05:00
// 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 )
2019-12-18 10:57:15 -05:00
l . attrOnList = growBitmap ( reqLen , l . attrOnList )
2019-12-11 14:05:14 -05:00
}
// 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 )
2019-12-11 13:39:39 -05:00
}
2019-09-28 22:42:35 -04:00
}
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-12-11 13:39:39 -05:00
if s := relocs . l . Syms [ relocs . extIdx ] ; s != nil {
rel := s . R [ j ]
2019-10-16 15:44:04 -04:00
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-12-11 13:39:39 -05:00
if relocs . extIdx != 0 {
pp := relocs . l . getPayload ( relocs . extIdx )
return pp . relocs [ j ]
}
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 ,
}
}
2019-10-16 16:21:42 -04:00
// 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 {
2019-10-23 11:04:16 -04:00
return dst [ : 0 ]
2019-10-16 16:21:42 -04:00
}
if cap ( dst ) < relocs . Count {
dst = make ( [ ] Reloc , relocs . Count )
}
dst = dst [ : 0 ]
2019-12-11 13:39:39 -05:00
if s := relocs . l . Syms [ relocs . extIdx ] ; s != nil {
2019-10-16 16:21:42 -04:00
for i := 0 ; i < relocs . Count ; i ++ {
2019-12-11 13:39:39 -05:00
erel := & s . R [ i ]
2019-10-16 16:21:42 -04:00
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
}
2019-12-11 13:39:39 -05:00
if relocs . extIdx != 0 {
pp := relocs . l . getPayload ( relocs . extIdx )
dst = append ( dst , pp . relocs ... )
return dst
}
2019-10-16 16:21:42 -04:00
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
}
2019-10-11 08:56:19 -04:00
// Relocs returns a Relocs object for the given global sym.
func ( l * Loader ) Relocs ( i Sym ) Relocs {
2019-10-17 11:06:11 -04:00
if l . IsExternal ( i ) {
2019-10-16 15:44:04 -04:00
if s := l . Syms [ i ] ; s != nil {
2019-12-11 13:39:39 -05:00
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 }
2019-10-16 15:44:04 -04:00
}
2019-10-11 08:56:19 -04:00
return Relocs { }
}
2019-10-14 10:06:37 -04:00
r , li := l . toLocal ( i )
2019-12-11 13:39:39 -05:00
if r == nil {
panic ( fmt . Sprintf ( "trying to get oreader for invalid sym %d\n\n" , 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-12-13 13:34:43 -05:00
// 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 }
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-24 11:59:49 -04:00
or := & oReader { r , unit , localSymVersion , r . Flags ( ) , pkgprefix , nil }
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-16 09:29:56 -04:00
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 { } { }
}
2019-10-18 17:08:35 -04:00
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 )
}
}
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-24 11:27:47 -04:00
nr := 0 // total number of sym.Reloc's we'll need
2019-10-04 22:05:41 -04:00
for _ , o := range l . objs [ 1 : ] {
2019-10-24 11:27:47 -04:00
nr += loadObjSyms ( l , syms , o . r )
2019-10-04 22:05:41 -04:00
}
2019-12-16 14:14:29 -05:00
// 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 )
2019-10-04 22:05:41 -04:00
for i := l . extStart ; i <= l . max ; i ++ {
2019-10-16 15:44:04 -04:00
if s := l . Syms [ i ] ; s != nil {
2019-12-11 14:05:14 -05:00
s . Attr . Set ( sym . AttrReachable , l . attrReachable . has ( i ) )
2019-12-16 14:14:29 -05:00
continue
}
2019-12-18 15:14:46 -05:00
if i != l . getOverwrite ( i ) {
continue
}
2019-12-16 14:14:29 -05:00
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.
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 )
2020-01-06 20:37:50 -05:00
if pp . gotype != 0 {
s . Gotype = l . Syms [ pp . gotype ]
}
2019-12-16 14:14:29 -05:00
// 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
// Convert outer/sub relationships
if outer , ok := l . outer [ i ] ; ok {
s . Outer = l . Syms [ outer ]
}
if sub , ok := l . sub [ i ] ; ok {
s . Sub = l . Syms [ sub ]
}
// Preprocess symbol and set reachability and onlist.
preprocess ( arch , s )
s . Attr . Set ( sym . AttrReachable , l . attrReachable . has ( i ) )
s . Attr . Set ( sym . AttrOnList , l . attrOnList . has ( i ) )
// Set sub-symbol attribute. FIXME: would be better
// to do away with this and just use l.OuterSymbol() != 0
// elsewhere within the linker.
s . Attr . Set ( sym . AttrSubSymbol , s . Outer != nil )
// Copy over dynimplib, dynimpvers, extname.
if l . SymExtname ( i ) != "" {
s . SetExtname ( l . SymExtname ( i ) )
}
if l . SymDynimplib ( i ) != "" {
s . SetDynimplib ( l . SymDynimplib ( i ) )
}
if l . SymDynimpvers ( i ) != "" {
s . SetDynimpvers ( l . SymDynimpvers ( i ) )
2019-10-04 22:05:41 -04:00
}
}
// 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-10-31 21:53:49 -04:00
2019-12-16 14:14:29 -05:00
// 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.
2019-10-31 21:53:49 -04:00
// 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
}
}
}
}
2019-09-30 11:43:41 -04:00
}
2019-09-17 16:14:37 -04:00
2019-10-17 11:06:11 -04:00
// 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
}
2019-11-27 12:33:35 -05:00
// 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).
2019-11-25 14:07:59 -05:00
anonVerReplacement := syms . IncVersion ( )
2019-10-17 11:06:11 -04:00
for _ , s := range l . Syms {
2019-11-25 14:07:59 -05:00
if s == nil {
continue
}
if s . Name != "" && s . Version >= 0 {
2019-10-17 11:06:11 -04:00
syms . Add ( s )
2019-11-27 12:33:35 -05:00
} else {
syms . Allsym = append ( syms . Allsym , s )
2019-10-17 11:06:11 -04:00
}
2019-11-25 14:07:59 -05:00
if s . Version < 0 {
s . Version = int16 ( anonVerReplacement )
}
2019-10-17 11:06:11 -04:00
}
}
2019-11-27 12:33:35 -05:00
// 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
}
2019-12-11 13:39:39 -05:00
// 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 {
2019-12-11 14:05:14 -05:00
panic ( "sym already present in installSym" )
2019-12-11 13:39:39 -05:00
}
l . Syms [ i ] = s
}
2019-10-17 11:06:11 -04:00
// addNewSym adds a new sym.Symbol to the i-th index in the list of symbols.
2019-11-27 12:33:35 -05:00
func ( l * Loader ) addNewSym ( i Sym , name string , ver int , unit * sym . CompilationUnit , t sym . SymKind ) * sym . Symbol {
s := l . allocSym ( name , ver )
2019-10-17 11:06:11 -04:00
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
2019-11-01 10:58:27 -04:00
l . growSyms ( int ( i ) )
2019-12-11 13:39:39 -05:00
l . installSym ( i , s )
2019-10-17 11:06:11 -04:00
return s
}
2019-10-24 11:27:47 -04:00
// 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 {
2019-10-14 10:06:37 -04:00
istart := l . startIndex ( r )
2019-10-24 11:27:47 -04:00
nr := 0
2019-09-17 16:14:37 -04:00
for i , n := 0 , r . NSym ( ) + r . NNonpkgdef ( ) ; i < n ; i ++ {
2019-10-17 11:06:11 -04:00
// 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.
2019-12-11 14:05:14 -05:00
s . Attr . Set ( sym . AttrReachable , l . attrReachable . has ( istart + Sym ( i ) ) )
2019-10-24 11:27:47 -04:00
nr += r . NReloc ( i )
2019-10-17 11:06:11 -04:00
continue
}
2019-09-17 16:14:37 -04:00
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 )
2019-10-18 12:11:56 -04:00
if osym . ABI != goobj2 . SymABIstatic && l . symsByName [ ver ] [ name ] != 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-17 11:06:11 -04:00
log . Fatalf ( "missing type for %s in %s" , name , r . unit . Lib )
2019-09-24 17:31:12 -04:00
}
2019-12-11 14:05:14 -05:00
if ! l . attrReachable . 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
2019-11-27 12:33:35 -05:00
s := l . addNewSym ( istart + Sym ( i ) , name , ver , r . unit , t )
2019-12-11 14:05:14 -05:00
s . Attr . Set ( sym . AttrReachable , l . attrReachable . has ( istart + Sym ( i ) ) )
2019-10-24 11:27:47 -04:00
nr += r . NReloc ( i )
2019-10-04 22:05:41 -04:00
}
2019-10-24 11:27:47 -04:00
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
2019-10-04 22:05:41 -04:00
}
2019-11-27 12:33:35 -05:00
// loadSymbol loads a single symbol by name.
2019-10-17 11:06:11 -04:00
// NB: This function does NOT set the symbol as reachable.
2019-11-27 12:33:35 -05:00
func ( l * Loader ) loadSymbol ( name string , version int ) * sym . Symbol {
2019-10-17 11:06:11 -04:00
global := l . Lookup ( name , version )
// If we're already loaded, bail.
2019-11-01 10:58:27 -04:00
if global != 0 && int ( global ) < len ( l . Syms ) && l . Syms [ global ] != nil {
2019-10-17 11:06:11 -04:00
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
}
2019-11-27 12:33:35 -05:00
return l . addNewSym ( istart + Sym ( i ) , name , version , r . unit , sym . AbiSymKindToSymKind [ objabi . SymKind ( osym . Type ) ] )
2019-10-17 11:06:11 -04:00
}
2019-11-01 10:58:27 -04:00
// 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).
2019-11-27 12:33:35 -05:00
func ( l * Loader ) LookupOrCreate ( name string , version int ) * sym . Symbol {
2019-11-01 10:58:27 -04:00
i := l . Lookup ( name , version )
if i != 0 {
// symbol exists
if int ( i ) < len ( l . Syms ) && l . Syms [ i ] != nil {
2019-11-27 12:33:35 -05:00
return l . Syms [ i ]
2019-11-01 10:58:27 -04:00
}
if l . IsExternal ( i ) {
panic ( "Can't load an external symbol." )
}
2019-11-27 12:33:35 -05:00
return l . loadSymbol ( name , version )
2019-11-01 10:58:27 -04:00
}
i = l . AddExtSym ( name , version )
2019-11-27 12:33:35 -05:00
s := l . allocSym ( name , version )
2019-11-01 10:58:27 -04:00
l . Syms [ i ] = s
return s
}
2019-12-16 14:14:29 -05:00
// 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 )
// 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
}
}
2020-01-06 20:37:50 -05:00
// 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 )
}
}
2019-12-16 14:14:29 -05:00
// 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 {
panic ( "lookup failed for clone of non-external symbol" )
}
l . symsByName [ sver ] [ sname ] = ns
}
// Add an overwrite entry (in case there are relocations against
// the old symbol).
l . overwrite [ symIdx ] = ns
// FIXME: copy other attributes? reachable is the main one, and we
// don't expect it to be set at this point.
return ns
}
2019-12-11 13:39:39 -05:00
// CreateExtSym creates a new external symbol with the specified name
// without adding it to any lookup tables, returning a Sym index for it.
func ( l * Loader ) CreateExtSym ( name string ) Sym {
2019-12-18 10:57:15 -05:00
// Assign a new unique negative version -- this is to mark the
// symbol so that it can be skipped when ExtractSymbols is adding
// ext syms to the sym.Symbols hash.
l . anonVersion --
return l . newExtSym ( name , l . anonVersion )
2019-12-11 13:39:39 -05:00
}
2019-11-25 14:07:59 -05:00
// Create creates a symbol with the specified name, returning a
// sym.Symbol object for it. This method is intended for static/hidden
// symbols discovered while loading host objects. We can see more than
// one instance of a given static symbol with the same name/version,
// so we can't add them to the lookup tables "as is". Instead assign
// them fictitious (unique) versions, starting at -1 and decreasing by
// one for each newly created symbol, and record them in the
// extStaticSyms hash.
2019-11-27 12:33:35 -05:00
func ( l * Loader ) Create ( name string ) * sym . Symbol {
2019-11-22 15:27:01 -05:00
i := l . max + 1
l . max ++
if l . extStart == 0 {
l . extStart = i
}
2019-11-25 14:07:59 -05:00
// Assign a new unique negative version -- this is to mark the
// symbol so that it can be skipped when ExtractSymbols is adding
// ext syms to the sym.Symbols hash.
l . anonVersion --
ver := l . anonVersion
2019-11-22 15:27:01 -05:00
l . growSyms ( int ( i ) )
2019-11-27 12:33:35 -05:00
s := l . allocSym ( name , ver )
2019-12-11 13:39:39 -05:00
l . installSym ( i , s )
2019-11-25 14:07:59 -05:00
l . extStaticSyms [ nameVer { name , ver } ] = i
2019-11-22 15:27:01 -05:00
return s
}
2019-10-04 22:05:41 -04:00
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 ]
}
2019-10-24 11:27:47 -04:00
funcs := [ ] funcInfoSym { }
fdsyms := [ ] * sym . Symbol { }
var funcAllocCounts funcAllocInfo
2019-10-04 22:05:41 -04:00
pcdataBase := r . PcdataBase ( )
2019-10-16 16:21:42 -04:00
rslice := [ ] Reloc { }
2019-10-04 22:05:41 -04:00
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-18 11:19:32 -04:00
if dupok {
2019-10-18 12:11:56 -04:00
if dupsym := l . symsByName [ ver ] [ name ] ; dupsym != istart + Sym ( i ) {
2019-12-11 14:05:14 -05:00
if l . attrReachable . has ( dupsym ) {
2019-10-18 11:19:32 -04:00
// 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 )
2019-11-21 16:03:58 -05:00
lib . DupTextSyms2 = append ( lib . DupTextSyms2 , sym . LoaderSym ( dupsym ) )
2019-10-18 11:19:32 -04:00
}
2019-10-11 17:43:32 -04:00
}
2019-10-18 11:19:32 -04:00
continue
2019-10-11 17:43:32 -04:00
}
}
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 )
2019-10-16 16:21:42 -04:00
rslice = relocs . ReadAll ( rslice )
2019-10-24 11:27:47 -04:00
batch := l . relocBatch
s . R = batch [ : relocs . Count : relocs . Count ]
l . relocBatch = batch [ relocs . Count : ]
2019-12-16 14:14:29 -05:00
l . convertRelocations ( rslice , s )
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 :
2019-10-24 11:27:47 -04:00
fdsyms = append ( fdsyms , 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
}
if isym == - 1 {
continue
}
2019-10-24 11:27:47 -04:00
// Record function sym and associated info for additional
// processing in the loop below.
fwis := funcInfoSym { s : s , isym : isym , osym : osym }
funcs = append ( funcs , fwis )
// Read the goobj2.FuncInfo for this text symbol so that we can
// collect allocation counts. We'll read it again in the loop
// below.
b := r . Data ( isym )
info := goobj2 . FuncInfo { }
info . Read ( b )
funcAllocCounts . symPtr += uint32 ( len ( info . File ) )
funcAllocCounts . pcData += uint32 ( len ( info . Pcdata ) )
funcAllocCounts . inlCall += uint32 ( len ( info . InlTree ) )
funcAllocCounts . fdOff += uint32 ( len ( info . Funcdataoff ) )
}
// At this point we can do batch allocation of the sym.FuncInfo's,
// along with the slices of sub-objects they use.
fiBatch := make ( [ ] sym . FuncInfo , len ( funcs ) )
inlCallBatch := make ( [ ] sym . InlinedCall , funcAllocCounts . inlCall )
symPtrBatch := make ( [ ] * sym . Symbol , funcAllocCounts . symPtr )
pcDataBatch := make ( [ ] sym . Pcdata , funcAllocCounts . pcData )
fdOffBatch := make ( [ ] int64 , funcAllocCounts . fdOff )
// Populate FuncInfo contents for func symbols.
for fi := 0 ; fi < len ( funcs ) ; fi ++ {
s := funcs [ fi ] . s
isym := funcs [ fi ] . isym
osym := funcs [ fi ] . osym
s . FuncInfo = & fiBatch [ 0 ]
fiBatch = fiBatch [ 1 : ]
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
}
2019-09-24 17:31:12 -04:00
pc := s . FuncInfo
2019-10-24 11:27:47 -04:00
if len ( info . Funcdataoff ) != 0 {
nfd := len ( info . Funcdataoff )
pc . Funcdata = fdsyms [ : nfd : nfd ]
fdsyms = fdsyms [ nfd : ]
2019-09-24 17:31:12 -04:00
}
2019-10-24 11:27:47 -04:00
info . Pcdata = append ( info . Pcdata , info . PcdataEnd ) // for the ease of knowing where it ends
2019-09-24 17:31:12 -04:00
pc . Args = int32 ( info . Args )
pc . Locals = int32 ( info . Locals )
2019-10-24 11:27:47 -04:00
npc := len ( info . Pcdata ) - 1 // -1 as we appended one above
pc . Pcdata = pcDataBatch [ : npc : npc ]
pcDataBatch = pcDataBatch [ npc : ]
nfd := len ( info . Funcdataoff )
pc . Funcdataoff = fdOffBatch [ : nfd : nfd ]
fdOffBatch = fdOffBatch [ nfd : ]
nsp := len ( info . File )
pc . File = symPtrBatch [ : nsp : nsp ]
symPtrBatch = symPtrBatch [ nsp : ]
nic := len ( info . InlTree )
pc . InlTree = inlCallBatch [ : nic : nic ]
inlCallBatch = inlCallBatch [ nic : ]
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
2019-10-24 11:27:47 -04:00
dupok := osym . Dupok ( )
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 )
2019-11-21 16:03:58 -05:00
lib . Textp2 = append ( lib . Textp2 , sym . LoaderSym ( isym ) )
2019-10-04 22:05:41 -04:00
} else {
2019-10-24 11:27:47 -04:00
// there may be a dup in another package
2019-10-04 22:05:41 -04:00
// put into a temp list and add to text later
lib . DupTextSyms = append ( lib . DupTextSyms , s )
2019-11-21 16:03:58 -05:00
lib . DupTextSyms2 = append ( lib . DupTextSyms2 , sym . LoaderSym ( isym ) )
2019-10-04 22:05:41 -04:00
}
2019-09-17 16:14:37 -04:00
}
}
2019-09-30 11:43:41 -04:00
2019-12-16 14:14:29 -05:00
// convertRelocations takes a vector of loader.Reloc relocations and
// translates them into an equivalent set of sym.Reloc relocations on
// the symbol "dst", performing fixups along the way for ABI aliases,
// etc. It is assumed that the called has pre-allocated the dst symbol
// relocations slice.
func ( l * Loader ) convertRelocations ( src [ ] Reloc , dst * sym . Symbol ) {
for j := range dst . R {
r := src [ j ]
rs := r . Sym
sz := r . Size
rt := r . Type
if rt == objabi . R_METHODOFF {
if l . attrReachable . has ( rs ) {
rt = objabi . R_ADDROFF
} else {
sz = 0
rs = 0
}
}
if rt == objabi . R_WEAKADDROFF && ! l . attrReachable . has ( rs ) {
rs = 0
sz = 0
}
if rs != 0 && l . Syms [ rs ] != nil && l . Syms [ rs ] . Type == sym . SABIALIAS {
rsrelocs := l . Relocs ( rs )
rs = rsrelocs . At ( 0 ) . Sym
}
dst . R [ j ] = sym . Reloc {
Off : r . Off ,
Siz : sz ,
Type : rt ,
Add : r . Add ,
Sym : l . Syms [ rs ] ,
}
}
}
2019-10-14 10:06:37 -04:00
var emptyPkg = [ ] byte ( ` "". ` )
2019-11-02 00:38:21 -04:00
func patchDWARFName1 ( p [ ] byte , r * oReader ) ( [ ] byte , int ) {
2019-09-30 11:43:41 -04:00
// This is kind of ugly. Really the package name should not
// even be included here.
2019-11-02 00:38:21 -04:00
if len ( p ) < 1 || p [ 0 ] != dwarf . DW_ABRV_FUNCTION {
return p , - 1
2019-09-30 11:43:41 -04:00
}
2019-11-02 00:38:21 -04:00
e := bytes . IndexByte ( p , 0 )
2019-09-30 11:43:41 -04:00
if e == - 1 {
2019-11-02 00:38:21 -04:00
return p , - 1
2019-09-30 11:43:41 -04:00
}
2019-11-02 00:38:21 -04:00
if ! bytes . Contains ( p [ : e ] , emptyPkg ) {
return p , - 1
2019-09-30 11:43:41 -04:00
}
pkgprefix := [ ] byte ( r . pkgprefix )
2019-11-02 00:38:21 -04:00
patched := bytes . Replace ( p [ : e ] , emptyPkg , pkgprefix , - 1 )
return append ( patched , p [ e : ] ... ) , e
}
2019-09-30 11:43:41 -04:00
2019-11-02 00:38:21 -04:00
func patchDWARFName ( s * sym . Symbol , r * oReader ) {
patched , e := patchDWARFName1 ( s . P , r )
if e == - 1 {
return
}
s . P = patched
2019-09-30 11:43:41 -04:00
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 )
}
}
2019-12-11 13:39:39 -05:00
fmt . Println ( "extStart:" , l . extStart )
2019-12-18 15:14:46 -05:00
fmt . Println ( "max:" , l . max )
2019-10-16 15:44:04 -04:00
fmt . Println ( "syms" )
for i , s := range l . Syms {
if i == 0 {
continue
}
if s != nil {
fmt . Println ( i , s , s . Type )
} else {
2019-12-18 15:14:46 -05:00
otag := ""
si := Sym ( i )
if _ , ok := l . overwrite [ si ] ; ok {
si = l . getOverwrite ( si )
otag = fmt . Sprintf ( " <overwritten to %d>" , si )
}
fmt . Println ( i , l . SymName ( si ) , "<not loaded>" , otag )
2019-10-16 15:44:04 -04:00
}
}
fmt . Println ( "overwrite:" , l . overwrite )
fmt . Println ( "symsByName" )
2019-10-18 12:11:56 -04:00
for name , i := range l . symsByName [ 0 ] {
fmt . Println ( i , name , 0 )
}
for name , i := range l . symsByName [ 1 ] {
fmt . Println ( i , name , 1 )
2019-10-16 15:44:04 -04:00
}
}