aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/loader
diff options
context:
space:
mode:
authorThan McIntosh <thanm@google.com>2019-12-11 14:17:14 -0500
committerThan McIntosh <thanm@google.com>2019-12-18 14:24:57 +0000
commit66c74b78caf1628f058bf92ccf13c1f2b4054cfd (patch)
tree8ee4fae5ec651327c63efd7910349991a21c84cf /src/cmd/link/internal/loader
parente6b044b20040f76a5602a7fe6fc3d6e994376df1 (diff)
downloadgo-66c74b78caf1628f058bf92ccf13c1f2b4054cfd.tar.xz
[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>
Diffstat (limited to 'src/cmd/link/internal/loader')
-rw-r--r--src/cmd/link/internal/loader/loader.go69
-rw-r--r--src/cmd/link/internal/loader/loader_test.go53
2 files changed, 120 insertions, 2 deletions
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index f238df7f5a..64ab620798 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -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.
diff --git a/src/cmd/link/internal/loader/loader_test.go b/src/cmd/link/internal/loader/loader_test.go
index ec3090bd5a..0bfcfb59bc 100644
--- a/src/cmd/link/internal/loader/loader_test.go
+++ b/src/cmd/link/internal/loader/loader_test.go
@@ -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)
+ }
+}