Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lld/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ if (LLD_DEFAULT_LD_LLD_IS_MINGW)
add_definitions("-DLLD_DEFAULT_LD_LLD_IS_MINGW=1")
endif()

option(LLD_LINK_GPL3 "Allow LLD to link to GPLv3-licensed plugins, e.g. liblto_plugin.so")
option(LLD_ENABLE_GNU_LTO "Enable support for GNU LTO plugin")
if(!LLD_LINK_GPL3)
# Support for GNU LTO require linking to liblto_plugin.so from GCC which is
# licensed as GPLv3.
set(LLD_ENABLE_GNU_LTO FALSE)
endif()

if (MSVC)
add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.'
add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header.
Expand Down
14 changes: 14 additions & 0 deletions lld/ELF/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ if(LLVM_ENABLE_ZSTD)
list(APPEND imported_libs ${zstd_target})
endif()

set(GNULTO_INCLUDE_DIR "" CACHE PATH "Additional directory, where CMake should search for plugin-api.h")
if(LLD_ENABLE_GNU_LTO)
find_package(GNULTO REQUIRED)
include(CheckSymbolExists)
check_symbol_exists(dlopen "dlfcn.h" HAVE_DLOPEN)
if(NOT HAVE_DLOPEN)
message(FATAL_ERROR "Could not find the definition of dlopen(). Is dlfcn.h available?")
endif()
endif()

configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/../include/lld/config.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/../include/lld/config.h)

add_lld_library(lldELF
AArch64ErrataFix.cpp
Arch/AArch64.cpp
Expand Down
7 changes: 6 additions & 1 deletion lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class TargetInfo;
struct Ctx;
struct Partition;
struct PhdrEntry;
class IRCompiler;

class BssSection;
class GdbIndexSection;
Expand Down Expand Up @@ -191,6 +192,7 @@ class LinkerDriver {
void inferMachineType();
template <class ELFT> void link(llvm::opt::InputArgList &args);
template <class ELFT> void compileBitcodeFiles(bool skipLinkedOutput);
template <class ELFT> void compileGccIRFiles(bool skipLinkedOutput);
bool tryAddFatLTOFile(MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive, bool lazy);
// True if we are in --whole-archive and --no-whole-archive.
Expand All @@ -199,7 +201,7 @@ class LinkerDriver {
// True if we are in --start-lib and --end-lib.
bool inLib = false;

std::unique_ptr<BitcodeCompiler> lto;
std::unique_ptr<IRCompiler> lto;
SmallVector<std::unique_ptr<InputFile>, 0> files, ltoObjectFiles;

public:
Expand Down Expand Up @@ -241,9 +243,12 @@ struct Config {
llvm::StringRef optRemarksPasses;
llvm::StringRef optRemarksFormat;
llvm::StringRef optStatsFilename;
llvm::StringRef plugin;
llvm::SmallVector<std::string, 0> pluginOpt;
llvm::StringRef progName;
llvm::StringRef printArchiveStats;
llvm::StringRef printSymbolOrder;
llvm::StringRef resolutionFile;
llvm::StringRef soName;
llvm::StringRef sysroot;
llvm::StringRef thinLTOCacheDir;
Expand Down
76 changes: 71 additions & 5 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,15 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {

cl::ResetAllOptionOccurrences();

// Ignore -plugin=LLVMgold.so because we don't need to load it.
StringRef v = args.getLastArgValue(OPT_plugin);
if (!v.empty() && !v.ends_with("LLVMgold.so")) {
if (!llvm::sys::fs::exists(v))
ErrAlways(ctx) << "Cannot find plugin " << v;
else
ctx.arg.plugin = v;
}

// Parse LTO options.
if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq))
parseClangOption(ctx, ctx.saver.save("-mcpu=" + StringRef(arg->getValue())),
Expand All @@ -1802,14 +1811,32 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
arg->getSpelling());

// GCC collect2 passes -plugin-opt=path/to/lto-wrapper with an absolute or
// relative path. Just ignore. If not ended with "lto-wrapper" (or
// "lto-wrapper.exe" for GCC cross-compiled for Windows), consider it an
// unsupported LLVMgold.so option and error.
// relative path. If not ended with "lto-wrapper" (or "lto-wrapper.exe" for
// GCC cross-compiled for Windows), consider it an unsupported LLVMgold.so
// option and error.
for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq)) {
StringRef v(arg->getValue());
if (!v.ends_with("lto-wrapper") && !v.ends_with("lto-wrapper.exe"))
ErrAlways(ctx) << arg->getSpelling() << ": unknown plugin option '"
<< arg->getValue() << "'";
else if (!ctx.arg.plugin.empty())
#if LLD_ENABLE_GNU_LTO
ctx.arg.pluginOpt.push_back(v.str());
#else
ErrAlways(ctx) << arg->getSpelling()
<< " : support for GNU LTO is disabled";
#endif
}

// Parse GCC collect2 options.
if (!ctx.arg.plugin.empty()) {
#if LLD_ENABLE_GNU_LTO
StringRef v = args.getLastArgValue(OPT_plugin_opt_fresolution);
if (!v.empty()) {
ctx.arg.resolutionFile = v;
ctx.arg.pluginOpt.push_back(std::string("-fresolution=" + v.str()));
}
#endif
}

ctx.arg.passPlugins = args::getStrings(args, OPT_load_pass_plugins);
Expand Down Expand Up @@ -2689,7 +2716,7 @@ static void markBuffersAsDontNeed(Ctx &ctx, bool skipLinkedOutput) {
}

// This function is where all the optimizations of link-time
// optimization takes place. When LTO is in use, some input files are
// optimization takes place. When LLVM LTO is in use, some input files are
// not in native object file format but in the LLVM bitcode format.
// This function compiles bitcode files into a few big native files
// using LLVM functions and replaces bitcode symbols with the results.
Expand Down Expand Up @@ -2738,6 +2765,39 @@ void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
}
}

