diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:08:33 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:08:33 +0000 | 
| commit | 20d35e67e67f106f617c939725101223211659f0 (patch) | |
| tree | 64eb963cbf5ba58765e0a6b64a440965d66a7a4d /ELF/Driver.cpp | |
| parent | ae1a339de31cf4065777531959a11e55a2e5fa00 (diff) | |
Notes
Diffstat (limited to 'ELF/Driver.cpp')
| -rw-r--r-- | ELF/Driver.cpp | 590 | 
1 files changed, 477 insertions, 113 deletions
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index cc76fea2ad5e5..1fc552f011b64 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -30,9 +30,9 @@  #include "InputFiles.h"  #include "InputSection.h"  #include "LinkerScript.h" +#include "MarkLive.h"  #include "OutputSections.h"  #include "ScriptParser.h" -#include "Strings.h"  #include "SymbolTable.h"  #include "Symbols.h"  #include "SyntheticSections.h" @@ -42,12 +42,16 @@  #include "lld/Common/Driver.h"  #include "lld/Common/ErrorHandler.h"  #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" +#include "lld/Common/TargetOptionsCommandFlags.h"  #include "lld/Common/Threads.h"  #include "lld/Common/Version.h" +#include "llvm/ADT/SetVector.h"  #include "llvm/ADT/StringExtras.h"  #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" @@ -66,16 +70,18 @@ using namespace lld::elf;  Configuration *elf::Config;  LinkerDriver *elf::Driver; -static void setConfigs(); +static void setConfigs(opt::InputArgList &Args);  bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,                 raw_ostream &Error) { -  errorHandler().LogName = Args[0]; +  errorHandler().LogName = sys::path::filename(Args[0]);    errorHandler().ErrorLimitExceededMsg =        "too many errors emitted, stopping now (use "        "-error-limit=0 to see all errors)";    errorHandler().ErrorOS = &Error; +  errorHandler().ExitEarly = CanExitEarly;    errorHandler().ColorDiagnostics = Error.has_colors(); +    InputSections.clear();    OutputSections.clear();    Tar = nullptr; @@ -88,14 +94,14 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,    Driver = make<LinkerDriver>();    Script = make<LinkerScript>();    Symtab = make<SymbolTable>(); -  Config->Argv = {Args.begin(), Args.end()}; +  Config->ProgName = Args[0]; -  Driver->main(Args, CanExitEarly); +  Driver->main(Args);    // Exit immediately if we don't need to return to the caller.    // This saves time because the overhead of calling destructors    // for all globally-allocated objects is not negligible. -  if (Config->ExitEarly) +  if (CanExitEarly)      exitLld(errorCount() ? 1 : 0);    freeArena(); @@ -113,7 +119,8 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {    std::pair<ELFKind, uint16_t> Ret =        StringSwitch<std::pair<ELFKind, uint16_t>>(S) -          .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) +          .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec", +                 {ELF64LEKind, EM_AARCH64})            .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})            .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})            .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) @@ -122,6 +129,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {            .Case("elf64btsmip", {ELF64BEKind, EM_MIPS})            .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})            .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) +          .Case("elf64lppc", {ELF64LEKind, EM_PPC64})            .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})            .Case("elf_i386", {ELF32LEKind, EM_386})            .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) @@ -228,11 +236,15 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {      Files.push_back(          createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path));      return; -  default: +  case file_magic::bitcode: +  case file_magic::elf_relocatable:      if (InLib)        Files.push_back(make<LazyObjFile>(MBRef, "", 0));      else        Files.push_back(createObjectFile(MBRef)); +    break; +  default: +    error(Path + ": unknown file type");    }  } @@ -248,18 +260,11 @@ void LinkerDriver::addLibrary(StringRef Name) {  // LTO calls LLVM functions to compile bitcode files to native code.  // Technically this can be delayed until we read bitcode files, but  // we don't bother to do lazily because the initialization is fast. -static void initLLVM(opt::InputArgList &Args) { +static void initLLVM() {    InitializeAllTargets();    InitializeAllTargetMCs();    InitializeAllAsmPrinters();    InitializeAllAsmParsers(); - -  // Parse and evaluate -mllvm options. -  std::vector<const char *> V; -  V.push_back("lld (LLVM option parsing)"); -  for (auto *Arg : Args.filtered(OPT_mllvm)) -    V.push_back(Arg->getValue()); -  cl::ParseCommandLineOptions(V.size(), V.data());  }  // Some command line options or some combinations of them are not allowed. @@ -290,7 +295,9 @@ static void checkOptions(opt::InputArgList &Args) {        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->GdbIndex) +      error("-r and --gdb-index may not be used together"); +    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"); @@ -310,7 +317,37 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) {    return false;  } -void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { +static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2, +                     bool Default) { +  for (auto *Arg : Args.filtered_reverse(OPT_z)) { +    if (K1 == Arg->getValue()) +      return true; +    if (K2 == Arg->getValue()) +      return false; +  } +  return Default; +} + +static bool isKnown(StringRef S) { +  return S == "combreloc" || S == "copyreloc" || S == "defs" || +         S == "execstack" || S == "hazardplt" || S == "initfirst" || +         S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" || +         S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" || +         S == "nodlopen" || S == "noexecstack" || +         S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" || +         S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" || +         S == "rodynamic" || S == "text" || S == "wxneeded" || +         S.startswith("max-page-size=") || S.startswith("stack-size="); +} + +// Report an error for an unknown -z option. +static void checkZOptions(opt::InputArgList &Args) { +  for (auto *Arg : Args.filtered(OPT_z)) +    if (!isKnown(Arg->getValue())) +      error("unknown -z value: " + StringRef(Arg->getValue())); +} + +void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {    ELFOptTable Parser;    opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); @@ -319,7 +356,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {    // Handle -help    if (Args.hasArg(OPT_help)) { -    printHelp(ArgsArr[0]); +    printHelp();      return;    } @@ -348,9 +385,6 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {    if (Args.hasArg(OPT_version))      return; -  Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); -  errorHandler().ExitEarly = Config->ExitEarly; -    if (const char *Path = getReproduceOption(Args)) {      // Note that --reproduce is a debug option so you can ignore it      // if you are trying to understand the whole picture of the code. @@ -368,10 +402,14 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {    }    readConfigs(Args); -  initLLVM(Args); +  checkZOptions(Args); +  initLLVM();    createFiles(Args); +  if (errorCount()) +    return; +    inferMachineType(); -  setConfigs(); +  setConfigs(Args);    checkOptions(Args);    if (errorCount())      return; @@ -482,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; @@ -556,6 +603,8 @@ getBuildId(opt::InputArgList &Args) {      return {BuildIdKind::Fast, {}};    StringRef S = Arg->getValue(); +  if (S == "fast") +    return {BuildIdKind::Fast, {}};    if (S == "md5")      return {BuildIdKind::Md5, {}};    if (S == "sha1" || S == "tree") @@ -570,6 +619,57 @@ getBuildId(opt::InputArgList &Args) {    return {BuildIdKind::None, {}};  } +static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) { +  StringRef S = Args.getLastArgValue(OPT_pack_dyn_relocs, "none"); +  if (S == "android") +    return {true, false}; +  if (S == "relr") +    return {false, true}; +  if (S == "android+relr") +    return {true, true}; + +  if (S != "none") +    error("unknown -pack-dyn-relocs format: " + S); +  return {false, false}; +} + +static void readCallGraph(MemoryBufferRef MB) { +  // Build a map from symbol name to section +  DenseMap<StringRef, const Symbol *> SymbolNameToSymbol; +  for (InputFile *File : ObjectFiles) +    for (Symbol *Sym : File->getSymbols()) +      SymbolNameToSymbol[Sym->getName()] = Sym; + +  for (StringRef L : args::getLines(MB)) { +    SmallVector<StringRef, 3> Fields; +    L.split(Fields, ' '); +    uint64_t Count; +    if (Fields.size() != 3 || !to_integer(Fields[2], Count)) +      fatal(MB.getBufferIdentifier() + ": parse error"); +    const Symbol *FromSym = SymbolNameToSymbol.lookup(Fields[0]); +    const Symbol *ToSym = SymbolNameToSymbol.lookup(Fields[1]); +    if (Config->WarnSymbolOrdering) { +      if (!FromSym) +        warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[0]); +      if (!ToSym) +        warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[1]); +    } +    if (!FromSym || !ToSym || Count == 0) +      continue; +    warnUnorderableSymbol(FromSym); +    warnUnorderableSymbol(ToSym); +    const Defined *FromSymD = dyn_cast<Defined>(FromSym); +    const Defined *ToSymD = dyn_cast<Defined>(ToSym); +    if (!FromSymD || !ToSymD) +      continue; +    const auto *FromSB = dyn_cast_or_null<InputSectionBase>(FromSymD->Section); +    const auto *ToSB = dyn_cast_or_null<InputSectionBase>(ToSymD->Section); +    if (!FromSB || !ToSB) +      continue; +    Config->CallGraphProfile[std::make_pair(FromSB, ToSB)] += Count; +  } +} +  static bool getCompressDebugSections(opt::InputArgList &Args) {    StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");    if (S == "none") @@ -581,54 +681,98 @@ static bool getCompressDebugSections(opt::InputArgList &Args) {    return true;  } -static int parseInt(StringRef S, opt::Arg *Arg) { -  int V = 0; -  if (!to_integer(S, V, 10)) -    error(Arg->getSpelling() + ": number expected, but got '" + S + "'"); -  return V; +static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &Args, +                                                        unsigned Id) { +  auto *Arg = Args.getLastArg(Id); +  if (!Arg) +    return {"", ""}; + +  StringRef S = Arg->getValue(); +  std::pair<StringRef, StringRef> Ret = S.split(';'); +  if (Ret.second.empty()) +    error(Arg->getSpelling() + " expects 'old;new' format, but got " + S); +  return Ret; +} + +// Parse the symbol ordering file and warn for any duplicate entries. +static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef MB) { +  SetVector<StringRef> Names; +  for (StringRef S : args::getLines(MB)) +    if (!Names.insert(S) && Config->WarnSymbolOrdering) +      warn(MB.getBufferIdentifier() + ": duplicate ordered symbol: " + S); + +  return Names.takeVector(); +} + +static void parseClangOption(StringRef Opt, const Twine &Msg) { +  std::string Err; +  raw_string_ostream OS(Err); + +  const char *Argv[] = {Config->ProgName.data(), Opt.data()}; +  if (cl::ParseCommandLineOptions(2, Argv, "", &OS)) +    return; +  OS.flush(); +  error(Msg + ": " + StringRef(Err).trim());  }  // Initializes Config members by the command line options.  void LinkerDriver::readConfigs(opt::InputArgList &Args) { +  errorHandler().Verbose = Args.hasArg(OPT_verbose); +  errorHandler().FatalWarnings = +      Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); +  ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); +    Config->AllowMultipleDefinition = -      Args.hasArg(OPT_allow_multiple_definition) || hasZOption(Args, "muldefs"); +      Args.hasFlag(OPT_allow_multiple_definition, +                   OPT_no_allow_multiple_definition, false) || +      hasZOption(Args, "muldefs");    Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary);    Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);    Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); +  Config->CheckSections = +      Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true);    Config->Chroot = Args.getLastArgValue(OPT_chroot);    Config->CompressDebugSections = getCompressDebugSections(Args); +  Config->Cref = Args.hasFlag(OPT_cref, OPT_no_cref, false);    Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common,                                        !Args.hasArg(OPT_relocatable));    Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);    Config->DisableVerify = Args.hasArg(OPT_disable_verify);    Config->Discard = getDiscard(Args); +  Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq);    Config->DynamicLinker = getDynamicLinker(Args);    Config->EhFrameHdr =        Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false);    Config->EmitRelocs = Args.hasArg(OPT_emit_relocs); -  Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags); +  Config->EnableNewDtags = +      Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);    Config->Entry = Args.getLastArgValue(OPT_entry);    Config->ExportDynamic =        Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); -  errorHandler().FatalWarnings = -      Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);    Config->FilterList = args::getStrings(Args, OPT_filter);    Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");    Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419);    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->ICFData = Args.hasArg(OPT_icf_data); +  Config->ICF = getICF(Args); +  Config->IgnoreDataAddressEquality = +      Args.hasArg(OPT_ignore_data_address_equality); +  Config->IgnoreFunctionAddressEquality = +      Args.hasArg(OPT_ignore_function_address_equality);    Config->Init = Args.getLastArgValue(OPT_init, "_init");    Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline); +  Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager); +  Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager);    Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes);    Config->LTOO = args::getInteger(Args, OPT_lto_O, 2); +  Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq);    Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); +  Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile);    Config->MapFile = Args.getLastArgValue(OPT_Map); -  Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique); +  Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0);    Config->MergeArmExidx =        Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); -  Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);    Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);    Config->Nostdlib = Args.hasArg(OPT_nostdlib);    Config->OFormatBinary = isOutputFormatBinary(Args); @@ -638,7 +782,9 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {    Config->Optimize = args::getInteger(Args, OPT_O, 1);    Config->OrphanHandling = getOrphanHandling(Args);    Config->OutputFile = Args.getLastArgValue(OPT_o); -  Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false); +  Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false); +  Config->PrintIcfSections = +      Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);    Config->PrintGcSections =        Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);    Config->Rpath = getRpath(Args); @@ -658,46 +804,58 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {    Config->ThinLTOCachePolicy = CHECK(        parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),        "--thinlto-cache-policy: invalid cache policy"); +  Config->ThinLTOEmitImportsFiles = +      Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files); +  Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) || +                             Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq); +  Config->ThinLTOIndexOnlyArg = +      Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq);    Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u); -  ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); +  Config->ThinLTOObjectSuffixReplace = +      getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq); +  Config->ThinLTOPrefixReplace = +      getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq);    Config->Trace = Args.hasArg(OPT_trace);    Config->Undefined = args::getStrings(Args, OPT_undefined); +  Config->UndefinedVersion = +      Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true); +  Config->UseAndroidRelrTags = Args.hasFlag( +      OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false);    Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args); -  Config->Verbose = Args.hasArg(OPT_verbose); -  errorHandler().Verbose = Config->Verbose; -  Config->WarnCommon = Args.hasArg(OPT_warn_common); -  Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); -  Config->ZExecstack = hasZOption(Args, "execstack"); -  Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc"); +  Config->WarnBackrefs = +      Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); +  Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); +  Config->WarnSymbolOrdering = +      Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); +  Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true); +  Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true); +  Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false); +  Config->ZHazardplt = hasZOption(Args, "hazardplt"); +  Config->ZInitfirst = hasZOption(Args, "initfirst"); +  Config->ZKeepTextSectionPrefix = getZFlag( +      Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);    Config->ZNodelete = hasZOption(Args, "nodelete");    Config->ZNodlopen = hasZOption(Args, "nodlopen"); -  Config->ZNow = hasZOption(Args, "now"); +  Config->ZNow = getZFlag(Args, "now", "lazy", false);    Config->ZOrigin = hasZOption(Args, "origin"); -  Config->ZRelro = !hasZOption(Args, "norelro"); +  Config->ZRelro = getZFlag(Args, "relro", "norelro", true); +  Config->ZRetpolineplt = hasZOption(Args, "retpolineplt");    Config->ZRodynamic = hasZOption(Args, "rodynamic");    Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0); -  Config->ZText = !hasZOption(Args, "notext"); +  Config->ZText = getZFlag(Args, "text", "notext", true);    Config->ZWxneeded = hasZOption(Args, "wxneeded"); -  // Parse LTO plugin-related options for compatibility with gold. -  for (auto *Arg : Args.filtered(OPT_plugin_opt, OPT_plugin_opt_eq)) { -    StringRef S = Arg->getValue(); -    if (S == "disable-verify") -      Config->DisableVerify = true; -    else if (S == "save-temps") -      Config->SaveTemps = true; -    else if (S.startswith("O")) -      Config->LTOO = parseInt(S.substr(1), Arg); -    else if (S.startswith("lto-partitions=")) -      Config->LTOPartitions = parseInt(S.substr(15), Arg); -    else if (S.startswith("jobs=")) -      Config->ThinLTOJobs = parseInt(S.substr(5), Arg); -    else if (!S.startswith("/") && !S.startswith("-fresolution=") && -             !S.startswith("-pass-through=") && !S.startswith("mcpu=") && -             !S.startswith("thinlto") && S != "-function-sections" && -             S != "-data-sections") -      error(Arg->getSpelling() + ": unknown option: " + S); -  } +  // Parse LTO options. +  if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq)) +    parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())), +                     Arg->getSpelling()); + +  for (auto *Arg : Args.filtered(OPT_plugin_opt)) +    parseClangOption(Arg->getValue(), Arg->getSpelling()); + +  // Parse -mllvm options. +  for (auto *Arg : Args.filtered(OPT_mllvm)) +    parseClangOption(Arg->getValue(), Arg->getSpelling());    if (Config->LTOO > 3)      error("invalid optimization level for LTO: " + Twine(Config->LTOO)); @@ -740,17 +898,12 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {    std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args); -  if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs_eq)) { -    StringRef S = Arg->getValue(); -    if (S == "android") -      Config->AndroidPackDynRelocs = true; -    else if (S != "none") -      error("unknown -pack-dyn-relocs format: " + S); -  } +  std::tie(Config->AndroidPackDynRelocs, Config->RelrPackDynRelocs) = +      getPackDynRelocs(Args);    if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))      if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) -      Config->SymbolOrderingFile = args::getLines(*Buffer); +      Config->SymbolOrderingFile = getSymbolOrderingFile(*Buffer);    // If --retain-symbol-file is used, we'll keep only the symbols listed in    // the file and discard all others. @@ -778,32 +931,67 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {            {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});    } +  // If --export-dynamic-symbol=foo is given and symbol foo is defined in +  // an object file in an archive file, that object file should be pulled +  // out and linked. (It doesn't have to behave like that from technical +  // point of view, but this is needed for compatibility with GNU.) +  for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) +    Config->Undefined.push_back(Arg->getValue()); +    for (auto *Arg : Args.filtered(OPT_version_script)) -    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) -      readVersionScript(*Buffer); +    if (Optional<std::string> Path = searchScript(Arg->getValue())) { +      if (Optional<MemoryBufferRef> Buffer = readFile(*Path)) +        readVersionScript(*Buffer); +    } else { +      error(Twine("cannot find version script ") + Arg->getValue()); +    }  }  // Some Config members do not directly correspond to any particular  // command line options, but computed based on other Config values.  // This function initialize such members. See Config.h for the details  // of these values. -static void setConfigs() { +static void setConfigs(opt::InputArgList &Args) {    ELFKind Kind = Config->EKind;    uint16_t Machine = Config->EMachine; -  // There is an ILP32 ABI for x86-64, although it's not very popular. -  // It is called the x32 ABI. -  bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64); -    Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);    Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind);    Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind);    Config->Endianness =        Config->IsLE ? support::endianness::little : support::endianness::big;    Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS); -  Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi;    Config->Pic = Config->Pie || Config->Shared;    Config->Wordsize = Config->Is64 ? 8 : 4; + +  // There is an ILP32 ABI for x86-64, although it's not very popular. +  // It is called the x32 ABI. +  bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64); + +  // ELF defines two different ways to store relocation addends as shown below: +  // +  //  Rel:  Addends are stored to the location where relocations are applied. +  //  Rela: Addends are stored as part of relocation entry. +  // +  // In other words, Rela makes it easy to read addends at the price of extra +  // 4 or 8 byte for each relocation entry. We don't know why ELF defined two +  // different mechanisms in the first place, but this is how the spec is +  // defined. +  // +  // You cannot choose which one, Rel or Rela, you want to use. Instead each +  // ABI defines which one you need to use. The following expression expresses +  // that. +  Config->IsRela = +      (Config->Is64 || IsX32 || Machine == EM_PPC) && Machine != EM_MIPS; + +  // If the output uses REL relocations we must store the dynamic relocation +  // addends to the output sections. We also store addends for RELA relocations +  // if --apply-dynamic-relocs is used. +  // We default to not writing the addends when using RELA relocations since +  // any standard conforming tool can find it in r_addend. +  Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs, +                                      OPT_no_apply_dynamic_relocs, false) || +                         !Config->IsRela;  }  // Returns a value of "-format" option. @@ -818,6 +1006,10 @@ static bool getBinaryOption(StringRef S) {  }  void LinkerDriver::createFiles(opt::InputArgList &Args) { +  // For --{push,pop}-state. +  std::vector<std::tuple<bool, bool, bool>> Stack; + +  // Iterate over argv to process input files and positional arguments.    for (auto *Arg : Args) {      switch (Arg->getOption().getUnaliasedOption().getID()) {      case OPT_library: @@ -826,8 +1018,15 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {      case OPT_INPUT:        addFile(Arg->getValue(), /*WithLOption=*/false);        break; +    case OPT_defsym: { +      StringRef From; +      StringRef To; +      std::tie(From, To) = StringRef(Arg->getValue()).split('='); +      readDefsym(From, MemoryBufferRef(To, "-defsym")); +      break; +    }      case OPT_script: -      if (Optional<std::string> Path = searchLinkerScript(Arg->getValue())) { +      if (Optional<std::string> Path = searchScript(Arg->getValue())) {          if (Optional<MemoryBufferRef> MB = readFile(*Path))            readLinkerScript(*MB);          break; @@ -855,11 +1054,48 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {      case OPT_no_whole_archive:        InWholeArchive = false;        break; +    case OPT_just_symbols: +      if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) { +        Files.push_back(createObjectFile(*MB)); +        Files.back()->JustSymbols = true; +      } +      break; +    case OPT_start_group: +      if (InputFile::IsInGroup) +        error("nested --start-group"); +      InputFile::IsInGroup = true; +      break; +    case OPT_end_group: +      if (!InputFile::IsInGroup) +        error("stray --end-group"); +      InputFile::IsInGroup = false; +      ++InputFile::NextGroupId; +      break;      case OPT_start_lib: +      if (InLib) +        error("nested --start-lib"); +      if (InputFile::IsInGroup) +        error("may not nest --start-lib in --start-group");        InLib = true; +      InputFile::IsInGroup = true;        break;      case OPT_end_lib: +      if (!InLib) +        error("stray --end-lib");        InLib = false; +      InputFile::IsInGroup = false; +      ++InputFile::NextGroupId; +      break; +    case OPT_push_state: +      Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive); +      break; +    case OPT_pop_state: +      if (Stack.empty()) { +        error("unbalanced --push-state/--pop-state"); +        break; +      } +      std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back(); +      Stack.pop_back();        break;      }    } @@ -932,14 +1168,6 @@ static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {    return Ret;  } -static Optional<StringRef> getArchiveName(InputFile *File) { -  if (isa<ArchiveFile>(File)) -    return File->getName(); -  if (!File->ArchiveName.empty()) -    return File->ArchiveName; -  return None; -} -  // Handles the -exclude-libs option. If a static library file is specified  // by the -exclude-libs option, all public symbols from the archive become  // private unless otherwise specified by version scripts or something. @@ -947,16 +1175,132 @@ static Optional<StringRef> getArchiveName(InputFile *File) {  //  // This is not a popular option, but some programs such as bionic libc use it.  template <class ELFT> -static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) { +static void excludeLibs(opt::InputArgList &Args) {    DenseSet<StringRef> Libs = getExcludeLibs(Args);    bool All = Libs.count("ALL"); -  for (InputFile *File : Files) -    if (Optional<StringRef> Archive = getArchiveName(File)) -      if (All || Libs.count(path::filename(*Archive))) +  auto Visit = [&](InputFile *File) { +    if (!File->ArchiveName.empty()) +      if (All || Libs.count(path::filename(File->ArchiveName)))          for (Symbol *Sym : File->getSymbols()) -          if (!Sym->isLocal()) +          if (!Sym->isLocal() && Sym->File == File)              Sym->VersionId = VER_NDX_LOCAL; +  }; + +  for (InputFile *File : ObjectFiles) +    Visit(File); + +  for (BitcodeFile *File : BitcodeFiles) +    Visit(File); +} + +// Force Sym to be entered in the output. Used for -u or equivalent. +template <class ELFT> static void handleUndefined(StringRef Name) { +  Symbol *Sym = Symtab->find(Name); +  if (!Sym) +    return; + +  // Since symbol S may not be used inside the program, LTO may +  // eliminate it. Mark the symbol as "used" to prevent it. +  Sym->IsUsedInRegularObj = true; + +  if (Sym->isLazy()) +    Symtab->fetchLazy<ELFT>(Sym); +} + +template <class ELFT> static bool shouldDemote(Symbol &Sym) { +  // If all references to a DSO happen to be weak, the DSO is not added to +  // DT_NEEDED. If that happens, we need to eliminate shared symbols created +  // from the DSO. Otherwise, they become dangling references that point to a +  // non-existent DSO. +  if (auto *S = dyn_cast<SharedSymbol>(&Sym)) +    return !S->getFile<ELFT>().IsNeeded; + +  // We are done processing archives, so lazy symbols that were used but not +  // found can be converted to undefined. We could also just delete the other +  // lazy symbols, but that seems to be more work than it is worth. +  return Sym.isLazy() && Sym.IsUsedInRegularObj; +} + +// Some files, such as .so or files between -{start,end}-lib may be removed +// after their symbols are added to the symbol table. If that happens, we +// need to remove symbols that refer files that no longer exist, so that +// they won't appear in the symbol table of the output file. +// +// We remove symbols by demoting them to undefined symbol. +template <class ELFT> static void demoteSymbols() { +  for (Symbol *Sym : Symtab->getSymbols()) { +    if (shouldDemote<ELFT>(*Sym)) { +      bool Used = Sym->Used; +      replaceSymbol<Undefined>(Sym, nullptr, Sym->getName(), Sym->Binding, +                               Sym->StOther, Sym->Type); +      Sym->Used = Used; +    } +  } +} + +// The section referred to by S is considered address-significant. Set the +// KeepUnique flag on the section if appropriate. +static void markAddrsig(Symbol *S) { +  if (auto *D = dyn_cast_or_null<Defined>(S)) +    if (D->Section) +      // We don't need to keep text sections unique under --icf=all even if they +      // are address-significant. +      if (Config->ICF == ICFLevel::Safe || !(D->Section->Flags & SHF_EXECINSTR)) +        D->Section->KeepUnique = true; +} + +// Record sections that define symbols mentioned in --keep-unique <symbol> +// 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(); +    auto *D = dyn_cast_or_null<Defined>(Symtab->find(Name)); +    if (!D || !D->Section) { +      warn("could not find symbol " + Name + " to keep unique"); +      continue; +    } +    D->Section->KeepUnique = true; +  } + +  // --icf=all --ignore-data-address-equality means that we can ignore +  // the dynsym and address-significance tables entirely. +  if (Config->ICF == ICFLevel::All && Config->IgnoreDataAddressEquality) +    return; + +  // 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()) +      markAddrsig(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); +        markAddrsig(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) +        markAddrsig(S); +    } +  }  }  // Do actual linking. Note that when this function is called, @@ -1007,14 +1351,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {    for (InputFile *F : Files)      Symtab->addFile<ELFT>(F); -  // Process -defsym option. -  for (auto *Arg : Args.filtered(OPT_defsym)) { -    StringRef From; -    StringRef To; -    std::tie(From, To) = StringRef(Arg->getValue()).split('='); -    readDefsym(From, MemoryBufferRef(To, "-defsym")); -  } -    // Now that we have every file, we can decide if we will need a    // dynamic symbol table.    // We need one if we were asked to export dynamic symbols or if we are @@ -1031,23 +1367,29 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {    // Handle the `--undefined <sym>` options.    for (StringRef S : Config->Undefined) -    Symtab->fetchIfLazy<ELFT>(S); +    handleUndefined<ELFT>(S);    // If an entry symbol is in a static archive, pull out that file now    // to complete the symbol table. After this, no new names except a    // few linker-synthesized ones will be added to the symbol table. -  Symtab->fetchIfLazy<ELFT>(Config->Entry); +  handleUndefined<ELFT>(Config->Entry);    // Return if there were name resolution errors.    if (errorCount())      return; -  // Handle undefined symbols in DSOs. -  Symtab->scanShlibUndefined<ELFT>(); +  // Now when we read all script files, we want to finalize order of linker +  // script commands, which can be not yet final because of INSERT commands. +  Script->processInsertCommands(); + +  // We want to declare linker script's symbols early, +  // so that we can version them. +  // They also might be exported if referenced by DSOs. +  Script->declareSymbols();    // Handle the -exclude-libs option.    if (Args.hasArg(OPT_exclude_libs)) -    excludeLibs<ELFT>(Args, Files); +    excludeLibs<ELFT>(Args);    // Create ElfHeader early. We need a dummy section in    // addReservedSymbols to mark the created symbols as not absolute. @@ -1059,16 +1401,29 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {      addReservedSymbols();    // Apply version scripts. -  Symtab->scanVersionScript(); +  // +  // For a relocatable output, version scripts don't make sense, and +  // parsing a symbol version string (e.g. dropping "@ver1" from a symbol +  // name "foo@ver1") rather do harm, so we don't call this if -r is given. +  if (!Config->Relocatable) +    Symtab->scanVersionScript();    // Create wrapped symbols for -wrap option.    for (auto *Arg : Args.filtered(OPT_wrap))      Symtab->addSymbolWrap<ELFT>(Arg->getValue()); +  // Do link-time optimization if given files are LLVM bitcode files. +  // This compiles bitcode files into real object files.    Symtab->addCombinedLTOObject<ELFT>();    if (errorCount())      return; +  // If -thinlto-index-only is given, we should create only "index +  // files" and not object files. Index file creation is already done +  // in addCombinedLTOObject, so we are done if that's the case. +  if (Config->ThinLTOIndexOnly) +    return; +    // Apply symbol renames for -wrap.    Symtab->applySymbolWrap(); @@ -1115,11 +1470,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {    // Do size optimizations: garbage collection, merging of SHF_MERGE sections    // and identical code folding. -  markLive<ELFT>();    decompressSections(); +  splitSections<ELFT>(); +  markLive<ELFT>(); +  demoteSymbols<ELFT>();    mergeSections(); -  if (Config->ICF) +  if (Config->ICF != ICFLevel::None) { +    findKeepUniqueSections<ELFT>(Args);      doIcf<ELFT>(); +  } + +  // Read the callgraph now that we know what was gced or icfed +  if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file)) +    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) +      readCallGraph(*Buffer);    // Write the result to the file.    writeResult<ELFT>();  | 
