// Copyright 2016 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/link/internal/sym" ) // deadcode marks all reachable symbols. // // The basis of the dead code elimination is a flood fill of symbols, // following their relocations, beginning at *flagEntrySymbol. // // This flood fill is wrapped in logic for pruning unused methods. // All methods are mentioned by relocations on their receiver's *rtype. // These relocations are specially defined as R_METHODOFF by the compiler // so we can detect and manipulated them here. // // There are three ways a method of a reachable type can be invoked: // // 1. direct call // 2. through a reachable interface type // 3. reflect.Value.Call, .Method, or reflect.Method.Func // // The first case is handled by the flood fill, a directly called method // is marked as reachable. // // The second case is handled by decomposing all reachable interface // types into method signatures. Each encountered method is compared // against the interface method signatures, if it matches it is marked // as reachable. This is extremely conservative, but easy and correct. // // The third case is handled by looking to see if any of: // - reflect.Value.Call is reachable // - reflect.Value.Method is reachable // - reflect.Type.Method or MethodByName is called. // If any of these happen, all bets are off and all exported methods // of reachable types are marked reachable. // // Any unreached text symbols are removed from ctxt.Textp. func deadcode(ctxt *Link) { deadcode2(ctxt) } // addToTextp populates the context Textp slice (needed in various places // in the linker) and also the unit Textp slices (needed by the "old" // phase 2 DWARF generation). func addToTextp(ctxt *Link) { // First set up ctxt.Textp, based on ctxt.Textp2. textp := make([]*sym.Symbol, 0, len(ctxt.Textp2)) haveshlibs := len(ctxt.Shlibs) > 0 for _, tsym := range ctxt.Textp2 { sp := ctxt.loader.Syms[tsym] if sp == nil || !ctxt.loader.AttrReachable(tsym) { panic("should never happen") } if haveshlibs && sp.Type == sym.SDYNIMPORT { continue } textp = append(textp, sp) } ctxt.Textp = textp // 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). The loop below canonicalizes the File to the package // with which it will be laid down in text. Assumes that // ctxt.Library is already in postorder. for _, doInternal := range [2]bool{true, false} { for _, lib := range ctxt.Library { if isRuntimeDepPkg(lib.Pkg) != doInternal { continue } for _, dsym := range lib.DupTextSyms2 { tsp := ctxt.loader.Syms[dsym] if !tsp.Attr.OnList() { tsp.Attr |= sym.AttrOnList tsp.File = objabi.PathToPrefix(lib.Pkg) } } } } // Finally, set up compilation unit Textp slices. Can be removed // once loader-Sym DWARF-gen phase 2 is always enabled. for _, lib := range ctxt.Library { for _, unit := range lib.Units { for _, usym := range unit.Textp2 { usp := ctxt.loader.Syms[usym] usp.Attr |= sym.AttrOnList unit.Textp = append(unit.Textp, usp) } } } }