// 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) } func addToTextp(ctxt *Link) { // Remove dead text but keep file information (z symbols). textp := []*sym.Symbol{} for _, s := range ctxt.Textp { if s.Attr.Reachable() { textp = append(textp, s) } } // Put reachable text symbols into Textp. // do it in postorder so that packages are laid down in dependency order // internal first, then everything else ctxt.Library = postorder(ctxt.Library) for _, doInternal := range [2]bool{true, false} { for _, lib := range ctxt.Library { if isRuntimeDepPkg(lib.Pkg) != doInternal { continue } libtextp := lib.Textp[:0] for _, s := range lib.Textp { if s.Attr.Reachable() { textp = append(textp, s) libtextp = append(libtextp, s) if s.Unit != nil { s.Unit.Textp = append(s.Unit.Textp, s) } } } for _, s := range lib.DupTextSyms { if s.Attr.Reachable() && !s.Attr.OnList() { textp = append(textp, s) libtextp = append(libtextp, s) if s.Unit != nil { s.Unit.Textp = append(s.Unit.Textp, s) } s.Attr |= sym.AttrOnList // dupok symbols may be defined in multiple packages. its // associated package is chosen sort of arbitrarily (the // first containing package that the linker loads). canonicalize // it here to the package with which it will be laid down // in text. s.File = objabi.PathToPrefix(lib.Pkg) } } lib.Textp = libtextp } } ctxt.Textp = textp if len(ctxt.Shlibs) > 0 { // We might have overwritten some functions above (this tends to happen for the // autogenerated type equality/hashing functions) and we don't want to generated // pcln table entries for these any more so remove them from Textp. textp := make([]*sym.Symbol, 0, len(ctxt.Textp)) for _, s := range ctxt.Textp { if s.Type != sym.SDYNIMPORT { textp = append(textp, s) } } ctxt.Textp = textp } }