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"
"cmd/internal/goobj2"
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/sym"
2020-01-03 15:17:26 -05:00
"debug/elf"
2019-09-17 16:14:37 -04:00
"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 {
2020-03-11 17:00:08 -04:00
Count int // == len(rs), TODO: remove
rs [ ] goobj2 . Reloc2
2019-10-11 08:56:19 -04:00
li int // local index of symbol whose relocs we're examining
r * oReader // object reader for containing package
l * Loader // loader
}
// 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
}
2020-03-05 11:29:24 -05:00
// Reloc2 holds a "handle" to access a relocation record from an
// object file.
type Reloc2 struct {
* goobj2 . Reloc2
r * oReader
l * Loader
2020-03-13 11:43:35 -04:00
// External reloc types may not fit into a uint8 which the Go object file uses.
// Store it here, instead of in the byte of goobj2.Reloc2.
// For Go symbols this will always be 0.
// goobj2.Reloc2.Type() + typ is always the right type, for both Go and external
// symbols.
typ objabi . RelocType
2020-03-05 11:29:24 -05:00
}
2020-03-13 11:43:35 -04:00
func ( rel Reloc2 ) Type ( ) objabi . RelocType { return objabi . RelocType ( rel . Reloc2 . Type ( ) ) + rel . typ }
2020-03-05 11:29:24 -05:00
func ( rel Reloc2 ) Sym ( ) Sym { return rel . l . resolve ( rel . r , rel . Reloc2 . Sym ( ) ) }
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
2020-03-04 11:32:46 -05:00
syms [ ] Sym // Sym's global index, indexed by local index
ndef int // cache goobj2.Reader.NSym()
objidx uint32 // index of this reader in the objs slice
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-09-17 16:14:37 -04:00
}
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
// objSym represents a symbol in an object file. It is a tuple of
// the object and the symbol's local index.
// For external symbols, r is l.extReader, s is its index into the
// payload array.
// {nil, 0} represents the nil symbol.
type objSym struct {
r * oReader
s int // local index
}
2019-09-17 16:14:37 -04:00
type nameVer struct {
name string
v int
}
2020-02-25 15:15:11 -05:00
type Bitmap [ ] uint32
2019-09-28 22:42:35 -04:00
// set the i-th bit.
2020-02-25 15:15:11 -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.
2020-02-25 15:15:11 -05:00
func ( bm Bitmap ) Unset ( i Sym ) {
2019-12-11 14:05:14 -05:00
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.
2020-02-25 15:15:11 -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.
2020-02-25 15:15:11 -05:00
func ( bm Bitmap ) Len ( ) int {
2019-12-11 13:39:39 -05:00
return len ( bm ) * 32
}
2020-02-25 15:15:11 -05:00
func MakeBitmap ( n int ) Bitmap {
return make ( Bitmap , ( n + 31 ) / 32 )
2019-09-28 22:42:35 -04:00
}
2019-12-11 13:39:39 -05:00
// growBitmap insures that the specified bitmap has enough capacity,
// reallocating (doubling the size) if needed.
2020-02-25 15:15:11 -05:00
func growBitmap ( reqLen int , b Bitmap ) Bitmap {
curLen := b . Len ( )
2019-12-11 13:39:39 -05:00
if reqLen > curLen {
2020-02-25 15:15:11 -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
2020-02-11 10:27:15 -05:00
// read adds its defined package symbols to the global index space.
// Nonpackage symbols are not yet added.
2019-12-11 13:39:39 -05:00
//
2020-02-11 10:27:15 -05:00
// - In loader.LoadNonpkgSyms, add non-package defined symbols and
// references in all object files to the global index space.
2019-12-11 13:39:39 -05:00
//
// - 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
2020-02-11 10:27:15 -05:00
// loader stores symbol payloads in loader.payloads using SymbolBuilder.
2019-12-11 13:39:39 -05:00
//
2020-02-11 10:27:15 -05:00
// - For now, in loader.LoadFull we convert all symbols (Go + external)
// to sym.Symbols.
2019-12-11 13:39:39 -05:00
//
// - 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.
//
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
// - Each symbol gets a unique global index. For duplicated and
// overwriting/overwritten symbols, the second (or later) appearance
// of the symbol gets the same global index as the first appearance.
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)
extStart Sym // from this index on, the symbols are externally defined
builtinSyms [ ] Sym // global index of builtin symbols
2019-09-17 16:14:37 -04:00
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
objSyms [ ] objSym // global index mapping to local index
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
2019-09-17 16:14:37 -04:00
2020-02-07 10:26:06 -05:00
extReader * oReader // a dummy oReader, for external symbols
2020-01-29 22:10:51 -05:00
payloadBatch [ ] extSymPayload
payloads [ ] * extSymPayload // contents of linker-materialized external syms
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.
2020-02-25 15:15:11 -05:00
attrReachable Bitmap // reachable symbols, indexed by global index
attrOnList Bitmap // "on list" symbols, indexed by global index
attrLocal Bitmap // "local" symbols, indexed by global index
attrNotInSymbolTable Bitmap // "not in symtab" symbols, indexed by glob idx
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-11 14:05:14 -05:00
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
2020-01-03 15:17:26 -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
elfType map [ Sym ] elf . SymType // stores elf type symbol property
2020-01-03 15:25:28 -05:00
symFile map [ Sym ] string // stores file for shlib-derived syms
2020-01-27 15:31:41 -05:00
plt map [ Sym ] int32 // stores dynimport for pe objects
got map [ Sym ] int32 // stores got for pe objects
2019-12-12 08:08:40 -05:00
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
}
2020-02-11 10:27:15 -05:00
const (
2019-11-20 10:43:11 -05:00
pkgDef = iota
2020-02-11 10:27:15 -05:00
nonPkgDef
nonPkgRef
)
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-03 15:25:28 -05:00
objidx uint32 // index of original object if sym made by cloneToExternal
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 ) ,
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
objs : [ ] objIdx { { } } , // reserve index 0 for nil symbol
objSyms : [ ] objSym { { } } , // reserve index 0 for nil symbol
extReader : & oReader { } ,
2020-02-26 00:58:29 -05:00
symsByName : [ 2 ] map [ string ] Sym { make ( map [ string ] Sym , 100000 ) , make ( map [ string ] Sym , 50000 ) } , // preallocate ~2MB for ABI0 and ~1MB for ABI1 symbols
2019-12-18 10:57:15 -05:00
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 ) ,
2020-01-03 15:17:26 -05:00
elfType : make ( map [ Sym ] elf . SymType ) ,
2020-01-03 15:25:28 -05:00
symFile : make ( map [ Sym ] string ) ,
2020-01-27 15:31:41 -05:00
plt : make ( map [ Sym ] int32 ) ,
got : make ( map [ Sym ] int32 ) ,
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 { } ) ,
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
}
}
// 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
}
2020-02-05 16:52:12 -05:00
i := Sym ( len ( l . objSyms ) )
2019-09-17 16:14:37 -04:00
l . start [ r ] = i
2020-02-03 12:37:35 -05:00
l . objs = append ( l . objs , objIdx { r , i } )
2019-09-17 16:14:37 -04:00
return i
}
2020-02-03 12:37:35 -05:00
// Add a symbol from an object file, return the global index and whether it is added.
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
// If the symbol already exist, it returns the index of that symbol.
2020-02-11 10:27:15 -05:00
func ( l * Loader ) AddSym ( name string , ver int , r * oReader , li int , kind int , dupok bool , typ sym . SymKind ) ( Sym , bool ) {
2019-09-28 22:42:35 -04:00
if l . extStart != 0 {
panic ( "AddSym called after AddExtSym is called" )
}
2020-02-03 12:37:35 -05:00
i := Sym ( len ( l . objSyms ) )
addToGlobal := func ( ) {
l . objSyms = append ( l . objSyms , objSym { r , li } )
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
}
if name == "" {
2020-02-03 12:37:35 -05:00
addToGlobal ( )
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
return i , true // unnamed aux symbol
}
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.
2020-02-03 12:37:35 -05:00
addToGlobal ( )
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
return i , true
2019-10-18 11:19:32 -04:00
}
2020-02-11 10:27:15 -05:00
if kind == pkgDef {
// Defined package symbols cannot be dup to each other.
// We load all the package symbols first, so we don't need
// to check dup here.
// We still add it to the lookup table, as it may still be
// referenced by name (e.g. through linkname).
l . symsByName [ ver ] [ name ] = i
addToGlobal ( )
return i , true
}
// Non-package (named) symbol. Check if it already exists.
2020-02-03 12:37:35 -05:00
oldi , existed := l . symsByName [ ver ] [ name ]
if ! existed {
l . symsByName [ ver ] [ name ] = i
addToGlobal ( )
return i , true
}
// symbol already exists
if dupok {
if l . flags & FlagStrictDups != 0 {
l . checkdup ( name , r , li , oldi )
}
return oldi , false
}
oldr , oldli := l . toLocal ( oldi )
oldsym := goobj2 . Sym { }
2020-02-07 11:02:42 -05:00
oldsym . ReadWithoutName ( oldr . Reader , oldr . SymOff ( oldli ) )
2020-02-03 12:37:35 -05:00
if oldsym . Dupok ( ) {
return oldi , false
}
overwrite := r . DataSize ( li ) != 0
if overwrite {
// new symbol overwrites old symbol.
oldtyp := sym . AbiSymKindToSymKind [ objabi . SymKind ( oldsym . Type ) ]
if ! ( oldtyp . IsData ( ) && oldr . DataSize ( oldli ) == 0 ) {
log . Fatalf ( "duplicated definition of symbol " + name )
}
l . objSyms [ oldi ] = objSym { r , li }
} else {
// old symbol overwrites new symbol.
if ! typ . IsData ( ) { // only allow overwriting data symbol
log . Fatalf ( "duplicated definition of symbol " + name )
2019-09-17 16:14:37 -04:00
}
}
2020-02-03 12:37:35 -05:00
return oldi , true
2019-09-17 16:14:37 -04:00
}
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 {
2020-02-05 16:52:12 -05:00
i := Sym ( len ( l . objSyms ) )
2019-12-11 13:39:39 -05:00
if l . extStart == 0 {
l . extStart = i
}
l . growSyms ( int ( i ) )
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
pi := l . newPayload ( name , ver )
l . objSyms = append ( l . objSyms , objSym { l . extReader , int ( pi ) } )
l . extReader . syms = append ( l . extReader . syms , i )
2019-12-11 13:39:39 -05:00
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 {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
return i
2019-12-11 13:39:39 -05:00
}
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 {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
r , _ := l . toLocal ( i )
2020-02-05 16:52:12 -05:00
return l . isExtReader ( r )
}
func ( l * Loader ) isExtReader ( r * oReader ) bool {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
return r == l . extReader
}
// For external symbol, return its index in the payloads array.
// XXX result is actually not a global index. We (ab)use the Sym type
// so we don't need conversion for accessing bitmaps.
func ( l * Loader ) extIndex ( i Sym ) Sym {
_ , li := l . toLocal ( i )
return Sym ( li )
}
// Get a new payload for external symbol, return its index in
// the payloads array.
func ( l * Loader ) newPayload ( name string , ver int ) int {
pi := len ( l . payloads )
pp := l . allocPayload ( )
pp . name = name
pp . ver = ver
l . payloads = append ( l . payloads , pp )
l . growExtAttrBitmaps ( )
return pi
2019-10-16 15:44:04 -04:00
}
2019-12-11 13:39:39 -05:00
// getPayload returns a pointer to the extSymPayload struct for an
2020-02-01 17:04:34 -05:00
// external symbol if the symbol has a payload. Will panic if the
// symbol in question is bogus (zero or not an external sym).
2019-12-11 13:39:39 -05:00
func ( l * Loader ) getPayload ( i Sym ) * extSymPayload {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if ! l . IsExternal ( i ) {
2019-12-11 13:39:39 -05:00
panic ( fmt . Sprintf ( "bogus symbol index %d in getPayload" , i ) )
}
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
pi := l . extIndex ( i )
2020-01-29 22:10:51 -05:00
return l . payloads [ pi ]
}
// allocPayload allocates a new payload.
func ( l * Loader ) allocPayload ( ) * extSymPayload {
batch := l . payloadBatch
if len ( batch ) == 0 {
batch = make ( [ ] extSymPayload , 1000 )
}
p := & batch [ 0 ]
l . payloadBatch = batch [ 1 : ]
return p
2019-12-11 13:39:39 -05:00
}
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 ]
}
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
// Ensure Syms slice has enough space.
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-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-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 {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
return r . syms [ i ]
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 ) {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
return l . objSyms [ i ] . r , int ( l . objSyms [ i ] . s )
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 :
2020-03-05 16:43:37 -05:00
// {0, X} with non-zero X is never a valid sym reference from a Go object.
// We steal this space for symbol references from external objects.
// In this case, X is just the global index.
if l . isExtReader ( r ) {
return Sym ( s . SymIdx )
}
2019-09-30 11:43:41 -04:00
if s . SymIdx != 0 {
panic ( "bad sym ref" )
}
return 0
case goobj2 . PkgIdxNone :
2020-02-07 10:26:06 -05:00
i := int ( s . SymIdx ) + r . ndef
2020-01-30 17:27:27 -05:00
return r . syms [ i ]
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-11-02 00:38:21 -04:00
// Check that duplicate symbols have same contents.
2020-02-03 12:37:35 -05:00
func ( l * Loader ) checkdup ( name string , r * oReader , li int , dup Sym ) {
2019-11-02 00:38:21 -04:00
p := r . Data ( li )
rdup , ldup := l . toLocal ( dup )
pdup := rdup . Data ( ldup )
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 {
2020-02-05 16:52:12 -05:00
return len ( l . objSyms )
2019-09-28 22:42:35 -04:00
}
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-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-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 ) {
pp := l . getPayload ( i )
return pp . ver
}
r , li := l . toLocal ( i )
osym := goobj2 . Sym { }
2020-02-07 11:02:42 -05:00
osym . ReadWithoutName ( r . Reader , r . SymOff ( li ) )
2019-12-26 13:39:04 -05:00
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-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 { }
2020-02-07 11:02:42 -05:00
osym . ReadWithoutName ( r . Reader , r . SymOff ( li ) )
2019-09-28 22:42:35 -04:00
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 { }
2020-02-07 10:26:06 -05:00
osym . ReadFlag ( r . Reader , r . SymOff ( li ) )
2019-10-08 18:21:22 -04:00
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 {
2020-02-25 15:15:11 -05:00
return l . attrReachable . Has ( i )
2019-12-11 14:05:14 -05:00
}
// SetAttrReachable sets the reachability property for a symbol (see
// AttrReachable).
func ( l * Loader ) SetAttrReachable ( i Sym , v bool ) {
if v {
2020-02-25 15:15:11 -05:00
l . attrReachable . Set ( i )
2019-12-11 14:05:14 -05:00
} else {
2020-02-25 15:15:11 -05:00
l . attrReachable . Unset ( i )
2019-12-11 14:05:14 -05:00
}
}
// 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 {
2020-02-25 15:15:11 -05:00
return l . attrOnList . Has ( i )
2019-12-11 14:05:14 -05:00
}
// SetAttrOnList sets the "on list" property for a symbol (see
// AttrOnList).
func ( l * Loader ) SetAttrOnList ( i Sym , v bool ) {
if v {
2020-02-25 15:15:11 -05:00
l . attrOnList . Set ( i )
2019-12-11 14:05:14 -05:00
} else {
2020-02-25 15:15:11 -05:00
l . attrOnList . Unset ( i )
2019-12-11 14:05:14 -05:00
}
}
2019-12-30 14:24:29 -05:00
// AttrLocal returns true for symbols that are only visible within the
// module (executable or shared library) being linked. This attribute
// is applied to thunks and certain other linker-generated symbols.
func ( l * Loader ) AttrLocal ( i Sym ) bool {
2020-02-25 15:15:11 -05:00
return l . attrLocal . Has ( i )
2019-12-30 14:24:29 -05:00
}
// SetAttrLocal the "local" property for a symbol (see AttrLocal above).
func ( l * Loader ) SetAttrLocal ( i Sym , v bool ) {
if v {
2020-02-25 15:15:11 -05:00
l . attrLocal . Set ( i )
2019-12-30 14:24:29 -05:00
} else {
2020-02-25 15:15:11 -05:00
l . attrLocal . Unset ( i )
2019-12-30 14:24:29 -05:00
}
}
2020-01-07 15:47:43 -05:00
// AttrNotInSymbolTable returns true for symbols that should not be
// added to the symbol table of the final generated load module.
func ( l * Loader ) AttrNotInSymbolTable ( i Sym ) bool {
2020-02-25 15:15:11 -05:00
return l . attrNotInSymbolTable . Has ( i )
2020-01-07 15:47:43 -05:00
}
// SetAttrNotInSymbolTable the "not in symtab" property for a symbol
// (see AttrNotInSymbolTable above).
func ( l * Loader ) SetAttrNotInSymbolTable ( i Sym , v bool ) {
if v {
2020-02-25 15:15:11 -05:00
l . attrNotInSymbolTable . Set ( i )
2020-01-07 15:47:43 -05:00
} else {
2020-02-25 15:15:11 -05:00
l . attrNotInSymbolTable . Unset ( i )
2020-01-07 15:47:43 -05:00
}
}
2019-12-11 14:05:14 -05:00
// 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 {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if ! l . IsExternal ( i ) {
2019-12-11 14:05:14 -05:00
return false
}
2020-02-25 15:15:11 -05:00
return l . attrVisibilityHidden . Has ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
}
// SetAttrVisibilityHidden sets the "hidden visibility" property for a
// symbol (see AttrVisibilityHidden).
func ( l * Loader ) SetAttrVisibilityHidden ( i Sym , v bool ) {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if ! l . IsExternal ( i ) {
2019-12-11 14:05:14 -05:00
panic ( "tried to set visibility attr on non-external symbol" )
}
if v {
2020-02-25 15:15:11 -05:00
l . attrVisibilityHidden . Set ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
} else {
2020-02-25 15:15:11 -05:00
l . attrVisibilityHidden . Unset ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
}
}
// AttrDuplicateOK returns true for a symbol that can be present in
// multiple object files.
func ( l * Loader ) AttrDuplicateOK ( i Sym ) bool {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if ! l . IsExternal ( i ) {
2019-12-11 14:05:14 -05:00
// 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 { }
2020-02-07 10:26:06 -05:00
osym . ReadFlag ( r . Reader , r . SymOff ( li ) )
2019-12-11 14:05:14 -05:00
return osym . Dupok ( )
}
2020-02-25 15:15:11 -05:00
return l . attrDuplicateOK . Has ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
}
// SetAttrDuplicateOK sets the "duplicate OK" property for an external
// symbol (see AttrDuplicateOK).
func ( l * Loader ) SetAttrDuplicateOK ( i Sym , v bool ) {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if ! l . IsExternal ( i ) {
2019-12-11 14:05:14 -05:00
panic ( "tried to set dupok attr on non-external symbol" )
}
if v {
2020-02-25 15:15:11 -05:00
l . attrDuplicateOK . Set ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
} else {
2020-02-25 15:15:11 -05:00
l . attrDuplicateOK . Unset ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
}
}
// AttrShared returns true for symbols compiled with the -shared option.
func ( l * Loader ) AttrShared ( i Sym ) bool {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if ! l . IsExternal ( i ) {
2019-12-11 14:05:14 -05:00
// 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
}
2020-02-25 15:15:11 -05:00
return l . attrShared . Has ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
}
// SetAttrShared sets the "shared" property for an external
// symbol (see AttrShared).
func ( l * Loader ) SetAttrShared ( i Sym , v bool ) {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if ! l . IsExternal ( i ) {
2020-02-14 16:12:51 -05:00
panic ( fmt . Sprintf ( "tried to set shared attr on non-external symbol %d %s" , i , l . SymName ( i ) ) )
2019-12-11 14:05:14 -05:00
}
if v {
2020-02-25 15:15:11 -05:00
l . attrShared . Set ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
} else {
2020-02-25 15:15:11 -05:00
l . attrShared . Unset ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
}
}
// AttrExternal returns true for function symbols loaded from host
// object files.
func ( l * Loader ) AttrExternal ( i Sym ) bool {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if ! l . IsExternal ( i ) {
2019-12-11 14:05:14 -05:00
return false
}
2020-02-25 15:15:11 -05:00
return l . attrExternal . Has ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
}
// SetAttrExternal sets the "external" property for an host object
// symbol (see AttrExternal).
func ( l * Loader ) SetAttrExternal ( i Sym , v bool ) {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if ! l . IsExternal ( i ) {
2020-01-22 15:24:39 -05:00
panic ( fmt . Sprintf ( "tried to set external attr on non-external symbol %q" , l . RawSymName ( i ) ) )
2019-12-11 14:05:14 -05:00
}
if v {
2020-02-25 15:15:11 -05:00
l . attrExternal . Set ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
} else {
2020-02-25 15:15:11 -05:00
l . attrExternal . Unset ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
}
}
// 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
}
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
if l . IsExternal ( i ) {
2019-12-16 14:14:29 -05:00
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
}
2020-02-17 01:27:11 -05:00
// Returns whether the i-th symbol is nosplit.
func ( l * Loader ) IsNoSplit ( i Sym ) bool {
return l . SymAttr ( i ) & goobj2 . SymFlagNoSplit != 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-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
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2019-12-11 14:24:19 -05:00
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
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2019-12-12 08:08:40 -05:00
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
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2019-12-12 08:08:40 -05:00
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 {
2020-03-12 23:35:46 -04:00
if s , ok := l . extname [ i ] ; ok {
return s
}
return l . SymName ( i )
2019-12-12 08:08:40 -05:00
}
// SetSymExtname sets the "extname" attribute for a symbol.
func ( l * Loader ) SetSymExtname ( i Sym , value string ) {
// reject bad symbols
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2019-12-12 08:08:40 -05:00
panic ( "bad symbol index in SetExtname" )
}
if value == "" {
delete ( l . extname , i )
} else {
l . extname [ i ] = value
}
}
2020-01-03 15:17:26 -05:00
// SymElfType returns the previously recorded ELF type for a symbol
// (used only for symbols read from shared libraries by ldshlibsyms).
// It is not set for symbols defined by the packages being linked or
// by symbols read by ldelf (and so is left as elf.STT_NOTYPE).
func ( l * Loader ) SymElfType ( i Sym ) elf . SymType {
if et , ok := l . elfType [ i ] ; ok {
return et
}
return elf . STT_NOTYPE
}
2020-01-27 15:31:41 -05:00
// SetSymElfType sets the elf type attribute for a symbol.
2020-01-03 15:17:26 -05:00
func ( l * Loader ) SetSymElfType ( i Sym , et elf . SymType ) {
// reject bad symbols
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2020-01-03 15:17:26 -05:00
panic ( "bad symbol index in SetSymElfType" )
}
if et == elf . STT_NOTYPE {
delete ( l . elfType , i )
} else {
l . elfType [ i ] = et
}
}
2020-01-27 15:31:41 -05:00
// SetPlt sets the plt value for pe symbols.
func ( l * Loader ) SetPlt ( i Sym , v int32 ) {
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2020-01-27 15:31:41 -05:00
panic ( "bad symbol for SetPlt" )
}
if v == 0 {
delete ( l . plt , i )
} else {
l . plt [ i ] = v
}
}
// SetGot sets the got value for pe symbols.
func ( l * Loader ) SetGot ( i Sym , v int32 ) {
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2020-01-27 15:31:41 -05:00
panic ( "bad symbol for SetPlt" )
}
if v == 0 {
delete ( l . got , i )
} else {
l . got [ i ] = v
}
}
2020-01-08 12:57:41 -05:00
// SymGoType returns the 'Gotype' property for a given symbol (set by
// the Go compiler for variable symbols). This version relies on
// reading aux symbols for the target sym -- it could be that a faster
// approach would be to check for gotype during preload and copy the
// results in to a map (might want to try this at some point and see
// if it helps speed things up).
func ( l * Loader ) SymGoType ( i Sym ) Sym {
if l . IsExternal ( i ) {
pp := l . getPayload ( i )
return pp . gotype
}
r , li := l . toLocal ( i )
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 :
return l . resolve ( r , a . Sym )
}
}
return 0
}
// SymUnit returns the compilation unit for a given symbol (which will
// typically be nil for external or linker-manufactured symbols).
func ( l * Loader ) SymUnit ( i Sym ) * sym . CompilationUnit {
if l . IsExternal ( i ) {
pp := l . getPayload ( i )
if pp . objidx != 0 {
r := l . objs [ pp . objidx ] . r
return r . unit
}
return nil
}
r , _ := l . toLocal ( i )
return r . unit
}
2020-01-03 15:25:28 -05:00
// SymFile returns the file for a symbol, which is normally the
// package the symbol came from (for regular compiler-generated Go
// symbols), but in the case of building with "-linkshared" (when a
// symbol is read from a a shared library), will hold the library
// name.
func ( l * Loader ) SymFile ( i Sym ) string {
if l . IsExternal ( i ) {
if f , ok := l . symFile [ i ] ; ok {
return f
}
pp := l . getPayload ( i )
if pp . objidx != 0 {
r := l . objs [ pp . objidx ] . r
return r . unit . Lib . File
}
return ""
}
r , _ := l . toLocal ( i )
return r . unit . Lib . File
}
// SetSymFile sets the file attribute for a symbol. This is
// needed mainly for external symbols, specifically those imported
// from shared libraries.
func ( l * Loader ) SetSymFile ( i Sym , file string ) {
// reject bad symbols
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2020-01-03 15:25:28 -05:00
panic ( "bad symbol index in SetSymFile" )
}
if ! l . IsExternal ( i ) {
panic ( "can't set file for non-external sym" )
}
l . symFile [ i ] = file
}
2019-12-12 08:08:40 -05:00
// 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
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2019-12-12 08:08:40 -05:00
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-11-20 10:43:11 -05:00
// GetFuncDwarfAuxSyms collects and returns the auxiliary DWARF
// symbols associated with a given function symbol. Prior to the
// introduction of the loader, this was done purely using name
// lookups, e.f. for function with name XYZ we would then look up
// go.info.XYZ, etc.
// FIXME: once all of dwarfgen is converted over to the loader,
// it would save some space to make these aux symbols nameless.
func ( l * Loader ) GetFuncDwarfAuxSyms ( fnSymIdx Sym ) ( auxDwarfInfo , auxDwarfLoc , auxDwarfRanges , auxDwarfLines Sym ) {
if l . SymType ( fnSymIdx ) != sym . STEXT {
log . Fatalf ( "error: non-function sym %d/%s t=%s passed to GetFuncDwarfAuxSyms" , fnSymIdx , l . SymName ( fnSymIdx ) , l . SymType ( fnSymIdx ) . String ( ) )
}
if l . IsExternal ( fnSymIdx ) {
// Current expectation is that any external function will
// not have auxsyms.
return
}
naux := l . NAux ( fnSymIdx )
if naux == 0 {
return
}
r , li := l . toLocal ( fnSymIdx )
for i := 0 ; i < naux ; i ++ {
a := goobj2 . Aux { }
a . Read ( r . Reader , r . AuxOff ( li , i ) )
switch a . Type {
case goobj2 . AuxDwarfInfo :
auxDwarfInfo = l . resolve ( r , a . Sym )
if l . SymType ( auxDwarfInfo ) != sym . SDWARFINFO {
panic ( "aux dwarf info sym with wrong type" )
}
case goobj2 . AuxDwarfLoc :
auxDwarfLoc = l . resolve ( r , a . Sym )
if l . SymType ( auxDwarfLoc ) != sym . SDWARFLOC {
panic ( "aux dwarf loc sym with wrong type" )
}
case goobj2 . AuxDwarfRanges :
auxDwarfRanges = l . resolve ( r , a . Sym )
if l . SymType ( auxDwarfRanges ) != sym . SDWARFRANGE {
panic ( "aux dwarf ranges sym with wrong type" )
}
case goobj2 . AuxDwarfLines :
auxDwarfLines = l . resolve ( r , a . Sym )
if l . SymType ( auxDwarfLines ) != sym . SDWARFLINES {
panic ( "aux dwarf lines sym with wrong type" )
}
}
}
return
}
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 )
2020-02-07 10:26:06 -05:00
a := goobj2 . Aux { }
2019-10-25 12:39:20 -04:00
for i := 0 ; i < naux ; i ++ {
2020-02-07 10:26:06 -05:00
a . ReadSym ( r . Reader , r . AuxOff ( li , i ) )
2019-10-25 12:39:20 -04:00
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 ) {
// 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 {
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 {
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 ) {
2020-02-25 15:15:11 -05:00
if reqLen > l . attrReachable . Len ( ) {
2019-12-11 14:05:14 -05:00
// 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-30 14:24:29 -05:00
l . attrLocal = growBitmap ( reqLen , l . attrLocal )
2020-01-07 15:47:43 -05:00
l . attrNotInSymbolTable = growBitmap ( reqLen , l . attrNotInSymbolTable )
2019-12-11 14:05:14 -05:00
}
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
l . growExtAttrBitmaps ( )
}
func ( l * Loader ) growExtAttrBitmaps ( ) {
// These are indexed by external symbol index (e.g. l.extIndex(i))
extReqLen := len ( l . payloads )
2020-02-25 15:15:11 -05:00
if extReqLen > l . attrVisibilityHidden . Len ( ) {
2019-12-11 14:05:14 -05:00
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 {
2020-02-05 16:52:12 -05:00
if relocs . l . isExtReader ( relocs . r ) {
pp := relocs . l . payloads [ relocs . li ]
2019-12-11 13:39:39 -05:00
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 ,
}
}
2020-03-05 11:29:24 -05:00
func ( relocs * Relocs ) At2 ( j int ) Reloc2 {
if relocs . l . isExtReader ( relocs . r ) {
2020-03-05 16:43:37 -05:00
pp := relocs . l . payloads [ relocs . li ]
r := pp . relocs [ j ]
// XXX populate a goobj2.Reloc from external reloc record.
// Ugly. Maybe we just want to use this format to store the
// reloc record in the first place?
2020-03-11 17:00:08 -04:00
// Also there is more speedup if we could remove the
// conditional here.
2020-03-05 16:43:37 -05:00
var b goobj2 . Reloc2
2020-03-13 11:43:35 -04:00
b . Set ( r . Off , r . Size , 0 , r . Add , goobj2 . SymRef { PkgIdx : 0 , SymIdx : uint32 ( r . Sym ) } )
return Reloc2 { & b , relocs . r , relocs . l , r . Type }
2020-03-05 11:29:24 -05:00
}
2020-03-11 17:00:08 -04:00
return Reloc2 { & relocs . rs [ j ] , relocs . r , relocs . l , 0 }
2020-03-05 11:29:24 -05:00
}
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 {
2020-02-07 10:26:06 -05:00
return relocs . readAll ( dst , false )
}
// ReadSyms method reads all relocation target symbols and reloc types
// for a symbol into the specified slice. It is like ReadAll but only
// fill in the Sym and Type fields.
func ( relocs * Relocs ) ReadSyms ( dst [ ] Reloc ) [ ] Reloc {
return relocs . readAll ( dst , true )
}
func ( relocs * Relocs ) readAll ( dst [ ] Reloc , onlySymType bool ) [ ] Reloc {
2019-10-16 16:21:42 -04:00
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 ]
2020-02-05 16:52:12 -05:00
if relocs . l . isExtReader ( relocs . r ) {
pp := relocs . l . payloads [ relocs . li ]
2019-12-11 13:39:39 -05:00
dst = append ( dst , pp . relocs ... )
return dst
}
2019-10-16 16:21:42 -04:00
off := relocs . r . RelocOff ( relocs . li , 0 )
2020-02-07 10:26:06 -05:00
rel := goobj2 . Reloc { }
2019-10-16 16:21:42 -04:00
for i := 0 ; i < relocs . Count ; i ++ {
2020-02-07 10:26:06 -05:00
if onlySymType {
rel . ReadSymType ( relocs . r . Reader , off )
} else {
rel . Read ( relocs . r . Reader , off )
}
2019-10-16 16:21:42 -04:00
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-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 {
2020-02-05 16:52:12 -05:00
var n int
2020-03-11 17:00:08 -04:00
var rs [ ] goobj2 . Reloc2
2020-02-05 16:52:12 -05:00
if l . isExtReader ( r ) {
pp := l . payloads [ li ]
n = len ( pp . relocs )
} else {
2020-03-11 17:00:08 -04:00
rs = r . Relocs2 ( li )
n = len ( rs )
2020-02-05 16:52:12 -05:00
}
2019-10-11 08:56:19 -04:00
return Relocs {
2020-02-05 16:52:12 -05:00
Count : n ,
2020-03-11 17:00:08 -04:00
rs : rs ,
2019-10-11 08:56:19 -04:00
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 }
2020-02-25 15:14:31 -05:00
// FuncInfo provides hooks to access goobj2.FuncInfo in the objects.
type FuncInfo struct {
l * Loader
r * oReader
data [ ] byte
}
func ( fi * FuncInfo ) Valid ( ) bool { return fi . r != nil }
func ( fi * FuncInfo ) Locals ( ) int {
return int ( ( * goobj2 . FuncInfo ) ( nil ) . ReadLocals ( fi . data ) )
}
func ( fi * FuncInfo ) Pcsp ( ) [ ] byte {
pcsp , end := ( * goobj2 . FuncInfo ) ( nil ) . ReadPcsp ( fi . data )
return fi . r . BytesAt ( fi . r . PcdataBase ( ) + pcsp , int ( end - pcsp ) )
}
// TODO: more accessors.
func ( l * Loader ) FuncInfo ( i Sym ) FuncInfo {
if l . IsExternal ( i ) {
return FuncInfo { }
}
r , li := l . toLocal ( i )
n := r . NAux ( li )
for j := 0 ; j < n ; j ++ {
a := goobj2 . Aux { }
a . Read ( r . Reader , r . AuxOff ( li , j ) )
if a . Type == goobj2 . AuxFuncInfo {
b := r . Data ( int ( a . Sym . SymIdx ) )
return FuncInfo { l , r , b }
}
}
return FuncInfo { }
}
2020-02-11 10:27:15 -05:00
// Preload a package: add autolibs, add defined package symbols to the symbol table.
// Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
// Does not read symbol data.
2020-02-12 17:50:21 -05:00
func ( l * Loader ) Preload ( syms * sym . Symbols , f * bio . Reader , lib * sym . Library , unit * sym . CompilationUnit , length int64 , 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 ) + "."
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
ndef := r . NSym ( )
nnonpkgdef := r . NNonpkgdef ( )
2020-03-04 11:32:46 -05:00
or := & oReader { r , unit , localSymVersion , r . Flags ( ) , pkgprefix , make ( [ ] Sym , ndef + nnonpkgdef + r . NNonpkgref ( ) ) , ndef , uint32 ( len ( l . objs ) ) }
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 )
}
2020-02-11 10:27:15 -05:00
l . addObj ( lib . Pkg , or )
l . preloadSyms ( or , pkgDef )
// The caller expects us consuming all the data
f . MustSeek ( length , os . SEEK_CUR )
}
// Preload symbols of given kind from an object.
func ( l * Loader ) preloadSyms ( r * oReader , kind int ) {
ndef := r . NSym ( )
nnonpkgdef := r . NNonpkgdef ( )
var start , end int
switch kind {
case pkgDef :
start = 0
end = ndef
case nonPkgDef :
start = ndef
end = ndef + nnonpkgdef
default :
panic ( "preloadSyms: bad kind" )
}
l . growSyms ( len ( l . objSyms ) + end - start )
l . growAttrBitmaps ( len ( l . objSyms ) + end - start )
for i := start ; i < end ; i ++ {
2019-09-17 16:14:37 -04:00
osym := goobj2 . Sym { }
2020-02-11 10:27:15 -05:00
osym . Read ( r . Reader , r . SymOff ( i ) )
name := strings . Replace ( osym . Name , "\"\"." , r . pkgprefix , - 1 )
v := abiToVer ( osym . ABI , r . version )
2019-10-14 11:17:18 -04:00
dupok := osym . Dupok ( )
2020-02-11 10:27:15 -05:00
gi , added := l . AddSym ( name , v , r , i , kind , dupok , sym . AbiSymKindToSymKind [ objabi . SymKind ( osym . Type ) ] )
r . syms [ i ] = gi
2020-01-07 15:47:43 -05:00
if ! added {
continue
}
2020-02-19 09:44:23 -05:00
if osym . TopFrame ( ) {
l . SetAttrTopFrame ( gi , true )
}
2020-01-07 15:47:43 -05:00
if strings . HasPrefix ( name , "go.itablink." ) {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
l . itablink [ gi ] = struct { } { }
2019-10-16 09:29:56 -04:00
}
2020-01-07 15:47:43 -05:00
if strings . HasPrefix ( name , "runtime." ) {
2019-10-18 17:08:35 -04:00
if bi := goobj2 . BuiltinIdx ( name , v ) ; bi != - 1 {
// This is a definition of a builtin symbol. Record where it is.
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
l . builtinSyms [ bi ] = gi
2019-10-18 17:08:35 -04:00
}
}
2020-01-07 15:47:43 -05:00
if strings . HasPrefix ( name , "go.string." ) ||
2019-11-20 10:43:11 -05:00
strings . HasPrefix ( name , "gclocals·" ) ||
2020-01-07 15:47:43 -05:00
strings . HasPrefix ( name , "runtime.gcbits." ) {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
l . SetAttrNotInSymbolTable ( gi , true )
2020-01-07 15:47:43 -05:00
}
2019-09-17 16:14:37 -04:00
}
}
2020-02-11 10:27:15 -05:00
// Add non-package symbols and references to external symbols (which are always
// named).
2020-02-12 17:50:21 -05:00
func ( l * Loader ) LoadNonpkgSyms ( syms * sym . Symbols ) {
2020-02-11 10:27:15 -05:00
for _ , o := range l . objs [ 1 : ] {
l . preloadSyms ( o . r , nonPkgDef )
}
2019-09-30 11:43:41 -04:00
for _ , o := range l . objs [ 1 : ] {
2020-02-12 17:50:21 -05:00
loadObjRefs ( l , o . r , syms )
2019-09-30 11:43:41 -04:00
}
}
2020-02-12 17:50:21 -05:00
func loadObjRefs ( l * Loader , r * oReader , 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 )
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
r . syms [ ndef + i ] = 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).
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
toConvert := make ( [ ] Sym , 0 , len ( l . payloads ) )
for _ , i := range l . extReader . syms {
2019-12-16 14:14:29 -05:00
sname := l . RawSymName ( i )
2020-02-25 15:15:11 -05:00
if ! l . attrReachable . Has ( i ) && ! strings . HasPrefix ( sname , "gofile.." ) { // XXX file symbols are used but not marked
2019-12-16 14:14:29 -05:00
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
2019-12-06 20:11:36 -05:00
// outer/sub processing below. Note that once we do this,
// we'll need to get at the payload for a symbol with direct
// reference to l.payloads[] as opposed to calling l.getPayload().
2019-12-16 14:14:29 -05:00
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.
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
pp := l . payloads [ l . extIndex ( i ) ]
2019-12-16 14:14:29 -05:00
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 ]
}
2020-01-03 15:25:28 -05:00
s . Value = l . values [ i ]
if f , ok := l . symFile [ i ] ; ok {
s . File = f
} else if pp . objidx != 0 {
s . File = l . objs [ pp . objidx ] . r . unit . Lib . File
}
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 ) : ]
2020-02-14 16:12:51 -05:00
l . convertRelocations ( pp . relocs , s , false )
2019-12-16 14:14:29 -05:00
// Copy data
s . P = pp . data
2019-12-06 20:11:36 -05:00
// Transfer over attributes.
l . migrateAttributes ( i , s )
2019-12-16 14:14:29 -05:00
2019-12-06 20:11:36 -05:00
// Preprocess symbol. May set 'AttrLocal'.
2019-12-16 14:14:29 -05:00
preprocess ( arch , s )
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.)
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
for _ , i := range l . extReader . syms {
2019-10-31 21:53:49 -04:00
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
2020-02-14 16:12:51 -05:00
// PropagateSymbolChangesBackToLoader is a temporary shim function
// that copies over a given sym.Symbol into the equivalent representation
// in the loader world. The intent is to enable converting a given
// linker phase/pass from dealing with sym.Symbol's to a modernized
// pass that works with loader.Sym, in cases where the "loader.Sym
// wavefront" has not yet reached the pass in question. For such work
// the recipe is to first call PropagateSymbolChangesBackToLoader(),
// then exexute the pass working with the loader, then call
// PropagateLoaderChangesToSymbols to copy the changes made by the
// pass back to the sym.Symbol world.
func ( l * Loader ) PropagateSymbolChangesBackToLoader ( ) {
// For the moment we only copy symbol values, and we don't touch
// any new sym.Symbols created since loadlibfull() was run. This
// seems to be what's needed for DWARF gen.
for i := Sym ( 1 ) ; i < Sym ( len ( l . objSyms ) ) ; i ++ {
s := l . Syms [ i ]
if s != nil {
if s . Value != l . SymValue ( i ) {
l . SetSymValue ( i , s . Value )
}
}
}
}
// PropagateLoaderChangesToSymbols is a temporary shim function that
// takes a list of loader.Sym symbols and works to copy their contents
// and attributes over to a corresponding sym.Symbol. See the
// PropagateSymbolChangesBackToLoader header comment for more info.
//
// WARNING: this function is brittle and depends heavily on loader
// implementation. A key problem with doing this is that as things
// stand at the moment, some sym.Symbol contents/attributes are
// populated only when converting from loader.Sym to sym.Symbol
// in loadlibfull, meaning if we may wipe out some information
// when copying back.
func ( l * Loader ) PropagateLoaderChangesToSymbols ( toconvert [ ] Sym , syms * sym . Symbols ) [ ] * sym . Symbol {
result := [ ] * sym . Symbol { }
relocfixup := [ ] Sym { }
// Note: this loop needs to allow for the possibility that we may
// see "new" symbols on the 'toconvert' list that come from object
// files (for example, DWARF location lists), as opposed to just
// newly manufactured symbols (ex: DWARF section symbols such as
// ".debug_info"). This means that we have to be careful not to
// stomp on sym.Symbol attributes/content that was set up in
// in loadlibfull().
// Also note that in order for the relocation fixup to work, we
// have to do this in two passes -- one pass to create the symbols,
// and then a second fix up the relocations once all necessary
// sym.Symbols are created.
// First pass, symbol creation and symbol data fixup.
anonVerReplacement := syms . IncVersion ( )
rslice := [ ] Reloc { }
for _ , cand := range toconvert {
sn := l . SymName ( cand )
sv := l . SymVersion ( cand )
[dev.link] cmd/link: demote dwarf {range,loc} sub-symbols to aux
When the compiler emits DWARF for a function F, in addition to the
text symbol for F, it emits a set of sibling or child symbols that
carry the various DWARF bits for F (for example, go.info.F,
go.ranges.F, go.loc.F, and so on).
Prior to the linker modernization work, name lookup was the way you
made your way from a function symbol to one of its child DWARF
symbols. We now have a new mechanism (aux symbols), so there is really
no need for the DWARF sub-symbols to be named or to be dupok.
This patch converts DWARF "range" and "loc" sub-symbols to be pure aux
syms: unnamed, and connected to their parent text symbol only via aux
data. This should presumably have performance benefits in that we add
fewer symbols to the linker lookup tables.
Other related DWARF sub-symbols (ex: go.line.*) will be handled in a
subsequent patch.
Change-Id: Iae3ec2d42452962d4afc1df4a1bd89ccdeadc6e4
Reviewed-on: https://go-review.googlesource.com/c/go/+/222673
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2020-03-09 11:42:03 -04:00
st := l . SymType ( cand )
2020-02-14 16:12:51 -05:00
if sv < 0 {
sv = anonVerReplacement
}
s := l . Syms [ cand ]
isnew := false
if sn == "" {
// Don't install anonymous symbols in the lookup tab.
if s == nil {
[dev.link] cmd/link: demote dwarf {range,loc} sub-symbols to aux
When the compiler emits DWARF for a function F, in addition to the
text symbol for F, it emits a set of sibling or child symbols that
carry the various DWARF bits for F (for example, go.info.F,
go.ranges.F, go.loc.F, and so on).
Prior to the linker modernization work, name lookup was the way you
made your way from a function symbol to one of its child DWARF
symbols. We now have a new mechanism (aux symbols), so there is really
no need for the DWARF sub-symbols to be named or to be dupok.
This patch converts DWARF "range" and "loc" sub-symbols to be pure aux
syms: unnamed, and connected to their parent text symbol only via aux
data. This should presumably have performance benefits in that we add
fewer symbols to the linker lookup tables.
Other related DWARF sub-symbols (ex: go.line.*) will be handled in a
subsequent patch.
Change-Id: Iae3ec2d42452962d4afc1df4a1bd89ccdeadc6e4
Reviewed-on: https://go-review.googlesource.com/c/go/+/222673
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2020-03-09 11:42:03 -04:00
s = l . allocSym ( sn , sv )
2020-02-14 16:12:51 -05:00
l . installSym ( cand , s )
}
isnew = true
} else {
if s != nil {
// Already have a symbol for this -- it must be
// something that was previously processed by
// loadObjFull. Note that the symbol in question may
// or may not be in the name lookup map.
} else {
isnew = true
s = syms . Lookup ( sn , sv )
}
}
result = append ( result , s )
// Always copy these from new to old.
s . Value = l . SymValue ( cand )
[dev.link] cmd/link: demote dwarf {range,loc} sub-symbols to aux
When the compiler emits DWARF for a function F, in addition to the
text symbol for F, it emits a set of sibling or child symbols that
carry the various DWARF bits for F (for example, go.info.F,
go.ranges.F, go.loc.F, and so on).
Prior to the linker modernization work, name lookup was the way you
made your way from a function symbol to one of its child DWARF
symbols. We now have a new mechanism (aux symbols), so there is really
no need for the DWARF sub-symbols to be named or to be dupok.
This patch converts DWARF "range" and "loc" sub-symbols to be pure aux
syms: unnamed, and connected to their parent text symbol only via aux
data. This should presumably have performance benefits in that we add
fewer symbols to the linker lookup tables.
Other related DWARF sub-symbols (ex: go.line.*) will be handled in a
subsequent patch.
Change-Id: Iae3ec2d42452962d4afc1df4a1bd89ccdeadc6e4
Reviewed-on: https://go-review.googlesource.com/c/go/+/222673
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2020-03-09 11:42:03 -04:00
s . Type = st
2020-02-14 16:12:51 -05:00
// If the data for a symbol has increased in size, make sure
// we bring the new content across.
relfix := isnew
if isnew || len ( l . Data ( cand ) ) > len ( s . P ) {
s . P = l . Data ( cand )
s . Size = int64 ( len ( s . P ) )
relfix = true
}
// For 'new' symbols, copy other content (such as Gotype,
// sym file, relocations, etc).
if isnew {
if gt := l . SymGoType ( cand ) ; gt != 0 {
s . Gotype = l . Syms [ gt ]
}
if f , ok := l . symFile [ cand ] ; ok {
s . File = f
} else {
r , _ := l . toLocal ( cand )
if r != nil && r != l . extReader {
s . File = l . SymFile ( cand )
}
}
}
// If this symbol has any DWARF file relocations, we need to
// make sure that the relocations are copied back over, since
[dev.link] cmd/link: demote dwarf {range,loc} sub-symbols to aux
When the compiler emits DWARF for a function F, in addition to the
text symbol for F, it emits a set of sibling or child symbols that
carry the various DWARF bits for F (for example, go.info.F,
go.ranges.F, go.loc.F, and so on).
Prior to the linker modernization work, name lookup was the way you
made your way from a function symbol to one of its child DWARF
symbols. We now have a new mechanism (aux symbols), so there is really
no need for the DWARF sub-symbols to be named or to be dupok.
This patch converts DWARF "range" and "loc" sub-symbols to be pure aux
syms: unnamed, and connected to their parent text symbol only via aux
data. This should presumably have performance benefits in that we add
fewer symbols to the linker lookup tables.
Other related DWARF sub-symbols (ex: go.line.*) will be handled in a
subsequent patch.
Change-Id: Iae3ec2d42452962d4afc1df4a1bd89ccdeadc6e4
Reviewed-on: https://go-review.googlesource.com/c/go/+/222673
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2020-03-09 11:42:03 -04:00
// DWARF-gen alters the offset values for these relocs. Also:
// if this is an info symbol and it refers to a previously
// unseen range/loc symbol, we'll need to fix up relocations
// for it as well.
2020-02-14 16:12:51 -05:00
relocs := l . Relocs ( cand )
rslice = relocs . ReadSyms ( rslice )
for ri := range rslice {
if rslice [ ri ] . Type == objabi . R_DWARFFILEREF {
relfix = true
break
}
[dev.link] cmd/link: demote dwarf {range,loc} sub-symbols to aux
When the compiler emits DWARF for a function F, in addition to the
text symbol for F, it emits a set of sibling or child symbols that
carry the various DWARF bits for F (for example, go.info.F,
go.ranges.F, go.loc.F, and so on).
Prior to the linker modernization work, name lookup was the way you
made your way from a function symbol to one of its child DWARF
symbols. We now have a new mechanism (aux symbols), so there is really
no need for the DWARF sub-symbols to be named or to be dupok.
This patch converts DWARF "range" and "loc" sub-symbols to be pure aux
syms: unnamed, and connected to their parent text symbol only via aux
data. This should presumably have performance benefits in that we add
fewer symbols to the linker lookup tables.
Other related DWARF sub-symbols (ex: go.line.*) will be handled in a
subsequent patch.
Change-Id: Iae3ec2d42452962d4afc1df4a1bd89ccdeadc6e4
Reviewed-on: https://go-review.googlesource.com/c/go/+/222673
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2020-03-09 11:42:03 -04:00
if st != sym . SDWARFINFO {
continue
}
rst := l . SymType ( rslice [ ri ] . Sym )
if rst == sym . SDWARFRANGE || rst == sym . SDWARFLOC {
relfix = true
break
}
2020-02-14 16:12:51 -05:00
}
if relfix {
relocfixup = append ( relocfixup , cand )
}
// If new symbol, call a helper to migrate attributes.
// Otherwise touch only not-in-symbol-table, since there are
// some attrs that are only set up at the point where we
// convert loader.Sym to sym.Symbol.
if isnew {
l . migrateAttributes ( cand , s )
} else {
if l . AttrNotInSymbolTable ( cand ) {
s . Attr . Set ( sym . AttrNotInSymbolTable , true )
}
}
}
// Second pass to fix up relocations.
for _ , cand := range relocfixup {
s := l . Syms [ cand ]
relocs := l . Relocs ( cand )
rslice = relocs . ReadAll ( rslice )
s . R = make ( [ ] sym . Reloc , len ( rslice ) )
l . convertRelocations ( rslice , s , true )
}
return result
}
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.
2020-02-12 17:20:00 -05:00
func ( l * Loader ) ExtractSymbols ( syms * sym . Symbols , rp map [ * sym . Symbol ] * sym . Symbol ) {
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
}
2020-02-26 00:58:29 -05:00
syms . Allsym = append ( syms . Allsym , s ) // XXX still add to Allsym for now, as there are code looping through Allsym
2019-11-25 14:07:59 -05:00
if s . Version < 0 {
s . Version = int16 ( anonVerReplacement )
}
2019-10-17 11:06:11 -04:00
}
2020-02-12 17:20:00 -05:00
for i , s := range l . Reachparent {
if i == 0 {
continue
}
rp [ l . Syms [ i ] ] = l . Syms [ s ]
}
2020-02-26 00:58:29 -05:00
// Provide lookup functions for sym.Symbols.
syms . Lookup = func ( name string , ver int ) * sym . Symbol {
i := l . LookupOrCreateSym ( name , ver )
if s := l . Syms [ i ] ; s != nil {
return s
}
s := l . allocSym ( name , ver )
l . installSym ( i , s )
syms . Allsym = append ( syms . Allsym , s ) // XXX see above
return s
}
syms . ROLookup = func ( name string , ver int ) * sym . Symbol {
i := l . Lookup ( name , ver )
return l . Syms [ i ]
}
syms . Rename = func ( old , new string , ver int ) {
// annoying... maybe there is a better way to do this
if ver >= 2 {
panic ( "cannot rename static symbol" )
}
i := l . Lookup ( old , ver )
s := l . Syms [ i ]
s . Name = new
if s . Extname ( ) == old {
s . SetExtname ( new )
}
delete ( l . symsByName [ ver ] , old )
// This mirrors the old code. But I'm not sure if the logic of
// handling dup in the old code actually works, or necessary.
dupi := l . symsByName [ ver ] [ new ]
dup := l . Syms [ dupi ]
if dup == nil {
l . symsByName [ ver ] [ new ] = i
} else {
if s . Type == 0 {
dup . Attr |= s . Attr
* s = * dup
} else if dup . Type == 0 {
s . Attr |= dup . Attr
* dup = * s
l . symsByName [ ver ] [ new ] = i
}
}
}
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 {
nr := 0
2019-09-17 16:14:37 -04:00
for i , n := 0 , r . NSym ( ) + r . NNonpkgdef ( ) ; i < n ; i ++ {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
gi := r . syms [ i ]
2020-02-07 10:26:06 -05:00
if r2 , i2 := l . toLocal ( gi ) ; r2 != r || i2 != i {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
continue // come from a different object
}
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-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
}
2020-03-03 22:50:34 -05:00
if ! l . attrReachable . Has ( gi ) && name != "runtime.addmoduledata" && name != "runtime.lastmoduledatap" {
2019-09-28 22:42:35 -04:00
// No need to load unreachable symbols.
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
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
s := l . addNewSym ( gi , name , ver , r . unit , t )
l . migrateAttributes ( gi , s )
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-12-16 14:14:29 -05:00
// cloneToExternal takes the existing object file symbol (symIdx)
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
// and creates a new external symbol payload 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 an external symbol
// payload.
// XXX maybe rename? makeExtPayload?
func ( l * Loader ) cloneToExternal ( symIdx Sym ) {
2019-12-16 14:14:29 -05:00
if l . IsExternal ( symIdx ) {
panic ( "sym is already external, no need for clone" )
}
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
l . growSyms ( int ( symIdx ) )
2019-12-16 14:14:29 -05:00
// 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.
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
pi := l . newPayload ( sname , sver )
pp := l . payloads [ pi ]
2019-12-16 14:14:29 -05:00
pp . kind = skind
pp . ver = sver
pp . size = int64 ( osym . Siz )
2020-03-04 11:32:46 -05:00
pp . objidx = r . objidx
2019-12-16 14:14:29 -05:00
// 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 )
}
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 )
}
}
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
// Install new payload to global index space.
// (This needs to happen at the end, as the accessors above
// need to access the old symbol content.)
l . objSyms [ symIdx ] = objSym { l . extReader , pi }
l . extReader . syms = append ( l . extReader . syms , symIdx )
2019-12-16 14:14:29 -05:00
}
2019-12-06 20:11:36 -05:00
// copyAttributes copies over all of the attributes of symbol 'src' to
// symbol 'dst'. The assumption is that 'dst' is an external symbol.
func ( l * Loader ) copyAttributes ( src Sym , dst Sym ) {
l . SetAttrReachable ( dst , l . AttrReachable ( src ) )
l . SetAttrOnList ( dst , l . AttrOnList ( src ) )
l . SetAttrLocal ( dst , l . AttrLocal ( src ) )
2020-01-07 15:47:43 -05:00
l . SetAttrNotInSymbolTable ( dst , l . AttrNotInSymbolTable ( src ) )
2019-12-06 20:11:36 -05:00
l . SetAttrVisibilityHidden ( dst , l . AttrVisibilityHidden ( src ) )
l . SetAttrDuplicateOK ( dst , l . AttrDuplicateOK ( src ) )
l . SetAttrShared ( dst , l . AttrShared ( src ) )
l . SetAttrExternal ( dst , l . AttrExternal ( src ) )
l . SetAttrTopFrame ( dst , l . AttrTopFrame ( src ) )
l . SetAttrSpecial ( dst , l . AttrSpecial ( src ) )
l . SetAttrCgoExportDynamic ( dst , l . AttrCgoExportDynamic ( src ) )
l . SetAttrCgoExportStatic ( dst , l . AttrCgoExportStatic ( src ) )
2020-01-22 15:24:39 -05:00
l . SetAttrReadOnly ( dst , l . AttrReadOnly ( src ) )
2019-12-06 20:11:36 -05:00
}
// migrateAttributes copies over all of the attributes of symbol 'src' to
// sym.Symbol 'dst'.
func ( l * Loader ) migrateAttributes ( src Sym , dst * sym . Symbol ) {
dst . Attr . Set ( sym . AttrReachable , l . AttrReachable ( src ) )
dst . Attr . Set ( sym . AttrOnList , l . AttrOnList ( src ) )
dst . Attr . Set ( sym . AttrLocal , l . AttrLocal ( src ) )
2020-01-07 15:47:43 -05:00
dst . Attr . Set ( sym . AttrNotInSymbolTable , l . AttrNotInSymbolTable ( src ) )
2020-02-19 09:44:23 -05:00
dst . Attr . Set ( sym . AttrNoSplit , l . IsNoSplit ( src ) )
2019-12-06 20:11:36 -05:00
dst . Attr . Set ( sym . AttrVisibilityHidden , l . AttrVisibilityHidden ( src ) )
dst . Attr . Set ( sym . AttrDuplicateOK , l . AttrDuplicateOK ( src ) )
dst . Attr . Set ( sym . AttrShared , l . AttrShared ( src ) )
dst . Attr . Set ( sym . AttrExternal , l . AttrExternal ( src ) )
dst . Attr . Set ( sym . AttrTopFrame , l . AttrTopFrame ( src ) )
dst . Attr . Set ( sym . AttrSpecial , l . AttrSpecial ( src ) )
dst . Attr . Set ( sym . AttrCgoExportDynamic , l . AttrCgoExportDynamic ( src ) )
dst . Attr . Set ( sym . AttrCgoExportStatic , l . AttrCgoExportStatic ( src ) )
2020-01-22 15:24:39 -05:00
dst . Attr . Set ( sym . AttrReadOnly , l . AttrReadOnly ( src ) )
2019-12-06 20:11:36 -05:00
// Convert outer/sub relationships
if outer , ok := l . outer [ src ] ; ok {
dst . Outer = l . Syms [ outer ]
}
if sub , ok := l . sub [ src ] ; ok {
dst . Sub = l . Syms [ sub ]
}
// Set sub-symbol attribute. FIXME: would be better to do away
// with this and just use l.OuterSymbol() != 0 elsewhere within
// the linker.
dst . Attr . Set ( sym . AttrSubSymbol , dst . Outer != nil )
// Copy over dynimplib, dynimpvers, extname.
if l . SymExtname ( src ) != "" {
dst . SetExtname ( l . SymExtname ( src ) )
}
if l . SymDynimplib ( src ) != "" {
dst . SetDynimplib ( l . SymDynimplib ( src ) )
}
if l . SymDynimpvers ( src ) != "" {
dst . SetDynimpvers ( l . SymDynimpvers ( src ) )
}
// Copy ELF type if set.
if et , ok := l . elfType [ src ] ; ok {
dst . SetElfType ( et )
}
2020-01-27 15:31:41 -05:00
// Copy pe objects values if set.
if plt , ok := l . plt [ src ] ; ok {
dst . SetPlt ( plt )
}
if got , ok := l . got [ src ] ; ok {
dst . SetGot ( got )
}
2019-12-06 20:11:36 -05:00
}
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-10-04 22:05:41 -04:00
func loadObjFull ( l * Loader , r * oReader ) {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
lib := r . unit . Lib
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 ++ {
2020-02-03 12:37:35 -05:00
// A symbol may be a dup or overwritten. In this case, its
// content will actually be provided by a different object
// (to which its global index points). Skip those symbols.
gi := l . toGlobal ( r , i )
var isdup bool
if r2 , i2 := l . toLocal ( gi ) ; r2 != r || i2 != i {
isdup = true
}
2019-10-04 22:05:41 -04:00
osym := goobj2 . Sym { }
2020-02-07 11:02:42 -05:00
osym . ReadWithoutName ( r . Reader , r . SymOff ( i ) )
2019-10-14 11:17:18 -04:00
dupok := osym . Dupok ( )
2020-02-03 12:37:35 -05:00
if dupok && isdup {
2020-02-25 15:15:11 -05:00
if l . attrReachable . Has ( gi ) {
2020-02-03 12:37:35 -05: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 [ gi ]
if s . Type == sym . STEXT {
lib . DupTextSyms = append ( lib . DupTextSyms , s )
2019-10-11 17:43:32 -04:00
}
}
2020-02-03 12:37:35 -05:00
continue
2019-10-11 17:43:32 -04:00
}
2020-02-03 12:37:35 -05:00
if isdup {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
continue // come from a different object
}
s := l . Syms [ gi ]
2019-10-11 17:43:32 -04:00
if s == nil {
continue
}
2019-10-04 22:05:41 -04:00
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 : ]
2020-02-14 16:12:51 -05:00
l . convertRelocations ( rslice , s , false )
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 )
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 )
2020-02-17 01:27:11 -05:00
if osym . NoSplit ( ) {
2019-09-17 16:14:37 -04:00
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 )
} 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-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,
2020-02-14 16:12:51 -05:00
// etc. It is assumed that the caller has pre-allocated the dst symbol
// relocations slice. If 'strict' is set, then this method will
// panic if it finds a relocation targeting a nil symbol.
func ( l * Loader ) convertRelocations ( src [ ] Reloc , dst * sym . Symbol , strict bool ) {
2019-12-16 14:14:29 -05:00
for j := range dst . R {
r := src [ j ]
rs := r . Sym
sz := r . Size
rt := r . Type
if rt == objabi . R_METHODOFF {
2020-02-25 15:15:11 -05:00
if l . attrReachable . Has ( rs ) {
2019-12-16 14:14:29 -05:00
rt = objabi . R_ADDROFF
} else {
sz = 0
rs = 0
}
}
2020-02-25 15:15:11 -05:00
if rt == objabi . R_WEAKADDROFF && ! l . attrReachable . Has ( rs ) {
2019-12-16 14:14:29 -05:00
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
}
2020-02-14 16:12:51 -05:00
if strict && rs != 0 && l . Syms [ rs ] == nil && rt != objabi . R_USETYPE {
panic ( "nil reloc target in convertRelocations" )
}
2019-12-16 14:14:29 -05:00
dst . R [ j ] = sym . Reloc {
Off : r . Off ,
Siz : sz ,
Type : rt ,
Add : r . Add ,
Sym : l . Syms [ rs ] ,
}
}
}
2019-12-06 20:11:36 -05:00
// UndefinedRelocTargets iterates through the global symbol index
// space, looking for symbols with relocations targeting undefined
// references. The linker's loadlib method uses this to determine if
// there are unresolved references to functions in system libraries
// (for example, libgcc.a), presumably due to CGO code. Return
// value is a list of loader.Sym's corresponding to the undefined
// cross-refs. The "limit" param controls the maximum number of
// results returned; if "limit" is -1, then all undefs are returned.
func ( l * Loader ) UndefinedRelocTargets ( limit int ) [ ] Sym {
result := [ ] Sym { }
rslice := [ ] Reloc { }
2020-02-05 16:52:12 -05:00
for si := Sym ( 1 ) ; si < Sym ( len ( l . objSyms ) ) ; si ++ {
2019-12-06 20:11:36 -05:00
relocs := l . Relocs ( si )
2020-02-07 10:26:06 -05:00
rslice = relocs . ReadSyms ( rslice )
2019-12-06 20:11:36 -05:00
for ri := 0 ; ri < relocs . Count ; ri ++ {
r := & rslice [ ri ]
if r . Sym != 0 && l . SymType ( r . Sym ) == sym . SXREF && l . RawSymName ( r . Sym ) != ".got" {
result = append ( result , r . Sym )
if limit != - 1 && len ( result ) >= limit {
break
}
}
}
}
return result
}
2019-11-20 10:43:11 -05:00
// AssignTextSymbolOrder populates the Textp2 slices within each
// library and compilation unit, insuring that packages are laid down
2020-02-25 09:07:39 -05:00
// in dependency order (internal first, then everything else). Return value
// is a slice of all text syms.
func ( l * Loader ) AssignTextSymbolOrder ( libs [ ] * sym . Library , intlibs [ ] bool , extsyms [ ] Sym ) [ ] Sym {
2019-11-20 10:43:11 -05:00
// Library Textp2 lists should be empty at this point.
for _ , lib := range libs {
if len ( lib . Textp2 ) != 0 {
panic ( "expected empty Textp2 slice for library" )
}
if len ( lib . DupTextSyms2 ) != 0 {
panic ( "expected empty DupTextSyms2 slice for library" )
}
}
// Used to record which dupok symbol we've assigned to a unit.
// Can't use the onlist attribute here because it will need to
// clear for the later assignment of the sym.Symbol to a unit.
// NB: we can convert to using onList once we no longer have to
// call the regular addToTextp.
2020-02-25 15:15:11 -05:00
assignedToUnit := MakeBitmap ( l . NSym ( ) + 1 )
2019-11-20 10:43:11 -05:00
2020-02-25 09:07:39 -05:00
// Start off textp2 with reachable external syms.
textp2 := [ ] Sym { }
for _ , sym := range extsyms {
if ! l . attrReachable . Has ( sym ) {
continue
}
textp2 = append ( textp2 , sym )
}
2019-11-20 10:43:11 -05:00
// Walk through all text symbols from Go object files and append
// them to their corresponding library's textp2 list.
for _ , o := range l . objs [ 1 : ] {
r := o . r
lib := r . unit . Lib
for i , n := 0 , r . NSym ( ) + r . NNonpkgdef ( ) ; i < n ; i ++ {
gi := l . toGlobal ( r , i )
2020-02-25 09:07:39 -05:00
if ! l . attrReachable . Has ( gi ) {
continue
}
2019-11-20 10:43:11 -05:00
osym := goobj2 . Sym { }
osym . ReadWithoutName ( r . Reader , r . SymOff ( i ) )
st := sym . AbiSymKindToSymKind [ objabi . SymKind ( osym . Type ) ]
if st != sym . STEXT {
continue
}
2020-02-25 09:07:39 -05:00
dupok := osym . Dupok ( )
2019-11-20 10:43:11 -05:00
if r2 , i2 := l . toLocal ( gi ) ; r2 != r || i2 != i {
2020-02-25 09:07:39 -05:00
// A dupok text 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.
lib . DupTextSyms2 = append ( lib . DupTextSyms2 , sym . LoaderSym ( gi ) )
2019-11-20 10:43:11 -05:00
continue // symbol in different object
}
2020-02-25 09:07:39 -05:00
if dupok {
lib . DupTextSyms2 = append ( lib . DupTextSyms2 , sym . LoaderSym ( gi ) )
}
2019-11-20 10:43:11 -05:00
lib . Textp2 = append ( lib . Textp2 , sym . LoaderSym ( gi ) )
}
}
// Now redo the assignment of text symbols to libs/units.
for _ , doInternal := range [ 2 ] bool { true , false } {
for idx , lib := range libs {
if intlibs [ idx ] != doInternal {
continue
}
libtextp2 := [ ] sym . LoaderSym { }
2020-02-25 09:07:39 -05:00
lists := [ 2 ] [ ] sym . LoaderSym { lib . Textp2 , lib . DupTextSyms2 }
for _ , list := range lists {
for _ , s := range list {
2019-11-20 10:43:11 -05:00
sym := Sym ( s )
2020-02-25 15:15:11 -05:00
if l . attrReachable . Has ( sym ) && ! assignedToUnit . Has ( sym ) {
2019-11-20 10:43:11 -05:00
libtextp2 = append ( libtextp2 , s )
2020-02-25 09:07:39 -05:00
textp2 = append ( textp2 , sym )
2019-11-20 10:43:11 -05:00
unit := l . SymUnit ( sym )
if unit != nil {
unit . Textp2 = append ( unit . Textp2 , s )
2020-02-25 15:15:11 -05:00
assignedToUnit . Set ( sym )
2019-11-20 10:43:11 -05:00
}
}
}
}
lib . Textp2 = libtextp2
}
}
2020-02-14 16:12:51 -05:00
2020-02-25 09:07:39 -05:00
return textp2
2019-11-20 10:43:11 -05:00
}
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 )
2020-02-05 16:52:12 -05:00
fmt . Println ( "Nsyms:" , len ( l . objSyms ) )
2019-10-16 15:44:04 -04:00
fmt . Println ( "syms" )
2019-11-20 10:43:11 -05:00
for i := Sym ( 1 ) ; i < Sym ( len ( l . objSyms ) ) ; i ++ {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
pi := interface { } ( "" )
if l . IsExternal ( i ) {
pi = fmt . Sprintf ( "<ext %d>" , l . extIndex ( i ) )
}
var s * sym . Symbol
if int ( i ) < len ( l . Syms ) {
s = l . Syms [ i ]
2019-10-16 15:44:04 -04:00
}
if s != nil {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
fmt . Println ( i , s , s . Type , pi )
2019-10-16 15:44:04 -04:00
} else {
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
fmt . Println ( i , l . SymName ( i ) , "<not loaded>" , pi )
2019-10-16 15:44:04 -04:00
}
}
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
}
[dev.link] cmd/link: make symbol's global index unique
Currently, when mapping symbol's local index to global index, for
duplicated and overwriting/overwritten symbols, each appearance
of the symbol gets a global index, with one being the "primary",
and others "redirect" to it through the overwrite map. Basically,
the local-global index mapping is one to one, with overwrite/
dedup happening in global index level.
This has a few drawbacks:
- All symbol accesses effectively need to query the overwrite
map. This may hurt performance.
- For multi-level overwrites, (Y overwrites X, Z overwrites Y),
this can get quite complicated, and we have to follow the
redirection recursively.
- Failed to follow or to update the overwrite map leads to bugs.
In this CL, we change the index mapping mechanism so that each
symbol get a unique global index. Multiple appearances of the
same symbol get the same index. Now the local-global index
mapping is N to one. Overwrite/dedup happens directly in the
local-global mapping.
We keep both mapping directions in arrays. Each object carries
an array for its local-global mapping. The loader carries an
array mapping global index to the "primary" local index, which is
the one we should load from. This way, we can get rid of the
overwrite map, and index conversions are simply array accesses.
TODO: we still make reservation of the index space upfront, and
leave holes for dup symbols. Maybe get rid of the reservation and
holes.
Change-Id: Ia251489d5f2ff16a0b3156a71d141a70cdf03a4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/217064
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-01-28 18:18:58 -05:00
fmt . Println ( "payloads:" )
for i := range l . payloads {
pp := l . payloads [ i ]
fmt . Println ( i , pp . name , pp . ver , pp . kind )
}
2019-10-16 15:44:04 -04:00
}