aboutsummaryrefslogtreecommitdiffstats
path: root/ELF/Driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/Driver.cpp')
-rw-r--r--ELF/Driver.cpp150
1 files changed, 108 insertions, 42 deletions
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index fbfc71d22b7e..96257a4c7624 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -48,6 +48,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/LTO/LTO.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/GlobPattern.h"
@@ -65,24 +66,23 @@ using namespace llvm::object;
using namespace llvm::sys;
using namespace llvm::support;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
-Configuration *elf::config;
-LinkerDriver *elf::driver;
+Configuration *config;
+LinkerDriver *driver;
static void setConfigs(opt::InputArgList &args);
static void readConfigs(opt::InputArgList &args);
-bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
- raw_ostream &error) {
+bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &error) {
errorHandler().logName = args::getFilenameWithoutExe(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();
+ enableColors(error.has_colors());
inputSections.clear();
outputSections.clear();
@@ -299,6 +299,9 @@ static void checkOptions() {
if (config->fixCortexA53Errata843419 && config->emachine != EM_AARCH64)
error("--fix-cortex-a53-843419 is only supported on AArch64 targets");
+ if (config->fixCortexA8 && config->emachine != EM_ARM)
+ error("--fix-cortex-a8 is only supported on ARM targets");
+
if (config->tocOptimize && config->emachine != EM_PPC64)
error("--toc-optimize is only supported on the PowerPC64 target");
@@ -314,6 +317,9 @@ static void checkOptions() {
if (!config->relocatable && !config->defineCommon)
error("-no-define-common not supported in non relocatable output");
+ if (config->strip == StripPolicy::All && config->emitRelocs)
+ error("--strip-all and --emit-relocs may not be used together");
+
if (config->zText && config->zIfuncNoplt)
error("-z text and -z ifunc-noplt may not be used together");
@@ -328,6 +334,8 @@ static void checkOptions() {
error("-r and --icf may not be used together");
if (config->pie)
error("-r and -pie may not be used together");
+ if (config->exportDynamic)
+ error("-r and --export-dynamic may not be used together");
}
if (config->executeOnly) {
@@ -373,17 +381,32 @@ static bool getZFlag(opt::InputArgList &args, StringRef k1, StringRef k2,
return Default;
}
+static SeparateSegmentKind getZSeparate(opt::InputArgList &args) {
+ for (auto *arg : args.filtered_reverse(OPT_z)) {
+ StringRef v = arg->getValue();
+ if (v == "noseparate-code")
+ return SeparateSegmentKind::None;
+ if (v == "separate-code")
+ return SeparateSegmentKind::Code;
+ if (v == "separate-loadable-segments")
+ return SeparateSegmentKind::Loadable;
+ }
+ return SeparateSegmentKind::None;
+}
+
static bool isKnownZFlag(StringRef s) {
return s == "combreloc" || s == "copyreloc" || s == "defs" ||
s == "execstack" || s == "global" || s == "hazardplt" ||
s == "ifunc-noplt" || s == "initfirst" || s == "interpose" ||
s == "keep-text-section-prefix" || s == "lazy" || s == "muldefs" ||
+ s == "separate-code" || s == "separate-loadable-segments" ||
s == "nocombreloc" || s == "nocopyreloc" || s == "nodefaultlib" ||
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("common-page-size") || s.startswith("max-page-size=") ||
+ s == "nokeep-text-section-prefix" || s == "norelro" ||
+ s == "noseparate-code" || s == "notext" || s == "now" ||
+ s == "origin" || s == "relro" || s == "retpolineplt" ||
+ s == "rodynamic" || s == "text" || s == "undefs" || s == "wxneeded" ||
+ s.startswith("common-page-size=") || s.startswith("max-page-size=") ||
s.startswith("stack-size=");
}
@@ -513,6 +536,8 @@ static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) {
case OPT_z:
if (StringRef(arg->getValue()) == "defs")
return errorOrWarn;
+ if (StringRef(arg->getValue()) == "undefs")
+ return UnresolvedPolicy::Ignore;
continue;
}
}
@@ -747,6 +772,12 @@ static bool getCompressDebugSections(opt::InputArgList &args) {
return true;
}
+static StringRef getAliasSpelling(opt::Arg *arg) {
+ if (const opt::Arg *alias = arg->getAlias())
+ return alias->getSpelling();
+ return arg->getSpelling();
+}
+
static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args,
unsigned id) {
auto *arg = args.getLastArg(id);
@@ -756,7 +787,7 @@ static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args,
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);
+ error(getAliasSpelling(arg) + " expects 'old;new' format, but got " + s);
return ret;
}
@@ -829,6 +860,7 @@ static void readConfigs(opt::InputArgList &args) {
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 = args.hasArg(OPT_force_bti);
config->requireCET = args.hasArg(OPT_require_cet);
config->gcSections = args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false);
@@ -847,7 +879,7 @@ static void readConfigs(opt::InputArgList &args) {
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->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->mapFile = args.getLastArgValue(OPT_Map);
@@ -892,17 +924,15 @@ static void 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->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files);
+ 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_plugin_opt_thinlto_object_suffix_replace_eq);
+ getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq);
config->thinLTOPrefixReplace =
- getOldNewOptions(args, OPT_plugin_opt_thinlto_prefix_replace_eq);
+ getOldNewOptions(args, OPT_thinlto_prefix_replace_eq);
config->trace = args.hasArg(OPT_trace);
config->undefined = args::getStrings(args, OPT_undefined);
config->undefinedVersion =
@@ -935,6 +965,7 @@ static void readConfigs(opt::InputArgList &args) {
config->zRelro = getZFlag(args, "relro", "norelro", true);
config->zRetpolineplt = hasZOption(args, "retpolineplt");
config->zRodynamic = hasZOption(args, "rodynamic");
+ config->zSeparate = getZSeparate(args);
config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0);
config->zText = getZFlag(args, "text", "notext", true);
config->zWxneeded = hasZOption(args, "wxneeded");
@@ -966,7 +997,8 @@ static void readConfigs(opt::InputArgList &args) {
StringRef s = arg->getValue();
std::tie(config->ekind, config->emachine, config->osabi) =
parseEmulation(s);
- config->mipsN32Abi = (s == "elf32btsmipn32" || s == "elf32ltsmipn32");
+ config->mipsN32Abi =
+ (s.startswith("elf32btsmipn32") || s.startswith("elf32ltsmipn32"));
config->emulation = s;
}
@@ -1009,30 +1041,33 @@ static void readConfigs(opt::InputArgList &args) {
}
}
+ assert(config->versionDefinitions.empty());
+ config->versionDefinitions.push_back({"local", (uint16_t)VER_NDX_LOCAL, {}});
+ config->versionDefinitions.push_back(
+ {"global", (uint16_t)VER_NDX_GLOBAL, {}});
+
// If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
if (auto *arg = args.getLastArg(OPT_retain_symbols_file)) {
- config->defaultSymbolVersion = VER_NDX_LOCAL;
+ config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(
+ {"*", /*isExternCpp=*/false, /*hasWildcard=*/true});
if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
for (StringRef s : args::getLines(*buffer))
- config->versionScriptGlobals.push_back(
- {s, /*IsExternCpp*/ false, /*HasWildcard*/ false});
+ config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back(
+ {s, /*isExternCpp=*/false, /*hasWildcard=*/false});
}
- bool hasExportDynamic =
- args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, 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 (!hasExportDynamic) {
+ 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});
+ {arg->getValue(), /*isExternCpp=*/false, /*hasWildcard=*/false});
}
// If --export-dynamic-symbol=foo is given and symbol foo is defined in
@@ -1658,12 +1693,6 @@ template <class ELFT> static uint32_t getAndFeatures() {
return ret;
}
-static const char *libcallRoutineNames[] = {
-#define HANDLE_LIBCALL(code, name) name,
-#include "llvm/IR/RuntimeLibcalls.def"
-#undef HANDLE_LIBCALL
-};
-
// 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) {
@@ -1754,7 +1783,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// libcall symbols will be added to the link after LTO when we add the LTO
// object file to the link.
if (!bitcodeFiles.empty())
- for (const char *s : libcallRoutineNames)
+ for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
handleLibcall(s);
// Return if there were name resolution errors.
@@ -1879,20 +1908,54 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
"feature detected");
}
- // This adds a .comment section containing a version string. We have to add it
- // before mergeSections because the .comment section is a mergeable section.
+ // This adds a .comment section containing a version string.
if (!config->relocatable)
inputSections.push_back(createCommentSection());
// Replace common symbols with regular symbols.
replaceCommonSymbols();
- // Do size optimizations: garbage collection, merging of SHF_MERGE sections
- // and identical code folding.
+ // Split SHF_MERGE and .eh_frame sections into pieces in preparation for garbage collection.
splitSections<ELFT>();
+
+ // Garbage collection and removal of shared symbols from unused shared objects.
markLive<ELFT>();
demoteSharedSymbols();
- mergeSections();
+
+ // Make copies of any input sections that need to be copied into each
+ // partition.
+ copySectionsIntoPartitions();
+
+ // Create synthesized sections such as .got and .plt. This is called before
+ // processSectionCommands() so that they can be placed by SECTIONS commands.
+ createSyntheticSections<ELFT>();
+
+ // Some input sections that are used for exception handling need to be moved
+ // into synthetic sections. Do that now so that they aren't assigned to
+ // output sections in the usual way.
+ if (!config->relocatable)
+ combineEhSections();
+
+ // Create output sections described by SECTIONS commands.
+ script->processSectionCommands();
+
+ // Linker scripts control how input sections are assigned to output sections.
+ // Input sections that were not handled by scripts are called "orphans", and
+ // they are assigned to output sections by the default rule. Process that.
+ script->addOrphanSections();
+
+ // Migrate InputSectionDescription::sectionBases to sections. This includes
+ // merging MergeInputSections into a single MergeSyntheticSection. From this
+ // point onwards InputSectionDescription::sections should be used instead of
+ // sectionBases.
+ for (BaseCommand *base : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(base))
+ sec->finalizeInputSections();
+ llvm::erase_if(inputSections,
+ [](InputSectionBase *s) { return isa<MergeInputSection>(s); });
+
+ // Two input sections with different output sections should not be folded.
+ // ICF runs after processSectionCommands() so that we know the output sections.
if (config->icf != ICFLevel::None) {
findKeepUniqueSections<ELFT>(args);
doIcf<ELFT>();
@@ -1909,3 +1972,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// Write the result to the file.
writeResult<ELFT>();
}
+
+} // namespace elf
+} // namespace lld