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"
2020-08-02 19:36:28 -04:00
"cmd/internal/goobj"
2019-09-17 16:14:37 -04:00
"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"
"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-08-02 19:36:28 -04:00
rs [ ] goobj . Reloc
2019-10-11 08:56:19 -04:00
2020-05-12 20:08:27 -04:00
li uint32 // local index of symbol whose relocs we're examining
2019-10-11 08:56:19 -04:00
r * oReader // object reader for containing package
l * Loader // loader
}
2020-04-26 01:42:55 -04:00
// ExtReloc contains the payload for an external relocation.
type ExtReloc struct {
Xsym Sym
Xadd int64
2020-07-28 21:35:53 -04:00
Type objabi . RelocType
Size uint8
2020-04-30 21:15:54 -04:00
}
2020-07-29 13:26:50 -04:00
// Reloc holds a "handle" to access a relocation record from an
2020-03-05 11:29:24 -05:00
// object file.
2020-07-29 13:26:50 -04:00
type Reloc struct {
2020-08-02 19:36:28 -04:00
* goobj . Reloc
2020-03-05 11:29:24 -05:00
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.
2020-08-02 19:36:28 -04:00
// Store it here, instead of in the byte of goobj.Reloc.
2020-04-23 09:18:44 -04:00
// For Go symbols this will always be zero.
2020-08-02 19:36:28 -04:00
// goobj.Reloc.Type() + typ is always the right type, for both Go and external
2020-03-13 11:43:35 -04:00
// symbols.
typ objabi . RelocType
2020-03-05 11:29:24 -05:00
}
2020-07-29 13:26:50 -04:00
func ( rel Reloc ) Type ( ) objabi . RelocType { return objabi . RelocType ( rel . Reloc . Type ( ) ) + rel . typ }
func ( rel Reloc ) Sym ( ) Sym { return rel . l . resolve ( rel . r , rel . Reloc . Sym ( ) ) }
2020-08-02 19:36:28 -04:00
func ( rel Reloc ) SetSym ( s Sym ) { rel . Reloc . SetSym ( goobj . SymRef { PkgIdx : 0 , SymIdx : uint32 ( s ) } ) }
2020-03-28 16:46:47 -04:00
2020-07-29 13:26:50 -04:00
func ( rel Reloc ) SetType ( t objabi . RelocType ) {
2020-03-28 16:46:47 -04:00
if t != objabi . RelocType ( uint8 ( t ) ) {
2020-07-29 13:26:50 -04:00
panic ( "SetType: type doesn't fit into Reloc" )
2020-03-28 16:46:47 -04:00
}
2020-04-09 20:45:14 -04:00
rel . Reloc . SetType ( uint8 ( t ) )
2020-04-23 09:18:44 -04:00
if rel . typ != 0 {
// should use SymbolBuilder.SetRelocType
panic ( "wrong method to set reloc type" )
}
2020-03-28 16:46:47 -04:00
}
2020-03-05 11:29:24 -05:00
2020-07-29 13:26:50 -04:00
// Aux holds a "handle" to access an aux symbol record from an
2020-03-06 01:15:07 -05:00
// object file.
2020-07-29 13:26:50 -04:00
type Aux struct {
2020-08-02 19:36:28 -04:00
* goobj . Aux
2020-03-06 01:15:07 -05:00
r * oReader
l * Loader
}
2020-07-29 13:26:50 -04:00
func ( a Aux ) Sym ( ) Sym { return a . l . resolve ( a . r , a . Aux . Sym ( ) ) }
2020-03-06 01:15:07 -05:00
2019-09-30 11:43:41 -04:00
// oReader is a wrapper type of obj.Reader, along with some
// extra information.
type oReader struct {
2020-08-02 19:36:28 -04:00
* goobj . Reader
2020-07-13 15:05:09 -04:00
unit * sym . CompilationUnit
version int // version of static symbol
flags uint32 // read from object file
pkgprefix string
syms [ ] Sym // Sym's global index, indexed by local index
2020-08-02 19:36:28 -04:00
ndef int // cache goobj.Reader.NSym()
nhashed64def int // cache goobj.Reader.NHashed64Def()
nhasheddef int // cache goobj.Reader.NHashedDef()
2020-07-13 15:05:09 -04:00
objidx uint32 // index of this reader in the objs slice
2019-09-30 11:43:41 -04:00
}
2020-07-10 18:49:01 -04:00
// Total number of defined symbols (package symbols, hashed symbols, and
// non-package symbols).
2020-07-13 15:05:09 -04:00
func ( r * oReader ) NAlldef ( ) int { return r . ndef + r . nhashed64def + r . nhasheddef + r . NNonpkgdef ( ) }
2020-07-10 18:49:01 -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.
2020-05-12 20:08:27 -04:00
// For external symbols, objidx is the index of l.extReader (extObj),
// s is its index into the payload array.
// {0, 0} represents the nil symbol.
[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
type objSym struct {
2020-05-12 20:08:27 -04:00
objidx uint32 // index of the object (in l.objs array)
s uint32 // local index
[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
}
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-04-24 22:45:05 -04:00
// return the number of bits set.
func ( bm Bitmap ) Count ( ) int {
s := 0
for _ , x := range bm {
s += bits . OnesCount32 ( x )
}
return s
}
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
}
2020-07-29 19:32:31 -04:00
type symAndSize struct {
sym Sym
size uint32
2020-07-12 17:57:11 -04:00
}
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
//
[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
2020-07-29 19:44:49 -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
2020-04-21 18:50:49 -04:00
sects [ ] * sym . Section // sections
symSects [ ] uint16 // symbol's section, index to sects array
2019-12-11 13:39:39 -05:00
2020-04-30 16:01:03 -04:00
align [ ] uint8 // symbol 2^N alignment, indexed by global index
2020-07-30 17:19:13 -04:00
deferReturnTramp map [ Sym ] bool // whether the symbol is a trampoline of a deferreturn call
2019-10-16 09:29:56 -04:00
2019-09-30 11:43:41 -04:00
objByPkg map [ string ] * oReader // map package path to its Go object reader
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
[dev.link] cmd/compile, cmd/link: remove dead methods if type is not used in interface
Currently, a method of a reachable type is live if it matches a
method of a reachable interface. In fact, we only need to retain
the method if the type is actually converted to an interface. If
the type is never converted to an interface, there is no way to
call the method through an interface method call (but the type
descriptor could still be used, e.g. in calling
runtime.newobject).
A type can be used in an interface in two ways:
- directly converted to interface. (Any interface counts, as it
is possible to convert one interface to another.)
- obtained by reflection from a related type (e.g. obtaining an
interface of T from []T).
For the former, we let the compiler emit a marker on the type
descriptor symbol when it is converted to an interface. In the
linker, we only need to check methods of marked types.
For the latter, when the linker visits a marked type, it needs to
visit all its "child" types as marked (i.e. potentially could be
converted to interface).
This reduces binary size:
cmd/compile 18792016 18706096 (-0.5%)
cmd/go 14120572 13398948 (-5.1%)
Change-Id: I4465c7eeabf575f4dc84017214c610fa05ae31fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/237298
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-06-08 18:38:59 -04:00
attrNotInSymbolTable Bitmap // "not in symtab" symbols, indexed by global idx
attrUsedInIface Bitmap // "used in interface" symbols, indexed by global idx
2020-02-25 15:15:11 -05:00
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
2020-06-19 15:35:28 -04:00
generatedSyms map [ Sym ] struct { } // symbols that generate their content
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
2020-04-28 10:37:33 -04: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
elfSym map [ Sym ] int32 // stores elf sym symbol property
localElfSym map [ Sym ] int32 // stores "local" elf sym symbol property
symPkg map [ Sym ] string // stores package for symbol, or library for shlib-derived syms
plt map [ Sym ] int32 // stores dynimport for pe objects
got map [ Sym ] int32 // stores got for pe objects
dynid map [ Sym ] int32 // stores Dynid for symbol
2019-12-12 08:08:40 -05:00
2020-04-01 15:57:46 -04:00
relocVariant map [ relocId ] sym . RelocVariant // stores variant relocs
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
2019-11-02 00:38:21 -04:00
flags uint32
2020-07-29 18:10:15 -04:00
hasUnknownPkgPath bool // if any Go object has unknown package path
2019-11-02 00:38:21 -04:00
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
2019-12-11 14:36:17 -05:00
elfsetstring elfsetstringFunc
2020-03-19 11:04:37 -04:00
2020-04-22 15:16:06 -04:00
errorReporter * ErrorReporter
2020-07-10 18:49:01 -04:00
2020-07-29 19:44:49 -04:00
npkgsyms int // number of package symbols, for accounting
nhashedsyms int // number of hashed symbols, for accounting
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-07-13 15:05:09 -04:00
hashed64Def
2020-07-10 18:49:01 -04:00
hashedDef
2020-02-11 10:27:15 -05:00
nonPkgDef
nonPkgRef
)
2020-05-12 20:08:27 -04:00
// objidx
const (
nilObj = iota
extObj
goObjStart
)
2020-05-12 17:16:51 -04:00
type elfsetstringFunc func ( str string , off int )
2019-12-11 14:36:17 -05:00
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 {
2020-03-28 16:46:47 -04:00
name string // TODO: would this be better as offset into str table?
size int64
ver int
kind sym . SymKind
objidx uint32 // index of original object if sym made by cloneToExternal
2020-08-02 19:36:28 -04:00
relocs [ ] goobj . Reloc
2020-03-28 16:46:47 -04:00
reltypes [ ] objabi . RelocType // relocation types
data [ ] byte
2020-08-02 19:36:28 -04:00
auxs [ ] goobj . Aux
2019-12-11 13:39:39 -05:00
}
2019-11-02 00:38:21 -04:00
const (
// Loader.flags
FlagStrictDups = 1 << iota
)
2020-04-22 15:16:06 -04:00
func NewLoader ( flags uint32 , elfsetstring elfsetstringFunc , reporter * ErrorReporter ) * Loader {
2020-08-02 19:36:28 -04:00
nbuiltin := goobj . NBuiltin ( )
2020-05-12 20:08:27 -04:00
extReader := & oReader { objidx : extObj }
2020-04-22 15:16:06 -04:00
ldr := & Loader {
2019-12-18 10:57:15 -05:00
start : make ( map [ * oReader ] Sym ) ,
2020-05-12 20:08:27 -04:00
objs : [ ] objIdx { { } , { extReader , 0 } } , // reserve index 0 for nil symbol, 1 for external symbols
objSyms : make ( [ ] objSym , 1 , 100000 ) , // reserve index 0 for nil symbol
extReader : extReader ,
2020-07-10 18:49:01 -04:00
symsByName : [ 2 ] map [ string ] Sym { make ( map [ string ] Sym , 80000 ) , 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 ) ,
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-04-28 10:37:33 -04:00
elfSym : make ( map [ Sym ] int32 ) ,
localElfSym : make ( map [ Sym ] int32 ) ,
2020-04-06 20:56:34 -04:00
symPkg : make ( map [ Sym ] string ) ,
2020-01-27 15:31:41 -05:00
plt : make ( map [ Sym ] int32 ) ,
got : make ( map [ Sym ] int32 ) ,
2020-03-18 14:32:17 -04:00
dynid : 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 { } ) ,
2020-06-19 15:35:28 -04:00
generatedSyms : make ( map [ Sym ] struct { } ) ,
2020-05-14 19:22:59 -04:00
deferReturnTramp : make ( map [ Sym ] bool ) ,
2019-12-18 10:57:15 -05:00
extStaticSyms : make ( map [ nameVer ] Sym ) ,
builtinSyms : make ( [ ] Sym , nbuiltin ) ,
flags : flags ,
2019-12-11 14:36:17 -05:00
elfsetstring : elfsetstring ,
2020-04-22 15:16:06 -04:00
errorReporter : reporter ,
2020-04-21 18:50:49 -04:00
sects : [ ] * sym . Section { nil } , // reserve index 0 for nil section
2019-09-17 16:14:37 -04:00
}
2020-04-22 15:16:06 -04:00
reporter . ldr = ldr
return ldr
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 } )
2020-07-29 18:10:15 -04:00
if r . NeedNameExpansion ( ) && ! r . FromAssembly ( ) {
l . hasUnknownPkgPath = true
}
2019-09-17 16:14:37 -04:00
return i
}
2020-07-29 19:32:31 -04:00
// Add a symbol from an object file, return the global index.
[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-08-02 19:36:28 -04:00
func ( st * loadState ) addSym ( name string , ver int , r * oReader , li uint32 , kind int , osym * goobj . Sym ) Sym {
2020-07-29 19:44:49 -04:00
l := st . l
2019-09-28 22:42:35 -04:00
if l . extStart != 0 {
2020-07-12 17:57:11 -04:00
panic ( "addSym called after external symbol is created" )
2019-09-28 22:42:35 -04:00
}
2020-02-03 12:37:35 -05:00
i := Sym ( len ( l . objSyms ) )
addToGlobal := func ( ) {
2020-05-12 20:08:27 -04:00
l . objSyms = append ( l . objSyms , objSym { r . objidx , 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
}
2020-07-13 15:05:09 -04:00
if name == "" && kind != hashed64Def && kind != hashedDef {
2020-02-03 12:37:35 -05:00
addToGlobal ( )
2020-07-29 19:32:31 -04:00
return i // unnamed aux symbol
[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
}
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 ( )
2020-07-29 19:32:31 -04:00
return i
2019-10-18 11:19:32 -04:00
}
2020-07-10 18:49:01 -04:00
switch kind {
case pkgDef :
2020-02-11 10:27:15 -05:00
// 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 ( )
2020-07-29 19:32:31 -04:00
return i
2020-07-20 18:07:00 -04:00
case hashed64Def , hashedDef :
2020-07-13 15:05:09 -04:00
// Hashed (content-addressable) symbol. Check the hash
// but don't add to name lookup table, as they are not
// referenced by name. Also no need to do overwriting
// check, as same hash indicates same content.
2020-07-29 19:32:31 -04:00
var checkHash func ( ) ( symAndSize , bool )
var addToHashMap func ( symAndSize )
2020-08-02 19:36:28 -04:00
var h64 uint64 // only used for hashed64Def
var h * goobj . HashType // only used for hashedDef
2020-07-20 18:07:00 -04:00
if kind == hashed64Def {
2020-07-29 19:32:31 -04:00
checkHash = func ( ) ( symAndSize , bool ) {
2020-07-20 18:07:00 -04:00
h64 = r . Hash64 ( li - uint32 ( r . ndef ) )
2020-07-29 19:44:49 -04:00
s , existed := st . hashed64Syms [ h64 ]
2020-07-20 18:07:00 -04:00
return s , existed
}
2020-07-29 19:44:49 -04:00
addToHashMap = func ( ss symAndSize ) { st . hashed64Syms [ h64 ] = ss }
2020-07-20 18:07:00 -04:00
} else {
2020-07-29 19:32:31 -04:00
checkHash = func ( ) ( symAndSize , bool ) {
2020-07-20 18:07:00 -04:00
h = r . Hash ( li - uint32 ( r . ndef + r . nhashed64def ) )
2020-07-29 19:44:49 -04:00
s , existed := st . hashedSyms [ * h ]
2020-07-20 18:07:00 -04:00
return s , existed
}
2020-07-29 19:44:49 -04:00
addToHashMap = func ( ss symAndSize ) { st . hashedSyms [ * h ] = ss }
2020-07-20 18:07:00 -04:00
}
2020-07-13 15:05:09 -04:00
siz := osym . Siz ( )
2020-07-20 18:07:00 -04:00
if s , existed := checkHash ( ) ; existed {
// The content hash is built from symbol data and relocations. In the
// object file, the symbol data may not always contain trailing zeros,
// e.g. for [5]int{1,2,3} and [100]int{1,2,3}, the data is same
// (although the size is different).
// Also, for short symbols, the content hash is the identity function of
// the 8 bytes, and trailing zeros doesn't change the hash value, e.g.
2020-07-13 15:05:09 -04:00
// hash("A") == hash("A\0\0\0").
// So when two symbols have the same hash, we need to use the one with
2020-07-20 18:07:00 -04:00
// larger size.
2020-07-29 19:32:31 -04:00
if siz > s . size {
2020-07-13 15:05:09 -04:00
// New symbol has larger size, use the new one. Rewrite the index mapping.
l . objSyms [ s . sym ] = objSym { r . objidx , li }
2020-07-29 19:32:31 -04:00
addToHashMap ( symAndSize { s . sym , siz } )
2020-07-12 17:57:11 -04:00
}
2020-07-29 19:32:31 -04:00
return s . sym
2020-07-10 18:49:01 -04:00
}
2020-07-29 19:32:31 -04:00
addToHashMap ( symAndSize { i , siz } )
2020-07-10 18:49:01 -04:00
addToGlobal ( )
2020-07-29 19:32:31 -04:00
return i
2020-02-11 10:27:15 -05:00
}
// 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 ( )
2020-07-29 19:32:31 -04:00
return i
2020-02-03 12:37:35 -05:00
}
// symbol already exists
2020-07-12 17:57:11 -04:00
if osym . Dupok ( ) {
2020-02-03 12:37:35 -05:00
if l . flags & FlagStrictDups != 0 {
l . checkdup ( name , r , li , oldi )
}
2020-07-29 19:32:31 -04:00
return oldi
2020-02-03 12:37:35 -05:00
}
oldr , oldli := l . toLocal ( oldi )
2020-04-09 20:45:14 -04:00
oldsym := oldr . Sym ( oldli )
2020-02-03 12:37:35 -05:00
if oldsym . Dupok ( ) {
2020-07-29 19:32:31 -04:00
return oldi
2020-02-03 12:37:35 -05:00
}
overwrite := r . DataSize ( li ) != 0
if overwrite {
// new symbol overwrites old symbol.
2020-03-31 20:56:10 -04:00
oldtyp := sym . AbiSymKindToSymKind [ objabi . SymKind ( oldsym . Type ( ) ) ]
2020-02-03 12:37:35 -05:00
if ! ( oldtyp . IsData ( ) && oldr . DataSize ( oldli ) == 0 ) {
log . Fatalf ( "duplicated definition of symbol " + name )
}
2020-05-12 20:08:27 -04:00
l . objSyms [ oldi ] = objSym { r . objidx , li }
2020-02-03 12:37:35 -05:00
} else {
// old symbol overwrites new symbol.
2020-07-12 17:57:11 -04:00
typ := sym . AbiSymKindToSymKind [ objabi . SymKind ( oldsym . Type ( ) ) ]
2020-02-03 12:37:35 -05:00
if ! typ . IsData ( ) { // only allow overwriting data symbol
log . Fatalf ( "duplicated definition of symbol " + name )
2019-09-17 16:14:37 -04:00
}
}
2020-07-29 19:32:31 -04:00
return oldi
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
}
2020-05-11 15:11:36 -04:00
l . growValues ( int ( i ) + 1 )
l . growAttrBitmaps ( int ( i ) + 1 )
[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 )
2020-05-12 20:08:27 -04:00
l . objSyms = append ( l . objSyms , objSym { l . extReader . objidx , uint32 ( pi ) } )
[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 . extReader . syms = append ( l . extReader . syms , i )
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 ]
}
2019-09-17 16:14:37 -04:00
// Convert a local index to a global index.
2020-05-12 20:08:27 -04:00
func ( l * Loader ) toGlobal ( r * oReader , i uint32 ) 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.
2020-05-12 20:08:27 -04:00
func ( l * Loader ) toLocal ( i Sym ) ( * oReader , uint32 ) {
return l . objs [ l . objSyms [ i ] . objidx ] . r , 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.
2020-08-02 19:36:28 -04:00
func ( l * Loader ) resolve ( r * oReader , s goobj . SymRef ) Sym {
2019-09-30 11:43:41 -04:00
var rr * oReader
switch p := s . PkgIdx ; p {
2020-08-02 19:36:28 -04:00
case goobj . 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
2020-08-02 19:36:28 -04:00
case goobj . PkgIdxHashed64 :
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 ]
2020-08-02 19:36:28 -04:00
case goobj . PkgIdxHashed :
2020-07-13 15:05:09 -04:00
i := int ( s . SymIdx ) + r . ndef + r . nhashed64def
return r . syms [ i ]
2020-08-02 19:36:28 -04:00
case goobj . PkgIdxNone :
2020-07-13 15:05:09 -04:00
i := int ( s . SymIdx ) + r . ndef + r . nhashed64def + r . nhasheddef
2020-07-10 18:49:01 -04:00
return r . syms [ i ]
2020-08-02 19:36:28 -04:00
case goobj . PkgIdxBuiltin :
2019-10-18 17:08:35 -04:00
return l . builtinSyms [ s . SymIdx ]
2020-08-02 19:36:28 -04:00
case goobj . PkgIdxSelf :
2019-09-30 11:43:41 -04:00
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
}
2020-05-12 20:08:27 -04:00
return l . toGlobal ( rr , 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-05-12 20:08:27 -04:00
func ( l * Loader ) checkdup ( name string , r * oReader , li uint32 , 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 )
2020-06-08 12:39:56 -04:00
// For the moment, allow DWARF subprogram DIEs for
2019-11-02 00:38:21 -04:00
// 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.
2020-06-08 12:39:56 -04:00
allowed := strings . HasPrefix ( name , "go.info.go.interface" ) ||
2019-11-02 00:38:21 -04:00
strings . HasPrefix ( name , "go.info.go.builtin" ) ||
strings . HasPrefix ( name , "go.debuglines" )
2020-06-08 12:39:56 -04:00
if ! allowed {
2019-11-02 00:38:21 -04:00
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 )
}
2020-04-24 22:45:05 -04:00
// Number of reachable symbols.
func ( l * Loader ) NReachableSym ( ) int {
return l . attrReachable . Count ( )
}
2020-07-16 16:18:49 -04:00
// SymNameLen returns the length of the symbol name, trying hard not to load
// the name.
func ( l * Loader ) SymNameLen ( i Sym ) int {
// Not much we can do about external symbols.
if l . IsExternal ( i ) {
return len ( l . SymName ( i ) )
}
r , li := l . toLocal ( i )
le := r . Sym ( li ) . NameLen ( r . Reader )
if ! r . NeedNameExpansion ( ) {
return le
}
// Just load the symbol name. We don't know how expanded it'll be.
return len ( l . SymName ( i ) )
}
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 )
2020-04-09 20:45:14 -04:00
return r . Sym ( li ) . Name ( r . Reader )
2019-09-28 22:42:35 -04:00
}
// 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 )
2020-05-18 18:20:18 -04:00
name := r . Sym ( li ) . Name ( r . Reader )
if ! r . NeedNameExpansion ( ) {
return name
}
return strings . Replace ( name , "\"\"." , r . pkgprefix , - 1 )
2019-09-28 22:42:35 -04:00
}
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 )
2020-04-09 20:45:14 -04:00
return int ( abiToVer ( r . Sym ( li ) . ABI ( ) , r . version ) )
2019-12-26 13:39:04 -05:00
}
2020-06-30 10:22:13 -04:00
func ( l * Loader ) IsFileLocal ( i Sym ) bool {
return l . SymVersion ( i ) >= sym . SymVerStatic
}
// IsFromAssembly returns true if this symbol is derived from an
// object file generated by the Go assembler.
func ( l * Loader ) IsFromAssembly ( i Sym ) bool {
if l . IsExternal ( i ) {
return false
}
r , _ := l . toLocal ( i )
return r . FromAssembly ( )
}
2020-05-07 22:22:54 -04:00
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 )
2020-04-09 20:45:14 -04:00
return sym . AbiSymKindToSymKind [ objabi . SymKind ( r . Sym ( li ) . Type ( ) ) ]
2019-09-28 22:42:35 -04:00
}
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 ) {
2020-04-08 19:46:00 -04:00
// TODO: do something? External symbols have different representation of attributes.
// For now, ReflectMethod, NoSplit, GoType, and Typelink are used and they 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 )
2020-04-09 20:45:14 -04:00
return r . Sym ( li ) . Flag ( )
2019-10-08 18:21:22 -04:00
}
2020-04-06 15:58:21 -04:00
// Returns the size of the i-th symbol.
func ( l * Loader ) SymSize ( i Sym ) int64 {
if l . IsExternal ( i ) {
pp := l . getPayload ( i )
return pp . size
}
r , li := l . toLocal ( i )
2020-04-09 20:45:14 -04:00
return int64 ( r . Sym ( li ) . Siz ( ) )
2020-04-06 15:58:21 -04:00
}
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
}
}
[dev.link] cmd/compile, cmd/link: remove dead methods if type is not used in interface
Currently, a method of a reachable type is live if it matches a
method of a reachable interface. In fact, we only need to retain
the method if the type is actually converted to an interface. If
the type is never converted to an interface, there is no way to
call the method through an interface method call (but the type
descriptor could still be used, e.g. in calling
runtime.newobject).
A type can be used in an interface in two ways:
- directly converted to interface. (Any interface counts, as it
is possible to convert one interface to another.)
- obtained by reflection from a related type (e.g. obtaining an
interface of T from []T).
For the former, we let the compiler emit a marker on the type
descriptor symbol when it is converted to an interface. In the
linker, we only need to check methods of marked types.
For the latter, when the linker visits a marked type, it needs to
visit all its "child" types as marked (i.e. potentially could be
converted to interface).
This reduces binary size:
cmd/compile 18792016 18706096 (-0.5%)
cmd/go 14120572 13398948 (-5.1%)
Change-Id: I4465c7eeabf575f4dc84017214c610fa05ae31fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/237298
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-06-08 18:38:59 -04:00
// AttrUsedInIface returns true for a type symbol that is used in
// an interface.
func ( l * Loader ) AttrUsedInIface ( i Sym ) bool {
return l . attrUsedInIface . Has ( i )
}
func ( l * Loader ) SetAttrUsedInIface ( i Sym , v bool ) {
if v {
l . attrUsedInIface . Set ( i )
} else {
l . attrUsedInIface . Unset ( i )
}
}
2020-04-23 14:28:20 -04:00
// SymAddr checks that a symbol is reachable, and returns its value.
func ( l * Loader ) SymAddr ( i Sym ) int64 {
if ! l . AttrReachable ( i ) {
panic ( "unreachable symbol in symaddr" )
}
return l . values [ i ]
}
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 )
2020-04-09 20:45:14 -04:00
return r . Sym ( li ) . Dupok ( )
2019-12-11 14:05:14 -05:00
}
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 )
2020-05-18 18:20:18 -04:00
return r . Shared ( )
2019-12-11 14:05:14 -05:00
}
2020-02-25 15:15:11 -05:00
return l . attrShared . Has ( l . extIndex ( i ) )
2019-12-11 14:05:14 -05:00
}
2020-03-20 08:31:38 -04:00
// SetAttrShared sets the "shared" property for an external
// symbol (see AttrShared).
func ( l * Loader ) SetAttrShared ( i Sym , v bool ) {
if ! l . IsExternal ( i ) {
panic ( fmt . Sprintf ( "tried to set shared attr on non-external symbol %d %s" , i , l . SymName ( i ) ) )
}
if v {
l . attrShared . Set ( l . extIndex ( i ) )
} else {
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
}
2020-03-16 13:56:42 -04:00
// SetAttrCgoExportStatic sets the "cgo_export_static" for a symbol
2019-12-11 14:05:14 -05:00
// (see AttrCgoExportStatic).
func ( l * Loader ) SetAttrCgoExportStatic ( i Sym , v bool ) {
if v {
l . attrCgoExportStatic [ i ] = struct { } { }
} else {
delete ( l . attrCgoExportStatic , i )
}
}
2020-06-19 15:35:28 -04:00
// IsGeneratedSym returns true if a symbol's been previously marked as a
// generator symbol through the SetIsGeneratedSym. The functions for generator
// symbols are kept in the Link context.
func ( l * Loader ) IsGeneratedSym ( i Sym ) bool {
_ , ok := l . generatedSyms [ i ]
return ok
}
// SetIsGeneratedSym marks symbols as generated symbols. Data shouldn't be
// stored in generated symbols, and a function is registered and called for
// each of these symbols.
func ( l * Loader ) SetIsGeneratedSym ( i Sym , v bool ) {
if ! l . IsExternal ( i ) {
panic ( "only external symbols can be generated" )
}
if v {
l . generatedSyms [ i ] = struct { } { }
} else {
delete ( l . generatedSyms , i )
}
}
2020-03-24 12:08:36 -04:00
func ( l * Loader ) AttrCgoExport ( i Sym ) bool {
return l . AttrCgoExportDynamic ( i ) || 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 ) {
2020-03-16 13:56:42 -04:00
pp := l . getPayload ( i )
if pp . objidx != 0 {
return l . objs [ pp . objidx ] . r . ReadOnly ( )
}
2019-12-16 14:14:29 -05:00
return false
}
r , _ := l . toLocal ( i )
return r . ReadOnly ( )
}
2020-03-16 13:56:42 -04:00
// SetAttrReadOnly sets the "data is read only" property for a symbol
2019-12-16 14:14:29 -05:00
// (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.
2020-04-22 13:40:22 -04:00
//
// Note that in later stages of the linker, we set Outer(S) to some
// container symbol C, but don't set Sub(C). Thus we have two
// distinct scenarios:
//
// - Outer symbol covers the address ranges of its sub-symbols.
// Outer.Sub is set in this case.
// - Outer symbol doesn't conver the address ranges. It is zero-sized
// and doesn't have sub-symbols. In the case, the inner symbol is
// not actually a "SubSymbol". (Tricky!)
//
// This method returns TRUE only for sub-symbols in the first scenario.
//
// FIXME: would be better to do away with this and have a better way
// to represent container symbols.
2019-12-11 14:17:14 -05:00
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.
2020-04-22 13:40:22 -04:00
o := l . OuterSym ( i )
if o == 0 {
return false
}
return l . SubSym ( o ) != 0
2019-12-11 14:17:14 -05:00
}
2020-04-12 14:19:38 -04:00
// Note that we don't have a 'SetAttrSubSymbol' method in the loader;
2020-06-30 11:30:28 -04:00
// clients should instead use the AddInteriorSym method to establish
// containment relationships for host object symbols.
2019-12-11 14:17:14 -05:00
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 {
2020-08-02 19:36:28 -04:00
return l . SymAttr ( i ) & goobj . SymFlagReflectMethod != 0
2019-10-08 18:21:22 -04:00
}
2020-02-17 01:27:11 -05:00
// Returns whether the i-th symbol is nosplit.
func ( l * Loader ) IsNoSplit ( i Sym ) bool {
2020-08-02 19:36:28 -04:00
return l . SymAttr ( i ) & goobj . SymFlagNoSplit != 0
2020-02-17 01:27:11 -05:00
}
2019-10-16 09:13:59 -04:00
// Returns whether this is a Go type symbol.
func ( l * Loader ) IsGoType ( i Sym ) bool {
2020-08-02 19:36:28 -04:00
return l . SymAttr ( i ) & goobj . SymFlagGoType != 0
2019-10-16 09:13:59 -04:00
}
2020-04-08 19:46:00 -04:00
// Returns whether this symbol should be included in typelink.
func ( l * Loader ) IsTypelink ( i Sym ) bool {
2020-08-02 19:36:28 -04:00
return l . SymAttr ( i ) & goobj . SymFlagTypelink != 0
2020-04-08 19:46:00 -04:00
}
2020-07-30 17:19:13 -04:00
// Returns whether this symbol is an itab symbol.
func ( l * Loader ) IsItab ( i Sym ) bool {
if l . IsExternal ( i ) {
return false
2019-10-16 09:29:56 -04:00
}
2020-07-30 17:19:13 -04:00
r , li := l . toLocal ( i )
return r . Sym ( li ) . IsItab ( )
2019-10-16 09:29:56 -04:00
}
2020-05-14 19:22:59 -04:00
// Return whether this is a trampoline of a deferreturn call.
func ( l * Loader ) IsDeferReturnTramp ( i Sym ) bool {
return l . deferReturnTramp [ i ]
}
// Set that i is a trampoline of a deferreturn call.
func ( l * Loader ) SetIsDeferReturnTramp ( i Sym , v bool ) {
l . deferReturnTramp [ i ] = v
}
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
}
2020-04-23 14:28:20 -04:00
// AddToSymValue adds to the value of the i-th symbol. i is the global index.
func ( l * Loader ) AddToSymValue ( i Sym , val int64 ) {
l . values [ i ] += val
}
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 )
}
2020-07-21 14:32:09 -04:00
// FreeData clears the symbol data of an external symbol, allowing the memory
// to be freed earlier. No-op for non-external symbols.
2020-04-25 17:50:48 -04:00
// i is global index.
2020-07-21 14:32:09 -04:00
func ( l * Loader ) FreeData ( i Sym ) {
2020-04-25 17:50:48 -04:00
if l . IsExternal ( i ) {
pp := l . getPayload ( i )
if pp != nil {
2020-07-21 14:32:09 -04:00
pp . data = nil
2020-04-25 17:50:48 -04:00
}
}
}
2019-12-11 14:24:19 -05:00
// SymAlign returns the alignment for a symbol.
func ( l * Loader ) SymAlign ( i Sym ) int32 {
2020-04-30 16:01:03 -04:00
if int ( i ) >= len ( l . align ) {
// align is extended lazily -- it the sym in question is
// outside the range of the existing slice, then we assume its
// alignment has not yet been set.
return 0
2019-12-11 14:24:19 -05:00
}
// TODO: would it make sense to return an arch-specific
// alignment depending on section type? E.g. STEXT => 32,
// SDATA => 1, etc?
2020-04-30 16:01:03 -04:00
abits := l . align [ i ]
if abits == 0 {
return 0
}
return int32 ( 1 << ( abits - 1 ) )
2019-12-11 14:24:19 -05:00
}
// SetSymAlign sets the alignment for a symbol.
func ( l * Loader ) SetSymAlign ( i Sym , align int32 ) {
// Reject nonsense alignments.
2020-04-30 16:01:03 -04:00
if align < 0 || align & ( align - 1 ) != 0 {
2019-12-11 14:24:19 -05:00
panic ( "bad alignment value" )
}
2020-04-30 16:01:03 -04:00
if int ( i ) >= len ( l . align ) {
l . align = append ( l . align , make ( [ ] uint8 , l . NSym ( ) - len ( l . align ) ) ... )
}
2019-12-11 14:24:19 -05:00
if align == 0 {
2020-04-30 16:01:03 -04:00
l . align [ i ] = 0
2019-12-11 14:24:19 -05:00
}
2020-04-30 16:01:03 -04:00
l . align [ i ] = uint8 ( bits . Len32 ( uint32 ( align ) ) )
2019-12-11 14:24:19 -05:00
}
2020-04-06 15:58:21 -04:00
// SymValue returns the section of the i-th symbol. i is global index.
func ( l * Loader ) SymSect ( i Sym ) * sym . Section {
2020-04-23 08:43:29 -04:00
if int ( i ) >= len ( l . symSects ) {
// symSects is extended lazily -- it the sym in question is
// outside the range of the existing slice, then we assume its
// section has not yet been set.
return nil
}
2020-04-21 18:50:49 -04:00
return l . sects [ l . symSects [ i ] ]
2020-04-06 15:58:21 -04:00
}
2020-05-11 15:11:36 -04:00
// SetSymSect sets the section of the i-th symbol. i is global index.
2020-04-06 15:58:21 -04:00
func ( l * Loader ) SetSymSect ( i Sym , sect * sym . Section ) {
2020-04-21 18:50:49 -04:00
if int ( i ) >= len ( l . symSects ) {
l . symSects = append ( l . symSects , make ( [ ] uint16 , l . NSym ( ) - len ( l . symSects ) ) ... )
}
l . symSects [ i ] = sect . Index
}
// growSects grows the slice used to store symbol sections.
func ( l * Loader ) growSects ( reqLen int ) {
curLen := len ( l . symSects )
if reqLen > curLen {
l . symSects = append ( l . symSects , make ( [ ] uint16 , reqLen + 1 - curLen ) ... )
}
}
// NewSection creates a new (output) section.
func ( l * Loader ) NewSection ( ) * sym . Section {
sect := new ( sym . Section )
idx := len ( l . sects )
if idx != int ( uint16 ( idx ) ) {
panic ( "too many sections created" )
}
sect . Index = uint16 ( idx )
l . sects = append ( l . sects , sect )
return sect
2020-04-06 15:58:21 -04:00
}
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-04-28 10:37:33 -04:00
// SymElfSym returns the ELF symbol index for a given loader
// symbol, assigned during ELF symtab generation.
func ( l * Loader ) SymElfSym ( i Sym ) int32 {
return l . elfSym [ i ]
}
// SetSymElfSym sets the elf symbol index for a symbol.
func ( l * Loader ) SetSymElfSym ( i Sym , es int32 ) {
if i == 0 {
panic ( "bad sym index" )
}
if es == 0 {
delete ( l . elfSym , i )
} else {
l . elfSym [ i ] = es
}
}
// SymLocalElfSym returns the "local" ELF symbol index for a given loader
// symbol, assigned during ELF symtab generation.
func ( l * Loader ) SymLocalElfSym ( i Sym ) int32 {
return l . localElfSym [ i ]
}
// SetSymLocalElfSym sets the "local" elf symbol index for a symbol.
func ( l * Loader ) SetSymLocalElfSym ( i Sym , es int32 ) {
if i == 0 {
panic ( "bad sym index" )
}
if es == 0 {
delete ( l . localElfSym , i )
} else {
l . localElfSym [ i ] = es
}
}
2020-03-24 09:23:09 -04:00
// SymPlt returns the plt value for pe symbols.
func ( l * Loader ) SymPlt ( s Sym ) int32 {
if v , ok := l . plt [ s ] ; ok {
return v
}
return - 1
}
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" )
}
2020-03-24 09:23:09 -04:00
if v == - 1 {
2020-01-27 15:31:41 -05:00
delete ( l . plt , i )
} else {
l . plt [ i ] = v
}
}
2020-03-24 09:23:09 -04:00
// SymGot returns the got value for pe symbols.
func ( l * Loader ) SymGot ( s Sym ) int32 {
if v , ok := l . got [ s ] ; ok {
return v
}
return - 1
}
2020-01-27 15:31:41 -05:00
// 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-03-18 14:32:17 -04:00
panic ( "bad symbol for SetGot" )
2020-01-27 15:31:41 -05:00
}
2020-03-24 09:23:09 -04:00
if v == - 1 {
2020-01-27 15:31:41 -05:00
delete ( l . got , i )
} else {
l . got [ i ] = v
}
}
2020-03-18 14:32:17 -04:00
// SymDynid returns the "dynid" property for the specified symbol.
func ( l * Loader ) SymDynid ( i Sym ) int32 {
if s , ok := l . dynid [ i ] ; ok {
return s
}
return - 1
}
// SetSymDynid sets the "dynid" property for a symbol.
func ( l * Loader ) SetSymDynid ( i Sym , val int32 ) {
// reject bad symbols
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
panic ( "bad symbol index in SetSymDynid" )
}
if val == - 1 {
delete ( l . dynid , i )
} else {
l . dynid [ i ] = val
}
}
2020-04-21 18:37:43 -04:00
// DynIdSyms returns the set of symbols for which dynID is set to an
// interesting (non-default) value. This is expected to be a fairly
// small set.
func ( l * Loader ) DynidSyms ( ) [ ] Sym {
sl := make ( [ ] Sym , 0 , len ( l . dynid ) )
for s := range l . dynid {
sl = append ( sl , s )
}
2020-04-26 13:19:32 -04:00
sort . Slice ( sl , func ( i , j int ) bool { return sl [ i ] < sl [ j ] } )
2020-04-21 18:37:43 -04:00
return sl
}
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 {
2020-05-12 18:53:55 -04:00
var r * oReader
2020-08-02 19:36:28 -04:00
var auxs [ ] goobj . Aux
2020-01-08 12:57:41 -05:00
if l . IsExternal ( i ) {
pp := l . getPayload ( i )
2020-05-12 18:53:55 -04:00
r = l . objs [ pp . objidx ] . r
auxs = pp . auxs
} else {
2020-05-12 20:08:27 -04:00
var li uint32
2020-05-12 18:53:55 -04:00
r , li = l . toLocal ( i )
auxs = r . Auxs ( li )
2020-01-08 12:57:41 -05:00
}
2020-03-06 01:15:07 -05:00
for j := range auxs {
a := & auxs [ j ]
switch a . Type ( ) {
2020-08-02 19:36:28 -04:00
case goobj . AuxGotype :
2020-03-06 01:15:07 -05:00
return l . resolve ( r , a . Sym ( ) )
2020-01-08 12:57:41 -05:00
}
}
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-04-06 20:56:34 -04:00
// SymPkg returns the package where 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
// shared library), will hold the library name.
// NOTE: this correspondes to sym.Symbol.File field.
func ( l * Loader ) SymPkg ( i Sym ) string {
2020-04-10 19:13:01 -04:00
if f , ok := l . symPkg [ i ] ; ok {
return f
}
2020-01-03 15:25:28 -05:00
if l . IsExternal ( i ) {
pp := l . getPayload ( i )
if pp . objidx != 0 {
r := l . objs [ pp . objidx ] . r
2020-04-06 20:56:34 -04:00
return r . unit . Lib . Pkg
2020-01-03 15:25:28 -05:00
}
return ""
}
r , _ := l . toLocal ( i )
2020-04-06 20:56:34 -04:00
return r . unit . Lib . Pkg
2020-01-03 15:25:28 -05:00
}
2020-04-06 20:56:34 -04:00
// SetSymPkg sets the package/library for a symbol. This is
2020-01-03 15:25:28 -05:00
// needed mainly for external symbols, specifically those imported
// from shared libraries.
2020-04-06 20:56:34 -04:00
func ( l * Loader ) SetSymPkg ( i Sym , pkg string ) {
2020-01-03 15:25:28 -05:00
// reject bad symbols
2020-02-05 16:52:12 -05:00
if i >= Sym ( len ( l . objSyms ) ) || i == 0 {
2020-04-06 20:56:34 -04:00
panic ( "bad symbol index in SetSymPkg" )
2020-01-03 15:25:28 -05:00
}
2020-04-06 20:56:34 -04:00
l . symPkg [ i ] = pkg
2020-01-03 15:25:28 -05:00
}
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 ]
}
2020-03-24 09:23:09 -04:00
// SetSymLocalentry sets the "local entry" attribute for a symbol.
2019-12-12 08:08:40 -05:00
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 {
2020-03-24 09:23:09 -04:00
panic ( "bad symbol index in SetSymLocalentry" )
2019-12-12 08:08:40 -05:00
}
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 )
}
2020-03-06 01:15:07 -05:00
// Returns the "handle" to the j-th aux symbol of the i-th symbol.
2020-07-29 13:26:50 -04:00
func ( l * Loader ) Aux ( i Sym , j int ) Aux {
2020-03-06 01:15:07 -05:00
if l . IsExternal ( i ) {
2020-07-29 13:26:50 -04:00
return Aux { }
2020-03-06 01:15:07 -05:00
}
r , li := l . toLocal ( i )
if j >= r . NAux ( li ) {
2020-07-29 13:26:50 -04:00
return Aux { }
2020-03-06 01:15:07 -05:00
}
2020-07-29 13:26:50 -04:00
return Aux { r . Aux ( li , j ) , r , l }
2020-03-06 01:15:07 -05: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.
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
}
r , li := l . toLocal ( fnSymIdx )
2020-04-09 20:45:14 -04:00
auxs := r . Auxs ( li )
2020-03-28 15:26:05 -04:00
for i := range auxs {
a := & auxs [ i ]
switch a . Type ( ) {
2020-08-02 19:36:28 -04:00
case goobj . AuxDwarfInfo :
2020-03-28 15:26:05 -04:00
auxDwarfInfo = l . resolve ( r , a . Sym ( ) )
2020-05-20 13:51:59 -04:00
if l . SymType ( auxDwarfInfo ) != sym . SDWARFFCN {
2019-11-20 10:43:11 -05:00
panic ( "aux dwarf info sym with wrong type" )
}
2020-08-02 19:36:28 -04:00
case goobj . AuxDwarfLoc :
2020-03-28 15:26:05 -04:00
auxDwarfLoc = l . resolve ( r , a . Sym ( ) )
2019-11-20 10:43:11 -05:00
if l . SymType ( auxDwarfLoc ) != sym . SDWARFLOC {
panic ( "aux dwarf loc sym with wrong type" )
}
2020-08-02 19:36:28 -04:00
case goobj . AuxDwarfRanges :
2020-03-28 15:26:05 -04:00
auxDwarfRanges = l . resolve ( r , a . Sym ( ) )
2019-11-20 10:43:11 -05:00
if l . SymType ( auxDwarfRanges ) != sym . SDWARFRANGE {
panic ( "aux dwarf ranges sym with wrong type" )
}
2020-08-02 19:36:28 -04:00
case goobj . AuxDwarfLines :
2020-03-28 15:26:05 -04:00
auxDwarfLines = l . resolve ( r , a . Sym ( ) )
2019-11-20 10:43:11 -05:00
if l . SymType ( auxDwarfLines ) != sym . SDWARFLINES {
panic ( "aux dwarf lines sym with wrong type" )
}
}
}
return
}
2020-06-30 11:30:28 -04:00
// AddInteriorSym sets up 'interior' as an interior symbol of
// container/payload symbol 'container'. An interior symbol does not
// itself have data, but gives a name to a subrange of the data in its
// container symbol. The container itself may or may not have a name.
// This method is intended primarily for use in the host object
// loaders, to capture the semantics of symbols and sections in an
// object file. When reading a host object file, we'll typically
// encounter a static section symbol (ex: ".text") containing content
// for a collection of functions, then a series of ELF (or macho, etc)
// symbol table entries each of which points into a sub-section
// (offset and length) of its corresponding container symbol. Within
// the go linker we create a loader.Sym for the container (which is
// expected to have the actual content/payload) and then a set of
// interior loader.Sym's that point into a portion of the container.
func ( l * Loader ) AddInteriorSym ( container Sym , interior Sym ) {
// Container symbols are expected to have content/data.
// NB: this restriction may turn out to be too strict (it's possible
// to imagine a zero-sized container with an interior symbol pointing
// into it); it's ok to relax or remove it if we counter an
// oddball host object that triggers this.
if l . SymSize ( container ) == 0 && len ( l . Data ( container ) ) == 0 {
panic ( "unexpected empty container symbol" )
}
// The interior symbols for a container are not expected to have
// content/data or relocations.
if len ( l . Data ( interior ) ) != 0 {
panic ( "unexpected non-empty interior symbol" )
}
// Interior symbol is expected to be in the symbol table.
if l . AttrNotInSymbolTable ( interior ) {
panic ( "interior symbol must be in symtab" )
}
// Only a single level of containment is allowed.
if l . OuterSym ( container ) != 0 {
2019-12-11 14:17:14 -05:00
panic ( "outer has outer itself" )
}
2020-06-30 11:30:28 -04:00
// Interior sym should not already have a sibling.
if l . SubSym ( interior ) != 0 {
2019-12-11 14:17:14 -05:00
panic ( "sub set for subsym" )
}
2020-06-30 11:30:28 -04:00
// Interior sym should not already point at a container.
if l . OuterSym ( interior ) != 0 {
2019-12-11 14:17:14 -05:00
panic ( "outer already set for subsym" )
}
2020-06-30 11:30:28 -04:00
l . sub [ interior ] = l . sub [ container ]
l . sub [ container ] = interior
l . outer [ interior ] = container
2019-12-11 14:17:14 -05:00
}
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
}
2020-07-01 08:45:16 -04:00
// SetCarrierSym declares that 'c' is the carrier or container symbol
// for 's'. Carrier symbols are used in the linker to as a container
// for a collection of sub-symbols where the content of the
// sub-symbols is effectively concatenated to form the content of the
// carrier. The carrier is given a name in the output symbol table
// while the sub-symbol names are not. For example, the Go compiler
// emits named string symbols (type SGOSTRING) when compiling a
// package; after being deduplicated, these symbols are collected into
// a single unit by assigning them a new carrier symbol named
// "go.string.*" (which appears in the final symbol table for the
// output load module).
func ( l * Loader ) SetCarrierSym ( s Sym , c Sym ) {
if c == 0 {
panic ( "invalid carrier in SetCarrierSym" )
}
if s == 0 {
panic ( "invalid sub-symbol in SetCarrierSym" )
}
// Carrier symbols are not expected to have content/data. It is
// ok for them to have non-zero size (to allow for use of generator
// symbols).
if len ( l . Data ( c ) ) != 0 {
panic ( "unexpected non-empty carrier symbol" )
}
l . outer [ s ] = c
// relocsym's foldSubSymbolOffset requires that we only
// have a single level of containment-- enforce here.
if l . outer [ c ] != 0 {
panic ( "invalid nested carrier sym" )
2020-04-20 18:42:35 -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 )
[dev.link] cmd/compile, cmd/link: remove dead methods if type is not used in interface
Currently, a method of a reachable type is live if it matches a
method of a reachable interface. In fact, we only need to retain
the method if the type is actually converted to an interface. If
the type is never converted to an interface, there is no way to
call the method through an interface method call (but the type
descriptor could still be used, e.g. in calling
runtime.newobject).
A type can be used in an interface in two ways:
- directly converted to interface. (Any interface counts, as it
is possible to convert one interface to another.)
- obtained by reflection from a related type (e.g. obtaining an
interface of T from []T).
For the former, we let the compiler emit a marker on the type
descriptor symbol when it is converted to an interface. In the
linker, we only need to check methods of marked types.
For the latter, when the linker visits a marked type, it needs to
visit all its "child" types as marked (i.e. potentially could be
converted to interface).
This reduces binary size:
cmd/compile 18792016 18706096 (-0.5%)
cmd/go 14120572 13398948 (-5.1%)
Change-Id: I4465c7eeabf575f4dc84017214c610fa05ae31fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/237298
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-06-08 18:38:59 -04:00
l . attrUsedInIface = growBitmap ( reqLen , l . attrUsedInIface )
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
}
2020-03-30 10:04:00 -04:00
func ( relocs * Relocs ) Count ( ) int { return len ( relocs . rs ) }
2020-07-29 13:26:50 -04:00
// At returns the j-th reloc for a global symbol.
func ( relocs * Relocs ) At ( j int ) Reloc {
2020-03-05 11:29:24 -05:00
if relocs . l . isExtReader ( relocs . r ) {
2020-03-05 16:43:37 -05:00
pp := relocs . l . payloads [ relocs . li ]
2020-07-29 13:26:50 -04:00
return Reloc { & relocs . rs [ j ] , relocs . r , relocs . l , pp . reltypes [ j ] }
2020-03-05 11:29:24 -05:00
}
2020-07-29 13:26:50 -04:00
return Reloc { & relocs . rs [ j ] , relocs . r , relocs . l , 0 }
2020-03-05 11:29:24 -05:00
}
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.
2020-05-12 20:08:27 -04:00
func ( l * Loader ) relocs ( r * oReader , li uint32 ) Relocs {
2020-08-02 19:36:28 -04:00
var rs [ ] goobj . Reloc
2020-02-05 16:52:12 -05:00
if l . isExtReader ( r ) {
pp := l . payloads [ li ]
2020-03-28 16:46:47 -04:00
rs = pp . relocs
2020-02-05 16:52:12 -05:00
} else {
2020-04-09 20:45:14 -04:00
rs = r . Relocs ( li )
2020-02-05 16:52:12 -05:00
}
2019-10-11 08:56:19 -04:00
return Relocs {
2020-03-30 10:04:00 -04:00
rs : rs ,
li : li ,
r : r ,
l : l ,
2019-10-11 08:56:19 -04:00
}
}
2020-08-02 19:36:28 -04:00
// FuncInfo provides hooks to access goobj.FuncInfo in the objects.
2020-02-25 15:14:31 -05:00
type FuncInfo struct {
2020-04-08 11:56:43 -04:00
l * Loader
r * oReader
data [ ] byte
2020-08-02 19:36:28 -04:00
auxs [ ] goobj . Aux
lengths goobj . FuncInfoLengths
2020-02-25 15:14:31 -05:00
}
func ( fi * FuncInfo ) Valid ( ) bool { return fi . r != nil }
2020-04-08 11:56:43 -04:00
func ( fi * FuncInfo ) Args ( ) int {
2020-08-02 19:36:28 -04:00
return int ( ( * goobj . FuncInfo ) ( nil ) . ReadArgs ( fi . data ) )
2020-04-08 11:56:43 -04:00
}
2020-02-25 15:14:31 -05:00
func ( fi * FuncInfo ) Locals ( ) int {
2020-08-02 19:36:28 -04:00
return int ( ( * goobj . FuncInfo ) ( nil ) . ReadLocals ( fi . data ) )
2020-02-25 15:14:31 -05:00
}
2020-07-21 15:53:30 -04:00
func ( fi * FuncInfo ) FuncID ( ) objabi . FuncID {
2020-08-02 19:36:28 -04:00
return objabi . FuncID ( ( * goobj . FuncInfo ) ( nil ) . ReadFuncID ( fi . data ) )
2020-07-21 15:53:30 -04:00
}
2020-08-07 11:31:20 -04:00
func ( fi * FuncInfo ) Pcsp ( ) Sym {
sym := ( * goobj . FuncInfo ) ( nil ) . ReadPcsp ( fi . data )
return fi . l . resolve ( fi . r , sym )
2020-02-25 15:14:31 -05:00
}
2020-08-07 11:31:20 -04:00
func ( fi * FuncInfo ) Pcfile ( ) Sym {
sym := ( * goobj . FuncInfo ) ( nil ) . ReadPcfile ( fi . data )
return fi . l . resolve ( fi . r , sym )
2020-04-08 11:56:43 -04:00
}
2020-08-07 11:31:20 -04:00
func ( fi * FuncInfo ) Pcline ( ) Sym {
sym := ( * goobj . FuncInfo ) ( nil ) . ReadPcline ( fi . data )
return fi . l . resolve ( fi . r , sym )
}
func ( fi * FuncInfo ) Pcinline ( ) Sym {
sym := ( * goobj . FuncInfo ) ( nil ) . ReadPcinline ( fi . data )
return fi . l . resolve ( fi . r , sym )
2020-04-08 11:56:43 -04:00
}
// Preload has to be called prior to invoking the various methods
// below related to pcdata, funcdataoff, files, and inltree nodes.
func ( fi * FuncInfo ) Preload ( ) {
2020-08-02 19:36:28 -04:00
fi . lengths = ( * goobj . FuncInfo ) ( nil ) . ReadFuncInfoLengths ( fi . data )
2020-04-08 11:56:43 -04:00
}
2020-08-07 11:31:20 -04:00
func ( fi * FuncInfo ) Pcdata ( ) [ ] Sym {
2020-04-08 11:56:43 -04:00
if ! fi . lengths . Initialized {
panic ( "need to call Preload first" )
}
2020-08-07 11:31:20 -04:00
syms := ( * goobj . FuncInfo ) ( nil ) . ReadPcdata ( fi . data )
ret := make ( [ ] Sym , len ( syms ) )
for i := range ret {
ret [ i ] = fi . l . resolve ( fi . r , syms [ i ] )
2020-04-08 11:56:43 -04:00
}
2020-08-07 11:31:20 -04:00
return ret
2020-04-08 11:56:43 -04:00
}
func ( fi * FuncInfo ) NumFuncdataoff ( ) uint32 {
if ! fi . lengths . Initialized {
panic ( "need to call Preload first" )
}
return fi . lengths . NumFuncdataoff
}
func ( fi * FuncInfo ) Funcdataoff ( k int ) int64 {
if ! fi . lengths . Initialized {
panic ( "need to call Preload first" )
}
2020-08-02 19:36:28 -04:00
return ( * goobj . FuncInfo ) ( nil ) . ReadFuncdataoff ( fi . data , fi . lengths . FuncdataoffOff , uint32 ( k ) )
2020-04-08 11:56:43 -04:00
}
2020-04-10 14:12:44 -04:00
func ( fi * FuncInfo ) Funcdata ( syms [ ] Sym ) [ ] Sym {
2020-04-08 11:56:43 -04:00
if ! fi . lengths . Initialized {
panic ( "need to call Preload first" )
}
if int ( fi . lengths . NumFuncdataoff ) > cap ( syms ) {
syms = make ( [ ] Sym , 0 , fi . lengths . NumFuncdataoff )
} else {
syms = syms [ : 0 ]
}
2020-04-10 14:12:44 -04:00
for j := range fi . auxs {
a := & fi . auxs [ j ]
2020-08-02 19:36:28 -04:00
if a . Type ( ) == goobj . AuxFuncdata {
2020-04-08 11:56:43 -04:00
syms = append ( syms , fi . l . resolve ( fi . r , a . Sym ( ) ) )
}
}
return syms
}
func ( fi * FuncInfo ) NumFile ( ) uint32 {
if ! fi . lengths . Initialized {
panic ( "need to call Preload first" )
}
return fi . lengths . NumFile
}
2020-08-02 19:36:28 -04:00
func ( fi * FuncInfo ) File ( k int ) goobj . CUFileIndex {
2020-04-08 11:56:43 -04:00
if ! fi . lengths . Initialized {
panic ( "need to call Preload first" )
}
2020-08-02 19:36:28 -04:00
return ( * goobj . FuncInfo ) ( nil ) . ReadFile ( fi . data , fi . lengths . FileOff , uint32 ( k ) )
2020-04-08 11:56:43 -04:00
}
type InlTreeNode struct {
Parent int32
2020-08-02 19:36:28 -04:00
File goobj . CUFileIndex
2020-04-08 11:56:43 -04:00
Line int32
Func Sym
ParentPC int32
}
func ( fi * FuncInfo ) NumInlTree ( ) uint32 {
if ! fi . lengths . Initialized {
panic ( "need to call Preload first" )
}
return fi . lengths . NumInlTree
}
func ( fi * FuncInfo ) InlTree ( k int ) InlTreeNode {
if ! fi . lengths . Initialized {
panic ( "need to call Preload first" )
}
2020-08-02 19:36:28 -04:00
node := ( * goobj . FuncInfo ) ( nil ) . ReadInlTree ( fi . data , fi . lengths . InlTreeOff , uint32 ( k ) )
2020-04-08 11:56:43 -04:00
return InlTreeNode {
Parent : node . Parent ,
2020-07-29 11:06:02 -04:00
File : node . File ,
2020-04-08 11:56:43 -04:00
Line : node . Line ,
Func : fi . l . resolve ( fi . r , node . Func ) ,
ParentPC : node . ParentPC ,
}
}
2020-02-25 15:14:31 -05:00
func ( l * Loader ) FuncInfo ( i Sym ) FuncInfo {
2020-04-06 15:58:21 -04:00
var r * oReader
2020-08-02 19:36:28 -04:00
var auxs [ ] goobj . Aux
2020-02-25 15:14:31 -05:00
if l . IsExternal ( i ) {
2020-04-06 15:58:21 -04:00
pp := l . getPayload ( i )
if pp . objidx == 0 {
return FuncInfo { }
}
r = l . objs [ pp . objidx ] . r
auxs = pp . auxs
} else {
2020-05-12 20:08:27 -04:00
var li uint32
2020-04-06 15:58:21 -04:00
r , li = l . toLocal ( i )
2020-04-09 20:45:14 -04:00
auxs = r . Auxs ( li )
2020-02-25 15:14:31 -05:00
}
2020-03-06 01:15:07 -05:00
for j := range auxs {
a := & auxs [ j ]
2020-08-02 19:36:28 -04:00
if a . Type ( ) == goobj . AuxFuncInfo {
2020-05-12 20:08:27 -04:00
b := r . Data ( a . Sym ( ) . SymIdx )
2020-08-02 19:36:28 -04:00
return FuncInfo { l , r , b , auxs , goobj . FuncInfoLengths { } }
2020-02-25 15:14:31 -05:00
}
}
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-04-22 22:20:44 -04:00
// Returns the fingerprint of the object.
2020-08-02 19:36:28 -04:00
func ( l * Loader ) Preload ( localSymVersion int , f * bio . Reader , lib * sym . Library , unit * sym . CompilationUnit , length int64 ) goobj . FingerprintType {
2020-06-02 17:45:57 -04:00
roObject , readonly , err := f . Slice ( uint64 ( length ) ) // TODO: no need to map blocks that are for tools only (e.g. RefName)
2019-09-27 14:49:44 -04:00
if err != nil {
log . Fatal ( "cannot read object file:" , err )
}
2020-08-02 19:36:28 -04:00
r := goobj . NewReaderFromBytes ( roObject , readonly )
2019-09-17 16:14:37 -04:00
if r == nil {
2020-03-25 12:06:59 -04:00
if len ( roObject ) >= 8 && bytes . Equal ( roObject [ : 8 ] , [ ] byte ( "\x00go114ld" ) ) {
2020-05-01 19:13:30 -04:00
log . Fatalf ( "found object file %s in old format" , f . File ( ) . Name ( ) )
2020-03-25 12:06:59 -04:00
}
2019-09-17 16:14:37 -04:00
panic ( "cannot read object file" )
}
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 ( )
2020-07-13 15:05:09 -04:00
nhashed64def := r . NHashed64def ( )
2020-07-10 18:49:01 -04:00
nhasheddef := r . NHasheddef ( )
or := & oReader {
2020-07-13 15:05:09 -04:00
Reader : r ,
unit : unit ,
version : localSymVersion ,
flags : r . Flags ( ) ,
pkgprefix : pkgprefix ,
syms : make ( [ ] Sym , ndef + nhashed64def + nhasheddef + r . NNonpkgdef ( ) + r . NNonpkgref ( ) ) ,
ndef : ndef ,
nhasheddef : nhasheddef ,
nhashed64def : nhashed64def ,
objidx : uint32 ( len ( l . objs ) ) ,
2020-07-10 18:49:01 -04:00
}
2019-09-17 16:14:37 -04:00
// Autolib
2020-04-22 22:20:44 -04:00
lib . Autolib = append ( lib . Autolib , r . Autolib ( ) ... )
2019-09-17 16:14:37 -04:00
2019-09-30 11:43:41 -04:00
// DWARF file table
2020-07-29 11:06:02 -04:00
nfile := r . NFile ( )
unit . FileTable = make ( [ ] string , nfile )
for i := range unit . FileTable {
unit . FileTable [ i ] = r . File ( i )
2019-09-30 11:43:41 -04:00
}
2020-02-11 10:27:15 -05:00
l . addObj ( lib . Pkg , or )
2020-07-29 19:44:49 -04:00
st := loadState { l : l }
st . preloadSyms ( or , pkgDef )
2020-02-11 10:27:15 -05:00
// The caller expects us consuming all the data
f . MustSeek ( length , os . SEEK_CUR )
2020-04-22 22:20:44 -04:00
return r . Fingerprint ( )
2020-02-11 10:27:15 -05:00
}
2020-07-29 19:44:49 -04:00
// Holds the loader along with temporary states for loading symbols.
type loadState struct {
l * Loader
2020-08-02 19:36:28 -04:00
hashed64Syms map [ uint64 ] symAndSize // short hashed (content-addressable) symbols, keyed by content hash
hashedSyms map [ goobj . HashType ] symAndSize // hashed (content-addressable) symbols, keyed by content hash
2020-07-29 19:44:49 -04:00
}
2020-02-11 10:27:15 -05:00
// Preload symbols of given kind from an object.
2020-07-29 19:44:49 -04:00
func ( st * loadState ) preloadSyms ( r * oReader , kind int ) {
l := st . l
2020-05-12 20:08:27 -04:00
var start , end uint32
2020-02-11 10:27:15 -05:00
switch kind {
case pkgDef :
start = 0
2020-07-10 18:49:01 -04:00
end = uint32 ( r . ndef )
2020-07-13 15:05:09 -04:00
case hashed64Def :
2020-07-10 18:49:01 -04:00
start = uint32 ( r . ndef )
2020-07-13 15:05:09 -04:00
end = uint32 ( r . ndef + r . nhashed64def )
case hashedDef :
start = uint32 ( r . ndef + r . nhashed64def )
end = uint32 ( r . ndef + r . nhashed64def + r . nhasheddef )
2020-07-29 18:10:15 -04:00
if l . hasUnknownPkgPath {
// The content hash depends on symbol name expansion. If any package is
// built without fully expanded names, the content hash is unreliable.
// Treat them as named symbols.
// This is rare.
// (We don't need to do this for hashed64Def case, as there the hash
// function is simply the identity function, which doesn't depend on
// name expansion.)
kind = nonPkgDef
}
2020-02-11 10:27:15 -05:00
case nonPkgDef :
2020-07-13 15:05:09 -04:00
start = uint32 ( r . ndef + r . nhashed64def + r . nhasheddef )
end = uint32 ( r . ndef + r . nhashed64def + r . nhasheddef + r . NNonpkgdef ( ) )
2020-02-11 10:27:15 -05:00
default :
panic ( "preloadSyms: bad kind" )
}
2020-05-12 20:08:27 -04:00
l . growAttrBitmaps ( len ( l . objSyms ) + int ( end - start ) )
2020-05-18 18:20:18 -04:00
needNameExpansion := r . NeedNameExpansion ( )
2020-06-17 11:42:47 -04:00
loadingRuntimePkg := r . unit . Lib . Pkg == "runtime"
2020-02-11 10:27:15 -05:00
for i := start ; i < end ; i ++ {
2020-04-09 20:45:14 -04:00
osym := r . Sym ( i )
2020-07-10 18:49:01 -04:00
var name string
var v int
2020-07-13 15:05:09 -04:00
if kind != hashed64Def && kind != hashedDef { // we don't need the name, etc. for hashed symbols
2020-07-10 18:49:01 -04:00
name = osym . Name ( r . Reader )
if needNameExpansion {
name = strings . Replace ( name , "\"\"." , r . pkgprefix , - 1 )
}
v = abiToVer ( osym . ABI ( ) , r . version )
2020-05-18 18:20:18 -04:00
}
2020-07-29 19:44:49 -04:00
gi := st . addSym ( name , v , r , i , kind , osym )
2020-02-11 10:27:15 -05:00
r . syms [ i ] = gi
2020-02-19 09:44:23 -05:00
if osym . TopFrame ( ) {
l . SetAttrTopFrame ( gi , true )
}
2020-03-19 12:55:43 -04:00
if osym . Local ( ) {
l . SetAttrLocal ( gi , true )
}
[dev.link] cmd/compile, cmd/link: remove dead methods if type is not used in interface
Currently, a method of a reachable type is live if it matches a
method of a reachable interface. In fact, we only need to retain
the method if the type is actually converted to an interface. If
the type is never converted to an interface, there is no way to
call the method through an interface method call (but the type
descriptor could still be used, e.g. in calling
runtime.newobject).
A type can be used in an interface in two ways:
- directly converted to interface. (Any interface counts, as it
is possible to convert one interface to another.)
- obtained by reflection from a related type (e.g. obtaining an
interface of T from []T).
For the former, we let the compiler emit a marker on the type
descriptor symbol when it is converted to an interface. In the
linker, we only need to check methods of marked types.
For the latter, when the linker visits a marked type, it needs to
visit all its "child" types as marked (i.e. potentially could be
converted to interface).
This reduces binary size:
cmd/compile 18792016 18706096 (-0.5%)
cmd/go 14120572 13398948 (-5.1%)
Change-Id: I4465c7eeabf575f4dc84017214c610fa05ae31fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/237298
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-06-08 18:38:59 -04:00
if osym . UsedInIface ( ) {
l . SetAttrUsedInIface ( gi , true )
}
2020-06-17 11:42:47 -04:00
if strings . HasPrefix ( name , "runtime." ) ||
( loadingRuntimePkg && strings . HasPrefix ( name , "type." ) ) {
2020-08-02 19:36:28 -04:00
if bi := goobj . BuiltinIdx ( name , v ) ; bi != - 1 {
2019-10-18 17:08:35 -04:00
// 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-07-29 19:32:31 -04:00
if a := int32 ( osym . Align ( ) ) ; a != 0 && a > l . SymAlign ( gi ) {
l . SetSymAlign ( gi , a )
2020-04-02 12:48:13 -04:00
}
2019-09-17 16:14:37 -04:00
}
}
2020-07-10 18:49:01 -04:00
// Add hashed (content-addressable) symbols, non-package symbols, and
// references to external symbols (which are always named).
2020-04-22 11:35:03 -04:00
func ( l * Loader ) LoadNonpkgSyms ( arch * sys . Arch ) {
2020-07-10 18:49:01 -04:00
l . npkgsyms = l . NSym ( )
2020-07-29 19:44:49 -04:00
// Preallocate some space (a few hundreds KB) for some symbols.
// As of Go 1.15, linking cmd/compile has ~8000 hashed64 symbols and
// ~13000 hashed symbols.
st := loadState {
l : l ,
hashed64Syms : make ( map [ uint64 ] symAndSize , 10000 ) ,
2020-08-02 19:36:28 -04:00
hashedSyms : make ( map [ goobj . HashType ] symAndSize , 15000 ) ,
2020-07-29 19:44:49 -04:00
}
2020-05-12 20:08:27 -04:00
for _ , o := range l . objs [ goObjStart : ] {
2020-07-29 19:44:49 -04:00
st . preloadSyms ( o . r , hashed64Def )
st . preloadSyms ( o . r , hashedDef )
st . preloadSyms ( o . r , nonPkgDef )
2020-02-11 10:27:15 -05:00
}
2020-07-29 19:44:49 -04:00
l . nhashedsyms = len ( st . hashed64Syms ) + len ( st . hashedSyms )
2020-05-12 20:08:27 -04:00
for _ , o := range l . objs [ goObjStart : ] {
2020-04-22 11:35:03 -04:00
loadObjRefs ( l , o . r , arch )
2019-09-30 11:43:41 -04:00
}
2020-05-11 15:11:36 -04:00
l . values = make ( [ ] int64 , l . NSym ( ) , l . NSym ( ) + 1000 ) // +1000 make some room for external symbols
2019-09-30 11:43:41 -04:00
}
2020-04-22 11:35:03 -04:00
func loadObjRefs ( l * Loader , r * oReader , arch * sys . Arch ) {
[dev.link] cmd/compile, cmd/link: reference type symbol of defined type by index
The type descriptor symbol of a defined (named) type (and pointer
to it) is defined only in the package that defines the type. It
is not dupOK, unlike other type descriptors. So it can be
referenced by index. Currently it is referenced by name for
cross-package references, because the index is not exported and
so not known to the referencing package.
This CL passes the index through the export data, so the symbol
can be referenced by index, and does not need to be looked up by
name. This also makes such symbol references consistent: it is
referenced by index within the defining package and also cross-
package, which makes it easier for content hashing (in later CLs).
One complication is that we need to set flags on referenced
symbols (specifically, the UsedInIface flag). Before, they are
non-package refs, which naturally carry flags in the object file.
For indexed refs, we currently don't put their flags in the
object file. Introduce a new block for this.
Change-Id: I8126f8e318ac4e6609eb2ac136201fd6c264c256
Reviewed-on: https://go-review.googlesource.com/c/go/+/245718
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-07-27 14:46:16 -04:00
// load non-package refs
2020-07-10 18:49:01 -04:00
ndef := uint32 ( r . NAlldef ( ) )
2020-05-18 18:20:18 -04:00
needNameExpansion := r . NeedNameExpansion ( )
2020-05-12 20:08:27 -04:00
for i , n := uint32 ( 0 ) , uint32 ( r . NNonpkgref ( ) ) ; i < n ; i ++ {
2020-04-09 20:45:14 -04:00
osym := r . Sym ( ndef + i )
2020-05-18 18:20:18 -04:00
name := osym . Name ( r . Reader )
if needNameExpansion {
name = strings . Replace ( name , "\"\"." , r . pkgprefix , - 1 )
}
2020-03-31 20:56:10 -04:00
v := abiToVer ( osym . ABI ( ) , r . version )
2020-03-16 15:04:00 -04:00
r . syms [ ndef + i ] = l . LookupOrCreateSym ( name , v )
2020-04-22 11:35:03 -04:00
gi := r . syms [ ndef + i ]
2020-03-19 12:55:43 -04:00
if osym . Local ( ) {
l . SetAttrLocal ( gi , true )
}
[dev.link] cmd/compile, cmd/link: remove dead methods if type is not used in interface
Currently, a method of a reachable type is live if it matches a
method of a reachable interface. In fact, we only need to retain
the method if the type is actually converted to an interface. If
the type is never converted to an interface, there is no way to
call the method through an interface method call (but the type
descriptor could still be used, e.g. in calling
runtime.newobject).
A type can be used in an interface in two ways:
- directly converted to interface. (Any interface counts, as it
is possible to convert one interface to another.)
- obtained by reflection from a related type (e.g. obtaining an
interface of T from []T).
For the former, we let the compiler emit a marker on the type
descriptor symbol when it is converted to an interface. In the
linker, we only need to check methods of marked types.
For the latter, when the linker visits a marked type, it needs to
visit all its "child" types as marked (i.e. potentially could be
converted to interface).
This reduces binary size:
cmd/compile 18792016 18706096 (-0.5%)
cmd/go 14120572 13398948 (-5.1%)
Change-Id: I4465c7eeabf575f4dc84017214c610fa05ae31fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/237298
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-06-08 18:38:59 -04:00
if osym . UsedInIface ( ) {
l . SetAttrUsedInIface ( gi , true )
}
2019-09-17 16:14:37 -04:00
}
[dev.link] cmd/compile, cmd/link: reference type symbol of defined type by index
The type descriptor symbol of a defined (named) type (and pointer
to it) is defined only in the package that defines the type. It
is not dupOK, unlike other type descriptors. So it can be
referenced by index. Currently it is referenced by name for
cross-package references, because the index is not exported and
so not known to the referencing package.
This CL passes the index through the export data, so the symbol
can be referenced by index, and does not need to be looked up by
name. This also makes such symbol references consistent: it is
referenced by index within the defining package and also cross-
package, which makes it easier for content hashing (in later CLs).
One complication is that we need to set flags on referenced
symbols (specifically, the UsedInIface flag). Before, they are
non-package refs, which naturally carry flags in the object file.
For indexed refs, we currently don't put their flags in the
object file. Introduce a new block for this.
Change-Id: I8126f8e318ac4e6609eb2ac136201fd6c264c256
Reviewed-on: https://go-review.googlesource.com/c/go/+/245718
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-07-27 14:46:16 -04:00
// load flags of package refs
for i , n := 0 , r . NRefFlags ( ) ; i < n ; i ++ {
rf := r . RefFlags ( i )
gi := l . resolve ( r , rf . Sym ( ) )
2020-08-02 19:36:28 -04:00
if rf . Flag2 ( ) & goobj . SymFlagUsedInIface != 0 {
[dev.link] cmd/compile, cmd/link: reference type symbol of defined type by index
The type descriptor symbol of a defined (named) type (and pointer
to it) is defined only in the package that defines the type. It
is not dupOK, unlike other type descriptors. So it can be
referenced by index. Currently it is referenced by name for
cross-package references, because the index is not exported and
so not known to the referencing package.
This CL passes the index through the export data, so the symbol
can be referenced by index, and does not need to be looked up by
name. This also makes such symbol references consistent: it is
referenced by index within the defining package and also cross-
package, which makes it easier for content hashing (in later CLs).
One complication is that we need to set flags on referenced
symbols (specifically, the UsedInIface flag). Before, they are
non-package refs, which naturally carry flags in the object file.
For indexed refs, we currently don't put their flags in the
object file. Introduce a new block for this.
Change-Id: I8126f8e318ac4e6609eb2ac136201fd6c264c256
Reviewed-on: https://go-review.googlesource.com/c/go/+/245718
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-07-27 14:46:16 -04:00
l . SetAttrUsedInIface ( gi , true )
}
}
2019-09-17 16:14:37 -04:00
}
func abiToVer ( abi uint16 , localSymVersion int ) int {
var v int
2020-08-02 19:36:28 -04:00
if abi == goobj . SymABIstatic {
2019-09-17 16:14:37 -04:00
// 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
}
2020-03-20 08:31:38 -04:00
// ResolveABIAlias given a symbol returns the ABI alias target of that
// symbol. If the sym in question is not an alias, the sym itself is
// returned.
func ( l * Loader ) ResolveABIAlias ( s Sym ) Sym {
2020-04-30 01:39:18 -04:00
if s == 0 {
return 0
}
2020-03-20 08:31:38 -04:00
if l . SymType ( s ) != sym . SABIALIAS {
return s
}
relocs := l . Relocs ( s )
2020-07-29 13:26:50 -04:00
target := relocs . At ( 0 ) . Sym ( )
2020-03-20 08:31:38 -04:00
if l . SymType ( target ) == sym . SABIALIAS {
panic ( fmt . Sprintf ( "ABI alias %s references another ABI alias %s" , l . SymName ( s ) , l . SymName ( target ) ) )
}
return target
}
2020-04-21 18:37:43 -04:00
// TopLevelSym tests a symbol (by name and kind) to determine whether
// the symbol first class sym (participating in the link) or is an
// anonymous aux or sub-symbol containing some sub-part or payload of
// another symbol.
func ( l * Loader ) TopLevelSym ( s Sym ) bool {
return topLevelSym ( l . RawSymName ( s ) , l . SymType ( s ) )
}
// topLevelSym tests a symbol name and kind to determine whether
// the symbol first class sym (participating in the link) or is an
// anonymous aux or sub-symbol containing some sub-part or payload of
// another symbol.
func topLevelSym ( sname string , skind sym . SymKind ) bool {
if sname != "" {
return true
}
switch skind {
2020-05-20 13:51:59 -04:00
case sym . SDWARFFCN , sym . SDWARFABSFCN , sym . SDWARFTYPE , sym . SDWARFCONST , sym . SDWARFCUINFO , sym . SDWARFRANGE , sym . SDWARFLOC , sym . SDWARFLINES , sym . SGOFUNC :
2020-04-21 18:37:43 -04:00
return true
default :
return false
}
}
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.
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" )
}
// Read the particulars from object.
r , li := l . toLocal ( symIdx )
2020-04-09 20:45:14 -04:00
osym := r . Sym ( li )
2020-05-18 18:20:18 -04:00
sname := osym . Name ( r . Reader )
if r . NeedNameExpansion ( ) {
sname = strings . Replace ( sname , "\"\"." , r . pkgprefix , - 1 )
}
2020-03-31 20:56:10 -04:00
sver := abiToVer ( osym . ABI ( ) , r . version )
skind := sym . AbiSymKindToSymKind [ objabi . SymKind ( osym . Type ( ) ) ]
2019-12-16 14:14:29 -05:00
// 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
2020-03-31 20:56:10 -04:00
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).
2020-07-10 18:49:01 -04:00
if li < uint32 ( r . NAlldef ( ) ) {
2019-12-16 14:14:29 -05:00
// Copy relocations
relocs := l . Relocs ( symIdx )
2020-08-02 19:36:28 -04:00
pp . relocs = make ( [ ] goobj . Reloc , relocs . Count ( ) )
2020-03-30 10:04:00 -04:00
pp . reltypes = make ( [ ] objabi . RelocType , relocs . Count ( ) )
2020-03-28 16:46:47 -04:00
for i := range pp . relocs {
// Copy the relocs slice.
// Convert local reference to global reference.
2020-07-29 13:26:50 -04:00
rel := relocs . At ( i )
2020-08-02 19:36:28 -04:00
pp . relocs [ i ] . Set ( rel . Off ( ) , rel . Siz ( ) , 0 , rel . Add ( ) , goobj . SymRef { PkgIdx : 0 , SymIdx : uint32 ( rel . Sym ( ) ) } )
2020-03-28 16:46:47 -04:00
pp . reltypes [ i ] = rel . Type ( )
}
2019-12-16 14:14:29 -05:00
// 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.
2020-04-09 20:45:14 -04:00
auxs := r . Auxs ( li )
2020-04-06 15:58:21 -04:00
pp . auxs = auxs
2020-01-06 20:37:50 -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
// 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.)
2020-05-12 20:08:27 -04:00
l . objSyms [ symIdx ] = objSym { l . extReader . objidx , uint32 ( pi ) }
[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 . extReader . syms = append ( l . extReader . syms , symIdx )
2019-12-16 14:14:29 -05:00
}
2020-03-21 13:50:46 -04:00
// Copy the payload of symbol src to dst. Both src and dst must be external
// symbols.
// The intended use case is that when building/linking against a shared library,
// where we do symbol name mangling, the Go object file may have reference to
// the original symbol name whereas the shared library provides a symbol with
// the mangled name. When we do mangling, we copy payload of mangled to original.
func ( l * Loader ) CopySym ( src , dst Sym ) {
if ! l . IsExternal ( dst ) {
panic ( "dst is not external" ) //l.newExtSym(l.SymName(dst), l.SymVersion(dst))
}
if ! l . IsExternal ( src ) {
panic ( "src is not external" ) //l.cloneToExternal(src)
}
l . payloads [ l . extIndex ( dst ) ] = l . payloads [ l . extIndex ( src ) ]
2020-04-06 20:56:34 -04:00
l . SetSymPkg ( dst , l . SymPkg ( src ) )
2020-03-21 13:50:46 -04:00
// TODO: other attributes?
}
2020-03-20 08:31:38 -04:00
// CopyAttributes copies over all of the attributes of symbol 'src' to
// symbol 'dst'.
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 ) )
l . SetAttrNotInSymbolTable ( dst , l . AttrNotInSymbolTable ( src ) )
if l . IsExternal ( dst ) {
l . SetAttrVisibilityHidden ( dst , l . AttrVisibilityHidden ( src ) )
l . SetAttrDuplicateOK ( dst , l . AttrDuplicateOK ( src ) )
l . SetAttrShared ( dst , l . AttrShared ( src ) )
l . SetAttrExternal ( dst , l . AttrExternal ( src ) )
} else {
// Some attributes are modifiable only for external symbols.
// In such cases, don't try to transfer over the attribute
// from the source even if there is a clash. This comes up
// when copying attributes from a dupOK ABI wrapper symbol to
// the real target symbol (which may not be marked dupOK).
}
l . SetAttrTopFrame ( dst , l . AttrTopFrame ( src ) )
l . SetAttrSpecial ( dst , l . AttrSpecial ( src ) )
l . SetAttrCgoExportDynamic ( dst , l . AttrCgoExportDynamic ( src ) )
l . SetAttrCgoExportStatic ( dst , l . AttrCgoExportStatic ( src ) )
l . SetAttrReadOnly ( dst , l . AttrReadOnly ( src ) )
}
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.
2020-03-24 12:08:36 -04:00
func ( l * Loader ) CreateExtSym ( name string , ver int ) Sym {
return l . newExtSym ( name , ver )
}
// CreateStaticSym creates a new static symbol with the specified name
// without adding it to any lookup tables, returning a Sym index for it.
func ( l * Loader ) CreateStaticSym ( name string ) Sym {
2019-12-18 10:57:15 -05:00
// Assign a new unique negative version -- this is to mark the
2020-05-14 16:05:29 -04:00
// symbol so that it is not included in the name lookup table.
2019-12-18 10:57:15 -05:00
l . anonVersion --
return l . newExtSym ( name , l . anonVersion )
2019-12-11 13:39:39 -05:00
}
2020-04-28 01:08:12 -04:00
func ( l * Loader ) FreeSym ( i Sym ) {
if l . IsExternal ( i ) {
pp := l . getPayload ( i )
* pp = extSymPayload { }
}
}
2020-04-01 15:57:46 -04:00
// relocId is essentially a <S,R> tuple identifying the Rth
// relocation of symbol S.
type relocId struct {
sym Sym
ridx int
}
// SetRelocVariant sets the 'variant' property of a relocation on
// some specific symbol.
func ( l * Loader ) SetRelocVariant ( s Sym , ri int , v sym . RelocVariant ) {
// sanity check
if relocs := l . Relocs ( s ) ; ri >= relocs . Count ( ) {
panic ( "invalid relocation ID" )
}
if l . relocVariant == nil {
l . relocVariant = make ( map [ relocId ] sym . RelocVariant )
}
if v != 0 {
l . relocVariant [ relocId { s , ri } ] = v
} else {
delete ( l . relocVariant , relocId { s , ri } )
}
}
// RelocVariant returns the 'variant' property of a relocation on
// some specific symbol.
func ( l * Loader ) RelocVariant ( s Sym , ri int ) sym . RelocVariant {
return l . relocVariant [ relocId { s , ri } ]
2019-12-16 14:14:29 -05:00
}
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 { }
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-03-30 10:04:00 -04:00
for ri := 0 ; ri < relocs . Count ( ) ; ri ++ {
2020-07-29 13:26:50 -04:00
r := relocs . At ( ri )
2020-03-28 16:46:47 -04:00
rs := r . Sym ( )
if rs != 0 && l . SymType ( rs ) == sym . SXREF && l . RawSymName ( rs ) != ".got" {
result = append ( result , rs )
2019-12-06 20:11:36 -05:00
if limit != - 1 && len ( result ) >= limit {
break
}
}
}
}
return result
}
2020-05-15 18:35:05 -04:00
// AssignTextSymbolOrder populates the Textp slices within each
2019-11-20 10:43:11 -05:00
// 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
2020-05-15 18:35:05 -04:00
// Library Textp lists should be empty at this point.
2019-11-20 10:43:11 -05:00
for _ , lib := range libs {
2020-05-15 18:35:05 -04:00
if len ( lib . Textp ) != 0 {
panic ( "expected empty Textp slice for library" )
2019-11-20 10:43:11 -05:00
}
2020-05-15 18:35:05 -04:00
if len ( lib . DupTextSyms ) != 0 {
panic ( "expected empty DupTextSyms slice for library" )
2019-11-20 10:43:11 -05:00
}
}
// 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-05-15 18:35:05 -04:00
// Start off textp with reachable external syms.
textp := [ ] Sym { }
2020-02-25 09:07:39 -05:00
for _ , sym := range extsyms {
if ! l . attrReachable . Has ( sym ) {
continue
}
2020-05-15 18:35:05 -04:00
textp = append ( textp , sym )
2020-02-25 09:07:39 -05:00
}
2019-11-20 10:43:11 -05:00
// Walk through all text symbols from Go object files and append
2020-05-15 18:35:05 -04:00
// them to their corresponding library's textp list.
2020-05-12 20:08:27 -04:00
for _ , o := range l . objs [ goObjStart : ] {
2019-11-20 10:43:11 -05:00
r := o . r
lib := r . unit . Lib
2020-07-10 18:49:01 -04:00
for i , n := uint32 ( 0 ) , uint32 ( r . NAlldef ( ) ) ; i < n ; i ++ {
2019-11-20 10:43:11 -05:00
gi := l . toGlobal ( r , i )
2020-02-25 09:07:39 -05:00
if ! l . attrReachable . Has ( gi ) {
continue
}
2020-04-09 20:45:14 -04:00
osym := r . Sym ( i )
2020-03-31 20:56:10 -04:00
st := sym . AbiSymKindToSymKind [ objabi . SymKind ( osym . Type ( ) ) ]
2019-11-20 10:43:11 -05:00
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.
2020-05-15 18:35:05 -04:00
lib . DupTextSyms = append ( lib . DupTextSyms , 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 {
2020-05-15 18:35:05 -04:00
lib . DupTextSyms = append ( lib . DupTextSyms , sym . LoaderSym ( gi ) )
2020-04-06 15:58:21 -04:00
continue
2020-02-25 09:07:39 -05:00
}
2019-11-20 10:43:11 -05:00
2020-05-15 18:35:05 -04:00
lib . Textp = append ( lib . Textp , sym . LoaderSym ( gi ) )
2019-11-20 10:43:11 -05:00
}
}
2020-04-16 01:01:33 -04:00
// Now assemble global textp, and assign text symbols to units.
2019-11-20 10:43:11 -05:00
for _ , doInternal := range [ 2 ] bool { true , false } {
for idx , lib := range libs {
if intlibs [ idx ] != doInternal {
continue
}
2020-05-15 18:35:05 -04:00
lists := [ 2 ] [ ] sym . LoaderSym { lib . Textp , lib . DupTextSyms }
2020-04-10 19:13:01 -04:00
for i , list := range lists {
2020-02-25 09:07:39 -05:00
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 ) {
2020-05-15 18:35:05 -04:00
textp = append ( textp , sym )
2019-11-20 10:43:11 -05:00
unit := l . SymUnit ( sym )
if unit != nil {
2020-05-15 18:35:05 -04:00
unit . Textp = append ( unit . Textp , s )
2020-02-25 15:15:11 -05:00
assignedToUnit . Set ( sym )
2019-11-20 10:43:11 -05:00
}
2020-04-10 19:13:01 -04:00
// Dupok symbols may be defined in multiple packages; the
// associated package for a dupok sym is chosen sort of
// arbitrarily (the first containing package that the linker
// loads). Canonicalizes its Pkg to the package with which
// it will be laid down in text.
if i == 1 /* DupTextSyms2 */ && l . SymPkg ( sym ) != lib . Pkg {
l . SetSymPkg ( sym , lib . Pkg )
}
2019-11-20 10:43:11 -05:00
}
}
}
2020-05-15 18:35:05 -04:00
lib . Textp = nil
lib . DupTextSyms = nil
2019-11-20 10:43:11 -05:00
}
}
2020-02-14 16:12:51 -05:00
2020-05-15 18:35:05 -04:00
return textp
2019-11-20 10:43:11 -05:00
}
2020-04-22 15:16:06 -04:00
// ErrorReporter is a helper class for reporting errors.
type ErrorReporter struct {
ldr * Loader
AfterErrorAction func ( )
}
// Errorf method logs an error message.
//
// After each error, the error actions function will be invoked; this
// will either terminate the link immediately (if -h option given)
// or it will keep a count and exit if more than 20 errors have been printed.
//
// Logging an error means that on exit cmd/link will delete any
// output file and return a non-zero error code.
//
func ( reporter * ErrorReporter ) Errorf ( s Sym , format string , args ... interface { } ) {
if s != 0 && reporter . ldr . SymName ( s ) != "" {
format = reporter . ldr . SymName ( s ) + ": " + format
} else {
format = fmt . Sprintf ( "sym %d: %s" , s , format )
}
format += "\n"
fmt . Fprintf ( os . Stderr , format , args ... )
reporter . AfterErrorAction ( )
}
// GetErrorReporter returns the loader's associated error reporter.
func ( l * Loader ) GetErrorReporter ( ) * ErrorReporter {
return l . errorReporter
}
// Errorf method logs an error message. See ErrorReporter.Errorf for details.
func ( l * Loader ) Errorf ( s Sym , format string , args ... interface { } ) {
2020-04-24 15:18:54 -04:00
l . errorReporter . Errorf ( s , format , args ... )
2020-04-22 15:16:06 -04:00
}
2020-07-10 18:49:01 -04:00
// Symbol statistics.
func ( l * Loader ) Stat ( ) string {
s := fmt . Sprintf ( "%d symbols, %d reachable\n" , l . NSym ( ) , l . NReachableSym ( ) )
s += fmt . Sprintf ( "\t%d package symbols, %d hashed symbols, %d non-package symbols, %d external symbols\n" ,
2020-07-29 19:44:49 -04:00
l . npkgsyms , l . nhashedsyms , int ( l . extStart ) - l . npkgsyms - l . nhashedsyms , l . NSym ( ) - int ( l . extStart ) )
2020-07-10 18:49:01 -04:00
return s
}
2019-10-16 15:44:04 -04:00
// For debugging.
func ( l * Loader ) Dump ( ) {
fmt . Println ( "objs" )
2020-05-12 20:08:27 -04:00
for _ , obj := range l . objs [ goObjStart : ] {
2019-10-16 15:44:04 -04:00
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 ) )
}
2020-05-14 16:05:29 -04:00
fmt . Println ( i , l . SymName ( i ) , l . SymType ( i ) , 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
}