Re-land [LLD] Remove global state in lldCommon

Move all variables at file-scope or function-static-scope into a hosting structure (lld::CommonLinkerContext) that lives at lldMain()-scope. Drivers will inherit from this structure and add their own global state, in the same way as for the existing COFFLinkerContext.

See discussion in https://lists.llvm.org/pipermail/llvm-dev/2021-June/151184.html

The previous land f860fe362282ed69b9d4503a20e5d20b9a041189 caused issues in https://lab.llvm.org/buildbot/#/builders/123/builds/8383, fixed by 22ee510dac9440a74b2e5b3fe3ff13ccdbf55af3.

Differential Revision: https://reviews.llvm.org/D108850
This commit is contained in:
Alexandre Ganea 2022-01-20 14:53:18 -05:00
parent 57ebfea38c
commit 83d59e05b2
49 changed files with 522 additions and 400 deletions

View File

@ -47,7 +47,14 @@
// Make sure this comes before MSVCSetupApi.h
#include <comdef.h>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#endif
#include "MSVCSetupApi.h"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#include "llvm/Support/COM.h"
_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));

View File

@ -15,12 +15,13 @@
#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 {
class COFFLinkerContext : public CommonLinkerContext {
public:
COFFLinkerContext();
COFFLinkerContext(const COFFLinkerContext &) = delete;

View File

@ -12,7 +12,6 @@
#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"
@ -430,7 +429,7 @@ void SectionChunk::sortRelocations() {
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);

View File

@ -659,14 +659,14 @@ void DelayLoadContents::create(COFFLinkerContext &ctx, Defined *h) {
// 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));

View File

@ -19,9 +19,7 @@
#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"
@ -63,36 +61,22 @@ namespace coff {
std::unique_ptr<Configuration> config;
std::unique_ptr<LinkerDriver> driver;
bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
raw_ostream &stderrOS) {
lld::stdoutOS = &stdoutOS;
lld::stderrOS = &stderrOS;
bool 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 COFFLinkerContext;
errorHandler().cleanupCallback = []() {
freeArena();
};
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().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);
// 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;
return errorCount() == 0;
}
// Parse options of the form "old;new".
@ -162,7 +146,7 @@ static std::future<MBErrPair> createFutureForFile(std::string path) {
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;
}
@ -358,9 +342,9 @@ void LinkerDriver::parseDirectives(InputFile *file) {
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);
@ -442,11 +426,11 @@ StringRef LinkerDriver::doFindFile(StringRef filename) {
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;
@ -483,7 +467,7 @@ StringRef LinkerDriver::doFindLibMinGW(StringRef 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);
}
@ -492,7 +476,7 @@ StringRef LinkerDriver::doFindLib(StringRef filename) {
// 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.
@ -525,7 +509,7 @@ void LinkerDriver::addLibSearchPaths() {
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(';');
@ -873,8 +857,8 @@ static void parseModuleDefs(StringRef path) {
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)
@ -902,14 +886,14 @@ static void parseModuleDefs(StringRef path) {
// 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.aliasTarget = saver.save(e1.AliasTarget);
e2.name = saver().save(e1.Name);
e2.extName = saver().save(e1.ExtName);
e2.aliasTarget = saver().save(e1.AliasTarget);
e2.ordinal = e1.Ordinal;
e2.noname = e1.Noname;
e2.data = e1.Data;
@ -1906,9 +1890,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
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);
}

View File

@ -48,17 +48,17 @@ const uint16_t RT_MANIFEST = 24;
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)
@ -636,14 +636,14 @@ static StringRef killAt(StringRef sym, bool prefix) {
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;
}
@ -854,7 +854,7 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
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);
@ -901,7 +901,7 @@ ParsedDirectives ArgParser::parseDirectives(StringRef s) {
// 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:"))
@ -914,7 +914,7 @@ ParsedDirectives ArgParser::parseDirectives(StringRef s) {
// 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());
}
}
@ -948,7 +948,7 @@ void ArgParser::addLINK(SmallVector<const char *, 256> &argv) {
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());
}

View File

