aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/ld/deadcode2.go
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2019-09-28 22:42:35 -0400
committerCherry Zhang <cherryyz@google.com>2019-10-10 22:05:09 +0000
commit8a9be4921a3cc91c80c02bb5b4cf2ad129c0c7cc (patch)
treead2d93eab00815b71026cad0dbac503ba32f8489 /src/cmd/link/internal/ld/deadcode2.go
parentf7659d49be1839314ddc3a8606f8d6b3ce211b6b (diff)
downloadgo-8a9be4921a3cc91c80c02bb5b4cf2ad129c0c7cc.tar.xz
[dev.link] cmd/link: use index for deadcode
Switch the deadcode pass to use indices instead of Symbol structures when using new object file format. Delay loading symbol relocations and contents fully after the deadcode pass. The next step is not to create Symbol structures until deadcode is done. Method tracking logic hasn't been implemented. Currently, all methods of a reachable type are live. Change-Id: Iffcd06ff84e6e52bd9eb24d1220d94234d18ab6b Reviewed-on: https://go-review.googlesource.com/c/go/+/198199 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'src/cmd/link/internal/ld/deadcode2.go')
-rw-r--r--src/cmd/link/internal/ld/deadcode2.go144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/cmd/link/internal/ld/deadcode2.go b/src/cmd/link/internal/ld/deadcode2.go
new file mode 100644
index 0000000000..373cffc25e
--- /dev/null
+++ b/src/cmd/link/internal/ld/deadcode2.go
@@ -0,0 +1,144 @@
+// 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.
+
+package ld
+
+import (
+ "cmd/internal/objabi"
+ "cmd/internal/sys"
+ "cmd/link/internal/objfile"
+ "cmd/link/internal/sym"
+ "fmt"
+ "strings"
+)
+
+var _ = fmt.Print
+
+// TODO:
+// - Live method tracking:
+// Prune methods that are not directly called and cannot
+// be potentially called by interface or reflect call.
+// For now, all the methods from reachable type are alive.
+// - Shared object support:
+// It basically marks everything. We could consider using
+// a different mechanism to represent it.
+// - Field tracking support:
+// It needs to record from where the symbol is referenced.
+
+type workQueue []objfile.Sym
+
+func (q *workQueue) push(i objfile.Sym) { *q = append(*q, i) }
+func (q *workQueue) pop() objfile.Sym { i := (*q)[len(*q)-1]; *q = (*q)[:len(*q)-1]; return i }
+func (q *workQueue) empty() bool { return len(*q) == 0 }
+
+type deadcodePass2 struct {
+ ctxt *Link
+ loader *objfile.Loader
+ wq workQueue
+}
+
+func (d *deadcodePass2) init() {
+ d.loader.InitReachable()
+
+ var names []string
+
+ // In a normal binary, start at main.main and the init
+ // functions and mark what is reachable from there.
+ if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
+ names = append(names, "main.main", "main..inittask")
+ } else {
+ // The external linker refers main symbol directly.
+ if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
+ if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 {
+ *flagEntrySymbol = "_main"
+ } else {
+ *flagEntrySymbol = "main"
+ }
+ }
+ names = append(names, *flagEntrySymbol)
+ if d.ctxt.BuildMode == BuildModePlugin {
+ names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
+
+ // We don't keep the go.plugin.exports symbol,
+ // but we do keep the symbols it refers to.
+ exportsIdx := d.loader.Lookup("go.plugin.exports", 0)
+ if exportsIdx != 0 {
+ nreloc := d.loader.NReloc(exportsIdx)
+ for i := 0; i < nreloc; i++ {
+ d.mark(d.loader.RelocSym(exportsIdx, i))
+ }
+ }
+ }
+ }
+ for _, s := range dynexp {
+ d.mark(d.loader.Lookup(s.Name, int(s.Version)))
+ }
+
+ for _, name := range names {
+ // Mark symbol as an data/ABI0 symbol.
+ d.mark(d.loader.Lookup(name, 0))
+ // Also mark any Go functions (internal ABI).
+ d.mark(d.loader.Lookup(name, sym.SymVerABIInternal))
+ }
+}
+
+func (d *deadcodePass2) flood() {
+ for !d.wq.empty() {
+ symIdx := d.wq.pop()
+ nreloc := d.loader.NReloc(symIdx)
+ for i := 0; i < nreloc; i++ {
+ t := d.loader.RelocType(symIdx, i)
+ if t == objabi.R_WEAKADDROFF {
+ continue
+ }
+ if t == objabi.R_METHODOFF {
+ // TODO: we should do something about it
+ // For now, all the methods are considered live
+ }
+ d.mark(d.loader.RelocSym(symIdx, i))
+ }
+ naux := d.loader.NAux(symIdx)
+ for i := 0; i < naux; i++ {
+ d.mark(d.loader.AuxSym(symIdx, i))
+ }
+ }
+}
+
+func (d *deadcodePass2) mark(symIdx objfile.Sym) {
+ if symIdx != 0 && !d.loader.Reachable.Has(symIdx) {
+ d.wq.push(symIdx)
+ d.loader.Reachable.Set(symIdx)
+ }
+}
+
+func deadcode2(ctxt *Link) {
+ loader := ctxt.loader
+ d := deadcodePass2{ctxt: ctxt, loader: loader}
+ d.init()
+ d.flood()
+
+ n := loader.NSym()
+ if ctxt.BuildMode != BuildModeShared {
+ // Keep a itablink if the symbol it points at is being kept.
+ // (When BuildModeShared, always keep itablinks.)
+ for i := 1; i < n; i++ {
+ s := objfile.Sym(i)
+ if strings.HasPrefix(loader.RawSymName(s), "go.itablink.") {
+ if d.loader.NReloc(s) > 0 && loader.Reachable.Has(loader.RelocSym(s, 0)) {
+ loader.Reachable.Set(s)
+ }
+ }
+ }
+ }
+
+ // Set reachable attr for now.
+ for i := 1; i < n; i++ {
+ if loader.Reachable.Has(objfile.Sym(i)) {
+ s := loader.Syms[i]
+ if s != nil && s.Name != "" {
+ s.Attr.Set(sym.AttrReachable, true)
+ }
+ }
+ }
+}