diff options
Diffstat (limited to 'lld/ELF/Driver.cpp')
-rw-r--r-- | lld/ELF/Driver.cpp | 70 |
1 files changed, 62 insertions, 8 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 342e70953fb..98650a74b4e 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -51,6 +51,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" @@ -296,7 +297,7 @@ static void checkOptions(opt::InputArgList &Args) { error("-r and --gc-sections may not be used together"); if (Config->GdbIndex) error("-r and --gdb-index may not be used together"); - if (Config->ICF) + if (Config->ICF != ICFLevel::None) error("-r and --icf may not be used together"); if (Config->Pie) error("-r and -pie may not be used together"); @@ -519,6 +520,15 @@ static StringRef getDynamicLinker(opt::InputArgList &Args) { return Arg->getValue(); } +static ICFLevel getICF(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all); + if (!Arg || Arg->getOption().getID() == OPT_icf_none) + return ICFLevel::None; + if (Arg->getOption().getID() == OPT_icf_safe) + return ICFLevel::Safe; + return ICFLevel::All; +} + static StripPolicy getStrip(opt::InputArgList &Args) { if (Args.hasArg(OPT_relocatable)) return StripPolicy::None; @@ -745,7 +755,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { 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 = getICF(Args); Config->IgnoreDataAddressEquality = Args.hasArg(OPT_ignore_data_address_equality); Config->IgnoreFunctionAddressEquality = @@ -1225,16 +1235,60 @@ template <class ELFT> static void demoteSymbols() { } } +static bool keepUnique(Symbol *S) { + if (auto *D = dyn_cast_or_null<Defined>(S)) { + if (D->Section) { + D->Section->KeepUnique = true; + return true; + } + } + return false; +} + // Record sections that define symbols mentioned in --keep-unique <symbol> -// these sections are inelligible for ICF. +// and symbols referred to by address-significance tables. These sections are +// ineligible for ICF. +template <class ELFT> static void findKeepUniqueSections(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_keep_unique)) { StringRef Name = Arg->getValue(); - if (auto *Sym = dyn_cast_or_null<Defined>(Symtab->find(Name))) - Sym->Section->KeepUnique = true; - else + if (!keepUnique(Symtab->find(Name))) warn("could not find symbol " + Name + " to keep unique"); } + + if (Config->ICF == ICFLevel::Safe) { + // Symbols in the dynsym could be address-significant in other executables + // or DSOs, so we conservatively mark them as address-significant. + for (Symbol *S : Symtab->getSymbols()) + if (S->includeInDynsym()) + keepUnique(S); + + // Visit the address-significance table in each object file and mark each + // referenced symbol as address-significant. + for (InputFile *F : ObjectFiles) { + auto *Obj = cast<ObjFile<ELFT>>(F); + ArrayRef<Symbol *> Syms = Obj->getSymbols(); + if (Obj->AddrsigSec) { + ArrayRef<uint8_t> Contents = + check(Obj->getObj().getSectionContents(Obj->AddrsigSec)); + const uint8_t *Cur = Contents.begin(); + while (Cur != Contents.end()) { + unsigned Size; + const char *Err; + uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); + if (Err) + fatal(toString(F) + ": could not decode addrsig section: " + Err); + keepUnique(Syms[SymIndex]); + Cur += Size; + } + } else { + // If an object file does not have an address-significance table, + // conservatively mark all of its symbols as address-significant. + for (Symbol *S : Syms) + keepUnique(S); + } + } + } } // Do actual linking. Note that when this function is called, @@ -1409,8 +1463,8 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { markLive<ELFT>(); demoteSymbols<ELFT>(); mergeSections(); - if (Config->ICF) { - findKeepUniqueSections(Args); + if (Config->ICF != ICFLevel::None) { + findKeepUniqueSections<ELFT>(Args); doIcf<ELFT>(); } |