1
0
mirror of https://github.com/golang/go synced 2024-11-06 12:26:11 -07:00

[dev.link] cmd/link: support marking outer/sub for external loader.Sym

Add a loader mechanism for recording outer/sub relationships between
symbols without falling back on sym.Symbol. Also includes a new
"PrependSub" method that provides a way to chain a sub-symbol only the
list of an outer symbol (a common operation when manipulating
outer/sub relationships in the linker).

Change-Id: I70c72356945ceec2bacdcdc25bcc352bfb6765a1
Reviewed-on: https://go-review.googlesource.com/c/go/+/210777
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
This commit is contained in:
Than McIntosh 2019-12-11 14:17:14 -05:00
parent e6b044b200
commit 66c74b78ca
2 changed files with 120 additions and 2 deletions

View File

@ -185,6 +185,14 @@ type Loader struct {
attrCgoExportDynamic map[Sym]struct{} // "cgo_export_dynamic" symbols
attrCgoExportStatic map[Sym]struct{} // "cgo_export_static" symbols
// 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
// 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.
@ -220,6 +228,8 @@ func NewLoader(flags uint32) *Loader {
objs: []objIdx{{nil, 0, 0}},
symsByName: [2]map[string]Sym{make(map[string]Sym), make(map[string]Sym)},
objByPkg: make(map[string]*oReader),
outer: make(map[Sym]Sym),
sub: make(map[Sym]Sym),
overwrite: make(map[Sym]Sym),
itablink: make(map[Sym]struct{}),
extStaticSyms: make(map[nameVer]Sym),
@ -816,6 +826,34 @@ func (l *Loader) SetAttrCgoExportStatic(i Sym, v bool) {
}
}
// AttrSubSymbol returns true for symbols that are listed as a
// sub-symbol of some other outer symbol. The sub/outer mechanism is
// used when loading host objects (sections from the host object
// become regular linker symbols and symbols go on the Sub list of
// their section) and for constructing the global offset table when
// internally linking a dynamic executable.
func (l *Loader) AttrSubSymbol(i Sym) bool {
// we don't explicitly store this attribute any more -- return
// a value based on the sub-symbol setting.
return l.OuterSym(i) != 0
}
// AttrContainer returns true for symbols that are listed as a
// sub-symbol of some other outer symbol. The sub/outer mechanism is
// used when loading host objects (sections from the host object
// become regular linker symbols and symbols go on the Sub list of
// their section) and for constructing the global offset table when
// internally linking a dynamic executable.
func (l *Loader) AttrContainer(i Sym) bool {
// we don't explicitly store this attribute any more -- return
// a value based on the sub-symbol setting.
return l.SubSym(i) != 0
}
// Note that we don't have SetAttrSubSymbol' or 'SetAttrContainer' methods
// in the loader; clients should just use methods like PrependSub
// to establish these relationships
// Returns whether the i-th symbol has ReflectMethod attribute set.
func (l *Loader) IsReflectMethod(i Sym) bool {
return l.SymAttr(i)&goobj2.SymFlagReflectMethod != 0
@ -916,6 +954,30 @@ func (l *Loader) ReadAuxSyms(symIdx Sym, dst []Sym) []Sym {
return dst
}
// PrependSub prepends 'sub' onto the sub list for outer symbol 'outer'.
// Will panic if 'sub' already has an outer sym or sub sym.
// FIXME: should this be instead a method on SymbolBuilder?
func (l *Loader) PrependSub(outer Sym, sub Sym) {
if l.Syms[outer] != nil {
panic("not implemented for sym.Symbol based syms")
}
// NB: this presupposes that an outer sym can't be a sub symbol of
// some other outer-outer sym (I'm assuming this is true, but I
// haven't tested exhaustively).
if l.OuterSym(outer) != 0 {
panic("outer has outer itself")
}
if l.SubSym(sub) != 0 {
panic("sub set for subsym")
}
if l.OuterSym(sub) != 0 {
panic("outer already set for subsym")
}
l.sub[sub] = l.sub[outer]
l.sub[outer] = sub
l.outer[sub] = outer
}
// OuterSym gets the outer symbol for host object loaded symbols.
func (l *Loader) OuterSym(i Sym) Sym {
sym := l.Syms[i]
@ -923,7 +985,8 @@ func (l *Loader) OuterSym(i Sym) Sym {
outer := sym.Outer
return l.Lookup(outer.Name, int(outer.Version))
}
return 0
// FIXME: add check for isExternal?
return l.outer[i]
}
// SubSym gets the subsymbol for host object loaded symbols.
@ -933,7 +996,9 @@ func (l *Loader) SubSym(i Sym) Sym {
sub := sym.Sub
return l.Lookup(sub.Name, int(sub.Version))
}
return 0
// NB: note -- no check for l.isExternal(), since I am pretty sure
// that later phases in the linker set subsym for "type." syms
return l.sub[i]
}
// Initialize Reachable bitmap and its siblings for running deadcode pass.

View File

@ -110,3 +110,56 @@ func TestAddMaterializedSymbol(t *testing.T) {
}
}
}
func TestOuterSub(t *testing.T) {
ldr := NewLoader(0)
dummyOreader := oReader{version: -1}
or := &dummyOreader
// Populate loader with some symbols.
addDummyObjSym(t, ldr, or, "type.uint8")
es1 := ldr.AddExtSym("outer", 0)
es2 := ldr.AddExtSym("sub1", 0)
es3 := ldr.AddExtSym("sub2", 0)
// Should not have an outer sym initially
if ldr.OuterSym(es1) != 0 {
t.Errorf("es1 outer sym set ")
}
if ldr.SubSym(es2) != 0 {
t.Errorf("es2 outer sym set ")
}
// Establish first outer/sub relationship
ldr.PrependSub(es1, es2)
if ldr.OuterSym(es1) != 0 {
t.Errorf("ldr.OuterSym(es1) got %d wanted %d", ldr.OuterSym(es1), 0)
}
if ldr.OuterSym(es2) != es1 {
t.Errorf("ldr.OuterSym(es2) got %d wanted %d", ldr.OuterSym(es2), es1)
}
if ldr.SubSym(es1) != es2 {
t.Errorf("ldr.SubSym(es1) got %d wanted %d", ldr.SubSym(es1), es2)
}
if ldr.SubSym(es2) != 0 {
t.Errorf("ldr.SubSym(es2) got %d wanted %d", ldr.SubSym(es2), 0)
}
// Establish second outer/sub relationship
ldr.PrependSub(es1, es3)
if ldr.OuterSym(es1) != 0 {
t.Errorf("ldr.OuterSym(es1) got %d wanted %d", ldr.OuterSym(es1), 0)
}
if ldr.OuterSym(es2) != es1 {
t.Errorf("ldr.OuterSym(es2) got %d wanted %d", ldr.OuterSym(es2), es1)
}
if ldr.OuterSym(es3) != es1 {
t.Errorf("ldr.OuterSym(es3) got %d wanted %d", ldr.OuterSym(es3), es1)
}
if ldr.SubSym(es1) != es3 {
t.Errorf("ldr.SubSym(es1) got %d wanted %d", ldr.SubSym(es1), es3)
}
if ldr.SubSym(es3) != es2 {
t.Errorf("ldr.SubSym(es3) got %d wanted %d", ldr.SubSym(es3), es2)
}
}