It seems to be causing issues on https://lab.llvm.org/buildbot/#/builders/123/builds/8383
#include "InputFiles.h"
#include "SymbolTable.h"
#include "Writer.h"
-#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Timer.h"
namespace lld {
namespace coff {
-class COFFLinkerContext : public CommonLinkerContext {
+class COFFLinkerContext {
public:
COFFLinkerContext();
COFFLinkerContext(const COFFLinkerContext &) = delete;
#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
+#include "lld/Common/ErrorHandler.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/Object/COFF.h"
return;
warn("some relocations in " + file->getName() + " are not sorted");
MutableArrayRef<coff_relocation> newRelocs(
- bAlloc().Allocate<coff_relocation>(relocsSize), relocsSize);
+ bAlloc.Allocate<coff_relocation>(relocsSize), relocsSize);
memcpy(newRelocs.data(), relocsData, relocsSize * sizeof(coff_relocation));
llvm::sort(newRelocs, cmpByVa);
setRelocs(newRelocs);
// Add a syntentic symbol for this load thunk, using the "__imp_load"
// prefix, in case this thunk needs to be added to the list of valid
// call targets for Control Flow Guard.
- StringRef symName = saver().save("__imp_load_" + extName);
+ StringRef symName = saver.save("__imp_load_" + extName);
s->loadThunkSym =
cast<DefinedSynthetic>(ctx.symtab.addSynthetic(symName, t));
}
}
thunks.push_back(tm);
StringRef tmName =
- saver().save("__tailMerge_" + syms[0]->getDLLName().lower());
+ saver.save("__tailMerge_" + syms[0]->getDLLName().lower());
ctx.symtab.addSynthetic(tmName, tm);
// Terminate with null values.
addresses.push_back(make<NullChunk>(8));
#include "Writer.h"
#include "lld/Common/Args.h"
#include "lld/Common/Driver.h"
+#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Filesystem.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Timer.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/Optional.h"
std::unique_ptr<Configuration> config;
std::unique_ptr<LinkerDriver> driver;
-bool link(ArrayRef<const char *> args, raw_ostream &stdoutOS,
- raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {
- // This driver-specific context will be freed later by lldMain().
- // It is created on the heap to avoid destructors if 'exitEarly' is set.
- auto *ctx = new COFFLinkerContext;
+bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
+ raw_ostream &stderrOS) {
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
- ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
- ctx->e.logName = args::getFilenameWithoutExe(args[0]);
- ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now"
- " (use /errorlimit:0 to see all errors)";
+ errorHandler().cleanupCallback = []() {
+ freeArena();
+ };
+
+ errorHandler().logName = args::getFilenameWithoutExe(args[0]);
+ errorHandler().errorLimitExceededMsg =
+ "too many errors emitted, stopping now"
+ " (use /errorlimit:0 to see all errors)";
+ errorHandler().exitEarly = canExitEarly;
+ stderrOS.enable_colors(stderrOS.has_colors());
+ COFFLinkerContext ctx;
config = std::make_unique<Configuration>();
- driver = std::make_unique<LinkerDriver>(*ctx);
+ driver = std::make_unique<LinkerDriver>(ctx);
driver->linkerMain(args);
- return errorCount() == 0;
+ // Call exit() if we can to avoid calling destructors.
+ if (canExitEarly)
+ exitLld(errorCount() ? 1 : 0);
+
+ bool ret = errorCount() == 0;
+ if (!canExitEarly)
+ errorHandler().reset();
+ return ret;
}
// Parse options of the form "old;new".
static StringRef mangle(StringRef sym) {
assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN);
if (config->machine == I386)
- return saver().save("_" + sym);
+ return saver.save("_" + sym);
return sym;
}
Export exp = parseExport(e);
if (config->machine == I386 && config->mingw) {
if (!isDecorated(exp.name))
- exp.name = saver().save("_" + exp.name);
+ exp.name = saver.save("_" + exp.name);
if (!exp.extName.empty() && !isDecorated(exp.extName))
- exp.extName = saver().save("_" + exp.extName);
+ exp.extName = saver.save("_" + exp.extName);
}
exp.directives = true;
config->exports.push_back(exp);
SmallString<128> path = dir;
sys::path::append(path, filename);
if (sys::fs::exists(path.str()))
- return saver().save(path.str());
+ return saver.save(path.str());
if (!hasExt) {
path.append(".obj");
if (sys::fs::exists(path.str()))
- return saver().save(path.str());
+ return saver.save(path.str());
}
}
return filename;
SmallString<128> s = filename;
sys::path::replace_extension(s, ".a");
- StringRef libName = saver().save("lib" + s.str());
+ StringRef libName = saver.save("lib" + s.str());
return doFindFile(libName);
}
// Add ".lib" to Filename if that has no file extension.
bool hasExt = filename.contains('.');
if (!hasExt)
- filename = saver().save(filename + ".lib");
+ filename = saver.save(filename + ".lib");
StringRef ret = doFindFile(filename);
// For MinGW, if the find above didn't turn up anything, try
// looking for a MinGW formatted library name.
Optional<std::string> envOpt = Process::GetEnv("LIB");
if (!envOpt.hasValue())
return;
- StringRef env = saver().save(*envOpt);
+ StringRef env = saver.save(*envOpt);
while (!env.empty()) {
StringRef path;
std::tie(path, env) = env.split(';');
driver->takeBuffer(std::move(mb));
if (config->outputFile.empty())
- config->outputFile = std::string(saver().save(m.OutputFile));
- config->importName = std::string(saver().save(m.ImportName));
+ config->outputFile = std::string(saver.save(m.OutputFile));
+ config->importName = std::string(saver.save(m.ImportName));
if (m.ImageBase)
config->imageBase = m.ImageBase;
if (m.StackReserve)
// DLL instead. This is supported by both MS and GNU linkers.
if (!e1.ExtName.empty() && e1.ExtName != e1.Name &&
StringRef(e1.Name).contains('.')) {
- e2.name = saver().save(e1.ExtName);
- e2.forwardTo = saver().save(e1.Name);
+ e2.name = saver.save(e1.ExtName);
+ e2.forwardTo = saver.save(e1.Name);
config->exports.push_back(e2);
continue;
}
- e2.name = saver().save(e1.Name);
- e2.extName = saver().save(e1.ExtName);
+ e2.name = saver.save(e1.Name);
+ e2.extName = saver.save(e1.ExtName);
e2.ordinal = e1.Ordinal;
e2.noname = e1.Noname;
e2.data = e1.Data;
Export e = parseExport(arg->getValue());
if (config->machine == I386) {
if (!isDecorated(e.name))
- e.name = saver().save("_" + e.name);
+ e.name = saver.save("_" + e.name);
if (!e.extName.empty() && !isDecorated(e.extName))
- e.extName = saver().save("_" + e.extName);
+ e.extName = saver.save("_" + e.extName);
}
config->exports.push_back(e);
}
class Executor {
public:
- explicit Executor(StringRef s) : prog(saver().save(s)) {}
- void add(StringRef s) { args.push_back(saver().save(s)); }
- void add(std::string &s) { args.push_back(saver().save(s)); }
- void add(Twine s) { args.push_back(saver().save(s)); }
- void add(const char *s) { args.push_back(saver().save(s)); }
+ explicit Executor(StringRef s) : prog(saver.save(s)) {}
+ void add(StringRef s) { args.push_back(saver.save(s)); }
+ void add(std::string &s) { args.push_back(saver.save(s)); }
+ void add(Twine s) { args.push_back(saver.save(s)); }
+ void add(const char *s) { args.push_back(saver.save(s)); }
void run() {
ErrorOr<std::string> exeOrErr = sys::findProgramByName(prog);
if (auto ec = exeOrErr.getError())
fatal("unable to find " + prog + " in PATH: " + ec.message());
- StringRef exe = saver().save(*exeOrErr);
+ StringRef exe = saver.save(*exeOrErr);
args.insert(args.begin(), exe);
if (sys::ExecuteAndWait(args[0], args) != 0)
sym = sym.substr(0, sym.find('@', 1));
if (!sym.startswith("@")) {
if (prefix && !sym.startswith("_"))
- return saver().save("_" + sym);
+ return saver.save("_" + sym);
return sym;
}
// For fastcall, remove the leading @ and replace it with an
// underscore, if prefixes are used.
sym = sym.substr(1);
if (prefix)
- sym = saver().save("_" + sym);
+ sym = saver.save("_" + sym);
return sym;
}
argv.data() + argv.size());
if (!args.hasArg(OPT_lldignoreenv))
addLINK(expandedArgv);
- cl::ExpandResponseFiles(saver(), getQuotingStyle(args), expandedArgv);
+ cl::ExpandResponseFiles(saver, getQuotingStyle(args), expandedArgv);
args = optTable.ParseArgs(makeArrayRef(expandedArgv).drop_front(),
missingIndex, missingCount);
// Handle /EXPORT and /INCLUDE in a fast path. These directives can appear for
// potentially every symbol in the object, so they must be handled quickly.
SmallVector<StringRef, 16> tokens;
- cl::TokenizeWindowsCommandLineNoCopy(s, saver(), tokens);
+ cl::TokenizeWindowsCommandLineNoCopy(s, saver, tokens);
for (StringRef tok : tokens) {
if (tok.startswith_insensitive("/export:") ||
tok.startswith_insensitive("-export:"))
// already copied quoted arguments for us, so those do not need to be
// copied again.
bool HasNul = tok.end() != s.end() && tok.data()[tok.size()] == '\0';
- rest.push_back(HasNul ? tok.data() : saver().save(tok).data());
+ rest.push_back(HasNul ? tok.data() : saver.save(tok).data());
}
}
std::vector<const char *> ArgParser::tokenize(StringRef s) {
SmallVector<const char *, 16> tokens;
- cl::TokenizeWindowsCommandLine(s, saver(), tokens);
+ cl::TokenizeWindowsCommandLine(s, saver, tokens);
return std::vector<const char *>(tokens.begin(), tokens.end());
}
#include "SymbolTable.h"
#include "Symbols.h"
#include "lld/Common/DWARF.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm-c/lto.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
Optional<std::pair<std::string, unsigned>> ret = dwarf->getVariableLoc(var);
if (!ret)
return None;
- return std::make_pair(saver().save(ret->first), ret->second);
+ return std::make_pair(saver.save(ret->first), ret->second);
}
// Used only for DWARF debug info, which is not common (except in MinGW
fatal("broken import library");
// Read names and create an __imp_ symbol.
- StringRef name = saver().save(StringRef(buf + sizeof(*hdr)));
- StringRef impName = saver().save("__imp_" + name);
+ StringRef name = saver.save(StringRef(buf + sizeof(*hdr)));
+ StringRef impName = saver.save("__imp_" + name);
const char *nameStart = buf + sizeof(coff_import_header) + name.size() + 1;
dllName = std::string(StringRef(nameStart));
StringRef extName;
// into consideration at LTO time (which very likely causes undefined
// symbols later in the link stage). So we append file offset to make
// filename unique.
- MemoryBufferRef mbref(mb.getBuffer(),
- saver().save(archiveName.empty()
- ? path
- : archiveName +
- sys::path::filename(path) +
- utostr(offsetInArchive)));
+ MemoryBufferRef mbref(
+ mb.getBuffer(),
+ saver.save(archiveName.empty() ? path
+ : archiveName + sys::path::filename(path) +
+ utostr(offsetInArchive)));
obj = check(lto::InputFile::create(mbref));
}
} // namespace
void BitcodeFile::parse() {
- llvm::StringSaver &saver = lld::saver();
std::vector<std::pair<Symbol *, bool>> comdat(obj->getComdatTable().size());
for (size_t i = 0; i != obj->getComdatTable().size(); ++i)
// FIXME: Check nodeduplicate
s->nameType = ImportNameType::IMPORT_NAME;
if (coffObj->getMachine() == I386) {
- s->symbolName = symbolName = saver().save("_" + symbolName);
+ s->symbolName = symbolName = saver.save("_" + symbolName);
s->nameType = ImportNameType::IMPORT_NAME_NOPREFIX;
}
- StringRef impName = saver().save("__imp_" + symbolName);
+ StringRef impName = saver.save("__imp_" + symbolName);
ctx.symtab.addLazyDLLSymbol(this, s, impName);
if (code)
ctx.symtab.addLazyDLLSymbol(this, s, symbolName);
size_t impSize = s->dllName.size() + s->symbolName.size() + 2; // +2 for NULs
size_t size = sizeof(coff_import_header) + impSize;
- char *buf = bAlloc().Allocate<char>(size);
+ char *buf = bAlloc.Allocate<char>(size);
memset(buf, 0, size);
char *p = buf;
auto *imp = reinterpret_cast<coff_import_header *>(p);
#include "InputFiles.h"
#include "Symbols.h"
#include "lld/Common/Args.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
// - foo.exe.lto.1.obj
// - ...
StringRef ltoObjName =
- saver().save(Twine(config->outputFile) + ".lto" +
- (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".obj");
+ saver.save(Twine(config->outputFile) + ".lto" +
+ (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".obj");
// Get the native object contents either from the cache or from memory. Do
// not use the cached MemoryBuffer directly, or the PDB will not be
#include "Driver.h"
#include "InputFiles.h"
#include "SymbolTable.h"
+#include "lld/Common/ErrorHandler.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Object/COFF.h"
static StringRef mangle(Twine sym) {
assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN);
if (config->machine == I386)
- return saver().save("_" + sym);
- return saver().save(sym);
+ return saver.save("_" + sym);
+ return saver.save(sym);
}
// Handles -wrap option.
// referenced it or not, though.)
if (imp) {
DefinedLocalImport *wrapimp = make<DefinedLocalImport>(
- saver().save("__imp_" + w.wrap->getName()), d);
+ saver.save("__imp_" + w.wrap->getName()), d);
ctx.symtab.localImportChunks.push_back(wrapimp->getChunk());
map[imp] = wrapimp;
}
#include "Symbols.h"
#include "TypeMerger.h"
#include "Writer.h"
+#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Timer.h"
#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
public:
PDBLinker(COFFLinkerContext &ctx)
- : builder(bAlloc()), tMerger(ctx, bAlloc()), ctx(ctx) {
+ : builder(bAlloc), tMerger(ctx, bAlloc), ctx(ctx) {
// This isn't strictly necessary, but link.exe usually puts an empty string
// as the first "valid" string in the string table, so we do the same in
// order to maintain as much byte-for-byte compatibility as possible.
case SymbolKind::S_LPROCREF: {
// sym is a temporary object, so we have to copy and reallocate the record
// to stabilize it.
- uint8_t *mem = bAlloc().Allocate<uint8_t>(sym.length());
+ uint8_t *mem = bAlloc.Allocate<uint8_t>(sym.length());
memcpy(mem, sym.data().data(), sym.length());
builder.addGlobalSymbol(CVSymbol(makeArrayRef(mem, sym.length())));
break;
// Allocate memory for a .debug$S / .debug$F section and relocate it.
static ArrayRef<uint8_t> relocateDebugChunk(SectionChunk &debugChunk) {
- uint8_t *buffer = bAlloc().Allocate<uint8_t>(debugChunk.getSize());
+ uint8_t *buffer = bAlloc.Allocate<uint8_t>(debugChunk.getSize());
assert(debugChunk.getOutputSectionIdx() == 0 &&
"debug sections should not be in output sections");
debugChunk.writeTo(buffer);
ebs.Fields.push_back(path);
ebs.Fields.push_back("cmd");
ebs.Fields.push_back(argStr);
- llvm::BumpPtrAllocator &bAlloc = lld::bAlloc();
mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
ons, bAlloc, CodeViewContainer::Pdb));
mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
cgs.Characteristics |= llvm::COFF::IMAGE_SCN_MEM_WRITE;
mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
- cgs, bAlloc(), CodeViewContainer::Pdb));
+ cgs, bAlloc, CodeViewContainer::Pdb));
}
static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &mod,
sym.Rva = os.getRVA();
sym.SectionNumber = os.sectionIndex;
mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
- sym, bAlloc(), CodeViewContainer::Pdb));
+ sym, bAlloc, CodeViewContainer::Pdb));
// Skip COFF groups in MinGW because it adds a significant footprint to the
// PDB, due to each function being in its own section
ts.Segment = thunkOS->sectionIndex;
ts.Offset = thunkChunk->getRVA() - thunkOS->getRVA();
- llvm::BumpPtrAllocator &bAlloc = lld::bAlloc();
mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol(
ons, bAlloc, CodeViewContainer::Pdb));
mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol(
const DILineInfo &lineInfo = *optionalLineInfo;
if (lineInfo.FileName == DILineInfo::BadString)
return None;
- return std::make_pair(saver().save(lineInfo.FileName), lineInfo.Line);
+ return std::make_pair(saver.save(lineInfo.FileName), lineInfo.Line);
}
static Optional<std::pair<StringRef, uint32_t>>
MutableArrayRef<coff_relocation> newRelocs;
if (originalRelocs.data() == curRelocs.data()) {
newRelocs = makeMutableArrayRef(
- bAlloc().Allocate<coff_relocation>(originalRelocs.size()),
+ bAlloc.Allocate<coff_relocation>(originalRelocs.size()),
originalRelocs.size());
} else {
newRelocs = makeMutableArrayRef(
add_lld_library(lldCommon
Args.cpp
- CommonLinkerContext.cpp
DWARF.cpp
ErrorHandler.cpp
Filesystem.cpp
+++ /dev/null
-//===- CommonLinkerContext.cpp --------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lld/Common/CommonLinkerContext.h"
-#include "lld/Common/ErrorHandler.h"
-#include "lld/Common/Memory.h"
-
-using namespace llvm;
-using namespace lld;
-
-// Reference to the current LLD instance. This is a temporary situation, until
-// we pass this context everywhere by reference, or we make it a thread_local,
-// as in https://reviews.llvm.org/D108850?id=370678 where each thread can be
-// associated with a LLD instance. Only then will LLD be free of global state.
-static CommonLinkerContext *lctx;
-
-CommonLinkerContext::CommonLinkerContext() { lctx = this; }
-
-CommonLinkerContext::~CommonLinkerContext() {
- assert(lctx);
- // Explicitly call the destructors since we created the objects with placement
- // new in SpecificAlloc::create().
- for (auto &it : instances)
- it.second->~SpecificAllocBase();
- lctx = nullptr;
-}
-
-CommonLinkerContext &lld::commonContext() {
- assert(lctx);
- return *lctx;
-}
-
-bool lld::hasContext() { return lctx != nullptr; }
-
-void CommonLinkerContext::destroy() {
- if (lctx == nullptr)
- return;
- delete lctx;
-}
#include "llvm/Support/Parallel.h"
-#include "lld/Common/CommonLinkerContext.h"
#include "llvm/ADT/Twine.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
+#include <mutex>
#include <regex>
using namespace llvm;
using namespace lld;
+// The functions defined in this file can be called from multiple threads,
+// but lld::outs() or lld::errs() are not thread-safe. We protect them using a
+// mutex.
+static std::mutex mu;
+
+// We want to separate multi-line messages with a newline. `sep` is "\n"
+// if the last messages was multi-line. Otherwise "".
+static StringRef sep;
+
static StringRef getSeparator(const Twine &msg) {
if (StringRef(msg.str()).contains('\n'))
return "\n";
return "";
}
-ErrorHandler::~ErrorHandler() {
- if (cleanupCallback)
- cleanupCallback();
-}
-
-void ErrorHandler::initialize(llvm::raw_ostream &stdoutOS,
- llvm::raw_ostream &stderrOS, bool exitEarly,
- bool disableOutput) {
- this->stdoutOS = &stdoutOS;
- this->stderrOS = &stderrOS;
- stderrOS.enable_colors(stderrOS.has_colors());
- this->exitEarly = exitEarly;
- this->disableOutput = disableOutput;
-}
+raw_ostream *lld::stdoutOS;
+raw_ostream *lld::stderrOS;
-void ErrorHandler::flushStreams() {
- std::lock_guard<std::mutex> lock(mu);
- outs().flush();
- errs().flush();
+ErrorHandler &lld::errorHandler() {
+ static ErrorHandler handler;
+ return handler;
}
-ErrorHandler &lld::errorHandler() { return context().e; }
-
raw_ostream &lld::outs() {
- ErrorHandler &e = errorHandler();
- return e.outs();
-}
-
-raw_ostream &lld::errs() {
- ErrorHandler &e = errorHandler();
- return e.errs();
-}
-
-raw_ostream &ErrorHandler::outs() {
- if (disableOutput)
+ if (errorHandler().disableOutput)
return llvm::nulls();
return stdoutOS ? *stdoutOS : llvm::outs();
}
-raw_ostream &ErrorHandler::errs() {
- if (disableOutput)
+raw_ostream &lld::errs() {
+ if (errorHandler().disableOutput)
return llvm::nulls();
return stderrOS ? *stderrOS : llvm::errs();
}
void lld::exitLld(int val) {
- if (hasContext()) {
- ErrorHandler &e = errorHandler();
- // Delete any temporary file, while keeping the memory mapping open.
- if (e.outputBuffer)
- e.outputBuffer->discard();
- }
+ // Delete any temporary file, while keeping the memory mapping open.
+ if (errorHandler().outputBuffer)
+ errorHandler().outputBuffer->discard();
// Re-throw a possible signal or exception once/if it was catched by
// safeLldMain().
if (!CrashRecoveryContext::GetCurrent())
llvm_shutdown();
- if (hasContext())
- lld::errorHandler().flushStreams();
-
+ {
+ std::lock_guard<std::mutex> lock(mu);
+ lld::outs().flush();
+ lld::errs().flush();
+ }
// When running inside safeLldMain(), restore the control flow back to the
// CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup,
// since we want to avoid further crashes on shutdown.
//===----------------------------------------------------------------------===//
#include "lld/Common/Memory.h"
-#include "lld/Common/CommonLinkerContext.h"
using namespace llvm;
using namespace lld;
-SpecificAllocBase *
-lld::SpecificAllocBase::getOrCreate(void *tag, size_t size, size_t align,
- SpecificAllocBase *(&creator)(void *)) {
- auto &instances = context().instances;
- auto &instance = instances[tag];
- if (instance == nullptr) {
- void *storage = context().bAlloc.Allocate(size, align);
- instance = creator(storage);
- }
- return instance;
+BumpPtrAllocator lld::bAlloc;
+StringSaver lld::saver{bAlloc};
+std::vector<SpecificAllocBase *> lld::SpecificAllocBase::instances;
+
+void lld::freeArena() {
+ for (SpecificAllocBase *alloc : SpecificAllocBase::instances)
+ alloc->reset();
+ bAlloc.Reset();
}
//===----------------------------------------------------------------------===//
#include "lld/Common/TargetOptionsCommandFlags.h"
+
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/Target/TargetOptions.h"
+static llvm::codegen::RegisterCodeGenFlags CGF;
+
llvm::TargetOptions lld::initTargetOptionsFromCodeGenFlags() {
return llvm::codegen::InitTargetOptionsFromCodeGenFlags(llvm::Triple());
}
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
patchee(p), patcheeOffset(off) {
this->parent = p->getParent();
patchSym = addSyntheticLocal(
- saver().save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC,
- 0, getSize(), *this);
- addSyntheticLocal(saver().save("$x"), STT_NOTYPE, 0, 0, *this);
+ saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0,
+ getSize(), *this);
+ addSyntheticLocal(saver.save("$x"), STT_NOTYPE, 0, 0, *this);
}
uint64_t Patch843419Section::getLDSTAddr() const {
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
patchee(p), patcheeOffset(off), instr(instr), isARM(isARM) {
parent = p->getParent();
patchSym = addSyntheticLocal(
- saver().save("__CortexA8657417_" + utohexstr(getBranchAddr())), STT_FUNC,
+ saver.save("__CortexA8657417_" + utohexstr(getBranchAddr())), STT_FUNC,
isARM ? 0 : 1, getSize(), *this);
- addSyntheticLocal(saver().save(isARM ? "$a" : "$t"), STT_NOTYPE, 0, 0, *this);
+ addSyntheticLocal(saver.save(isARM ? "$a" : "$t"), STT_NOTYPE, 0, 0, *this);
}
uint64_t Patch657417Section::getBranchAddr() const {
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
Symbol *sym = symtab->find(name);
if (!sym || sym->isDefined())
return false;
- sym->resolve(Defined{/*file=*/nullptr, saver().save(name), STB_GLOBAL,
+ sym->resolve(Defined{/*file=*/nullptr, saver.save(name), STB_GLOBAL,
STV_HIDDEN, STT_FUNC, value,
/*size=*/0, /*section=*/nullptr});
defined.push_back(cast<Defined>(sym));
static void setConfigs(opt::InputArgList &args);
static void readConfigs(opt::InputArgList &args);
-bool elf::link(ArrayRef<const char *> args, raw_ostream &stdoutOS,
- raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {
- // This driver-specific context will be freed later by lldMain().
- auto *ctx = new CommonLinkerContext;
+bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
+ raw_ostream &stdoutOS, raw_ostream &stderrOS) {
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
+
+ errorHandler().cleanupCallback = []() {
+ freeArena();
- ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
- ctx->e.cleanupCallback = []() {
inputSections.clear();
outputSections.clear();
memoryBuffers.clear();
SharedFile::vernauxNum = 0;
};
- ctx->e.logName = args::getFilenameWithoutExe(args[0]);
- ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use "
- "-error-limit=0 to see all errors)";
+
+ 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());
config = std::make_unique<Configuration>();
driver = std::make_unique<LinkerDriver>();
driver->linkerMain(args);
- return errorCount() == 0;
+ // 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.
+ int hasError = errorCount() ? 1 : 0;
+ if (canExitEarly)
+ exitLld(hasError);
+ else
+ errorHandler().reset();
+ return !hasError;
}
// Parses a linker -m option.
// 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))
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
//===----------------------------------------------------------------------===//
#include "Driver.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Reproduce.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/Optional.h"
for (size_t i = 0, e = args.size(); i != e; ++i) {
StringRef s = args[i];
if ((s == "-plugin-opt" || s == "--plugin-opt") && i + 1 != e) {
- v.push_back(saver().save(s + "=" + args[i + 1]).data());
+ v.push_back(saver.save(s + "=" + args[i + 1]).data());
++i;
} else {
v.push_back(args[i]);
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
- cl::ExpandResponseFiles(saver(), getQuotingStyle(args), vec);
+ cl::ExpandResponseFiles(saver, getQuotingStyle(args), vec);
concatLTOPluginOptions(vec);
args = this->ParseArgs(vec, missingIndex, missingCount);
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
-#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/DWARF.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/IR/LLVMContext.h"
// The --chroot option changes our virtual root directory.
// This is useful when you are dealing with files created by --reproduce.
if (!config->chroot.empty() && path.startswith("/"))
- path = saver().save(config->chroot + path);
+ path = saver.save(config->chroot + path);
log(path);
config->dependencyFiles.insert(llvm::CachedHashString(path));
}
StringRef verName = stringTable.data() + verneeds[idx];
versionedNameBuffer.clear();
- name = saver().save(
- (name + "@" + verName).toStringRef(versionedNameBuffer));
+ name =
+ saver.save((name + "@" + verName).toStringRef(versionedNameBuffer));
}
Symbol *s = symtab.addSymbol(
Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()});
reinterpret_cast<const Elf_Verdef *>(verdefs[idx])->getAux()->vda_name;
versionedNameBuffer.clear();
name = (name + "@" + verName).toStringRef(versionedNameBuffer);
- symtab.addSymbol(SharedSymbol{*this, saver().save(name), sym.getBinding(),
+ symtab.addSymbol(SharedSymbol{*this, saver.save(name), sym.getBinding(),
sym.st_other, sym.getType(), sym.st_value,
sym.st_size, alignment, idx});
}
// into consideration at LTO time (which very likely causes undefined
// symbols later in the link stage). So we append file offset to make
// filename unique.
- StringRef name = archiveName.empty()
- ? saver().save(path)
- : saver().save(archiveName + "(" + path::filename(path) +
- " at " + utostr(offsetInArchive) + ")");
+ StringRef name =
+ archiveName.empty()
+ ? saver.save(path)
+ : saver.save(archiveName + "(" + path::filename(path) + " at " +
+ utostr(offsetInArchive) + ")");
MemoryBufferRef mbref(mb.getBuffer(), name);
obj = CHECK(lto::InputFile::create(mbref), this);
if (sym) {
name = sym->getName();
} else {
- name = saver().save(objSym.getName());
+ name = saver.save(objSym.getName());
sym = symtab->insert(name);
}
symbols.resize(obj->symbols().size());
for (auto it : llvm::enumerate(obj->symbols()))
if (!it.value().isUndefined())
- symbols[it.index()] = symtab.addSymbol(
- LazyObject{*this, saver().save(it.value().getName())});
+ symbols[it.index()] =
+ symtab.addSymbol(LazyObject{*this, saver.save(it.value().getName())});
}
void BinaryFile::parse() {
if (!isAlnum(s[i]))
s[i] = '_';
- llvm::StringSaver &saver = lld::saver();
-
symtab->addSymbol(Defined{nullptr, saver.save(s + "_start"), STB_GLOBAL,
STV_DEFAULT, STT_OBJECT, 0, 0, section});
symtab->addSymbol(Defined{nullptr, saver.save(s + "_end"), STB_GLOBAL,
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
{
static std::mutex mu;
std::lock_guard<std::mutex> lock(mu);
- uncompressedBuf = bAlloc().Allocate<char>(size);
+ uncompressedBuf = bAlloc.Allocate<char>(size);
}
if (Error e = zlib::uncompress(toStringRef(rawData), uncompressedBuf, size))
// Restore the original section name.
// (e.g. ".zdebug_info" -> ".debug_info")
- name = saver().save("." + name.substr(2));
+ name = saver.save("." + name.substr(2));
return;
}
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
if (InputSectionBase *rel = isec->getRelocatedSection()) {
OutputSection *out = rel->getOutputSection();
if (s->type == SHT_RELA)
- return saver().save(".rela" + out->name);
- return saver().save(".rel" + out->name);
+ return saver.save(".rela" + out->name);
+ return saver.save(".rel" + out->name);
}
}
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ELF.h"
// As a workaround for glibc libc.a before 2.34
// (https://sourceware.org/PR27492), retain __libc_atexit and similar
// sections regardless of zStartStopGC.
- cNamedSections[saver().save("__start_" + sec->name)].push_back(sec);
- cNamedSections[saver().save("__stop_" + sec->name)].push_back(sec);
+ cNamedSections[saver.save("__start_" + sec->name)].push_back(sec);
+ cNamedSections[saver.save("__stop_" + sec->name)].push_back(sec);
}
}
#include "ScriptLexer.h"
#include "Symbols.h"
#include "Target.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/Memory.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
SmallString<128> pathData;
StringRef path = (config->sysroot + s).toStringRef(pathData);
if (sys::fs::exists(path))
- driver->addFile(saver().save(path), /*withLOption=*/false);
+ driver->addFile(saver.save(path), /*withLOption=*/false);
else
setError("cannot find " + s + " inside " + config->sysroot);
return;
if (config->sysroot.empty())
driver->addFile(s.substr(1), /*withLOption=*/false);
else
- driver->addFile(saver().save(config->sysroot + "/" + s.substr(1)),
+ driver->addFile(saver.save(config->sysroot + "/" + s.substr(1)),
/*withLOption=*/false);
} else if (s.startswith("-l")) {
// Case 3: search in the list of library paths.
} else {
// Finally, search in the list of library paths.
if (Optional<std::string> path = findFromSearchPaths(s))
- driver->addFile(saver().save(*path), /*withLOption=*/true);
+ driver->addFile(saver.save(*path), /*withLOption=*/true);
else
setError("unable to find " + s);
}
#include "Symbols.h"
#include "Target.h"
#include "Writer.h"
-#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/DWARF.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/SetOperations.h"
// This is only for testing.
StringRef s = getenv("LLD_VERSION");
if (s.empty())
- s = saver().save(Twine("Linker: ") + getLLDVersion());
+ s = saver.save(Twine("Linker: ") + getLLDVersion());
// +1 to include the terminating '\0'.
return {(const uint8_t *)s.data(), s.size() + 1};
InputSection *elf::createInterpSection() {
// StringSaver guarantees that the returned string ends with '\0'.
- StringRef s = saver().save(config->dynamicLinker);
+ StringRef s = saver.save(config->dynamicLinker);
ArrayRef<uint8_t> contents = {(const uint8_t *)s.data(), s.size() + 1};
return make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents,
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Endian.h"
}
void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__AArch64AbsLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__AArch64AbsLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$x", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 8, isec);
}
void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__AArch64ADRPThunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+ addSymbol(saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC,
+ 0, isec);
addSymbol("$x", STT_NOTYPE, 0, isec);
}
}
void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMv7ABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
}
}
void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv7ABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
}
}
void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMV7PILongThunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+ addSymbol(saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC,
+ 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
}
}
void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ThumbV7PILongThunk_" + destination.getName()),
+ addSymbol(saver.save("__ThumbV7PILongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
}
}
void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMv5ABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__ARMv5ABSLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 4, isec);
}
void ARMV5PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMV5PILongThunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+ addSymbol(saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC,
+ 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 12, isec);
}
}
void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv6MABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 8, isec);
}
void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv6MPILongThunk_" + destination.getName()),
+ addSymbol(saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 12, isec);
}
void MipsThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
isec);
}
}
void MicroMipsThunk::addSymbols(ThunkSection &isec) {
- Defined *d =
- addSymbol(saver().save("__microLA25Thunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+ Defined *d = addSymbol(
+ saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
d->stOther |= STO_MIPS_MICROMIPS;
}
}
void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
- Defined *d =
- addSymbol(saver().save("__microLA25Thunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+ Defined *d = addSymbol(
+ saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
d->stOther |= STO_MIPS_MICROMIPS;
}
else
os << ".plt_pic32.";
os << destination.getName();
- addSymbol(saver().save(os.str()), STT_FUNC, 0, isec);
+ addSymbol(saver.save(os.str()), STT_FUNC, 0, isec);
}
bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
}
void PPC32LongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
isec);
}
}
void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
- Defined *s = addSymbol(saver().save("__plt_" + destination.getName()),
- STT_FUNC, 0, isec);
+ Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC,
+ 0, isec);
s->needsTocRestore = true;
s->file = destination.file;
}
}
void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
- Defined *s = addSymbol(saver().save("__toc_save_" + destination.getName()),
+ Defined *s = addSymbol(saver.save("__toc_save_" + destination.getName()),
STT_FUNC, 0, isec);
s->needsTocRestore = true;
}
}
void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__gep_setup_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__gep_setup_" + destination.getName()), STT_FUNC, 0,
isec);
}
}
void PPC64PCRelPLTStub::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__plt_pcrel_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__plt_pcrel_" + destination.getName()), STT_FUNC, 0,
isec);
}
}
void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__long_branch_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0,
isec);
}
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Arrays.h"
-#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Filesystem.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
StringRef s = sec->name;
if (!isValidCIdentifier(s))
return;
- addOptionalRegular(saver().save("__start_" + s), sec, 0,
+ addOptionalRegular(saver.save("__start_" + s), sec, 0,
config->zStartStopVisibility);
- addOptionalRegular(saver().save("__stop_" + s), sec, -1,
+ addOptionalRegular(saver.save("__stop_" + s), sec, -1,
config->zStartStopVisibility);
}
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/TimeProfiler.h"
// get written are happy.
thunkInfo.isec->live = true;
- StringRef thunkName = saver().save(funcSym->getName() + ".thunk." +
- std::to_string(thunkInfo.sequence++));
+ StringRef thunkName = saver.save(funcSym->getName() + ".thunk." +
+ std::to_string(thunkInfo.sequence++));
r.referent = thunkInfo.sym = symtab->addDefined(
thunkName, /*file=*/nullptr, thunkInfo.isec, /*value=*/0,
/*size=*/thunkSize, /*isWeakDef=*/false, /*isPrivateExtern=*/true,
// only append suffix if realpath() succeeds
Twine suffixed = location + suffix;
if (fs::exists(suffixed))
- return resolvedFrameworks[key] = saver().save(suffixed.str());
+ return resolvedFrameworks[key] = saver.save(suffixed.str());
}
// Suffix lookup failed, fall through to the no-suffix case.
}
path::append(buffer, path);
// Do not warn about paths that are computed via the syslib roots
if (fs::is_directory(buffer)) {
- paths.push_back(saver().save(buffer.str()));
+ paths.push_back(saver.save(buffer.str()));
found = true;
}
}
SmallString<261> buffer(root);
path::append(buffer, path);
if (fs::is_directory(buffer))
- paths.push_back(saver().save(buffer.str()));
+ paths.push_back(saver.save(buffer.str()));
}
}
return paths;
symtab->addUndefined("dyld_stub_binder", /*file=*/nullptr, /*isWeak=*/false);
}
-bool macho::link(ArrayRef<const char *> argsArr, raw_ostream &stdoutOS,
- raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {
- // This driver-specific context will be freed later by lldMain().
- auto *ctx = new CommonLinkerContext;
+bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
+ raw_ostream &stdoutOS, raw_ostream &stderrOS) {
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
+
+ errorHandler().cleanupCallback = []() {
+ freeArena();
- ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
- ctx->e.cleanupCallback = []() {
resolvedFrameworks.clear();
resolvedLibraries.clear();
cachedReads.clear();
InputFile::resetIdCount();
};
- ctx->e.logName = args::getFilenameWithoutExe(argsArr[0]);
+ errorHandler().logName = args::getFilenameWithoutExe(argsArr[0]);
+ stderrOS.enable_colors(stderrOS.has_colors());
MachOOptTable parser;
InputArgList args = parser.parse(argsArr.slice(1));
- ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now "
- "(use --error-limit=0 to see all errors)";
- ctx->e.errorLimit = args::getInteger(args, OPT_error_limit_eq, 20);
- ctx->e.verbose = args.hasArg(OPT_verbose);
+ errorHandler().errorLimitExceededMsg =
+ "too many errors emitted, stopping now "
+ "(use --error-limit=0 to see all errors)";
+ errorHandler().errorLimit = args::getInteger(args, OPT_error_limit_eq, 20);
+ errorHandler().verbose = args.hasArg(OPT_verbose);
if (args.hasArg(OPT_help_hidden)) {
parser.printHelp(argsArr[0], /*showHidden=*/true);
// these are meaningful for our text based stripping
if (config->osoPrefix.equals(".") || config->osoPrefix.endswith(sep))
expanded += sep;
- config->osoPrefix = saver().save(expanded.str());
+ config->osoPrefix = saver.save(expanded.str());
}
}
// Parse LTO options.
if (const Arg *arg = args.getLastArg(OPT_mcpu))
- parseClangOption(saver().save("-mcpu=" + StringRef(arg->getValue())),
+ parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())),
arg->getSpelling());
for (const Arg *arg : args.filtered(OPT_mllvm))
timeTraceProfilerCleanup();
}
- return errorCount() == 0;
+
+ if (canExitEarly)
+ exitLld(errorCount() ? 1 : 0);
+
+ bool ret = errorCount() == 0;
+ errorHandler().reset();
+ return ret;
}
#include "Target.h"
#include "lld/Common/Args.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
- cl::ExpandResponseFiles(saver(), cl::TokenizeGNUCommandLine, vec);
+ cl::ExpandResponseFiles(saver, cl::TokenizeGNUCommandLine, vec);
InputArgList args = ParseArgs(vec, missingIndex, missingCount);
// Handle -fatal_warnings early since it converts missing argument warnings
bool tbdExists = fs::exists(tbdPath);
searchedDylib(tbdPath, tbdExists);
if (tbdExists)
- return saver().save(tbdPath.str());
+ return saver.save(tbdPath.str());
bool dylibExists = fs::exists(dylibPath);
searchedDylib(dylibPath, dylibExists);
if (dylibExists)
- return saver().save(dylibPath);
+ return saver.save(dylibPath);
return {};
}
bool exists = fs::exists(location);
searchedDylib(location, exists);
if (exists)
- return saver().save(location.str());
+ return saver.save(location.str());
}
}
return {};
#include "SyntheticSections.h"
#include "Target.h"
-#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/DWARF.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/iterator.h"
#include "llvm/BinaryFormat/MachO.h"
return cachedReads[key] = mbref;
}
- llvm::BumpPtrAllocator &bAlloc = lld::bAlloc();
-
// Object files and archive files may be fat files, which contain multiple
// real files for different CPU ISAs. Here, we search for a file that matches
// with the current link target and returns it as a MemoryBufferRef.
}
InputFile::InputFile(Kind kind, const InterfaceFile &interface)
- : id(idCount++), fileKind(kind), name(saver().save(interface.getPath())) {}
+ : id(idCount++), fileKind(kind), name(saver.save(interface.getPath())) {}
// Some sections comprise of fixed-size records, so instead of splitting them at
// symbol boundaries, we split them based on size. Records are distinct from
// Find all the $ld$* symbols to process first.
parseTrie(buf + c->export_off, c->export_size,
[&](const Twine &name, uint64_t flags) {
- StringRef savedName = saver().save(name);
+ StringRef savedName = saver.save(name);
if (handleLDSymbol(savedName))
return;
entries.push_back({savedName, flags});
umbrella = this;
this->umbrella = umbrella;
- installName = saver().save(interface.getInstallName());
+ installName = saver.save(interface.getInstallName());
compatibilityVersion = interface.getCompatibilityVersion().rawValue();
currentVersion = interface.getCurrentVersion().rawValue();
exportingFile = isImplicitlyLinked(installName) ? this : umbrella;
auto addSymbol = [&](const Twine &name) -> void {
- StringRef savedName = saver().save(name);
+ StringRef savedName = saver.save(name);
if (exportingFile->hiddenSymbols.contains(CachedHashStringRef(savedName)))
return;
config->platformInfo.minimum >= end)
return;
- this->installName = saver().save(installName);
+ this->installName = saver.save(installName);
if (!compatVersion.empty()) {
VersionTuple cVersion;
if (!condition.consume_front("os") || version.tryParse(condition))
warn("failed to parse os version, symbol '" + originalName + "' ignored");
else if (version == config->platformInfo.minimum)
- this->installName = saver().save(installName);
+ this->installName = saver.save(installName);
}
void DylibFile::handleLDHideSymbol(StringRef name, StringRef originalName) {
static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym,
BitcodeFile &file) {
- StringRef name = saver().save(objSym.getName());
+ StringRef name = saver.save(objSym.getName());
if (objSym.isUndefined())
return symtab->addUndefined(name, &file, /*isWeakRef=*/objSym.isWeak());
// So, we append the archive name to disambiguate two members with the same
// name from multiple different archives, and offset within the archive to
// disambiguate two members of the same name from a single archive.
- MemoryBufferRef mbref(mb.getBuffer(),
- saver().save(archiveName.empty()
- ? path
- : archiveName +
- sys::path::filename(path) +
- utostr(offsetInArchive)));
+ MemoryBufferRef mbref(
+ mb.getBuffer(),
+ saver.save(archiveName.empty() ? path
+ : archiveName + sys::path::filename(path) +
+ utostr(offsetInArchive)));
obj = check(lto::InputFile::create(mbref));
#include "Target.h"
#include "lld/Common/Args.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/LTO/Config.h"
modTime = getModTime(filePath);
}
ret.push_back(make<ObjFile>(
- MemoryBufferRef(buf[i], saver().save(filePath.str())), modTime, ""));
+ MemoryBufferRef(buf[i], saver.save(filePath.str())), modTime, ""));
}
for (std::unique_ptr<MemoryBuffer> &file : files)
if (file)
#include "SymbolTable.h"
#include "Symbols.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/EndianStream.h"
if (!dir.endswith(sep))
dir += sep;
stab.strx = stringTableSection.addString(
- saver().save(dir + compileUnit->getUnitDIE().getShortName()));
+ saver.save(dir + compileUnit->getUnitDIE().getShortName()));
stabs.emplace_back(std::move(stab));
}
if (!file->archiveName.empty())
path.append({"(", file->getName(), ")"});
- StringRef adjustedPath = saver().save(path.str());
+ StringRef adjustedPath = saver.save(path.str());
adjustedPath.consume_front(config->osoPrefix);
stab.strx = stringTableSection.addString(adjustedPath);
#include "UnwindInfoSection.h"
#include "lld/Common/Arrays.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/LEB128.h"
}
static void prepareSymbolRelocation(Symbol *sym, const InputSection *isec,
- const lld::macho::Reloc &r) {
+ const Reloc &r) {
assert(sym->isLive());
const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type);
continue;
for (auto it = isec->relocs.begin(); it != isec->relocs.end(); ++it) {
- lld::macho::Reloc &r = *it;
+ Reloc &r = *it;
if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) {
// Skip over the following UNSIGNED relocation -- it's just there as the
// minuend, and doesn't have the usual UNSIGNED semantics. We don't want
if (f->archiveName.empty())
filename = path::filename(f->getName());
else
- filename = saver().save(path::filename(f->archiveName) + "(" +
- path::filename(f->getName()) + ")");
+ filename = saver.save(path::filename(f->archiveName) + "(" +
+ path::filename(f->getName()) + ")");
return std::max(entry.objectFiles.lookup(filename), entry.anyObjectFile);
}
// This section contains space for just a single word, and will be used by
// dyld to cache an address to the image loader it uses.
- uint8_t *arr = bAlloc().Allocate<uint8_t>(target->wordSize);
+ uint8_t *arr = bAlloc.Allocate<uint8_t>(target->wordSize);
memset(arr, 0, target->wordSize);
in.imageLoaderCache = make<ConcatInputSection>(
segment_names::data, section_names::data, /*file=*/nullptr,
unsigned missingCount;
SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
- cl::ExpandResponseFiles(saver(), getQuotingStyle(), vec);
+ cl::ExpandResponseFiles(saver, getQuotingStyle(), vec);
opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount);
if (missingCount)
// Convert Unix-ish command line arguments to Windows-ish ones and
// then call coff::link.
-bool mingw::link(ArrayRef<const char *> argsArr, raw_ostream &stdoutOS,
- raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {
- auto *ctx = new CommonLinkerContext;
- ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
+bool mingw::link(ArrayRef<const char *> argsArr, bool canExitEarly,
+ raw_ostream &stdoutOS, raw_ostream &stderrOS) {
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
+
+ stderrOS.enable_colors(stderrOS.has_colors());
MinGWOptTable parser;
opt::InputArgList args = parser.parse(argsArr.slice(1));
// Pass the actual binary name, to make error messages be printed with
// the right prefix.
vec[0] = argsArr[0];
-
- // The context will be re-created in the COFF driver.
- lld::CommonLinkerContext::destroy();
-
- return coff::link(vec, stdoutOS, stderrOS, exitEarly, disableOutput);
+ return coff::link(vec, canExitEarly, stdoutOS, stderrOS);
}
+++ /dev/null
-//===- CommonLinkerContext.h ------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Entry point for all global state in lldCommon. The objective is for LLD to be
-// used "as a library" in a thread-safe manner.
-//
-// Instead of program-wide globals or function-local statics, we prefer
-// aggregating all "global" states into a heap-based structure
-// (CommonLinkerContext). This also achieves deterministic initialization &
-// shutdown for all "global" states.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_COMMON_COMMONLINKINGCONTEXT_H
-#define LLD_COMMON_COMMONLINKINGCONTEXT_H
-
-#include "lld/Common/ErrorHandler.h"
-#include "lld/Common/Memory.h"
-#include "llvm/CodeGen/CommandFlags.h"
-#include "llvm/Support/StringSaver.h"
-
-namespace llvm {
-class raw_ostream;
-} // namespace llvm
-
-namespace lld {
-struct SpecificAllocBase;
-class CommonLinkerContext {
-public:
- CommonLinkerContext();
- virtual ~CommonLinkerContext();
-
- static void destroy();
-
- llvm::BumpPtrAllocator bAlloc;
- llvm::StringSaver saver{bAlloc};
- llvm::DenseMap<void *, SpecificAllocBase *> instances;
-
- ErrorHandler e;
-
-private:
- llvm::codegen::RegisterCodeGenFlags cgf;
-};
-
-// Retrieve the global state. Currently only one state can exist per process,
-// but in the future we plan on supporting an arbitrary number of LLD instances
-// in a single process.
-CommonLinkerContext &commonContext();
-
-template <typename T = CommonLinkerContext> T &context() {
- return static_cast<T &>(commonContext());
-}
-
-bool hasContext();
-
-inline llvm::StringSaver &saver() { return context().saver; }
-inline llvm::BumpPtrAllocator &bAlloc() { return context().bAlloc; }
-} // namespace lld
-
-#endif
#ifndef LLD_COMMON_DRIVER_H
#define LLD_COMMON_DRIVER_H
-#include "lld/Common/CommonLinkerContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/raw_ostream.h"
llvm::raw_ostream &stderrOS);
namespace coff {
-bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
- llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
namespace mingw {
-bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
- llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
namespace elf {
-bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
- llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
namespace macho {
-bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
- llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
namespace wasm {
-bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
- llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
}
}
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include <mutex>
namespace llvm {
class DiagnosticInfo;
namespace lld {
+// We wrap stdout and stderr so that you can pass alternative stdout/stderr as
+// arguments to lld::*::link() functions.
+extern llvm::raw_ostream *stdoutOS;
+extern llvm::raw_ostream *stderrOS;
+
llvm::raw_ostream &outs();
llvm::raw_ostream &errs();
class ErrorHandler {
public:
- ~ErrorHandler();
-
- void initialize(llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS,
- bool exitEarly, bool disableOutput);
-
uint64_t errorCount = 0;
uint64_t errorLimit = 20;
StringRef errorLimitExceededMsg = "too many errors emitted, stopping now";
void message(const Twine &msg, llvm::raw_ostream &s);
void warn(const Twine &msg);
- raw_ostream &outs();
- raw_ostream &errs();
- void flushStreams();
+ void reset() {
+ if (cleanupCallback)
+ cleanupCallback();
+ *this = ErrorHandler();
+ }
std::unique_ptr<llvm::FileOutputBuffer> outputBuffer;
std::string getLocation(const Twine &msg);
void reportDiagnostic(StringRef location, Colors c, StringRef diagKind,
const Twine &msg);
-
- // We want to separate multi-line messages with a newline. `sep` is "\n"
- // if the last messages was multi-line. Otherwise "".
- llvm::StringRef sep;
-
- // We wrap stdout and stderr so that you can pass alternative stdout/stderr as
- // arguments to lld::*::link() functions. Since lld::outs() or lld::errs() can
- // be indirectly called from multiple threads, we protect them using a mutex.
- // In the future, we plan on supporting several concurent linker contexts,
- // which explains why the mutex is not a global but part of this context.
- std::mutex mu;
- llvm::raw_ostream *stdoutOS{};
- llvm::raw_ostream *stderrOS{};
};
/// Returns the default error handler.
#define LLD_COMMON_MEMORY_H
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/StringSaver.h"
+#include <vector>
namespace lld {
-// A base class only used by the CommonLinkerContext to keep track of the
-// SpecificAlloc<> instances.
+
+// Use this arena if your object doesn't have a destructor.
+extern llvm::BumpPtrAllocator bAlloc;
+extern llvm::StringSaver saver;
+
+void freeArena();
+
+// These two classes are hack to keep track of all
+// SpecificBumpPtrAllocator instances.
struct SpecificAllocBase {
+ SpecificAllocBase() { instances.push_back(this); }
virtual ~SpecificAllocBase() = default;
- static SpecificAllocBase *getOrCreate(void *tag, size_t size, size_t align,
- SpecificAllocBase *(&creator)(void *));
+ virtual void reset() = 0;
+ static std::vector<SpecificAllocBase *> instances;
};
-// An arena of specific types T, created on-demand.
template <class T> struct SpecificAlloc : public SpecificAllocBase {
- static SpecificAllocBase *create(void *storage) {
- return new (storage) SpecificAlloc<T>();
- }
+ void reset() override { alloc.DestroyAll(); }
llvm::SpecificBumpPtrAllocator<T> alloc;
- static int tag;
};
-// The address of this static member is only used as a key in
-// CommonLinkerContext::instances. Its value does not matter.
-template <class T> int SpecificAlloc<T>::tag = 0;
-
-// Creates the arena on-demand on the first call; or returns it, if it was
-// already created.
+// Use a static local for these singletons so they are only registered if an
+// object of this instance is ever constructed. Otherwise we will create and
+// register ELF allocators for COFF and the reverse.
template <typename T>
inline llvm::SpecificBumpPtrAllocator<T> &getSpecificAllocSingleton() {
- SpecificAllocBase *instance = SpecificAllocBase::getOrCreate(
- &SpecificAlloc<T>::tag, sizeof(SpecificAlloc<T>),
- alignof(SpecificAlloc<T>), SpecificAlloc<T>::create);
- return ((SpecificAlloc<T> *)instance)->alloc;
+ static SpecificAlloc<T> instance;
+ return instance.alloc;
}
-// Creates new instances of T off a (almost) contiguous arena/object pool. The
-// instances are destroyed whenever lldMain() goes out of scope.
+// Use this arena if your object has a destructor.
+// Your destructor will be invoked from freeArena().
template <typename T, typename... U> T *make(U &&... args) {
return new (getSpecificAllocSingleton<T>().Allocate())
T(std::forward<U>(args)...);
#ifndef LLD_CORE_LINKING_CONTEXT_H
#define LLD_CORE_LINKING_CONTEXT_H
-#include "lld/Common/CommonLinkerContext.h"
#include "lld/Core/Node.h"
#include "lld/Core/Reader.h"
#include "llvm/ADT/ArrayRef.h"
/// The base class LinkingContext contains the options needed by core linking.
/// Subclasses of LinkingContext have additional options needed by specific
/// Writers.
-class LinkingContext : public CommonLinkerContext {
+class LinkingContext {
public:
virtual ~LinkingContext();
// Expand response files (arguments in the form of @<filename>)
// to allow detecting the -m argument from arguments in them.
SmallVector<const char *, 256> expandedArgs(v.data(), v.data() + v.size());
- BumpPtrAllocator a;
- StringSaver saver(a);
cl::ExpandResponseFiles(saver, getDefaultQuotingStyle(), expandedArgs);
for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) {
if (StringRef(*it) != "-m")
return parseProgname(arg0);
}
-static bool inTestOutputDisabled = false;
-
/// Universal linker main(). This linker emulates the gnu, darwin, or
/// windows linker based on the argv[0] or -flavor option.
static int lldMain(int argc, const char **argv, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly = true) {
std::vector<const char *> args(argv, argv + argc);
- auto link = [&args]() {
- Flavor f = parseFlavor(args);
- if (f == Gnu && isPETarget(args))
- return mingw::link;
- if (f == Gnu)
- return elf::link;
- if (f == WinLink)
- return coff::link;
- if (f == Darwin)
- return macho::link;
- if (f == Wasm)
- return lld::wasm::link;
+ switch (parseFlavor(args)) {
+ case Gnu:
+ if (isPETarget(args))
+ return !mingw::link(args, exitEarly, stdoutOS, stderrOS);
+ return !elf::link(args, exitEarly, stdoutOS, stderrOS);
+ case WinLink:
+ return !coff::link(args, exitEarly, stdoutOS, stderrOS);
+ case Darwin:
+ return !macho::link(args, exitEarly, stdoutOS, stderrOS);
+ case Wasm:
+ return !lld::wasm::link(args, exitEarly, stdoutOS, stderrOS);
+ default:
die("lld is a generic driver.\n"
"Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"
" (WebAssembly) instead");
- }();
- // Run the driver. If an error occurs, false will be returned.
- int r = !link(args, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled);
-
- // 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 (exitEarly)
- exitLld(r);
-
- // Delete the global context and clear the global context pointer, so that it
- // cannot be accessed anymore.
- CommonLinkerContext::destroy();
-
- return r;
+ }
}
// Similar to lldMain except that exceptions are caught.
// Cleanup memory and reset everything back in pristine condition. This path
// is only taken when LLD is in test, or when it is used as a library.
llvm::CrashRecoveryContext crc;
- if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) {
+ if (!crc.RunSafely([&]() { errorHandler().reset(); })) {
// The memory is corrupted beyond any possible recovery.
return {r, /*canRunAgain=*/false};
}
for (unsigned i = inTestVerbosity(); i > 0; --i) {
// Disable stdout/stderr for all iterations but the last one.
- inTestOutputDisabled = (i != 1);
+ if (i != 1)
+ errorHandler().disableOutput = true;
// Execute one iteration.
auto r = safeLldMain(argc, argv, llvm::outs(), llvm::errs());
};
} // anonymous namespace
-bool link(ArrayRef<const char *> args, raw_ostream &stdoutOS,
- raw_ostream &stderrOS, bool exitEarly, bool disableOutput) {
- // This driver-specific context will be freed later by lldMain().
- auto *ctx = new CommonLinkerContext;
+bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
+ raw_ostream &stderrOS) {
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
- ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
- ctx->e.logName = args::getFilenameWithoutExe(args[0]);
- ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use "
- "-error-limit=0 to see all errors)";
+ errorHandler().cleanupCallback = []() { freeArena(); };
+
+ errorHandler().logName = args::getFilenameWithoutExe(args[0]);
+ errorHandler().errorLimitExceededMsg =
+ "too many errors emitted, stopping now (use "
+ "-error-limit=0 to see all errors)";
+ stderrOS.enable_colors(stderrOS.has_colors());
config = make<Configuration>();
symtab = make<SymbolTable>();
initLLVM();
LinkerDriver().linkerMain(args);
- return errorCount() == 0;
+ // 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);
+
+ return !errorCount();
}
// Create prefix string literals used in Options.td
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
- cl::ExpandResponseFiles(saver(), getQuotingStyle(args), vec);
+ cl::ExpandResponseFiles(saver, getQuotingStyle(args), vec);
args = this->ParseArgs(vec, missingIndex, missingCount);
handleColorDiagnostics(args);
if (!sym)
continue;
- Symbol *real = addUndefined(saver().save("__real_" + name));
- Symbol *wrap = addUndefined(saver().save("__wrap_" + name));
+ Symbol *real = addUndefined(saver.save("__real_" + name));
+ Symbol *wrap = addUndefined(saver.save("__wrap_" + name));
v.push_back({sym, real, wrap});
// We want to tell LTO not to inline symbols to be overwritten
#include "InputElement.h"
#include "OutputSegment.h"
#include "SymbolTable.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Reproduce.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/Wasm.h"
static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,
const lto::InputFile::Symbol &objSym,
BitcodeFile &f) {
- StringRef name = saver().save(objSym.getName());
+ StringRef name = saver.save(objSym.getName());
uint32_t flags = objSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0;
flags |= mapVisibility(objSym.getVisibility());
// symbols later in the link stage). So we append file offset to make
// filename unique.
StringRef name = archiveName.empty()
- ? saver().save(path)
- : saver().save(archiveName + "(" + path::filename(path) +
- " at " + utostr(offsetInArchive) + ")");
+ ? saver.save(path)
+ : saver.save(archiveName + "(" + path::filename(path) +
+ " at " + utostr(offsetInArchive) + ")");
MemoryBufferRef mbref(mb.getBuffer(), name);
obj = check(lto::InputFile::create(mbref));
#include "InputChunks.h"
#include "InputElement.h"
#include "WriterUtils.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/ADT/SetVector.h"
#define DEBUG_TYPE "lld"
void SymbolTable::replaceWithUndefined(Symbol *sym) {
// Add a synthetic dummy for weak undefined functions. These dummies will
// be GC'd if not used as the target of any "call" instructions.
- StringRef debugName = saver().save("undefined_weak:" + toString(*sym));
+ StringRef debugName = saver.save("undefined_weak:" + toString(*sym));
replaceWithUnreachable(sym, *sym->getSignature(), debugName);
// Hide our dummy to prevent export.
sym->setHidden(true);
if (symbol != defined) {
auto *f = cast<FunctionSymbol>(symbol);
reportFunctionSignatureMismatch(symName, f, defined, false);
- StringRef debugName =
- saver().save("signature_mismatch:" + toString(*f));
+ StringRef debugName = saver.save("signature_mismatch:" + toString(*f));
replaceWithUnreachable(f, *f->signature, debugName);
}
}
#include "SymbolTable.h"
#include "SyntheticSections.h"
#include "WriterUtils.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallSet.h"
else if (sec->type == WASM_SEC_CODE)
name = "reloc.CODE";
else if (sec->type == WASM_SEC_CUSTOM)
- name = saver().save("reloc." + sec->name);
+ name = saver.save("reloc." + sec->name);
else
llvm_unreachable(
"relocations only supported for code, data, or custom sections");
LLVM_DEBUG(dbgs() << "addStartStopSymbols: " << name << "\n");
uint64_t start = seg->startVA;
uint64_t stop = start + seg->size;
- symtab->addOptionalDataSymbol(saver().save("__start_" + name), start);
- symtab->addOptionalDataSymbol(saver().save("__stop_" + name), stop);
+ symtab->addOptionalDataSymbol(saver.save("__start_" + name), start);
+ symtab->addOptionalDataSymbol(saver.save("__stop_" + name), stop);
}
void Writer::addSections() {
writeUleb128(os, bodyContent.size(), "function size");
os << bodyContent;
}
- ArrayRef<uint8_t> body = arrayRefFromStringRef(saver().save(functionBody));
+ ArrayRef<uint8_t> body = arrayRefFromStringRef(saver.save(functionBody));
cast<SyntheticFunction>(func->function)->setBody(body);
}