diff options
Diffstat (limited to 'ELF/Driver.cpp')
-rw-r--r-- | ELF/Driver.cpp | 150 |
1 files changed, 108 insertions, 42 deletions
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index fbfc71d22b7e5..96257a4c76247 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 |