aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/Driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Driver.cpp')
-rw-r--r--lld/ELF/Driver.cpp389
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