@ -15,8 +15,6 @@
#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"
@ -905,7 +903,7 @@ ObjFile::getVariableLocation(StringRef var) {
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
@ -940,8 +938,8 @@ void ImportFile::parse() {
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;
@ -995,11 +993,12 @@ BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
// 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));
}
@ -1035,6 +1034,7 @@ FakeSectionChunk ltoDataSectionChunk(&ltoDataSection.section);
} // 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
@ -1156,11 +1156,11 @@ void DLLFile::parse() {
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);
@ -1179,7 +1179,7 @@ void DLLFile::makeImport(DLLFile::Symbol *s) {
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);

View File

@ -11,7 +11,7 @@
#include "InputFiles.h"
#include "Symbols.h"
#include "lld/Common/Args.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
@ -209,8 +209,8 @@ std::vector<InputFile *> BitcodeCompiler::compile(COFFLinkerContext &ctx) {
// - 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

View File

@ -11,7 +11,6 @@
#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"
@ -184,8 +183,8 @@ void lld::coff::writeDefFile(StringRef name) {
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.
@ -249,7 +248,7 @@ void lld::coff::wrapSymbols(COFFLinkerContext &ctx,
// 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;
}

View File

@ -16,7 +16,6 @@
#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"
@ -75,7 +74,7 @@ class PDBLinker {
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.
@ -501,7 +500,7 @@ static void addGlobalSymbol(pdb::GSIStreamBuilder &builder, uint16_t modIndex,
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;
@ -1003,7 +1002,7 @@ static void warnUnusable(InputFile *f, Error e) {
// 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);
@ -1417,6 +1416,7 @@ static void addCommonLinkerModuleSymbols(StringRef path,
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(
@ -1448,7 +1448,7 @@ static void addLinkerModuleCoffGroup(PartialSection *sec,
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,
@ -1461,7 +1461,7 @@ 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
@ -1536,6 +1536,7 @@ void PDBLinker::addImportFilesToPDB() {
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(

View File

@ -134,7 +134,7 @@ getFileLineDwarf(const SectionChunk *c, uint32_t addr) {
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>>

View File

@ -485,7 +485,7 @@ static bool createThunks(OutputSection *os, int margin) {
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(

View File

@ -28,6 +28,7 @@ set_source_files_properties("${version_inc}"
add_lld_library(lldCommon
Args.cpp
CommonLinkerContext.cpp
DWARF.cpp
ErrorHandler.cpp
Filesystem.cpp

View File

@ -0,0 +1,45 @@
//===- 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;
}

View File

@ -10,6 +10,7 @@
#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"
@ -18,51 +19,69 @@
#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 "";
}
raw_ostream *lld::stdoutOS;
raw_ostream *lld::stderrOS;
ErrorHandler &lld::errorHandler() {
static ErrorHandler handler;
return handler;
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;
}
void ErrorHandler::flushStreams() {
std::lock_guard<std::mutex> lock(mu);
outs().flush();
errs().flush();
}
ErrorHandler &lld::errorHandler() { return context().e; }
raw_ostream &lld::outs() {
if (errorHandler().disableOutput)
ErrorHandler &e = errorHandler();
return e.outs();
}
raw_ostream &lld::errs() {
ErrorHandler &e = errorHandler();
return e.errs();
}
raw_ostream &ErrorHandler::outs() {
if (disableOutput)
return llvm::nulls();
return stdoutOS ? *stdoutOS : llvm::outs();
}
raw_ostream &lld::errs() {
if (errorHandler().disableOutput)
raw_ostream &ErrorHandler::errs() {
if (disableOutput)
return llvm::nulls();
return stderrOS ? *stderrOS : llvm::errs();
}
void lld::exitLld(int val) {
// Delete any temporary file, while keeping the memory mapping open.
if (errorHandler().outputBuffer)
errorHandler().outputBuffer->discard();
if (hasContext()) {
ErrorHandler &e = errorHandler();
// Delete any temporary file, while keeping the memory mapping open.
if (e.outputBuffer)
e.outputBuffer->discard();
}
// Re-throw a possible signal or exception once/if it was catched by
// safeLldMain().
@ -75,11 +94,9 @@ void lld::exitLld(int val) {
if (!CrashRecoveryContext::GetCurrent())
llvm_shutdown();
{
std::lock_guard<std::mutex> lock(mu);
lld::outs().flush();
lld::errs().flush();
}
if (hasContext())
lld::errorHandler().flushStreams();
// 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.

View File

@ -7,16 +7,19 @@
//===----------------------------------------------------------------------===//
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
using namespace llvm;
using namespace lld;
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();
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;
}

View File

@ -7,12 +7,9 @@
//===----------------------------------------------------------------------===//
#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());
}

View File

@ -33,7 +33,7 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Strings.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
@ -398,9 +398,9 @@ Patch843419Section::Patch843419Section(InputSection *p, uint64_t off)
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 {

View File

@ -22,7 +22,7 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Strings.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
@ -142,9 +142,9 @@ Patch657417Section::Patch657417Section(InputSection *p, uint64_t off,
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 {

View File

@ -11,8 +11,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
@ -197,7 +196,7 @@ static bool addOptional(StringRef name, uint64_t value,
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));

View File

@ -77,14 +77,14 @@ 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();
@ -106,13 +106,9 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
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>();
@ -126,15 +122,7 @@ bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
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.
int hasError = errorCount() ? 1 : 0;
if (canExitEarly)
exitLld(hasError);
else
errorHandler().reset();
return !hasError;
return errorCount() == 0;
}
// Parses a linker -m option.
@ -1258,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))
@ -2071,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

View File

@ -13,8 +13,7 @@
//===----------------------------------------------------------------------===//
#include "Driver.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Reproduce.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/Optional.h"
@ -102,7 +101,7 @@ static void concatLTOPluginOptions(SmallVectorImpl<const char *> &args) {
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]);
@ -125,7 +124,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) {
// 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);

View File

@ -13,9 +13,8 @@
#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"
@ -111,7 +110,7 @@ Optional<MemoryBufferRef> elf::readFile(StringRef path) {
// 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));
@ -1518,8 +1517,8 @@ template <class ELFT> void SharedFile::parse() {
}
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()});
@ -1561,7 +1560,7 @@ template <class ELFT> void SharedFile::parse() {
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});
}
@ -1644,11 +1643,10 @@ BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
// 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);
@ -1684,7 +1682,7 @@ createBitcodeSymbol(Symbol *&sym, const std::vector<bool> &keptComdats,
if (sym) {
name = sym->getName();
} else {
name = saver.save(objSym.getName());
name = saver().save(objSym.getName());
sym = symtab->insert(name);
}
@ -1734,8 +1732,8 @@ void BitcodeFile::parseLazy() {
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() {
@ -1753,6 +1751,8 @@ 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,

View File

@ -18,8 +18,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
@ -143,7 +142,7 @@ void InputSectionBase::uncompress() const {
{
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))
@ -237,7 +236,7 @@ template <typename ELFT> void InputSectionBase::parseCompressedHeader() {
// Restore the original section name.
// (e.g. ".zdebug_info" -> ".debug_info")
name = saver.save("." + name.substr(2));
name = saver().save("." + name.substr(2));
return;
}

View File

@ -19,7 +19,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
@ -64,8 +64,8 @@ static StringRef getOutputSectionName(const InputSectionBase *s) {
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);
}
}

View File

@ -27,7 +27,7 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ELF.h"
@ -308,8 +308,8 @@ template <class ELFT> void MarkLive<ELFT>::run() {
// 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);
}
}

View File

@ -20,7 +20,7 @@
#include "ScriptLexer.h"
#include "Symbols.h"
#include "Target.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
@ -290,7 +290,7 @@ void ScriptParser::addFile(StringRef s) {
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;
@ -304,7 +304,7 @@ void ScriptParser::addFile(StringRef s) {
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.
@ -327,7 +327,7 @@ void ScriptParser::addFile(StringRef s) {
} 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);
}

View File

@ -22,9 +22,8 @@
#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"
@ -73,7 +72,7 @@ static ArrayRef<uint8_t> getVersion() {
// 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};
@ -255,7 +254,7 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
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,

View File

@ -27,8 +27,7 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Endian.h"
@ -434,7 +433,7 @@ void AArch64ABSLongThunk::writeTo(uint8_t *buf) {
}
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);
@ -460,8 +459,8 @@ void AArch64ADRPThunk::writeTo(uint8_t *buf) {
}
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);
}
@ -560,7 +559,7 @@ void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
}
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);
}
@ -578,7 +577,7 @@ void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
}
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);
}
@ -599,8 +598,8 @@ void ARMV7PILongThunk::writeLong(uint8_t *buf) {
}
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);
}
@ -620,7 +619,7 @@ void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
}
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);
}
@ -635,7 +634,7 @@ void ARMV5ABSLongThunk::writeLong(uint8_t *buf) {
}
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);
@ -661,8 +660,8 @@ void ARMV5PILongThunk::writeLong(uint8_t *buf) {
}
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);
}
@ -691,7 +690,7 @@ void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
}
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);
@ -717,7 +716,7 @@ void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
}
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);
@ -735,7 +734,7 @@ void MipsThunk::writeTo(uint8_t *buf) {
}
void MipsThunk::addSymbols(ThunkSection &isec) {
addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
addSymbol(saver().save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
isec);
}
@ -758,8 +757,9 @@ void MicroMipsThunk::writeTo(uint8_t *buf) {
}
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;
}
@ -782,8 +782,9 @@ void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
}
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;
}
@ -843,7 +844,7 @@ void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
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,
@ -852,7 +853,7 @@ 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);
}
@ -896,8 +897,8 @@ void PPC64PltCallStub::writeTo(uint8_t *buf) {
}
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;
}
@ -947,7 +948,7 @@ void PPC64R2SaveStub::writeTo(uint8_t *buf) {
}
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;
}
@ -983,7 +984,7 @@ void PPC64R12SetupStub::writeTo(uint8_t *buf) {
}
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);
}
@ -1019,7 +1020,7 @@ void PPC64PCRelPLTStub::writeTo(uint8_t *buf) {
}
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);
}
@ -1035,7 +1036,7 @@ void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
}
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);
}

