Index: lld/ELF/Config.h =================================================================== --- lld/ELF/Config.h +++ lld/ELF/Config.h @@ -46,6 +46,9 @@ // For --unresolved-symbols. enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll }; +// For --icf={all,safe,none}. +enum class ICFPolicy { All, Safe, None }; + // For --orphan-handling. enum class OrphanHandlingPolicy { Place, Warn, Error }; @@ -137,7 +140,6 @@ bool GnuUnique; bool HasDynamicList = false; bool HasDynSymTab; - bool ICF; bool IgnoreDataAddressEquality; bool IgnoreFunctionAddressEquality; bool LTODebugPassManager; @@ -183,6 +185,7 @@ bool ZRetpolineplt; bool ZWxneeded; DiscardPolicy Discard; + ICFPolicy ICF; OrphanHandlingPolicy OrphanHandling; SortSectionPolicy SortSection; StripPolicy Strip; Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -294,7 +294,7 @@ error("-r and -shared may not be used together"); if (Config->GcSections) error("-r and --gc-sections may not be used together"); - if (Config->ICF) + if (Config->ICF != ICFPolicy::None) error("-r and --icf may not be used together"); if (Config->Pie) error("-r and -pie may not be used together"); @@ -494,6 +494,15 @@ return Arg->getValue(); } +static ICFPolicy getICFPolicy(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_icf_all, OPT_icf_safe, OPT_icf_none); + if (Arg && Arg->getOption().getID() == OPT_icf_all) + return ICFPolicy::All; + if (Arg && Arg->getOption().getID() == OPT_icf_safe) + return ICFPolicy::Safe; + return ICFPolicy::None; +} + static StripPolicy getStrip(opt::InputArgList &Args) { if (Args.hasArg(OPT_relocatable)) return StripPolicy::None; @@ -701,7 +710,7 @@ Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true); Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); - Config->ICF = Args.hasFlag(OPT_icf_all, OPT_icf_none, false); + Config->ICF = getICFPolicy(Args); Config->IgnoreDataAddressEquality = Args.hasArg(OPT_ignore_data_address_equality); Config->IgnoreFunctionAddressEquality = @@ -1355,7 +1364,7 @@ markLive(); demoteSymbols(); mergeSections(); - if (Config->ICF) { + if (Config->ICF != ICFPolicy::None) { findKeepUniqueSections(Args); doIcf(); } Index: lld/ELF/ICF.cpp =================================================================== --- lld/ELF/ICF.cpp +++ lld/ELF/ICF.cpp @@ -78,12 +78,14 @@ #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "llvm/ADT/Hashing.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" #include #include +#include using namespace lld; using namespace lld::elf; @@ -162,8 +164,8 @@ // Returns true if section S is subject of ICF. static bool isEligible(InputSection *S) { - if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC) || - (S->Flags & SHF_WRITE)) + if (!S->Live || S->KeepUnique || S->IsAddressSignificant || + !(S->Flags & SHF_ALLOC) || (S->Flags & SHF_WRITE)) return false; // Don't merge read only data sections unless @@ -414,8 +416,27 @@ message(S); } +static std::regex CtorDtorRe(".*([\\w\\d]+)::~?\\1.*", + std::regex_constants::ECMAScript); + +static bool isCtorOrDtor(StringRef Name) { + Optional S = lld::demangleItanium(Name); + return S && std::regex_match(*S, CtorDtorRe); +} + +static void markSafeICF() { + for (Symbol *Sym : Symtab->getSymbols()) + if (auto *D = dyn_cast(Sym)) + if (D->Section && !D->Section->IsAddressSignificant) + if (!isCtorOrDtor(Sym->getName())) + D->Section->IsAddressSignificant = true; +} + // The main function of ICF. template void ICF::run() { + if (Config->ICF == ICFPolicy::Safe) + markSafeICF(); + // Collect sections to merge. for (InputSectionBase *Sec : InputSections) if (auto *S = dyn_cast(Sec)) Index: lld/ELF/InputSection.h =================================================================== --- lld/ELF/InputSection.h +++ lld/ELF/InputSection.h @@ -64,6 +64,8 @@ // Set for sections that should not be folded by ICF. unsigned KeepUnique : 1; + unsigned IsAddressSignificant : 1; + // These corresponds to the fields in Elf_Shdr. uint32_t Alignment; uint64_t Flags; @@ -88,8 +90,9 @@ uint64_t Entsize, uint64_t Alignment, uint32_t Type, uint32_t Info, uint32_t Link) : Name(Name), Repl(this), SectionKind(SectionKind), Live(false), - Bss(false), KeepUnique(false), Alignment(Alignment), Flags(Flags), - Entsize(Entsize), Type(Type), Link(Link), Info(Info) {} + Bss(false), KeepUnique(false), IsAddressSignificant(false), + Alignment(Alignment), Flags(Flags), Entsize(Entsize), Type(Type), + Link(Link), Info(Info) {} }; // This corresponds to a section of an input file. Index: lld/ELF/Options.td =================================================================== --- lld/ELF/Options.td +++ lld/ELF/Options.td @@ -179,6 +179,8 @@ def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">; +def icf_safe: F<"icf=safe">, HelpText<"Enable safe identical code folding">; + def ignore_function_address_equality: F<"ignore-function-address-equality">, HelpText<"lld can break the address equality of functions">;