summaryrefslogtreecommitdiff
path: root/lld/ELF/Driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Driver.cpp')
-rw-r--r--lld/ELF/Driver.cpp114
1 files changed, 74 insertions, 40 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 96257a4c76247..23da749d30785 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -75,14 +75,17 @@ LinkerDriver *driver;
static void setConfigs(opt::InputArgList &args);
static void readConfigs(opt::InputArgList &args);
-bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &error) {
+bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
+ raw_ostream &stderrOS) {
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
+
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;
- enableColors(error.has_colors());
+ stderrOS.enable_colors(stderrOS.has_colors());
inputSections.clear();
outputSections.clear();
@@ -162,10 +165,7 @@ std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers(
std::vector<std::pair<MemoryBufferRef, uint64_t>> v;
Error err = Error::success();
bool addToTar = file->isThin() && tar;
- for (const ErrorOr<Archive::Child> &cOrErr : file->children(err)) {
- Archive::Child c =
- CHECK(cOrErr, mb.getBufferIdentifier() +
- ": could not get the child of the archive");
+ for (const Archive::Child &c : file->children(err)) {
MemoryBufferRef mbref =
CHECK(c.getMemoryBufferRef(),
mb.getBufferIdentifier() +
@@ -346,14 +346,14 @@ static void checkOptions() {
error("-execute-only and -no-rosegment cannot be used together");
}
- if (config->zRetpolineplt && config->requireCET)
- error("--require-cet may not be used with -z retpolineplt");
+ if (config->zRetpolineplt && config->zForceIbt)
+ error("-z force-ibt may not be used with -z retpolineplt");
if (config->emachine != EM_AARCH64) {
if (config->pacPlt)
- error("--pac-plt only supported on AArch64");
+ error("-z pac-plt only supported on AArch64");
if (config->forceBTI)
- error("--force-bti only supported on AArch64");
+ error("-z force-bti only supported on AArch64");
}
}
@@ -394,18 +394,33 @@ static SeparateSegmentKind getZSeparate(opt::InputArgList &args) {
return SeparateSegmentKind::None;
}
+static GnuStackKind getZGnuStack(opt::InputArgList &args) {
+ for (auto *arg : args.filtered_reverse(OPT_z)) {
+ if (StringRef("execstack") == arg->getValue())
+ return GnuStackKind::Exec;
+ if (StringRef("noexecstack") == arg->getValue())
+ return GnuStackKind::NoExec;
+ if (StringRef("nognustack") == arg->getValue())
+ return GnuStackKind::None;
+ }
+
+ return GnuStackKind::NoExec;
+}
+
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 == "execstack" || s == "force-bti" || s == "force-ibt" ||
+ 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 == "noseparate-code" || s == "notext" || s == "now" ||
- s == "origin" || s == "relro" || s == "retpolineplt" ||
- s == "rodynamic" || s == "text" || s == "undefs" || s == "wxneeded" ||
+ 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=");
}
@@ -861,8 +876,7 @@ static void readConfigs(opt::InputArgList &args) {
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->forceBTI = hasZOption(args, "force-bti");
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);
@@ -886,6 +900,8 @@ static void readConfigs(opt::InputArgList &args) {
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->mmapOutputFile =
+ args.hasFlag(OPT_mmap_output_file, OPT_no_mmap_output_file, true);
config->nmagic = args.hasFlag(OPT_nmagic, OPT_no_nmagic, false);
config->noinhibitExec = args.hasArg(OPT_noinhibit_exec);
config->nostdlib = args.hasArg(OPT_nostdlib);
@@ -898,7 +914,7 @@ 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 = args.hasArg(OPT_pac_plt);
+ 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);
@@ -949,8 +965,9 @@ 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->zExecstack = getZFlag(args, "execstack", "noexecstack", false);
+ config->zForceIbt = hasZOption(args, "force-ibt");
config->zGlobal = hasZOption(args, "global");
+ config->zGnustack = getZGnuStack(args);
config->zHazardplt = hasZOption(args, "hazardplt");
config->zIfuncNoplt = hasZOption(args, "ifunc-noplt");
config->zInitfirst = hasZOption(args, "initfirst");
@@ -966,6 +983,7 @@ static void readConfigs(opt::InputArgList &args) {
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->zText = getZFlag(args, "text", "notext", true);
config->zWxneeded = hasZOption(args, "wxneeded");
@@ -992,6 +1010,14 @@ static void readConfigs(opt::InputArgList &args) {
if (config->splitStackAdjustSize < 0)
error("--split-stack-adjust-size: size must be >= 0");
+ // The text segment is traditionally the first segment, whose address equals
+ // the base address. However, lld places the R PT_LOAD first. -Ttext-segment
+ // is an old-fashioned option that does not play well with lld's layout.
+ // Suggest --image-base as a likely alternative.
+ if (args.hasArg(OPT_Ttext_segment))
+ error("-Ttext-segment is not supported. Use --image-base if you "
+ "intend to set the base address");
+
// Parse ELF{32,64}{LE,BE} and CPU type.
if (auto *arg = args.getLastArg(OPT_m)) {
StringRef s = arg->getValue();
@@ -1349,7 +1375,7 @@ static void excludeLibs(opt::InputArgList &args) {
if (!file->archiveName.empty())
if (all || libs.count(path::filename(file->archiveName)))
for (Symbol *sym : file->getSymbols())
- if (!sym->isLocal() && sym->file == file)
+ if (!sym->isUndefined() && !sym->isLocal() && sym->file == file)
sym->versionId = VER_NDX_LOCAL;
};
@@ -1370,7 +1396,7 @@ static void handleUndefined(Symbol *sym) {
sym->fetch();
}
-// As an extention to GNU linkers, lld supports a variant of `-u`
+// As an extension to GNU linkers, lld supports a variant of `-u`
// which accepts wildcard patterns. All symbols that match a given
// pattern are handled as if they were given by `-u`.
static void handleUndefinedGlob(StringRef arg) {
@@ -1381,13 +1407,13 @@ static void handleUndefinedGlob(StringRef arg) {
}
std::vector<Symbol *> syms;
- symtab->forEachSymbol([&](Symbol *sym) {
+ for (Symbol *sym : symtab->symbols()) {
// Calling Sym->fetch() from here is not safe because it may
// add new symbols to the symbol table, invalidating the
// current iterator. So we just keep a note.
if (pat->match(sym->getName()))
syms.push_back(sym);
- });
+ }
for (Symbol *sym : syms)
handleUndefined(sym);
@@ -1413,10 +1439,10 @@ static void handleLibcall(StringRef name) {
// result, the passes after the symbol resolution won't see any
// symbols of type CommonSymbol.
static void replaceCommonSymbols() {
- symtab->forEachSymbol([](Symbol *sym) {
+ for (Symbol *sym : symtab->symbols()) {
auto *s = dyn_cast<CommonSymbol>(sym);
if (!s)
- return;
+ continue;
auto *bss = make<BssSection>("COMMON", s->size, s->alignment);
bss->file = s->file;
@@ -1424,7 +1450,7 @@ static void replaceCommonSymbols() {
inputSections.push_back(bss);
s->replace(Defined{s->file, s->getName(), s->binding, s->stOther, s->type,
/*value=*/0, s->size, bss});
- });
+ }
}
// If all references to a DSO happen to be weak, the DSO is not added
@@ -1432,15 +1458,15 @@ static void replaceCommonSymbols() {
// created from the DSO. Otherwise, they become dangling references
// that point to a non-existent DSO.
static void demoteSharedSymbols() {
- symtab->forEachSymbol([](Symbol *sym) {
+ for (Symbol *sym : symtab->symbols()) {
auto *s = dyn_cast<SharedSymbol>(sym);
if (!s || s->getFile().isNeeded)
- return;
+ continue;
bool used = s->used;
s->replace(Undefined{nullptr, s->getName(), STB_WEAK, s->stOther, s->type});
s->used = used;
- });
+ }
}
// The section referred to by `s` is considered address-significant. Set the
@@ -1476,10 +1502,9 @@ static void findKeepUniqueSections(opt::InputArgList &args) {
// Symbols in the dynsym could be address-significant in other executables
// or DSOs, so we conservatively mark them as address-significant.
- symtab->forEachSymbol([&](Symbol *sym) {
+ for (Symbol *sym : symtab->symbols())
if (sym->includeInDynsym())
markAddrsig(sym);
- });
// Visit the address-significance table in each object file and mark each
// referenced symbol as address-significant.
@@ -1663,12 +1688,8 @@ static void wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {
// with CET. We enable the feature only when all object files are compatible
// with CET.
//
-// This function returns the merged feature flags. If 0, we cannot enable CET.
// This is also the case with AARCH64's BTI and PAC which use the similar
// GNU_PROPERTY_AARCH64_FEATURE_1_AND mechanism.
-//
-// Note that the CET-aware PLT is not implemented yet. We do error
-// check only.
template <class ELFT> static uint32_t getAndFeatures() {
if (config->emachine != EM_386 && config->emachine != EM_X86_64 &&
config->emachine != EM_AARCH64)
@@ -1678,10 +1699,14 @@ template <class ELFT> static uint32_t getAndFeatures() {
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) + ": --force-bti: file does not have BTI property");
+ warn(toString(f) + ": -z force-bti: file does not have BTI property");
features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
- } else if (!features && config->requireCET)
- error(toString(f) + ": --require-cet: file is not compatible with CET");
+ } else if (config->zForceIbt &&
+ !(features & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
+ warn(toString(f) + ": -z force-ibt: file does not have "
+ "GNU_PROPERTY_X86_FEATURE_1_IBT property");
+ features |= GNU_PROPERTY_X86_FEATURE_1_IBT;
+ }
ret &= features;
}
@@ -1689,6 +1714,9 @@ template <class ELFT> static uint32_t getAndFeatures() {
// 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;
return ret;
}
@@ -1765,6 +1793,12 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
for (StringRef pat : args::getStrings(args, OPT_undefined_glob))
handleUndefinedGlob(pat);
+ // Mark -init and -fini symbols so that the LTO doesn't eliminate them.
+ if (Symbol *sym = symtab->find(config->init))
+ sym->isUsedInRegularObj = true;
+ if (Symbol *sym = symtab->find(config->fini))
+ sym->isUsedInRegularObj = true;
+
// If any of our inputs are bitcode files, the LTO code generator may create
// references to certain library functions that might not be explicit in the
// bitcode file's symbol table. If any of those library functions are defined