View File

@ -20,8 +20,8 @@
#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"
@ -2216,9 +2216,9 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *sec) {
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);
}

View File

@ -13,8 +13,7 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/TimeProfiler.h"
@ -322,8 +321,8 @@ void ConcatOutputSection::finalize() {
// 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,

View File

@ -128,7 +128,7 @@ static Optional<StringRef> findFramework(StringRef name) {
// 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.
}
@ -165,7 +165,7 @@ getSearchPaths(unsigned optionCode, InputArgList &args,
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;
}
}
@ -183,7 +183,7 @@ getSearchPaths(unsigned optionCode, InputArgList &args,
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;
@ -1126,14 +1126,14 @@ static void referenceStubBinder() {
symtab->addUndefined("dyld_stub_binder", /*file=*/nullptr, /*isWeak=*/false);
}
bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
raw_ostream &stdoutOS, raw_ostream &stderrOS) {
lld::stdoutOS = &stdoutOS;
lld::stderrOS = &stderrOS;
errorHandler().cleanupCallback = []() {
freeArena();
bool macho::link(ArrayRef<const char *> argsArr, 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 = []() {
resolvedFrameworks.clear();
resolvedLibraries.clear();
cachedReads.clear();
@ -1154,17 +1154,15 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
InputFile::resetIdCount();
};
errorHandler().logName = args::getFilenameWithoutExe(argsArr[0]);
stderrOS.enable_colors(stderrOS.has_colors());
ctx->e.logName = args::getFilenameWithoutExe(argsArr[0]);
MachOOptTable parser;
InputArgList args = parser.parse(argsArr.slice(1));
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);
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);
if (args.hasArg(OPT_help_hidden)) {
parser.printHelp(argsArr[0], /*showHidden=*/true);
@ -1208,7 +1206,7 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
// 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());
}
}
@ -1496,7 +1494,7 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
// 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))
@ -1587,11 +1585,5 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
timeTraceProfilerCleanup();
}
if (canExitEarly)
exitLld(errorCount() ? 1 : 0);
bool ret = errorCount() == 0;
errorHandler().reset();
return ret;
return errorCount() == 0;
}

