diff options
Diffstat (limited to 'lld/ELF/Driver.cpp')
-rw-r--r-- | lld/ELF/Driver.cpp | 389 |
1 files changed, 272 insertions, 117 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 23da749d3078..4637a3b306da 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -43,7 +43,6 @@ #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" @@ -53,9 +52,11 @@ #include "llvm/Support/Compression.h" #include "llvm/Support/GlobPattern.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/Parallel.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include <cstdlib> #include <utility> @@ -65,18 +66,17 @@ using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::sys; using namespace llvm::support; +using namespace lld; +using namespace lld::elf; -namespace lld { -namespace elf { - -Configuration *config; -LinkerDriver *driver; +Configuration *elf::config; +LinkerDriver *elf::driver; static void setConfigs(opt::InputArgList &args); static void readConfigs(opt::InputArgList &args); -bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS, - raw_ostream &stderrOS) { +bool elf::link(ArrayRef<const char *> args, bool canExitEarly, + raw_ostream &stdoutOS, raw_ostream &stderrOS) { lld::stdoutOS = &stdoutOS; lld::stderrOS = &stderrOS; @@ -89,10 +89,13 @@ bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS, inputSections.clear(); outputSections.clear(); + archiveFiles.clear(); binaryFiles.clear(); bitcodeFiles.clear(); + lazyObjFiles.clear(); objectFiles.clear(); sharedFiles.clear(); + backwardReferences.clear(); config = make<Configuration>(); driver = make<LinkerDriver>(); @@ -147,6 +150,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef emul) { .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) .Case("elf_i386", {ELF32LEKind, EM_386}) .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) + .Case("elf64_sparc", {ELF64BEKind, EM_SPARCV9}) .Default({ELFNoneKind, EM_NONE}); if (ret.first == ELFNoneKind) @@ -350,9 +354,9 @@ static void checkOptions() { error("-z force-ibt may not be used with -z retpolineplt"); if (config->emachine != EM_AARCH64) { - if (config->pacPlt) + if (config->zPacPlt) error("-z pac-plt only supported on AArch64"); - if (config->forceBTI) + if (config->zForceBti) error("-z force-bti only supported on AArch64"); } } @@ -407,6 +411,24 @@ static GnuStackKind getZGnuStack(opt::InputArgList &args) { return GnuStackKind::NoExec; } +static uint8_t getZStartStopVisibility(opt::InputArgList &args) { + for (auto *arg : args.filtered_reverse(OPT_z)) { + std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('='); + if (kv.first == "start-stop-visibility") { + if (kv.second == "default") + return STV_DEFAULT; + else if (kv.second == "internal") + return STV_INTERNAL; + else if (kv.second == "hidden") + return STV_HIDDEN; + else if (kv.second == "protected") + return STV_PROTECTED; + error("unknown -z start-stop-visibility= value: " + StringRef(kv.second)); + } + } + return STV_PROTECTED; +} + static bool isKnownZFlag(StringRef s) { return s == "combreloc" || s == "copyreloc" || s == "defs" || s == "execstack" || s == "force-bti" || s == "force-ibt" || @@ -418,11 +440,13 @@ static bool isKnownZFlag(StringRef s) { s == "nodelete" || s == "nodlopen" || s == "noexecstack" || s == "nognustack" || s == "nokeep-text-section-prefix" || s == "norelro" || s == "noseparate-code" || s == "notext" || - s == "now" || s == "origin" || s == "pac-plt" || s == "relro" || - s == "retpolineplt" || s == "rodynamic" || s == "shstk" || - s == "text" || s == "undefs" || s == "wxneeded" || - s.startswith("common-page-size=") || s.startswith("max-page-size=") || - s.startswith("stack-size="); + s == "now" || s == "origin" || s == "pac-plt" || s == "rel" || + s == "rela" || s == "relro" || s == "retpolineplt" || + s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" || + s == "wxneeded" || s.startswith("common-page-size=") || + s.startswith("dead-reloc-in-nonalloc=") || + s.startswith("max-page-size=") || s.startswith("stack-size=") || + s.startswith("start-stop-visibility="); } // Report an error for an unknown -z option. @@ -487,37 +511,57 @@ void LinkerDriver::main(ArrayRef<const char *> argsArr) { if (args.hasArg(OPT_version)) return; - initLLVM(); - createFiles(args); - if (errorCount()) - return; + // Initialize time trace profiler. + if (config->timeTraceEnabled) + timeTraceProfilerInitialize(config->timeTraceGranularity, config->progName); - inferMachineType(); - setConfigs(args); - checkOptions(); - if (errorCount()) - return; + { + llvm::TimeTraceScope timeScope("ExecuteLinker"); - // The Target instance handles target-specific stuff, such as applying - // relocations or writing a PLT section. It also contains target-dependent - // values such as a default image base address. - target = getTarget(); + initLLVM(); + createFiles(args); + if (errorCount()) + return; - switch (config->ekind) { - case ELF32LEKind: - link<ELF32LE>(args); - return; - case ELF32BEKind: - link<ELF32BE>(args); - return; - case ELF64LEKind: - link<ELF64LE>(args); - return; - case ELF64BEKind: - link<ELF64BE>(args); - return; - default: - llvm_unreachable("unknown Config->EKind"); + inferMachineType(); + setConfigs(args); + checkOptions(); + if (errorCount()) + return; + + // The Target instance handles target-specific stuff, such as applying + // relocations or writing a PLT section. It also contains target-dependent + // values such as a default image base address. + target = getTarget(); + + switch (config->ekind) { + case ELF32LEKind: + link<ELF32LE>(args); + break; + case ELF32BEKind: + link<ELF32BE>(args); + break; + case ELF64LEKind: + link<ELF64LE>(args); + break; + case ELF64BEKind: + link<ELF64BE>(args); + break; + default: + llvm_unreachable("unknown Config->EKind"); + } + } + + if (config->timeTraceEnabled) { + if (auto E = timeTraceProfilerWrite(args.getLastArgValue(OPT_time_trace_file_eq).str(), + config->outputFile)) { + handleAllErrors(std::move(E), [&](const StringError &SE) { + error(SE.getMessage()); + }); + return; + } + + timeTraceProfilerCleanup(); } } @@ -586,9 +630,6 @@ static bool isOutputFormatBinary(opt::InputArgList &args) { } static DiscardPolicy getDiscard(opt::InputArgList &args) { - if (args.hasArg(OPT_relocatable)) - return DiscardPolicy::None; - auto *arg = args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); if (!arg) @@ -602,8 +643,13 @@ static DiscardPolicy getDiscard(opt::InputArgList &args) { static StringRef getDynamicLinker(opt::InputArgList &args) { auto *arg = args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker); - if (!arg || arg->getOption().getID() == OPT_no_dynamic_linker) + if (!arg) + return ""; + if (arg->getOption().getID() == OPT_no_dynamic_linker) { + // --no-dynamic-linker suppresses undefined weak symbols in .dynsym + config->noDynamicLinker = true; return ""; + } return arg->getValue(); } @@ -816,6 +862,22 @@ static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef mb) { return names.takeVector(); } +static bool getIsRela(opt::InputArgList &args) { + // If -z rel or -z rela is specified, use the last option. + for (auto *arg : args.filtered_reverse(OPT_z)) { + StringRef s(arg->getValue()); + if (s == "rel") + return false; + if (s == "rela") + return true; + } + + // Otherwise use the psABI defined relocation entry format. + uint16_t m = config->emachine; + return m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || m == EM_PPC || + m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64; +} + static void parseClangOption(StringRef opt, const Twine &msg) { std::string err; raw_string_ostream os(err); @@ -834,7 +896,6 @@ static void readConfigs(opt::InputArgList &args) { args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); errorHandler().vsDiagnostics = args.hasArg(OPT_visual_studio_diagnostics_format, false); - threadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true); config->allowMultipleDefinition = args.hasFlag(OPT_allow_multiple_definition, @@ -853,6 +914,8 @@ static void readConfigs(opt::InputArgList &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->optimizeBBJumps = + args.hasFlag(OPT_optimize_bb_jumps, OPT_no_optimize_bb_jumps, false); config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true); config->dependentLibraries = args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true); config->disableVerify = args.hasArg(OPT_disable_verify); @@ -874,9 +937,10 @@ static void readConfigs(opt::InputArgList &args) { args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, 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->fixCortexA8 = args.hasArg(OPT_fix_cortex_a8); - config->forceBTI = hasZOption(args, "force-bti"); + config->fixCortexA53Errata843419 = args.hasArg(OPT_fix_cortex_a53_843419) && + !args.hasArg(OPT_relocatable); + config->fixCortexA8 = + args.hasArg(OPT_fix_cortex_a8) && !args.hasArg(OPT_relocatable); 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); @@ -890,12 +954,20 @@ static void readConfigs(opt::InputArgList &args) { config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager); + config->ltoEmitAsm = args.hasArg(OPT_lto_emit_asm); config->ltoNewPassManager = args.hasArg(OPT_lto_new_pass_manager); config->ltoNewPmPasses = args.getLastArgValue(OPT_lto_newpm_passes); + config->ltoWholeProgramVisibility = + args.hasArg(OPT_lto_whole_program_visibility); config->ltoo = args::getInteger(args, OPT_lto_O, 2); config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq); config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile); + config->ltoBasicBlockSections = + args.getLastArgValue(OPT_lto_basicblock_sections); + config->ltoUniqueBasicBlockSectionNames = + args.hasFlag(OPT_lto_unique_bb_section_names, + OPT_no_lto_unique_bb_section_names, false); config->mapFile = args.getLastArgValue(OPT_Map); config->mipsGotSize = args::getInteger(args, OPT_mips_got_size, 0xfff0); config->mergeArmExidx = @@ -914,21 +986,23 @@ static void readConfigs(opt::InputArgList &args) { config->optimize = args::getInteger(args, OPT_O, 1); config->orphanHandling = getOrphanHandling(args); config->outputFile = args.getLastArgValue(OPT_o); - config->pacPlt = hasZOption(args, "pac-plt"); 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->printArchiveStats = args.getLastArgValue(OPT_print_archive_stats); config->printSymbolOrder = args.getLastArgValue(OPT_print_symbol_order); config->rpath = getRpath(args); config->relocatable = args.hasArg(OPT_relocatable); config->saveTemps = args.hasArg(OPT_save_temps); + if (args.hasArg(OPT_shuffle_sections)) + config->shuffleSectionSeed = args::getInteger(args, OPT_shuffle_sections, 0); config->searchPaths = args::getStrings(args, OPT_library_path); config->sectionStartMap = getSectionStartMap(args); config->shared = args.hasArg(OPT_shared); - config->singleRoRx = args.hasArg(OPT_no_rosegment); + config->singleRoRx = !args.hasFlag(OPT_rosegment, OPT_no_rosegment, true); config->soName = args.getLastArgValue(OPT_soname); config->sortSection = getSortSection(args); config->splitStackAdjustSize = args::getInteger(args, OPT_split_stack_adjust_size, 16384); @@ -944,15 +1018,20 @@ static void readConfigs(opt::InputArgList &args) { config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) || args.hasArg(OPT_thinlto_index_only_eq); config->thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq); - config->thinLTOJobs = args::getInteger(args, OPT_thinlto_jobs, -1u); config->thinLTOObjectSuffixReplace = getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq); config->thinLTOPrefixReplace = getOldNewOptions(args, OPT_thinlto_prefix_replace_eq); + config->thinLTOModulesToCompile = + args::getStrings(args, OPT_thinlto_single_module_eq); + config->timeTraceEnabled = args.hasArg(OPT_time_trace); + config->timeTraceGranularity = + args::getInteger(args, OPT_time_trace_granularity, 500); 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->unique = args.hasArg(OPT_unique); config->useAndroidRelrTags = args.hasFlag( OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false); config->unresolvedSymbols = getUnresolvedSymbolPolicy(args); @@ -965,6 +1044,7 @@ static void readConfigs(opt::InputArgList &args) { 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->zForceBti = hasZOption(args, "force-bti"); config->zForceIbt = hasZOption(args, "force-ibt"); config->zGlobal = hasZOption(args, "global"); config->zGnustack = getZGnuStack(args); @@ -979,33 +1059,78 @@ static void readConfigs(opt::InputArgList &args) { config->zNodlopen = hasZOption(args, "nodlopen"); config->zNow = getZFlag(args, "now", "lazy", false); config->zOrigin = hasZOption(args, "origin"); + config->zPacPlt = hasZOption(args, "pac-plt"); config->zRelro = getZFlag(args, "relro", "norelro", true); config->zRetpolineplt = hasZOption(args, "retpolineplt"); config->zRodynamic = hasZOption(args, "rodynamic"); config->zSeparate = getZSeparate(args); config->zShstk = hasZOption(args, "shstk"); config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0); + config->zStartStopVisibility = getZStartStopVisibility(args); config->zText = getZFlag(args, "text", "notext", true); config->zWxneeded = hasZOption(args, "wxneeded"); + for (opt::Arg *arg : args.filtered(OPT_z)) { + std::pair<StringRef, StringRef> option = + StringRef(arg->getValue()).split('='); + if (option.first != "dead-reloc-in-nonalloc") + continue; + constexpr StringRef errPrefix = "-z dead-reloc-in-nonalloc=: "; + std::pair<StringRef, StringRef> kv = option.second.split('='); + if (kv.first.empty() || kv.second.empty()) { + error(errPrefix + "expected <section_glob>=<value>"); + continue; + } + uint64_t v; + if (!to_integer(kv.second, v)) + error(errPrefix + "expected a non-negative integer, but got '" + + kv.second + "'"); + else if (Expected<GlobPattern> pat = GlobPattern::create(kv.first)) + config->deadRelocInNonAlloc.emplace_back(std::move(*pat), v); + else + error(errPrefix + toString(pat.takeError())); + } + // 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()); + for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq_minus)) + parseClangOption(std::string("-") + arg->getValue(), arg->getSpelling()); + + // GCC collect2 passes -plugin-opt=path/to/lto-wrapper with an absolute or + // relative path. Just ignore. If not ended with "lto-wrapper", consider it an + // unsupported LLVMgold.so option and error. + for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq)) + if (!StringRef(arg->getValue()).endswith("lto-wrapper")) + error(arg->getSpelling() + ": unknown plugin option '" + arg->getValue() + + "'"); // Parse -mllvm options. for (auto *arg : args.filtered(OPT_mllvm)) parseClangOption(arg->getValue(), arg->getSpelling()); + // --threads= takes a positive integer and provides the default value for + // --thinlto-jobs=. + if (auto *arg = args.getLastArg(OPT_threads)) { + StringRef v(arg->getValue()); + unsigned threads = 0; + if (!llvm::to_integer(v, threads, 0) || threads == 0) + error(arg->getSpelling() + ": expected a positive integer, but got '" + + arg->getValue() + "'"); + parallel::strategy = hardware_concurrency(threads); + config->thinLTOJobs = v; + } + if (auto *arg = args.getLastArg(OPT_thinlto_jobs)) + config->thinLTOJobs = arg->getValue(); + if (config->ltoo > 3) error("invalid optimization level for LTO: " + Twine(config->ltoo)); if (config->ltoPartitions == 0) error("--lto-partitions: number of threads must be > 0"); - if (config->thinLTOJobs == 0) - error("--thinlto-jobs: number of threads must be > 0"); + if (!get_threadpool_strategy(config->thinLTOJobs)) + error("--thinlto-jobs: invalid job count: " + config->thinLTOJobs); if (config->splitStackAdjustSize < 0) error("--split-stack-adjust-size: size must be >= 0"); @@ -1083,25 +1208,30 @@ static void readConfigs(opt::InputArgList &args) { {s, /*isExternCpp=*/false, /*hasWildcard=*/false}); } - // Parses -dynamic-list and -export-dynamic-symbol. They make some - // symbols private. Note that -export-dynamic takes precedence over them - // as it says all symbols should be exported. - if (!config->exportDynamic) { - for (auto *arg : args.filtered(OPT_dynamic_list)) - if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())) - readDynamicList(*buffer); - - for (auto *arg : args.filtered(OPT_export_dynamic_symbol)) - config->dynamicList.push_back( - {arg->getValue(), /*isExternCpp=*/false, /*hasWildcard=*/false}); + for (opt::Arg *arg : args.filtered(OPT_warn_backrefs_exclude)) { + StringRef pattern(arg->getValue()); + if (Expected<GlobPattern> pat = GlobPattern::create(pattern)) + config->warnBackrefsExclude.push_back(std::move(*pat)); + else + error(arg->getSpelling() + ": " + toString(pat.takeError())); } - // 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.) + // When producing an executable, --dynamic-list specifies non-local defined + // symbols whith are required to be exported. When producing a shared object, + // symbols not specified by --dynamic-list are non-preemptible. + config->symbolic = + args.hasArg(OPT_Bsymbolic) || args.hasArg(OPT_dynamic_list); + for (auto *arg : args.filtered(OPT_dynamic_list)) + if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue())) + readDynamicList(*buffer); + + // --export-dynamic-symbol specifies additional --dynamic-list symbols if any + // other option expresses a symbolic intention: -no-pie, -pie, -Bsymbolic, + // -Bsymbolic-functions (if STT_FUNC), --dynamic-list. for (auto *arg : args.filtered(OPT_export_dynamic_symbol)) - config->undefined.push_back(arg->getValue()); + config->dynamicList.push_back( + {arg->getValue(), /*isExternCpp=*/false, + /*hasWildcard=*/hasWildcard(arg->getValue())}); for (auto *arg : args.filtered(OPT_version_script)) if (Optional<std::string> path = searchScript(arg->getValue())) { @@ -1131,20 +1261,19 @@ static void setConfigs(opt::InputArgList &args) { // ELF defines two different ways to store relocation addends as shown below: // - // Rel: Addends are stored to the location where relocations are applied. + // Rel: Addends are stored to the location where relocations are applied. It + // cannot pack the full range of addend values for all relocation types, but + // this only affects relocation types that we don't support emitting as + // dynamic relocations (see getDynRel). // 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. + // 4 or 8 byte for each relocation entry. // - // 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 = m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || - m == EM_PPC || m == EM_PPC64 || m == EM_RISCV || - m == EM_X86_64; + // We pick the format for dynamic relocations according to the psABI for each + // processor, but a contrary choice can be made if the dynamic loader + // supports. + config->isRela = getIsRela(args); // If the output uses REL relocations we must store the dynamic relocation // addends to the output sections. We also store addends for RELA relocations @@ -1386,7 +1515,7 @@ static void excludeLibs(opt::InputArgList &args) { visit(file); } -// Force Sym to be entered in the output. Used for -u or equivalent. +// Force Sym to be entered in the output. static void handleUndefined(Symbol *sym) { // Since a symbol may not be used inside the program, LTO may // eliminate it. Mark the symbol as "used" to prevent it. @@ -1587,6 +1716,12 @@ static Symbol *addUndefined(StringRef name) { Undefined{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0}); } +static Symbol *addUnusedUndefined(StringRef name) { + Undefined sym{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0}; + sym.isUsedInRegularObj = false; + return symtab->addSymbol(sym); +} + // This function is where all the optimizations of link-time // optimization takes place. When LTO is in use, some input files are // not in native object file format but in the LLVM bitcode format. @@ -1595,6 +1730,7 @@ static Symbol *addUndefined(StringRef name) { // Because all bitcode files that the program consists of are passed to // the compiler at once, it can do a whole-program optimization. template <class ELFT> void LinkerDriver::compileBitcodeFiles() { + llvm::TimeTraceScope timeScope("LTO"); // Compile bitcode files and replace bitcode symbols. lto.reset(new BitcodeCompiler); for (BitcodeFile *file : bitcodeFiles) @@ -1603,8 +1739,11 @@ template <class ELFT> void LinkerDriver::compileBitcodeFiles() { for (InputFile *file : lto->compile()) { auto *obj = cast<ObjFile<ELFT>>(file); obj->parse(/*ignoreComdats=*/true); - for (Symbol *sym : obj->getGlobalSymbols()) - sym->parseSymbolVersion(); + + // Parse '@' in symbol names for non-relocatable output. + if (!config->relocatable) + for (Symbol *sym : obj->getGlobalSymbols()) + sym->parseSymbolVersion(); objectFiles.push_back(file); } } @@ -1698,8 +1837,9 @@ template <class ELFT> static uint32_t getAndFeatures() { uint32_t ret = -1; for (InputFile *f : objectFiles) { uint32_t features = cast<ObjFile<ELFT>>(f)->andFeatures; - if (config->forceBTI && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) { - warn(toString(f) + ": -z force-bti: file does not have BTI property"); + if (config->zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) { + warn(toString(f) + ": -z force-bti: file does not have " + "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property"); features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; } else if (config->zForceIbt && !(features & GNU_PROPERTY_X86_FEATURE_1_IBT)) { @@ -1707,13 +1847,14 @@ template <class ELFT> static uint32_t getAndFeatures() { "GNU_PROPERTY_X86_FEATURE_1_IBT property"); features |= GNU_PROPERTY_X86_FEATURE_1_IBT; } + if (config->zPacPlt && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) { + warn(toString(f) + ": -z pac-plt: file does not have " + "GNU_PROPERTY_AARCH64_FEATURE_1_PAC property"); + features |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC; + } ret &= features; } - // Force enable pointer authentication Plt, we don't warn in this case as - // this does not require support in the object for correctness. - if (config->pacPlt) - ret |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC; // Force enable Shadow Stack. if (config->zShstk) ret |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; @@ -1724,6 +1865,7 @@ template <class ELFT> static uint32_t getAndFeatures() { // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { + llvm::TimeTraceScope timeScope("Link", StringRef("LinkerDriver::Link")); // If a -hash-style option was not given, set to a default value, // which varies depending on the target. if (!args.hasArg(OPT_hash_style)) { @@ -1759,12 +1901,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { for (auto *arg : args.filtered(OPT_trace_symbol)) symtab->insert(arg->getValue())->traced = true; + // Handle -u/--undefined before input files. If both a.a and b.so define foo, + // -u foo a.a b.so will fetch a.a. + for (StringRef name : config->undefined) + addUnusedUndefined(name); + // Add all files to the symbol table. This will add almost all // symbols that we need to the symbol table. This process might // add files to the link, via autolinking, these files are always // appended to the Files vector. - for (size_t i = 0; i < files.size(); ++i) - parseFile(files[i]); + { + llvm::TimeTraceScope timeScope("Parse input files"); + for (size_t i = 0; i < files.size(); ++i) + parseFile(files[i]); + } // Now that we have every file, we can decide if we will need a // dynamic symbol table. @@ -1780,10 +1930,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { for (StringRef name : script->referencedSymbols) addUndefined(name); - // Handle the `--undefined <sym>` options. - for (StringRef arg : config->undefined) - if (Symbol *sym = symtab->find(arg)) - handleUndefined(sym); + // Prevent LTO from removing any definition referenced by -u. + for (StringRef name : config->undefined) + if (Defined *sym = dyn_cast_or_null<Defined>(symtab->find(name))) + sym->isUsedInRegularObj = true; // If an entry symbol is in a static archive, pull out that file now. if (Symbol *sym = symtab->find(config->entry)) @@ -1794,9 +1944,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { handleUndefinedGlob(pat); // Mark -init and -fini symbols so that the LTO doesn't eliminate them. - if (Symbol *sym = symtab->find(config->init)) + if (Symbol *sym = dyn_cast_or_null<Defined>(symtab->find(config->init))) sym->isUsedInRegularObj = true; - if (Symbol *sym = symtab->find(config->fini)) + if (Symbol *sym = dyn_cast_or_null<Defined>(symtab->find(config->fini))) sym->isUsedInRegularObj = true; // If any of our inputs are bitcode files, the LTO code generator may create @@ -1824,10 +1974,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { if (errorCount()) return; - // 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. @@ -1863,19 +2009,22 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // With this the symbol table should be complete. After this, no new names // except a few linker-synthesized ones will be added to the symbol table. compileBitcodeFiles<ELFT>(); + + // Symbol resolution finished. Report backward reference problems. + reportBackrefs(); 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; - - // Likewise, --plugin-opt=emit-llvm is an option to make LTO create - // an output file in bitcode and exit, so that you can just get a - // combined bitcode file. - if (config->emitLLVM) + // Likewise, --plugin-opt=emit-llvm and --plugin-opt=emit-asm are the + // options to create output files in bitcode or assembly code + // repsectively. No object files are generated. + // Also bail out here when only certain thinLTO modules are specified for + // compilation. The intermediate object file are the expected output. + if (config->thinLTOIndexOnly || config->emitLLVM || config->ltoEmitAsm || + !config->thinLTOModulesToCompile.empty()) return; // Apply symbol renames for -wrap. @@ -1901,8 +2050,17 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // We do not want to emit debug sections if --strip-all // or -strip-debug are given. - return config->strip != StripPolicy::None && - (s->name.startswith(".debug") || s->name.startswith(".zdebug")); + if (config->strip == StripPolicy::None) + return false; + + if (isDebugSection(*s)) + return true; + if (auto *isec = dyn_cast<InputSection>(s)) + if (InputSectionBase *rel = isec->getRelocatedSection()) + if (isDebugSection(*rel)) + return true; + + return false; }); // Now that the number of partitions is fixed, save a pointer to the main @@ -2006,6 +2164,3 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // Write the result to the file. writeResult<ELFT>(); } - -} // namespace elf -} // namespace lld |