aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lld/ELF/Driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lld/ELF/Driver.cpp')
-rw-r--r--contrib/llvm-project/lld/ELF/Driver.cpp171
1 files changed, 97 insertions, 74 deletions
diff --git a/contrib/llvm-project/lld/ELF/Driver.cpp b/contrib/llvm-project/lld/ELF/Driver.cpp
index 6b689f50cce7..de26afddd28b 100644
--- a/contrib/llvm-project/lld/ELF/Driver.cpp
+++ b/contrib/llvm-project/lld/ELF/Driver.cpp
@@ -77,16 +77,17 @@ std::unique_ptr<LinkerDriver> elf::driver;
static void setConfigs(opt::InputArgList &args);
static void readConfigs(opt::InputArgList &args);
-bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
- raw_ostream &stdoutOS, raw_ostream &stderrOS) {
- lld::stdoutOS = &stdoutOS;
- lld::stderrOS = &stderrOS;
-
- errorHandler().cleanupCallback = []() {
- freeArena();
-
+bool elf::link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
+ llvm::raw_ostream &stderrOS, bool exitEarly,
+ bool disableOutput) {
+ // This driver-specific context will be freed later by lldMain().
+ auto *ctx = new CommonLinkerContext;
+
+ ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
+ ctx->e.cleanupCallback = []() {
inputSections.clear();
outputSections.clear();
+ memoryBuffers.clear();
archiveFiles.clear();
binaryFiles.clear();
bitcodeFiles.clear();
@@ -95,43 +96,33 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
sharedFiles.clear();
backwardReferences.clear();
whyExtract.clear();
+ symAux.clear();
tar = nullptr;
- memset(&in, 0, sizeof(in));
+ in.reset();
- partitions = {Partition()};
+ partitions.clear();
+ partitions.emplace_back();
SharedFile::vernauxNum = 0;
};
-
- errorHandler().logName = args::getFilenameWithoutExe(args[0]);
- errorHandler().errorLimitExceededMsg =
- "too many errors emitted, stopping now (use "
- "-error-limit=0 to see all errors)";
- errorHandler().exitEarly = canExitEarly;
- stderrOS.enable_colors(stderrOS.has_colors());
+ ctx->e.logName = args::getFilenameWithoutExe(args[0]);
+ ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use "
+ "-error-limit=0 to see all errors)";
config = std::make_unique<Configuration>();
driver = std::make_unique<LinkerDriver>();
script = std::make_unique<LinkerScript>();
symtab = std::make_unique<SymbolTable>();
- partitions = {Partition()};
+ partitions.clear();
+ partitions.emplace_back();
config->progName = args[0];
driver->linkerMain(args);
- // Exit immediately if we don't need to return to the caller.
- // This saves time because the overhead of calling destructors
- // for all globally-allocated objects is not negligible.
- if (canExitEarly)
- exitLld(errorCount() ? 1 : 0);
-
- bool ret = errorCount() == 0;
- if (!canExitEarly)
- errorHandler().reset();
- return ret;
+ return errorCount() == 0;
}
// Parses a linker -m option.
@@ -232,23 +223,22 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) {
std::unique_ptr<Archive> file =
CHECK(Archive::create(mbref), path + ": failed to parse archive");
- // If an archive file has no symbol table, it is likely that a user
- // is attempting LTO and using a default ar command that doesn't
- // understand the LLVM bitcode file. It is a pretty common error, so
- // we'll handle it as if it had a symbol table.
+ // If an archive file has no symbol table, it may be intentional (used as a
+ // group of lazy object files where the symbol table is not useful), or the
+ // user is attempting LTO and using a default ar command that doesn't
+ // understand the LLVM bitcode file. Treat the archive as a group of lazy
+ // object files.
if (!file->isEmpty() && !file->hasSymbolTable()) {
- // Check if all members are bitcode files. If not, ignore, which is the
- // default action without the LTO hack described above.
- for (const std::pair<MemoryBufferRef, uint64_t> &p :
- getArchiveMembers(mbref))
- if (identify_magic(p.first.getBuffer()) != file_magic::bitcode) {
- error(path + ": archive has no index; run ranlib to add one");
- return;
- }
-
for (const std::pair<MemoryBufferRef, uint64_t> &p :
- getArchiveMembers(mbref))
- files.push_back(createLazyFile(p.first, path, p.second));
+ getArchiveMembers(mbref)) {
+ auto magic = identify_magic(p.first.getBuffer());
+ if (magic == file_magic::bitcode ||
+ magic == file_magic::elf_relocatable)
+ files.push_back(createLazyFile(p.first, path, p.second));
+ else
+ error(path + ": archive member '" + p.first.getBufferIdentifier() +
+ "' is neither ET_REL nor LLVM bitcode");
+ }
return;
}
@@ -1256,7 +1246,7 @@ static void readConfigs(opt::InputArgList &args) {
// Parse LTO options.
if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq))
- parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())),
+ parseClangOption(saver().save("-mcpu=" + StringRef(arg->getValue())),
arg->getSpelling());
for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq_minus))
@@ -1724,7 +1714,7 @@ static void handleUndefinedGlob(StringRef arg) {
// symbols to the symbol table, invalidating the current iterator.
std::vector<Symbol *> syms;
for (Symbol *sym : symtab->symbols())
- if (pat->match(sym->getName()))
+ if (!sym->isPlaceholder() && pat->match(sym->getName()))
syms.push_back(sym);
for (Symbol *sym : syms)
@@ -1847,8 +1837,7 @@ static void demoteSharedSymbols() {
llvm::TimeTraceScope timeScope("Demote shared symbols");
for (Symbol *sym : symtab->symbols()) {
auto *s = dyn_cast<SharedSymbol>(sym);
- if (!((s && !s->getFile().isNeeded) ||
- (sym->isLazy() && sym->isUsedInRegularObj)))
+ if (!(s && !s->getFile().isNeeded) && !sym->isLazy())
continue;
bool used = sym->used;
@@ -1985,6 +1974,28 @@ static Symbol *addUnusedUndefined(StringRef name,
return symtab->addSymbol(sym);
}
+static void markBuffersAsDontNeed(bool skipLinkedOutput) {
+ // With --thinlto-index-only, all buffers are nearly unused from now on
+ // (except symbol/section names used by infrequent passes). Mark input file
+ // buffers as MADV_DONTNEED so that these pages can be reused by the expensive
+ // thin link, saving memory.
+ if (skipLinkedOutput) {
+ for (MemoryBuffer &mb : llvm::make_pointee_range(memoryBuffers))
+ mb.dontNeedIfMmap();
+ return;
+ }
+
+ // Otherwise, just mark MemoryBuffers backing BitcodeFiles.
+ DenseSet<const char *> bufs;
+ for (BitcodeFile *file : bitcodeFiles)
+ bufs.insert(file->mb.getBufferStart());
+ for (BitcodeFile *file : lazyBitcodeFiles)
+ bufs.insert(file->mb.getBufferStart());
+ for (MemoryBuffer &mb : llvm::make_pointee_range(memoryBuffers))
+ if (bufs.count(mb.getBufferStart()))
+ mb.dontNeedIfMmap();
+}
+
// 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.
@@ -1992,13 +2003,17 @@ static Symbol *addUnusedUndefined(StringRef name,
// using LLVM functions and replaces bitcode symbols with the results.
// 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() {
+template <class ELFT>
+void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
llvm::TimeTraceScope timeScope("LTO");
// Compile bitcode files and replace bitcode symbols.
lto.reset(new BitcodeCompiler);
for (BitcodeFile *file : bitcodeFiles)
lto->add(*file);
+ if (!bitcodeFiles.empty())
+ markBuffersAsDontNeed(skipLinkedOutput);
+
for (InputFile *file : lto->compile()) {
auto *obj = cast<ObjFile<ELFT>>(file);
obj->parse(/*ignoreComdats=*/true);
@@ -2006,7 +2021,8 @@ template <class ELFT> void LinkerDriver::compileBitcodeFiles() {
// Parse '@' in symbol names for non-relocatable output.
if (!config->relocatable)
for (Symbol *sym : obj->getGlobalSymbols())
- sym->parseSymbolVersion();
+ if (sym->hasVersionSuffix)
+ sym->parseSymbolVersion();
objectFiles.push_back(obj);
}
}
@@ -2043,9 +2059,9 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
if (!sym)
continue;
- Symbol *real = addUnusedUndefined(saver.save("__real_" + name));
+ Symbol *real = addUnusedUndefined(saver().save("__real_" + name));
Symbol *wrap =
- addUnusedUndefined(saver.save("__wrap_" + name), sym->binding);
+ addUnusedUndefined(saver().save("__wrap_" + name), sym->binding);
v.push_back({sym, real, wrap});
// We want to tell LTO not to inline symbols to be overwritten
@@ -2080,8 +2096,10 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
map[w.real] = w.sym;
}
for (Symbol *sym : symtab->symbols()) {
- // Enumerate symbols with a non-default version (foo@v1).
- StringRef name = sym->getName();
+ // Enumerate symbols with a non-default version (foo@v1). hasVersionSuffix
+ // filters out most symbols but is not sufficient.
+ if (!sym->hasVersionSuffix)
+ continue;
const char *suffix1 = sym->getVersionSuffix();
if (suffix1[0] != '@' || suffix1[1] == '@')
continue;
@@ -2090,7 +2108,7 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
//
// * There is a definition of foo@v1 and foo@@v1.
// * There is a definition of foo@v1 and foo.
- Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find(name));
+ Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find(sym->getName()));
if (!sym2)
continue;
const char *suffix2 = sym2->getVersionSuffix();
@@ -2103,6 +2121,7 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
sym2->resolve(*sym);
// Eliminate foo@v1 from the symbol table.
sym->symbolKind = Symbol::PlaceholderKind;
+ sym->isUsedInRegularObj = false;
} else if (auto *sym1 = dyn_cast<Defined>(sym)) {
if (sym2->versionId > VER_NDX_GLOBAL
? config->versionDefinitions[sym2->versionId].name == suffix1 + 1
@@ -2115,6 +2134,7 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
// defined in the same place.
map.try_emplace(sym2, sym);
sym2->symbolKind = Symbol::PlaceholderKind;
+ sym2->isUsedInRegularObj = false;
}
}
}
@@ -2357,39 +2377,45 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
symtab->scanVersionScript();
}
+ // Skip the normal linked output if some LTO options are specified.
+ //
+ // For --thinlto-index-only, index file creation is performed in
+ // compileBitcodeFiles, so we are done afterwards. --plugin-opt=emit-llvm and
+ // --plugin-opt=emit-asm create output files in bitcode or assembly code,
+ // respectively. When only certain thinLTO modules are specified for
+ // compilation, the intermediate object file are the expected output.
+ const bool skipLinkedOutput = config->thinLTOIndexOnly || config->emitLLVM ||
+ config->ltoEmitAsm ||
+ !config->thinLTOModulesToCompile.empty();
+
// Do link-time optimization if given files are LLVM bitcode files.
// This compiles bitcode files into real object files.
//
// 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>();
-
- // Handle --exclude-libs again because lto.tmp may reference additional
- // libcalls symbols defined in an excluded archive. This may override
- // versionId set by scanVersionScript().
- if (args.hasArg(OPT_exclude_libs))
- excludeLibs(args);
+ compileBitcodeFiles<ELFT>(skipLinkedOutput);
// 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 compileBitcodeFiles, so we are done if that's the case.
- // Likewise, --plugin-opt=emit-llvm and --plugin-opt=emit-asm are the
- // options to create output files in bitcode or assembly code
- // respectively. 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())
+ // Bail out if normal linked output is skipped due to LTO.
+ if (skipLinkedOutput)
return;
+ // Handle --exclude-libs again because lto.tmp may reference additional
+ // libcalls symbols defined in an excluded archive. This may override
+ // versionId set by scanVersionScript().
+ if (args.hasArg(OPT_exclude_libs))
+ excludeLibs(args);
+
// Apply symbol renames for --wrap and combine foo@v1 and foo@@v1.
redirectSymbols(wrapped);
+ // Replace common symbols with regular symbols.
+ replaceCommonSymbols();
+
{
llvm::TimeTraceScope timeScope("Aggregate sections");
// Now that we have a complete list of input files.
@@ -2474,9 +2500,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
if (!config->relocatable)
inputSections.push_back(createCommentSection());
- // Replace common symbols with regular symbols.
- replaceCommonSymbols();
-
// Split SHF_MERGE and .eh_frame sections into pieces in preparation for garbage collection.
splitSections<ELFT>();