#if LLD_ENABLE_GNU_LTO
template <class ELFT>
void LinkerDriver::compileGccIRFiles(bool skipLinkedOutput) {
llvm::TimeTraceScope timeScope("LTO");
// Compile files and replace symbols.
GccIRCompiler *c = GccIRCompiler::getInstance(ctx);
lto.reset(c);

for (ELFFileBase *file : ctx.objectFiles)
c->add(*file);

ltoObjectFiles = c->compile();
for (auto &file : ltoObjectFiles) {
auto *obj = cast<ObjFile<ELFT>>(file.get());
obj->parse(/*ignoreComdats=*/true);

// For defined symbols in non-relocatable output,
// compute isExported and parse '@'.
if (!ctx.arg.relocatable)
for (Symbol *sym : obj->getGlobalSymbols()) {
if (!sym->isDefined())
continue;
if (ctx.arg.exportDynamic && sym->computeBinding(ctx) != STB_LOCAL)
sym->isExported = true;
if (sym->hasVersionSuffix)
sym->parseSymbolVersion(ctx);
}
ctx.objectFiles.push_back(obj);
}
return;
}
#endif

// The --wrap option is a feature to rename symbols so that you can write
// wrappers for existing functions. If you pass `--wrap=foo`, all
// occurrences of symbol `foo` are resolved to `__wrap_foo` (so, you are
Expand Down Expand Up @@ -3295,7 +3355,13 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// except a few linker-synthesized ones will be added to the symbol table.
const size_t numObjsBeforeLTO = ctx.objectFiles.size();
const size_t numInputFilesBeforeLTO = ctx.driver.files.size();
compileBitcodeFiles<ELFT>(skipLinkedOutput);
if (ctx.arg.plugin.empty()) {
compileBitcodeFiles<ELFT>(skipLinkedOutput);
#if LLD_ENABLE_GNU_LTO
} else {
compileGccIRFiles<ELFT>(skipLinkedOutput);
#endif
}

// Symbol resolution finished. Report backward reference problems,
// --print-archive-stats=, and --why-extract=.
Expand Down
6 changes: 3 additions & 3 deletions lld/ELF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1845,8 +1845,8 @@ static bool dtltoAdjustMemberPathIfThinArchive(Ctx &ctx, StringRef archivePath,
return true;
}

BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive, bool lazy)
IRFile::IRFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive, bool lazy)
: InputFile(ctx, BitcodeKind, mb) {
this->archiveName = archiveName;
this->lazy = lazy;
Expand Down Expand Up @@ -1958,7 +1958,7 @@ void BitcodeFile::parse() {
addDependentLibrary(ctx, l, this);
}

void BitcodeFile::parseLazy() {
void IRFile::parseLazy() {
numSymbols = obj->symbols().size();
symbols = std::make_unique<Symbol *[]>(numSymbols);
for (auto [i, irSym] : llvm::enumerate(obj->symbols())) {
Expand Down
21 changes: 16 additions & 5 deletions lld/ELF/InputFiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/Threading.h"
Expand Down Expand Up @@ -321,15 +322,25 @@ template <class ELFT> class ObjFile : public ELFFileBase {
ArrayRef<Elf_Word> shndxTable;
};

class BitcodeFile : public InputFile {
class IRFile : public InputFile {
public:
BitcodeFile(Ctx &, MemoryBufferRef m, StringRef archiveName,
uint64_t offsetInArchive, bool lazy);
IRFile(Ctx &ctx, MemoryBufferRef m, StringRef archiveName,
uint64_t offsetInArchive, bool lazy);
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
void parse();
virtual void parse() = 0;
void parseLazy();
void postParse();
virtual void postParse() = 0;
std::unique_ptr<llvm::lto::InputFile> obj;
};

class BitcodeFile : public IRFile {
public:
BitcodeFile(Ctx &ctx, MemoryBufferRef m, StringRef archiveName,
uint64_t offsetInArchive, bool lazy)
: IRFile(ctx, m, archiveName, offsetInArchive, lazy) {};
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
void parse() override;
void postParse() override;
std::vector<bool> keptComdats;
};

Expand Down
Loading