View File

@ -13,8 +13,7 @@
#include "Target.h"
#include "lld/Common/Args.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
@ -82,7 +81,7 @@ InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) {
// 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
@ -191,12 +190,12 @@ Optional<StringRef> macho::resolveDylibPath(StringRef dylibPath) {
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 {};
}
@ -261,7 +260,7 @@ macho::findPathCombination(const Twine &name,
bool exists = fs::exists(location);
searchedDylib(location, exists);
if (exists)
return saver.save(location.str());
return saver().save(location.str());
}
}
return {};

View File

@ -56,9 +56,8 @@
#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"
@ -210,6 +209,8 @@ Optional<MemoryBufferRef> macho::readFile(StringRef path) {
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.
@ -241,7 +242,7 @@ Optional<MemoryBufferRef> macho::readFile(StringRef path) {
}
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
@ -1211,7 +1212,7 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
// 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});
@ -1285,7 +1286,7 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
umbrella = this;
this->umbrella = umbrella;
installName = saver.save(interface.getInstallName());
installName = saver().save(interface.getInstallName());
compatibilityVersion = interface.getCompatibilityVersion().rawValue();
currentVersion = interface.getCurrentVersion().rawValue();
@ -1304,7 +1305,7 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
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;
@ -1423,7 +1424,7 @@ void DylibFile::handleLDPreviousSymbol(StringRef name, StringRef originalName) {
config->platformInfo.minimum >= end)
return;
this->installName = saver.save(installName);
this->installName = saver().save(installName);
if (!compatVersion.empty()) {
VersionTuple cVersion;
@ -1445,7 +1446,7 @@ void DylibFile::handleLDInstallNameSymbol(StringRef name,
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) {
@ -1550,7 +1551,7 @@ void ArchiveFile::fetch(const object::Archive::Symbol &sym) {
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());
@ -1592,11 +1593,12 @@ BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
// 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));
if (lazy)
@ -1620,7 +1622,7 @@ void BitcodeFile::parseLazy() {
const lto::InputFile::Symbol &objSym = it.value();
if (!objSym.isUndefined()) {
symbols[it.index()] =
symtab->addLazyObject(saver.save(objSym.getName()), *this);
symtab->addLazyObject(saver().save(objSym.getName()), *this);
if (!lazy)
break;
}

View File

@ -14,7 +14,7 @@
#include "Target.h"
#include "lld/Common/Args.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/LTO/Config.h"
@ -148,7 +148,7 @@ std::vector<ObjFile *> BitcodeCompiler::compile() {
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)

View File

@ -16,8 +16,7 @@
#include "SymbolTable.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/EndianStream.h"
@ -834,7 +833,7 @@ void SymtabSection::emitBeginSourceStab(DWARFUnit *compileUnit) {
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));
}
@ -856,7 +855,7 @@ void SymtabSection::emitObjectFileStab(ObjFile *file) {
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);

View File

@ -22,8 +22,7 @@
#include "UnwindInfoSection.h"
#include "lld/Common/Arrays.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/LEB128.h"
@ -611,7 +610,7 @@ static bool needsBinding(const Symbol *sym) {
}
static void prepareSymbolRelocation(Symbol *sym, const InputSection *isec,
const Reloc &r) {
const lld::macho::Reloc &r) {
assert(sym->isLive());
const RelocAttrs &relocAttrs = target->getRelocAttrs(r.type);
@ -644,7 +643,7 @@ void Writer::scanRelocations() {
continue;
for (auto it = isec->relocs.begin(); it != isec->relocs.end(); ++it) {
Reloc &r = *it;
lld::macho::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
@ -858,8 +857,8 @@ static size_t getSymbolPriority(const SymbolPriorityEntry &entry,
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);
}
@ -1216,7 +1215,7 @@ void macho::createSyntheticSections() {
// 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,

View File

@ -100,7 +100,7 @@ opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> argv) {
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)
@ -154,12 +154,11 @@ searchLibrary(StringRef name, ArrayRef<StringRef> searchPaths, bool bStatic) {
// Convert Unix-ish command line arguments to Windows-ish ones and
// then call coff::link.
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());
bool mingw::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly,
bool disableOutput) {
auto *ctx = new CommonLinkerContext;
ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
MinGWOptTable parser;
opt::InputArgList args = parser.parse(argsArr.slice(1));
@ -445,5 +444,9 @@ bool mingw::link(ArrayRef<const char *> argsArr, bool canExitEarly,
// Pass the actual binary name, to make error messages be printed with
// the right prefix.
vec[0] = argsArr[0];
return coff::link(vec, canExitEarly, stdoutOS, stderrOS);
// The context will be re-created in the COFF driver.
lld::CommonLinkerContext::destroy();
return coff::link(vec, stdoutOS, stderrOS, exitEarly, disableOutput);
}

View File

@ -0,0 +1,65 @@
//===- 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

View File

@ -9,6 +9,7 @@
#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"
@ -28,28 +29,28 @@ SafeReturn safeLldMain(int argc, const char **argv, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS);
namespace coff {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
}
namespace mingw {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
}
namespace elf {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
}
namespace macho {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
}
namespace wasm {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
}
}

View File

@ -73,6 +73,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
#include <mutex>
namespace llvm {
class DiagnosticInfo;
@ -81,11 +82,6 @@ class raw_ostream;
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();
@ -93,6 +89,11 @@ enum class ErrorTag { LibNotFound, SymbolNotFound };
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";
@ -112,11 +113,9 @@ public:
void message(const Twine &msg, llvm::raw_ostream &s);
void warn(const Twine &msg);
void reset() {
if (cleanupCallback)
cleanupCallback();
*this = ErrorHandler();
}
raw_ostream &outs();
raw_ostream &errs();
void flushStreams();
std::unique_ptr<llvm::FileOutputBuffer> outputBuffer;
@ -126,6 +125,19 @@ private:
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.

View File

@ -22,42 +22,41 @@
#define LLD_COMMON_MEMORY_H
#include "llvm/Support/Allocator.h"
#include "llvm/Support/StringSaver.h"
#include <vector>
namespace lld {
// 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.
// A base class only used by the CommonLinkerContext to keep track of the
// SpecificAlloc<> instances.
struct SpecificAllocBase {
SpecificAllocBase() { instances.push_back(this); }
virtual ~SpecificAllocBase() = default;
virtual void reset() = 0;
static std::vector<SpecificAllocBase *> instances;
static SpecificAllocBase *getOrCreate(void *tag, size_t size, size_t align,
SpecificAllocBase *(&creator)(void *));
};
// An arena of specific types T, created on-demand.
template <class T> struct SpecificAlloc : public SpecificAllocBase {
void reset() override { alloc.DestroyAll(); }
static SpecificAllocBase *create(void *storage) {
return new (storage) SpecificAlloc<T>();
}
llvm::SpecificBumpPtrAllocator<T> alloc;
static int tag;
};
// 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.
// 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.
template <typename T>
inline llvm::SpecificBumpPtrAllocator<T> &getSpecificAllocSingleton() {
static SpecificAlloc<T> instance;
return instance.alloc;
SpecificAllocBase *instance = SpecificAllocBase::getOrCreate(
&SpecificAlloc<T>::tag, sizeof(SpecificAlloc<T>),
alignof(SpecificAlloc<T>), SpecificAlloc<T>::create);
return ((SpecificAlloc<T> *)instance)->alloc;
}
// Use this arena if your object has a destructor.
// Your destructor will be invoked from freeArena().
// Creates new instances of T off a (almost) contiguous arena/object pool. The
// instances are destroyed whenever lldMain() goes out of scope.
template <typename T, typename... U> T *make(U &&... args) {
return new (getSpecificAllocSingleton<T>().Allocate())
T(std::forward<U>(args)...);

View File

@ -9,6 +9,7 @@
#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"
@ -34,7 +35,7 @@ class SharedLibraryFile;
/// The base class LinkingContext contains the options needed by core linking.
/// Subclasses of LinkingContext have additional options needed by specific
/// Writers.
class LinkingContext {
class LinkingContext : public CommonLinkerContext {
public:
virtual ~LinkingContext();

View File

@ -87,6 +87,8 @@ static bool isPETarget(std::vector<const char *> &v) {
// 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")
@ -134,27 +136,42 @@ static Flavor parseFlavor(std::vector<const char *> &v) {
return parseProgname(arg0);
}
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);
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");
}
auto link = [&args]() {
Flavor f = parseFlavor(args);
if (f == Gnu && isPETarget(args))
return mingw::link;
else if (f == Gnu)
return elf::link;
else if (f == WinLink)
return coff::link;
else if (f == Darwin)
return macho::link;
else if (f == Wasm)
return lld::wasm::link;
else
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.
bool r = link()(args, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled);
// Call exit() if we can to avoid calling destructors.
if (exitEarly)
exitLld(!r ? 1 : 0);
// Delete the global context and clear the global context pointer, so that it
// cannot be accessed anymore.
CommonLinkerContext::destroy();
return !r ? 1 : 0;
}
// Similar to lldMain except that exceptions are caught.
@ -176,7 +193,7 @@ SafeReturn lld::safeLldMain(int argc, const char **argv,
// 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([&]() { errorHandler().reset(); })) {
if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) {
// The memory is corrupted beyond any possible recovery.
return {r, /*canRunAgain=*/false};
}
@ -207,8 +224,7 @@ int main(int argc, const char **argv) {
for (unsigned i = inTestVerbosity(); i > 0; --i) {
// Disable stdout/stderr for all iterations but the last one.
if (i != 1)
errorHandler().disableOutput = true;
inTestOutputDisabled = (i != 1);
// Execute one iteration.
auto r = safeLldMain(argc, argv, llvm::outs(), llvm::errs());

View File

@ -81,18 +81,15 @@ private:
};
} // anonymous namespace
bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
raw_ostream &stderrOS) {
lld::stdoutOS = &stdoutOS;
lld::stderrOS = &stderrOS;
bool 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;
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());
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)";
config = make<Configuration>();
symtab = make<SymbolTable>();
@ -100,13 +97,7 @@ bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
initLLVM();
LinkerDriver().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);
return !errorCount();
return errorCount() == 0;
}
// Create prefix string literals used in Options.td
@ -189,7 +180,7 @@ opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> argv) {
// 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);
@ -760,8 +751,8 @@ static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &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

View File

@ -12,8 +12,7 @@
#include "InputElement.h"
#include "OutputSegment.h"
#include "SymbolTable.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Reproduce.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/Wasm.h"
@ -721,7 +720,7 @@ static uint8_t mapVisibility(GlobalValue::VisibilityTypes gvVisibility) {
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());
@ -756,9 +755,9 @@ BitcodeFile::BitcodeFile(MemoryBufferRef m, StringRef archiveName,
// 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));

View File

@ -11,8 +11,7 @@
#include "InputChunks.h"
#include "InputElement.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "llvm/ADT/SetVector.h"
#define DEBUG_TYPE "lld"
@ -843,7 +842,7 @@ InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym,
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);
@ -941,7 +940,8 @@ void SymbolTable::handleSymbolVariants() {
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);
}
}

View File

@ -17,8 +17,7 @@
#include "SymbolTable.h"
#include "SyntheticSections.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallSet.h"
@ -190,7 +189,7 @@ void Writer::createRelocSections() {
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");
@ -389,8 +388,8 @@ static void addStartStopSymbols(const OutputSegment *seg) {
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() {
@ -958,7 +957,7 @@ static void createFunction(DefinedFunction *func, StringRef bodyContent) {
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);
}

View File

@ -27,7 +27,14 @@
// DIA headers must come after windows headers.
#include <cvconst.h>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
#endif
#include <dia2.h>
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#include <diacreate.h>
#endif // LLVM_DEBUGINFO_PDB_DIA_DIASUPPORT_H