Vendor import of lld trunk r300422:

https://llvm.org/svn/llvm-project/lld/trunk@300422
This commit is contained in:
Dimitry Andric 2017-04-16 16:03:39 +00:00
parent 16787c9ce0
commit d2d3ebb819
369 changed files with 12798 additions and 7941 deletions

View file

@ -11,8 +11,11 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH")
endif()
execute_process(COMMAND "${LLVM_CONFIG_PATH}" "--obj-root" "--includedir"
execute_process(COMMAND "${LLVM_CONFIG_PATH}"
"--obj-root"
"--includedir"
"--cmakedir"
"--src-root"
RESULT_VARIABLE HAD_ERROR
OUTPUT_VARIABLE LLVM_CONFIG_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE)
@ -25,9 +28,11 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
list(GET LLVM_CONFIG_OUTPUT 0 OBJ_ROOT)
list(GET LLVM_CONFIG_OUTPUT 1 MAIN_INCLUDE_DIR)
list(GET LLVM_CONFIG_OUTPUT 2 LLVM_CMAKE_PATH)
list(GET LLVM_CONFIG_OUTPUT 3 MAIN_SRC_DIR)
set(LLVM_OBJ_ROOT ${OBJ_ROOT} CACHE PATH "path to LLVM build tree")
set(LLVM_MAIN_INCLUDE_DIR ${MAIN_INCLUDE_DIR} CACHE PATH "path to llvm/include")
set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
file(TO_CMAKE_PATH ${LLVM_OBJ_ROOT} LLVM_BINARY_DIR)
@ -49,6 +54,67 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
include(AddLLVM)
include(TableGen)
include(HandleLLVMOptions)
if(LLVM_INCLUDE_TESTS)
set(Python_ADDITIONAL_VERSIONS 2.7)
include(FindPythonInterp)
if(NOT PYTHONINTERP_FOUND)
message(FATAL_ERROR
"Unable to find Python interpreter, required for testing.
Please install Python or specify the PYTHON_EXECUTABLE CMake variable.")
endif()
if(${PYTHON_VERSION_STRING} VERSION_LESS 2.7)
message(FATAL_ERROR "Python 2.7 or newer is required")
endif()
# Check prebuilt llvm/utils.
if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX}
AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX})
set(LLVM_UTILS_PROVIDED ON)
endif()
if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
# Note: path not really used, except for checking if lit was found
set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
if(NOT LLVM_UTILS_PROVIDED)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not)
set(LLVM_UTILS_PROVIDED ON)
set(LLD_TEST_DEPS FileCheck not)
endif()
set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest)
if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h
AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}
AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt)
add_subdirectory(${UNITTEST_DIR} utils/unittest)
endif()
else()
# Seek installed Lit.
find_program(LLVM_LIT
NAMES llvm-lit lit.py lit
PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit"
DOC "Path to lit.py")
endif()
if(LLVM_LIT)
# Define the default arguments to use with 'lit', and an option for the user
# to override.
set(LIT_ARGS_DEFAULT "-sv")
if (MSVC OR XCODE)
set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
endif()
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
# On Win32 hosts, provide an option to specify the path to the GnuWin32 tools.
if(WIN32 AND NOT CYGWIN)
set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools")
endif()
else()
set(LLVM_INCLUDE_TESTS OFF)
endif()
endif()
endif()
set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})

View file

@ -15,6 +15,8 @@ add_lld_library(lldCOFF
ICF.cpp
InputFiles.cpp
Librarian.cpp
LTO.cpp
MapFile.cpp
MarkLive.cpp
ModuleDef.cpp
PDB.cpp
@ -25,6 +27,7 @@ add_lld_library(lldCOFF
LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
BitReader
Core
DebugInfoCodeView
DebugInfoMSF
@ -40,7 +43,7 @@ add_lld_library(lldCOFF
LINK_LIBS
lldCore
${PTHREAD_LIB}
${LLVM_PTHREAD_LIB}
DEPENDS
COFFOptionsTableGen

View file

@ -11,6 +11,7 @@
#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
@ -61,7 +62,7 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break;
case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break;
default:
fatal("unsupported relocation type");
fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
}
@ -76,7 +77,7 @@ void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break;
case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break;
default:
fatal("unsupported relocation type");
fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
}
@ -136,7 +137,7 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break;
case IMAGE_REL_ARM_SECREL: add32(Off, Sym->getSecrel()); break;
default:
fatal("unsupported relocation type");
fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
}
@ -226,7 +227,7 @@ void SectionChunk::printDiscardedMessage() const {
// Removed by dead-stripping. If it's removed by ICF, ICF already
// printed out the name, so don't repeat that here.
if (Sym && this == Repl)
outs() << "Discarded " << Sym->getName() << "\n";
message("Discarded " + Sym->getName());
}
StringRef SectionChunk::getDebugName() {

View file

@ -187,10 +187,10 @@ public:
const coff_section *Header;
private:
// A file this chunk was created from.
// The file that this chunk was created from.
ObjectFile *File;
private:
StringRef SectionName;
std::vector<SectionChunk *> AssocChildren;
llvm::iterator_range<const coff_relocation *> Relocs;

View file

@ -80,14 +80,16 @@ struct Configuration {
SymbolBody *Entry = nullptr;
bool NoEntry = false;
std::string OutputFile;
bool ColorDiagnostics;
bool DoGC = true;
bool DoICF = true;
uint64_t ErrorLimit = 20;
bool Relocatable = true;
bool Force = false;
bool Debug = false;
bool WriteSymtab = true;
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
StringRef PDBPath;
llvm::SmallString<128> PDBPath;
// Symbols in this set are considered as live by the garbage collector.
std::set<SymbolBody *> GCRoot;
@ -103,6 +105,8 @@ struct Configuration {
std::map<std::string, int> DLLOrder;
SymbolBody *DelayLoadHelper = nullptr;
bool SaveTemps = false;
// Used for SafeSEH.
Symbol *SEHTable = nullptr;
Symbol *SEHCount = nullptr;
@ -111,7 +115,9 @@ struct Configuration {
unsigned LTOOptLevel = 2;
// Used for /opt:lldltojobs=N
unsigned LTOJobs = 1;
unsigned LTOJobs = 0;
// Used for /opt:lldltopartitions=N
unsigned LTOPartitions = 1;
// Used for /merge:from=to (e.g. /merge:.rdata=.text)
std::map<StringRef, StringRef> Merge;
@ -135,6 +141,9 @@ struct Configuration {
// Used for /alternatename.
std::map<StringRef, StringRef> AlternateNames;
// Used for /lldmap.
std::string MapFile;
uint64_t ImageBase = -1;
uint64_t StackReserve = 1024 * 1024;
uint64_t StackCommit = 4096;
@ -151,6 +160,7 @@ struct Configuration {
bool TerminalServerAware = true;
bool LargeAddressAware = false;
bool HighEntropyVA = false;
bool AppContainer = false;
// This is for debugging.
bool DebugPdb = false;

View file

@ -19,6 +19,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/LibDriver/LibDriver.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
@ -31,17 +32,11 @@
#include <algorithm>
#include <memory>
#ifdef _MSC_VER
// <future> depends on <eh.h> for __uncaught_exception.
#include <eh.h>
#endif
#include <future>
using namespace llvm;
using namespace llvm::COFF;
using llvm::sys::Process;
using llvm::sys::fs::OpenFlags;
using llvm::sys::fs::file_magic;
using llvm::sys::fs::identify_magic;
@ -55,11 +50,16 @@ BumpPtrAllocator BAlloc;
StringSaver Saver{BAlloc};
std::vector<SpecificAllocBase *> SpecificAllocBase::Instances;
bool link(ArrayRef<const char *> Args) {
bool link(ArrayRef<const char *> Args, raw_ostream &Diag) {
ErrorCount = 0;
ErrorOS = &Diag;
Argv0 = Args[0];
Config = make<Configuration>();
Config->ColorDiagnostics =
(ErrorOS == &llvm::errs() && Process::StandardErrHasColors());
Driver = make<LinkerDriver>();
Driver->link(Args);
return true;
return !ErrorCount;
}
// Drop directory components and replace extension with ".exe" or ".dll".
@ -121,10 +121,12 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB) {
return Symtab.addFile(make<ArchiveFile>(MBRef));
if (Magic == file_magic::bitcode)
return Symtab.addFile(make<BitcodeFile>(MBRef));
if (Magic == file_magic::coff_cl_gl_object)
fatal(MBRef.getBufferIdentifier() + ": is not a native COFF file. "
error(MBRef.getBufferIdentifier() + ": is not a native COFF file. "
"Recompile without /GL");
Symtab.addFile(make<ObjectFile>(MBRef));
else
Symtab.addFile(make<ObjectFile>(MBRef));
}
void LinkerDriver::enqueuePath(StringRef Path) {
@ -134,12 +136,10 @@ void LinkerDriver::enqueuePath(StringRef Path) {
enqueueTask([=]() {
auto MBOrErr = Future->get();
if (MBOrErr.second)
fatal(MBOrErr.second, "could not open " + PathStr);
Driver->addBuffer(std::move(MBOrErr.first));
error("could not open " + PathStr + ": " + MBOrErr.second.message());
else
Driver->addBuffer(std::move(MBOrErr.first));
});
if (Config->OutputFile == "")
Config->OutputFile = getOutputPath(Path);
}
void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
@ -151,17 +151,18 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
}
InputFile *Obj;
if (Magic == file_magic::coff_object)
if (Magic == file_magic::coff_object) {
Obj = make<ObjectFile>(MB);
else if (Magic == file_magic::bitcode)
} else if (Magic == file_magic::bitcode) {
Obj = make<BitcodeFile>(MB);
else
fatal("unknown file type: " + MB.getBufferIdentifier());
} else {
error("unknown file type: " + MB.getBufferIdentifier());
return;
}
Obj->ParentName = ParentName;
Symtab.addFile(Obj);
if (Config->Verbose)
outs() << "Loaded " << toString(Obj) << " for " << SymName << "\n";
log("Loaded " + toString(Obj) + " for " + SymName);
}
void LinkerDriver::enqueueArchiveMember(const Archive::Child &C,
@ -234,7 +235,7 @@ void LinkerDriver::parseDirectives(StringRef S) {
case OPT_throwingnew:
break;
default:
fatal(Arg->getSpelling() + " is not allowed in .drectve");
error(Arg->getSpelling() + " is not allowed in .drectve");
}
}
}
@ -402,7 +403,8 @@ static unsigned parseDebugType(StringRef Arg) {
DebugTypes |= StringSwitch<unsigned>(Type.lower())
.Case("cv", static_cast<unsigned>(DebugType::CV))
.Case("pdata", static_cast<unsigned>(DebugType::PData))
.Case("fixup", static_cast<unsigned>(DebugType::Fixup));
.Case("fixup", static_cast<unsigned>(DebugType::Fixup))
.Default(0);
return DebugTypes;
}
@ -418,6 +420,132 @@ static std::string getMapFile(const opt::InputArgList &Args) {
return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str();
}
std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) {
std::vector<MemoryBufferRef> V;
Error Err = Error::success();
for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
Archive::Child C =
check(COrErr,
File->getFileName() + ": could not get the child of the archive");
MemoryBufferRef MBRef =
check(C.getMemoryBufferRef(),
File->getFileName() +
": could not get the buffer for a child of the archive");
V.push_back(MBRef);
}
if (Err)
fatal(File->getFileName() +
": Archive::children failed: " + toString(std::move(Err)));
return V;
}
// A helper function for filterBitcodeFiles.
static bool needsRebuilding(MemoryBufferRef MB) {
// The MSVC linker doesn't support thin archives, so if it's a thin
// archive, we always need to rebuild it.
std::unique_ptr<Archive> File =
check(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier());
if (File->isThin())
return true;
// Returns true if the archive contains at least one bitcode file.
for (MemoryBufferRef Member : getArchiveMembers(File.get()))
if (identify_magic(Member.getBuffer()) == file_magic::bitcode)
return true;
return false;
}
// Opens a given path as an archive file and removes bitcode files
// from them if exists. This function is to appease the MSVC linker as
// their linker doesn't like archive files containing non-native
// object files.
//
// If a given archive doesn't contain bitcode files, the archive path
// is returned as-is. Otherwise, a new temporary file is created and
// its path is returned.
static Optional<std::string>
filterBitcodeFiles(StringRef Path, std::vector<std::string> &TemporaryFiles) {
std::unique_ptr<MemoryBuffer> MB = check(
MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
MemoryBufferRef MBRef = MB->getMemBufferRef();
file_magic Magic = identify_magic(MBRef.getBuffer());
if (Magic == file_magic::bitcode)
return None;
if (Magic != file_magic::archive)
return Path.str();
if (!needsRebuilding(MBRef))
return Path.str();
std::unique_ptr<Archive> File =
check(Archive::create(MBRef),
MBRef.getBufferIdentifier() + ": failed to parse archive");
std::vector<NewArchiveMember> New;
for (MemoryBufferRef Member : getArchiveMembers(File.get()))
if (identify_magic(Member.getBuffer()) != file_magic::bitcode)
New.emplace_back(Member);
if (New.empty())
return None;
log("Creating a temporary archive for " + Path + " to remove bitcode files");
SmallString<128> S;
if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path),
".lib", S))
fatal(EC, "cannot create a temporary file");
std::string Temp = S.str();
TemporaryFiles.push_back(Temp);
std::pair<StringRef, std::error_code> Ret =
llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU,
/*Deterministics=*/true,
/*Thin=*/false);
if (Ret.second)
error("failed to create a new archive " + S.str() + ": " + Ret.first);
return Temp;
}
// Create response file contents and invoke the MSVC linker.
void LinkerDriver::invokeMSVC(opt::InputArgList &Args) {
std::string Rsp = "/nologo ";
std::vector<std::string> Temps;
for (auto *Arg : Args) {
switch (Arg->getOption().getID()) {
case OPT_linkrepro:
case OPT_lldmap:
case OPT_lldmap_file:
case OPT_lldsavetemps:
case OPT_msvclto:
// LLD-specific options are stripped.
break;
case OPT_opt:
if (!StringRef(Arg->getValue()).startswith("lld"))
Rsp += toString(Arg) + " ";
break;
case OPT_INPUT: {
if (Optional<StringRef> Path = doFindFile(Arg->getValue())) {
if (Optional<std::string> S = filterBitcodeFiles(*Path, Temps))
Rsp += quote(*S) + " ";
continue;
}
Rsp += quote(Arg->getValue()) + " ";
break;
}
default:
Rsp += toString(Arg) + " ";
}
}
std::vector<StringRef> ObjectFiles = Symtab.compileBitcodeFiles();
runMSVCLinker(Rsp, ObjectFiles);
for (StringRef Path : Temps)
sys::fs::remove(Path);
}
void LinkerDriver::enqueueTask(std::function<void()> Task) {
TaskQueue.push_back(std::move(Task));
}
@ -451,6 +579,22 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Parse command line options.
opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
// Parse and evaluate -mllvm options.
std::vector<const char *> V;
V.push_back("lld-link (LLVM option parsing)");
for (auto *Arg : Args.filtered(OPT_mllvm))
V.push_back(Arg->getValue());
cl::ParseCommandLineOptions(V.size(), V.data());
// Handle /errorlimit early, because error() depends on it.
if (auto *Arg = Args.getLastArg(OPT_errorlimit)) {
int N = 20;
StringRef S = Arg->getValue();
if (S.getAsInteger(10, N))
error(Arg->getSpelling() + " number expected, but got " + S);
Config->ErrorLimit = N;
}
// Handle /help
if (Args.hasArg(OPT_help)) {
printHelp(ArgsArr[0]);
@ -467,12 +611,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (ErrOrWriter) {
Tar = std::move(*ErrOrWriter);
} else {
errs() << "/linkrepro: failed to open " << Path << ": "
<< toString(ErrOrWriter.takeError()) << '\n';
error("/linkrepro: failed to open " + Path + ": " +
toString(ErrOrWriter.takeError()));
}
}
if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end())
if (!Args.hasArgNoClaim(OPT_INPUT))
fatal("no input files");
// Construct search path list.
@ -508,9 +652,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /noentry
if (Args.hasArg(OPT_noentry)) {
if (!Args.hasArg(OPT_dll))
fatal("/noentry must be specified with /dll");
Config->NoEntry = true;
if (Args.hasArg(OPT_dll))
Config->NoEntry = true;
else
error("/noentry must be specified with /dll");
}
// Handle /dll
@ -521,12 +666,17 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /fixed
if (Args.hasArg(OPT_fixed)) {
if (Args.hasArg(OPT_dynamicbase))
fatal("/fixed must not be specified with /dynamicbase");
Config->Relocatable = false;
Config->DynamicBase = false;
if (Args.hasArg(OPT_dynamicbase)) {
error("/fixed must not be specified with /dynamicbase");
} else {
Config->Relocatable = false;
Config->DynamicBase = false;
}
}
if (Args.hasArg(OPT_appcontainer))
Config->AppContainer = true;
// Handle /machine
if (auto *Arg = Args.getLastArg(OPT_machine))
Config->Machine = getMachineType(Arg->getValue());
@ -596,20 +746,31 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
StringRef OptLevel = StringRef(S).substr(7);
if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
Config->LTOOptLevel > 3)
fatal("/opt:lldlto: invalid optimization level: " + OptLevel);
error("/opt:lldlto: invalid optimization level: " + OptLevel);
continue;
}
if (StringRef(S).startswith("lldltojobs=")) {
StringRef Jobs = StringRef(S).substr(11);
if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0)
fatal("/opt:lldltojobs: invalid job count: " + Jobs);
error("/opt:lldltojobs: invalid job count: " + Jobs);
continue;
}
if (StringRef(S).startswith("lldltopartitions=")) {
StringRef N = StringRef(S).substr(17);
if (N.getAsInteger(10, Config->LTOPartitions) ||
Config->LTOPartitions == 0)
error("/opt:lldltopartitions: invalid partition count: " + N);
continue;
}
if (S != "ref" && S != "lbr" && S != "nolbr")
fatal("/opt: unknown option: " + S);
error("/opt: unknown option: " + S);
}
}
// Handle /lldsavetemps
if (Args.hasArg(OPT_lldsavetemps))
Config->SaveTemps = true;
// Handle /failifmismatch
for (auto *Arg : Args.filtered(OPT_failifmismatch))
checkFailIfMismatch(Arg->getValue());
@ -658,6 +819,11 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->DumpPdb = Args.hasArg(OPT_dumppdb);
Config->DebugPdb = Args.hasArg(OPT_debugpdb);
Config->MapFile = getMapFile(Args);
if (ErrorCount)
return;
// Create a list of input files. Files can be given as arguments
// for /defaultlib option.
std::vector<MemoryBufferRef> MBs;
@ -678,7 +844,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// We should have inferred a machine type by now from the input files, but if
// not we assume x64.
if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
errs() << "warning: /machine is not specified. x64 is assumed.\n";
warn("/machine is not specified. x64 is assumed");
Config->Machine = AMD64;
}
@ -715,8 +881,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (S.empty())
fatal("entry point must be defined");
Config->Entry = addUndefined(S);
if (Config->Verbose)
outs() << "Entry name inferred: " << S << "\n";
log("Entry name inferred: " + S);
}
// Handle /export
@ -749,6 +914,22 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
}
}
// Set default image name if neither /out or /def set it.
if (Config->OutputFile.empty()) {
Config->OutputFile =
getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue());
}
// Put the PDB next to the image if no /pdb flag was passed.
if (Config->Debug && Config->PDBPath.empty()) {
Config->PDBPath = Config->OutputFile;
sys::path::replace_extension(Config->PDBPath, ".pdb");
}
// Disable PDB generation if the user requested it.
if (Args.hasArg(OPT_nopdb))
Config->PDBPath = "";
// Set default image base if /base is not given.
if (Config->ImageBase == uint64_t(-1))
Config->ImageBase = getDefaultImageBase();
@ -801,6 +982,16 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
addUndefined(mangle("_load_config_used"));
} while (run());
if (ErrorCount)
return;
// If /msvclto is given, we use the MSVC linker to link LTO output files.
// This is useful because MSVC link.exe can generate complete PDBs.
if (Args.hasArg(OPT_msvclto)) {
invokeMSVC(Args);
exit(0);
}
// Do LTO by compiling bitcode input files to a set of native COFF files then
// link those files.
Symtab.addCombinedLTOObjects();
@ -818,10 +1009,13 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
}
// Handle /safeseh.
if (Args.hasArg(OPT_safeseh))
if (Args.hasArg(OPT_safeseh)) {
for (ObjectFile *File : Symtab.ObjectFiles)
if (!File->SEHCompat)
fatal("/safeseh: " + File->getName() + " is not compatible with SEH");
error("/safeseh: " + File->getName() + " is not compatible with SEH");
if (ErrorCount)
return;
}
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file.
@ -846,17 +1040,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Write the result.
writeResult(&Symtab);
// Create a symbol map file containing symbol VAs and their names
// to help debugging.
std::string MapFile = getMapFile(Args);
if (!MapFile.empty()) {
std::error_code EC;
raw_fd_ostream Out(MapFile, EC, OpenFlags::F_Text);
if (EC)
fatal(EC, "could not create the symbol map " + MapFile);
Symtab.printMap(Out);
}
// Call exit to avoid calling destructors.
exit(0);
}

View file

@ -107,6 +107,8 @@ private:
StringRef findDefaultEntry();
WindowsSubsystem inferSubsystem();
void invokeMSVC(llvm::opt::InputArgList &Args);
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB);
void addBuffer(std::unique_ptr<MemoryBuffer> MB);
void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
@ -178,6 +180,8 @@ void checkFailIfMismatch(StringRef Arg);
std::unique_ptr<MemoryBuffer>
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs);
void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects);
// Create enum with OPT_xxx values for each option in Options.td
enum {
OPT_INVALID = 0,

View file

@ -44,31 +44,33 @@ namespace {
class Executor {
public:
explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {}
void add(StringRef S) { Args.push_back(Saver.save(S).data()); }
void add(std::string &S) { Args.push_back(Saver.save(S).data()); }
void add(Twine S) { Args.push_back(Saver.save(S).data()); }
void add(const char *S) { Args.push_back(Saver.save(S).data()); }
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(EC, "unable to find " + Prog + " in PATH: ");
const char *Exe = Saver.save(*ExeOrErr).data();
StringRef Exe = Saver.save(*ExeOrErr);
Args.insert(Args.begin(), Exe);
Args.push_back(nullptr);
if (sys::ExecuteAndWait(Args[0], Args.data()) != 0) {
for (const char *S : Args)
if (S)
errs() << S << " ";
fatal("ExecuteAndWait failed");
}
std::vector<const char *> Vec;
for (StringRef S : Args)
Vec.push_back(S.data());
Vec.push_back(nullptr);
if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0)
fatal("ExecuteAndWait failed: " +
llvm::join(Args.begin(), Args.end(), " "));
}
private:
BumpPtrAllocator Alloc;
StringSaver Saver;
StringRef Prog;
std::vector<const char *> Args;
std::vector<StringRef> Args;
};
} // anonymous namespace
@ -167,8 +169,7 @@ void parseMerge(StringRef S) {
if (!Inserted) {
StringRef Existing = Pair.first->second;
if (Existing != To)
errs() << "warning: " << S << ": already merged into " << Existing
<< "\n";
warn(S + ": already merged into " + Existing);
}
}
@ -282,11 +283,19 @@ static void quoteAndPrint(raw_ostream &Out, StringRef S) {
namespace {
class TemporaryFile {
public:
TemporaryFile(StringRef Prefix, StringRef Extn) {
TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") {
SmallString<128> S;
if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S))
fatal(EC, "cannot create a temporary file");
Path = S.str();
if (!Contents.empty()) {
std::error_code EC;
raw_fd_ostream OS(Path, EC, sys::fs::F_None);
if (EC)
fatal(EC, "failed to open " + Path);
OS << Contents;
}
}
TemporaryFile(TemporaryFile &&Obj) {
@ -542,7 +551,7 @@ void fixupExports() {
Export *Existing = Pair.first->second;
if (E == *Existing || E.Name != Existing->Name)
continue;
errs() << "warning: duplicate /export option: " << E.Name << "\n";
warn("duplicate /export option: " + E.Name);
}
Config->Exports = std::move(V);
@ -617,6 +626,26 @@ convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
return File.getMemoryBuffer();
}
// Run MSVC link.exe for given in-memory object files.
// Command line options are copied from those given to LLD.
// This is for the /msvclto option.
void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects) {
// Write the in-memory object files to disk.
std::vector<TemporaryFile> Temps;
for (StringRef S : Objects) {
Temps.emplace_back("lto", "obj", S);
Rsp += quote(Temps.back().Path) + " ";
}
log("link.exe " + Rsp);
// Run MSVC link.exe.
Temps.emplace_back("lto", "rsp", Rsp);
Executor E("link.exe");
E.add(Twine("@" + Temps.back().Path));
E.run();
}
// Create OptTable
// Create prefix string literals used in Options.td
@ -653,16 +682,16 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
// Print the real command line if response files are expanded.
if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) {
outs() << "Command line:";
std::string Msg = "Command line:";
for (const char *S : Argv)
outs() << " " << S;
outs() << "\n";
Msg += " " + std::string(S);
message(Msg);
}
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
warn("ignoring unknown argument: " + Arg->getSpelling());
return Args;
}

View file

@ -8,11 +8,14 @@
//===----------------------------------------------------------------------===//
#include "Error.h"
#include "Config.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
#include <mutex>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
@ -21,10 +24,68 @@
using namespace llvm;
namespace lld {
// The functions defined in this file can be called from multiple threads,
// but outs() or errs() are not thread-safe. We protect them using a mutex.
static std::mutex Mu;
namespace coff {
StringRef Argv0;
uint64_t ErrorCount;
raw_ostream *ErrorOS;
static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) {
// Dealloc/destroy ManagedStatic variables before calling
// _exit(). In a non-LTO build, this is a nop. In an LTO
// build allows us to get the output of -time-passes.
llvm_shutdown();
outs().flush();
errs().flush();
_exit(Val);
}
static void print(StringRef S, raw_ostream::Colors C) {
*ErrorOS << Argv0 + ": ";
if (Config->ColorDiagnostics) {
ErrorOS->changeColor(C, true);
*ErrorOS << S;
ErrorOS->resetColor();
} else {
*ErrorOS << S;
}
}
void log(const Twine &Msg) {
if (Config->Verbose) {
std::lock_guard<std::mutex> Lock(Mu);
outs() << Argv0 << ": " << Msg << "\n";
}
}
void message(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
outs() << Msg << "\n";
outs().flush();
}
void error(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
print("error: ", raw_ostream::RED);
*ErrorOS << Msg << "\n";
} else if (ErrorCount == Config->ErrorLimit) {
print("error: ", raw_ostream::RED);
*ErrorOS << "too many errors emitted, stopping now"
<< " (use /ERRORLIMIT:0 to see all errors)\n";
exitLld(1);
}
++ErrorCount;
}
void fatal(const Twine &Msg) {
if (sys::Process::StandardErrHasColors()) {
if (Config->ColorDiagnostics) {
errs().changeColor(raw_ostream::RED, /*bold=*/true);
errs() << "error: ";
errs().resetColor();
@ -32,10 +93,7 @@ void fatal(const Twine &Msg) {
errs() << "error: ";
}
errs() << Msg << "\n";
outs().flush();
errs().flush();
_exit(1);
exitLld(1);
}
void fatal(std::error_code EC, const Twine &Msg) {
@ -46,5 +104,11 @@ void fatal(llvm::Error &Err, const Twine &Msg) {
fatal(errorToErrorCode(std::move(Err)), Msg);
}
void warn(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
print("warning: ", raw_ostream::MAGENTA);
*ErrorOS << Msg << "\n";
}
} // namespace coff
} // namespace lld

View file

@ -16,11 +16,19 @@
namespace lld {
namespace coff {
extern uint64_t ErrorCount;
extern llvm::raw_ostream *ErrorOS;
extern llvm::StringRef Argv0;
void log(const Twine &Msg);
void message(const Twine &Msg);
void warn(const Twine &Msg);
void error(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix);
template <class T> T check(ErrorOr<T> &&V, const Twine &Prefix) {
template <class T> T check(ErrorOr<T> V, const Twine &Prefix) {
if (auto EC = V.getError())
fatal(EC, Prefix);
return std::move(*V);

View file

@ -231,19 +231,16 @@ void ICF::run(const std::vector<Chunk *> &Vec) {
++Cnt;
} while (Repeat);
if (Config->Verbose)
outs() << "\nICF needed " << Cnt << " iterations\n";
log("ICF needed " + Twine(Cnt) + " iterations");
// Merge sections in the same colors.
forEachColor([&](size_t Begin, size_t End) {
if (End - Begin == 1)
return;
if (Config->Verbose)
outs() << "Selected " << Chunks[Begin]->getDebugName() << "\n";
log("Selected " + Chunks[Begin]->getDebugName());
for (size_t I = Begin + 1; I < End; ++I) {
if (Config->Verbose)
outs() << " Removed " << Chunks[I]->getDebugName() << "\n";
log(" Removed " + Chunks[I]->getDebugName());
Chunks[Begin]->replace(Chunks[I]);
}
});

View file

@ -19,8 +19,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/LTO/legacy/LTOModule.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/COFF.h"
@ -41,13 +39,23 @@ using namespace llvm::support::endian;
using llvm::Triple;
using llvm::support::ulittle32_t;
using llvm::sys::fs::file_magic;
using llvm::sys::fs::identify_magic;
namespace lld {
namespace coff {
LLVMContext BitcodeFile::Context;
/// Checks that Source is compatible with being a weak alias to Target.
/// If Source is Undefined and has no weak alias set, makes it a weak
/// alias to Target.
static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,
SymbolBody *Source, SymbolBody *Target) {
auto *U = dyn_cast<Undefined>(Source);
if (!U)
return;
else if (!U->WeakAlias)
U->WeakAlias = Target;
else if (U->WeakAlias != Target)
Symtab->reportDuplicate(Source->symbol(), F);
}
ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
@ -177,15 +185,9 @@ void ObjectFile::initializeSymbols() {
I += Sym.getNumberOfAuxSymbols();
LastSectionNumber = Sym.getSectionNumber();
}
for (auto WeakAlias : WeakAliases) {
auto *U = dyn_cast<Undefined>(WeakAlias.first);
if (!U)
continue;
// Report an error if two undefined symbols have different weak aliases.
if (U->WeakAlias && U->WeakAlias != SparseSymbolBodies[WeakAlias.second])
Symtab->reportDuplicate(U->symbol(), this);
U->WeakAlias = SparseSymbolBodies[WeakAlias.second];
}
for (auto WeakAlias : WeakAliases)
checkAndSetWeakAlias(Symtab, this, WeakAlias.first,
SparseSymbolBodies[WeakAlias.second]);
}
SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) {
@ -200,7 +202,10 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
if (Sym.isCommon()) {
auto *C = new (Alloc) CommonChunk(Sym);
Chunks.push_back(C);
return Symtab->addCommon(this, Sym, C)->body();
COFFObj->getSymbolName(Sym, Name);
Symbol *S =
Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C);
return S->body();
}
if (Sym.isAbsolute()) {
COFFObj->getSymbolName(Sym, Name);
@ -247,10 +252,14 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
}
DefinedRegular *B;
if (Sym.isExternal())
B = cast<DefinedRegular>(Symtab->addRegular(this, Sym, SC)->body());
else
B = new (Alloc) DefinedRegular(this, Sym, SC);
if (Sym.isExternal()) {
COFFObj->getSymbolName(Sym, Name);
Symbol *S =
Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC);
B = cast<DefinedRegular>(S->body());
} else
B = new (Alloc) DefinedRegular(this, /*Name*/ "", SC->isCOMDAT(),
/*IsExternal*/ false, Sym.getGeneric(), SC);
if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
SC->setSymbol(B);
@ -329,39 +338,32 @@ void ImportFile::parse() {
}
void BitcodeFile::parse() {
Context.enableDebugTypeODRUniquing();
ErrorOr<std::unique_ptr<LTOModule>> ModOrErr = LTOModule::createFromBuffer(
Context, MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions());
M = check(std::move(ModOrErr), "could not create LTO module");
StringSaver Saver(Alloc);
for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) {
lto_symbol_attributes Attrs = M->getSymbolAttributes(I);
if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
continue;
StringRef SymName = Saver.save(M->getSymbolName(I));
int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK;
if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) {
SymbolBodies.push_back(Symtab->addUndefined(SymName, this, false)->body());
Obj = check(lto::InputFile::create(MemoryBufferRef(
MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier()))));
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) {
StringRef SymName = Saver.save(ObjSym.getName());
Symbol *Sym;
if (ObjSym.isUndefined()) {
Sym = Symtab->addUndefined(SymName, this, false);
} else if (ObjSym.isCommon()) {
Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize());
} else if (ObjSym.isWeak() && ObjSym.isIndirect()) {
// Weak external.
Sym = Symtab->addUndefined(SymName, this, true);
std::string Fallback = ObjSym.getCOFFWeakExternalFallback();
SymbolBody *Alias = Symtab->addUndefined(Saver.save(Fallback));
checkAndSetWeakAlias(Symtab, this, Sym->body(), Alias);
} else {
bool Replaceable =
(SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common
(Attrs & LTO_SYMBOL_COMDAT) || // comdat
(SymbolDef == LTO_SYMBOL_DEFINITION_WEAK && // weak external
(Attrs & LTO_SYMBOL_ALIAS)));
SymbolBodies.push_back(
Symtab->addBitcode(this, SymName, Replaceable)->body());
bool IsCOMDAT = ObjSym.getComdatIndex() != -1;
Sym = Symtab->addRegular(this, SymName, IsCOMDAT);
}
SymbolBodies.push_back(Sym->body());
}
Directives = M->getLinkerOpts();
Directives = Obj->getCOFFLinkerOpts();
}
MachineTypes BitcodeFile::getMachineType() {
if (!M)
return IMAGE_FILE_MACHINE_UNKNOWN;
switch (Triple(M->getTargetTriple()).getArch()) {
switch (Triple(Obj->getTargetTriple()).getArch()) {
case Triple::x86_64:
return AMD64;
case Triple::x86:

View file

@ -13,8 +13,7 @@
#include "lld/Core/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/LTO/legacy/LTOModule.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/StringSaver.h"
@ -25,7 +24,6 @@
namespace lld {
namespace coff {
using llvm::LTOModule;
using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
using llvm::COFF::MachineTypes;
using llvm::object::Archive;
@ -174,7 +172,6 @@ public:
private:
void parse() override;
llvm::BumpPtrAllocator Alloc;
llvm::BumpPtrAllocator StringAllocAux;
llvm::StringSaver StringAlloc;
@ -191,16 +188,12 @@ public:
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
std::vector<SymbolBody *> &getSymbols() { return SymbolBodies; }
MachineTypes getMachineType() override;
std::unique_ptr<LTOModule> takeModule() { return std::move(M); }
static llvm::LLVMContext Context;
std::unique_ptr<llvm::lto::InputFile> Obj;
private:
void parse() override;
std::vector<SymbolBody *> SymbolBodies;
llvm::BumpPtrAllocator Alloc;
std::unique_ptr<LTOModule> M;
};
} // namespace coff

140
COFF/LTO.cpp Normal file
View file

@ -0,0 +1,140 @@
//===- LTO.cpp ------------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "LTO.h"
#include "Config.h"
#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
#include "lld/Core/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/Config.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/SymbolicFile.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstddef>
#include <memory>
#include <string>
#include <system_error>
#include <vector>
using namespace llvm;
using namespace llvm::object;
using namespace lld;
using namespace lld::coff;
static void diagnosticHandler(const DiagnosticInfo &DI) {
SmallString<128> ErrStorage;
raw_svector_ostream OS(ErrStorage);
DiagnosticPrinterRawOStream DP(OS);
DI.print(DP);
warn(ErrStorage);
}
static void checkError(Error E) {
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
error(EIB.message());
return Error::success();
});
}
static void saveBuffer(StringRef Buffer, const Twine &Path) {
std::error_code EC;
raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
if (EC)
error("cannot create " + Path + ": " + EC.message());
OS << Buffer;
}
static std::unique_ptr<lto::LTO> createLTO() {
lto::Config Conf;
Conf.Options = InitTargetOptionsFromCodeGenFlags();
Conf.RelocModel = Reloc::PIC_;
Conf.DisableVerify = true;
Conf.DiagHandler = diagnosticHandler;
Conf.OptLevel = Config->LTOOptLevel;
if (Config->SaveTemps)
checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
/*UseInputModulePath*/ true));
lto::ThinBackend Backend;
if (Config->LTOJobs != 0)
Backend = lto::createInProcessThinBackend(Config->LTOJobs);
return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
Config->LTOPartitions);
}
BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
static void undefine(Symbol *S) {
replaceBody<Undefined>(S, S->body()->getName());
}
void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
unsigned SymNum = 0;
std::vector<SymbolBody *> SymBodies = F.getSymbols();
std::vector<lto::SymbolResolution> Resols(SymBodies.size());
// Provide a resolution to the LTO API for each symbol.
for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
SymbolBody *B = SymBodies[SymNum];
Symbol *Sym = B->symbol();
lto::SymbolResolution &R = Resols[SymNum];
++SymNum;
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
// reports two symbols for module ASM defined. Without this check, lld
// flags an undefined in IR with a definition in ASM as prevailing.
// Once IRObjectFile is fixed to report only one symbol this hack can
// be removed.
R.Prevailing = !ObjSym.isUndefined() && B->getFile() == &F;
R.VisibleToRegularObj = Sym->IsUsedInRegularObj;
if (R.Prevailing)
undefine(Sym);
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() {
unsigned MaxTasks = LTOObj->getMaxTasks();
Buff.resize(MaxTasks);
checkError(LTOObj->run([&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
llvm::make_unique<raw_svector_ostream>(Buff[Task]));
}));
std::vector<StringRef> Ret;
for (unsigned I = 0; I != MaxTasks; ++I) {
if (Buff[I].empty())
continue;
if (Config->SaveTemps) {
if (I == 0)
saveBuffer(Buff[I], Config->OutputFile + ".lto.obj");
else
saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj");
}
Ret.emplace_back(Buff[I].data(), Buff[I].size());
}
return Ret;
}

56
COFF/LTO.h Normal file
View file

@ -0,0 +1,56 @@
//===- LTO.h ----------------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides a way to combine bitcode files into one COFF
// file by compiling them using LLVM.
//
// If LTO is in use, your input files are not in regular COFF files
// but instead LLVM bitcode files. In that case, the linker has to
// convert bitcode files into the native format so that we can create
// a COFF file that contains native code. This file provides that
// functionality.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_COFF_LTO_H
#define LLD_COFF_LTO_H
#include "lld/Core/LLVM.h"
#include "llvm/ADT/SmallString.h"
#include <memory>
#include <vector>
namespace llvm {
namespace lto {
class LTO;
}
}
namespace lld {
namespace coff {
class BitcodeFile;
class InputFile;
class BitcodeCompiler {
public:
BitcodeCompiler();
~BitcodeCompiler();
void add(BitcodeFile &F);
std::vector<StringRef> compile();
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
std::vector<SmallString<0>> Buff;
};
}
}
#endif

View file

@ -104,7 +104,18 @@ static ImportNameType getNameType(StringRef Sym, StringRef ExtName) {
static std::string replace(StringRef S, StringRef From, StringRef To) {
size_t Pos = S.find(From);
assert(Pos != StringRef::npos);
// From and To may be mangled, but substrings in S may not.
if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
From = From.substr(1);
To = To.substr(1);
Pos = S.find(From);
}
if (Pos == StringRef::npos) {
error(S + ": replacing '" + From + "' with '" + To + "' failed");
return "";
}
return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
}

114
COFF/MapFile.cpp Normal file
View file

@ -0,0 +1,114 @@
//===- MapFile.cpp --------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the /lldmap option. It shows lists in order and
// hierarchically the output sections, input sections, input files and
// symbol:
//
// Address Size Align Out In File Symbol
// =================================================================
// 00201000 00000015 4 .text
// 00201000 0000000e 4 .text
// 00201000 0000000e 4 test.o
// 0020100e 00000000 0 local
// 00201005 00000000 0 f(int)
//
//===----------------------------------------------------------------------===//
#include "MapFile.h"
#include "Error.h"
#include "Symbols.h"
#include "Writer.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::object;
using namespace lld;
using namespace lld::coff;
static void writeOutSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
uint64_t Align, StringRef Name) {
OS << format("%08llx %08llx %5lld ", Address, Size, Align)
<< left_justify(Name, 7);
}
static void writeInSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
uint64_t Align, StringRef Name) {
// Pass an empty name to align the text to the correct column.
writeOutSecLine(OS, Address, Size, Align, "");
OS << ' ' << left_justify(Name, 7);
}
static void writeFileLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
uint64_t Align, StringRef Name) {
// Pass an empty name to align the text to the correct column.
writeInSecLine(OS, Address, Size, Align, "");
OS << ' ' << left_justify(Name, 7);
}
static void writeSymbolLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
StringRef Name) {
// Pass an empty name to align the text to the correct column.
writeFileLine(OS, Address, Size, 0, "");
OS << ' ' << left_justify(Name, 7);
}
static void writeSectionChunk(raw_fd_ostream &OS, const SectionChunk *SC,
StringRef &PrevName) {
StringRef Name = SC->getSectionName();
if (Name != PrevName) {
writeInSecLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(), Name);
OS << '\n';
PrevName = Name;
}
coff::ObjectFile *File = SC->File;
if (!File)
return;
writeFileLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(),
toString(File));
OS << '\n';
ArrayRef<SymbolBody *> Syms = File->getSymbols();
for (SymbolBody *Sym : Syms) {
auto *DR = dyn_cast<DefinedRegular>(Sym);
if (!DR || DR->getChunk() != SC ||
DR->getCOFFSymbol().isSectionDefinition())
continue;
writeSymbolLine(OS, DR->getRVA(), SC->getSize(), toString(*Sym));
OS << '\n';
}
}
static void writeMapFile2(raw_fd_ostream &OS,
ArrayRef<OutputSection *> OutputSections) {
OS << "Address Size Align Out In File Symbol\n";
for (OutputSection *Sec : OutputSections) {
uint32_t VA = Sec->getRVA();
writeOutSecLine(OS, VA, Sec->getVirtualSize(), /*Align=*/PageSize,
Sec->getName());
OS << '\n';
StringRef PrevName = "";
for (Chunk *C : Sec->getChunks())
if (const auto *SC = dyn_cast<SectionChunk>(C))
writeSectionChunk(OS, SC, PrevName);
}
}
void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
if (Config->MapFile.empty())
return;
std::error_code EC;
raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
if (EC)
fatal("cannot open " + Config->MapFile + ": " + EC.message());
writeMapFile2(OS, OutputSections);
}

22
COFF/MapFile.h Normal file
View file

@ -0,0 +1,22 @@
//===- MapFile.h ------------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_COFF_MAPFILE_H
#define LLD_COFF_MAPFILE_H
#include "llvm/ADT/ArrayRef.h"
namespace lld {
namespace coff {
class OutputSection;
void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
}
}
#endif

View file

@ -163,17 +163,25 @@ private:
case KwHeapsize:
parseNumbers(&Config->HeapReserve, &Config->HeapCommit);
return;
case KwLibrary:
parseName(&Config->OutputFile, &Config->ImageBase);
if (!StringRef(Config->OutputFile).endswith_lower(".dll"))
Config->OutputFile += ".dll";
return;
case KwStacksize:
parseNumbers(&Config->StackReserve, &Config->StackCommit);
return;
case KwName:
parseName(&Config->OutputFile, &Config->ImageBase);
case KwLibrary:
case KwName: {
bool IsDll = Tok.K == KwLibrary; // Check before parseName.
std::string Name;
parseName(&Name, &Config->ImageBase);
// Append the appropriate file extension if not already present.
StringRef Ext = IsDll ? ".dll" : ".exe";
if (!StringRef(Name).endswith_lower(Ext))
Name += Ext;
// Set the output file, but don't override /out if it was already passed.
if (Config->OutputFile.empty())
Config->OutputFile = Name;
return;
}
case KwVersion:
parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
return;

View file

@ -21,6 +21,8 @@ def base : P<"base", "Base address of the program">;
def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
def delayload : P<"delayload", "Delay loaded DLL name">;
def entry : P<"entry", "Name of entry point symbol">;
def errorlimit : P<"errorlimit",
"Maximum number of errors to emit before stopping (0 = no limit)">;
def export : P<"export", "Export a function">;
// No help text because /failifmismatch is not intended to be used by the user.
def failifmismatch : P<"failifmismatch", "">;
@ -28,6 +30,8 @@ def heap : P<"heap", "Size of the heap">;
def implib : P<"implib", "Import library name">;
def libpath : P<"libpath", "Additional library search path">;
def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
def lldsavetemps : F<"lldsavetemps">,
HelpText<"Save temporary files instead of deleting them">;
def machine : P<"machine", "Specify target platform">;
def merge : P<"merge", "Combine sections">;
def mllvm : P<"mllvm", "Options to pass to LLVM">;
@ -78,6 +82,8 @@ def force_unresolved : F<"force:unresolved">;
defm allowbind: B<"allowbind", "Disable DLL binding">;
defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
defm appcontainer : B<"appcontainer",
"Image can only be run in an app container">;
defm dynamicbase : B<"dynamicbase",
"Disable address space layout randomization">;
defm fixed : B<"fixed", "Enable base relocations">;
@ -91,7 +97,9 @@ def help : F<"help">;
def help_q : Flag<["/?", "-?"], "">, Alias<help>;
// LLD extensions
def nopdb : F<"nopdb">, HelpText<"Disable PDB generation for DWARF users">;
def nosymtab : F<"nosymtab">;
def msvclto : F<"msvclto">;
// Flags for debugging
def debugpdb : F<"debugpdb">;

View file

@ -20,20 +20,23 @@
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>
@ -79,32 +82,49 @@ static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
return Data.slice(4);
}
// Merge .debug$T sections and returns it.
static std::vector<uint8_t> mergeDebugT(SymbolTable *Symtab) {
ScopedPrinter W(outs());
static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
codeview::TypeTableBuilder &TypeTable) {
// Start the TPI or IPI stream header.
TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
// Flatten the in memory type table.
TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
// FIXME: Hash types.
TpiBuilder.addTypeRecord(Rec, None);
});
}
// Merge .debug$T sections into IpiData and TpiData.
static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,
codeview::TypeTableBuilder &TypeTable,
codeview::TypeTableBuilder &IDTable) {
// Visit all .debug$T sections to add them to Builder.
codeview::TypeTableBuilder Builder(BAlloc);
for (ObjectFile *File : Symtab->ObjectFiles) {
ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
if (Data.empty())
continue;
msf::ByteStream Stream(Data);
BinaryByteStream Stream(Data, support::little);
codeview::CVTypeArray Types;
msf::StreamReader Reader(Stream);
BinaryStreamReader Reader(Stream);
// Follow type servers. If the same type server is encountered more than
// once for this instance of `PDBTypeServerHandler` (for example if many
// object files reference the same TypeServer), the types from the
// TypeServer will only be visited once.
pdb::PDBTypeServerHandler Handler;
Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
if (auto EC = Reader.readArray(Types, Reader.getLength()))
fatal(EC, "Reader::readArray failed");
if (!codeview::mergeTypeStreams(Builder, Types))
fatal("codeview::mergeTypeStreams failed");
if (auto Err =
codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types))
fatal(Err, "codeview::mergeTypeStreams failed");
}
// Construct section contents.
std::vector<uint8_t> V;
Builder.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
V.insert(V.end(), Rec.begin(), Rec.end());
});
return V;
// Construct TPI stream contents.
addTypeInfo(Builder.getTpiBuilder(), TypeTable);
// Construct IPI stream contents.
addTypeInfo(Builder.getIpiBuilder(), IDTable);
}
static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
@ -115,6 +135,8 @@ static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
TypeDatabase TDB;
TypeDumpVisitor TDV(TDB, &W, false);
// Use a default implementation that does not follow type servers and instead
// just dumps the contents of the TypeServer2 record.
CVTypeDumper TypeDumper(TDB);
if (auto EC = TypeDumper.dump(Data, TDV))
fatal(EC, "CVTypeDumper::dump failed");
@ -126,9 +148,9 @@ static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
if (Data.empty())
return;
msf::ByteStream Stream(Data);
BinaryByteStream Stream(Data, llvm::support::little);
CVSymbolArray Symbols;
msf::StreamReader Reader(Stream);
BinaryStreamReader Reader(Stream);
if (auto EC = Reader.readArray(Symbols, Reader.getLength()))
fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");
@ -148,17 +170,6 @@ static void dumpCodeView(SymbolTable *Symtab) {
}
}
static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
ArrayRef<uint8_t> Data) {
msf::ByteStream Stream(Data);
codeview::CVTypeArray Records;
msf::StreamReader Reader(Stream);
if (auto EC = Reader.readArray(Records, Reader.getLength()))
fatal(EC, "Reader.readArray failed");
for (const codeview::CVType &Rec : Records)
TpiBuilder.addTypeRecord(Rec);
}
// Creates a PDB file.
void coff::createPDB(StringRef Path, SymbolTable *Symtab,
ArrayRef<uint8_t> SectionTable,
@ -177,9 +188,12 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
// Add an Info stream.
auto &InfoBuilder = Builder.getInfoBuilder();
InfoBuilder.setAge(DI->PDB70.Age);
InfoBuilder.setGuid(
*reinterpret_cast<const pdb::PDB_UniqueId *>(&DI->PDB70.Signature));
InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);
pdb::PDB_UniqueId uuid{};
if (DI)
memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
InfoBuilder.setGuid(uuid);
// Should be the current time, but set 0 for reproducibilty.
InfoBuilder.setSignature(0);
InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
@ -188,18 +202,9 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
auto &DbiBuilder = Builder.getDbiBuilder();
DbiBuilder.setVersionHeader(pdb::PdbDbiV110);
// Add an empty TPI stream.
auto &TpiBuilder = Builder.getTpiBuilder();
TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
std::vector<uint8_t> TpiData;
if (Config->DebugPdb) {
TpiData = mergeDebugT(Symtab);
addTypeInfo(TpiBuilder, TpiData);
}
// Add an empty IPI stream.
auto &IpiBuilder = Builder.getIpiBuilder();
IpiBuilder.setVersionHeader(pdb::PdbTpiV80);
codeview::TypeTableBuilder TypeTable(BAlloc);
codeview::TypeTableBuilder IDTable(BAlloc);
mergeDebugT(Symtab, Builder, TypeTable, IDTable);
// Add Section Contributions.
std::vector<pdb::SectionContrib> Contribs =
@ -214,7 +219,7 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
pdb::DbiStreamBuilder::createSectionMap(Sections);
DbiBuilder.setSectionMap(SectionMap);
ExitOnErr(DbiBuilder.addModuleInfo("", "* Linker *"));
ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
// Add COFF section header stream.
ExitOnErr(

View file

@ -11,10 +11,10 @@
#include "Config.h"
#include "Driver.h"
#include "Error.h"
#include "LTO.h"
#include "Memory.h"
#include "Symbols.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/LTO/legacy/LTOCodeGenerator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <utility>
@ -24,11 +24,40 @@ using namespace llvm;
namespace lld {
namespace coff {
enum SymbolPreference {
SP_EXISTING = -1,
SP_CONFLICT = 0,
SP_NEW = 1,
};
/// Checks if an existing symbol S should be kept or replaced by a new symbol.
/// Returns SP_EXISTING when S should be kept, SP_NEW when the new symbol
/// should be kept, and SP_CONFLICT if no valid resolution exists.
static SymbolPreference compareDefined(Symbol *S, bool WasInserted,
bool NewIsCOMDAT) {
// If the symbol wasn't previously known, the new symbol wins by default.
if (WasInserted || !isa<Defined>(S->body()))
return SP_NEW;
// If the existing symbol is a DefinedRegular, both it and the new symbol
// must be comdats. In that case, we have no reason to prefer one symbol
// over the other, and we keep the existing one. If one of the symbols
// is not a comdat, we report a conflict.
if (auto *R = dyn_cast<DefinedRegular>(S->body())) {
if (NewIsCOMDAT && R->isCOMDAT())
return SP_EXISTING;
else
return SP_CONFLICT;
}
// Existing symbol is not a DefinedRegular; new symbol wins.
return SP_NEW;
}
SymbolTable *Symtab;
void SymbolTable::addFile(InputFile *File) {
if (Config->Verbose)
outs() << "Reading " << toString(File) << "\n";
log("Reading " + toString(File));
File->parse();
MachineTypes MT = File->getMachineType();
@ -51,8 +80,7 @@ void SymbolTable::addFile(InputFile *File) {
if (S.empty())
return;
if (Config->Verbose)
outs() << "Directives: " << toString(File) << ": " << S << "\n";
log("Directives: " + toString(File) + ": " + S);
Driver->parseDirectives(S);
}
@ -106,12 +134,11 @@ void SymbolTable::reportRemainingUndefines() {
return;
for (SymbolBody *B : Config->GCRoot)
if (Undefs.count(B))
errs() << "<root>: undefined symbol: " << B->getName() << "\n";
warn("<root>: undefined symbol: " + B->getName());
for (ObjectFile *File : ObjectFiles)
for (SymbolBody *Sym : File->getSymbols())
if (Undefs.count(Sym))
errs() << toString(File) << ": undefined symbol: " << Sym->getName()
<< "\n";
warn(toString(File) + ": undefined symbol: " + Sym->getName());
if (!Config->Force)
fatal("link failed");
}
@ -163,7 +190,7 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
}
void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
fatal("duplicate symbol: " + toString(*Existing->body()) + " in " +
error("duplicate symbol: " + toString(*Existing->body()) + " in " +
toString(Existing->body()->getFile()) + " and in " +
(NewFile ? toString(NewFile) : "(internal)"));
}
@ -204,59 +231,35 @@ Symbol *SymbolTable::addRelative(StringRef N, uint64_t VA) {
return S;
}
Symbol *SymbolTable::addRegular(ObjectFile *F, COFFSymbolRef Sym,
Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
const coff_symbol_generic *Sym,
SectionChunk *C) {
StringRef Name;
F->getCOFFObj()->getSymbolName(Sym, Name);
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
replaceBody<DefinedRegular>(S, F, Sym, C);
else if (auto *R = dyn_cast<DefinedRegular>(S->body())) {
if (!C->isCOMDAT() || !R->isCOMDAT())
reportDuplicate(S, F);
} else if (auto *B = dyn_cast<DefinedBitcode>(S->body())) {
if (B->IsReplaceable)
replaceBody<DefinedRegular>(S, F, Sym, C);
else if (!C->isCOMDAT())
reportDuplicate(S, F);
} else
replaceBody<DefinedRegular>(S, F, Sym, C);
return S;
}
Symbol *SymbolTable::addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N);
if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) {
replaceBody<DefinedBitcode>(S, F, N, IsReplaceable);
return S;
if (!isa<BitcodeFile>(F))
S->IsUsedInRegularObj = true;
SymbolPreference SP = compareDefined(S, WasInserted, IsCOMDAT);
if (SP == SP_CONFLICT) {
reportDuplicate(S, F);
} else if (SP == SP_NEW) {
replaceBody<DefinedRegular>(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C);
}
if (isa<DefinedCommon>(S->body()))
return S;
if (IsReplaceable)
if (isa<DefinedRegular>(S->body()) || isa<DefinedBitcode>(S->body()))
return S;
reportDuplicate(S, F);
return S;
}
Symbol *SymbolTable::addCommon(ObjectFile *F, COFFSymbolRef Sym,
CommonChunk *C) {
StringRef Name;
F->getCOFFObj()->getSymbolName(Sym, Name);
Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
const coff_symbol_generic *Sym, CommonChunk *C) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
S->IsUsedInRegularObj = true;
std::tie(S, WasInserted) = insert(N);
if (!isa<BitcodeFile>(F))
S->IsUsedInRegularObj = true;
if (WasInserted || !isa<DefinedCOFF>(S->body()))
replaceBody<DefinedCommon>(S, F, Sym, C);
replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
else if (auto *DC = dyn_cast<DefinedCommon>(S->body()))
if (Sym.getValue() > DC->getSize())
replaceBody<DefinedCommon>(S, F, Sym, C);
if (Size > DC->getSize())
replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
return S;
}
@ -345,75 +348,21 @@ SymbolBody *SymbolTable::addUndefined(StringRef Name) {
return addUndefined(Name, nullptr, false)->body();
}
void SymbolTable::printMap(llvm::raw_ostream &OS) {
for (ObjectFile *File : ObjectFiles) {
OS << toString(File) << ":\n";
for (SymbolBody *Body : File->getSymbols())
if (auto *R = dyn_cast<DefinedRegular>(Body))
if (R->getChunk()->isLive())
OS << Twine::utohexstr(Config->ImageBase + R->getRVA())
<< " " << R->getName() << "\n";
}
std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
LTO.reset(new BitcodeCompiler);
for (BitcodeFile *F : BitcodeFiles)
LTO->add(*F);
return LTO->compile();
}
void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFiles.empty())
return;
// Create an object file and add it to the symbol table by replacing any
// DefinedBitcode symbols with the definitions in the object file.
LTOCodeGenerator CG(BitcodeFile::Context);
CG.setOptLevel(Config->LTOOptLevel);
for (ObjectFile *Obj : createLTOObjects(&CG))
for (StringRef Object : compileBitcodeFiles()) {
auto *Obj = make<ObjectFile>(MemoryBufferRef(Object, "lto.tmp"));
Obj->parse();
}
// Combine and compile bitcode files and then return the result
// as a vector of regular COFF object files.
std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) {
// All symbols referenced by non-bitcode objects, including GC roots, must be
// preserved. We must also replace bitcode symbols with undefined symbols so
// that they may be replaced with real definitions without conflicting.
for (BitcodeFile *File : BitcodeFiles)
for (SymbolBody *Body : File->getSymbols()) {
if (!isa<DefinedBitcode>(Body))
continue;
if (Body->symbol()->IsUsedInRegularObj)
CG->addMustPreserveSymbol(Body->getName());
replaceBody<Undefined>(Body->symbol(), Body->getName());
}
CG->setModule(BitcodeFiles[0]->takeModule());
for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I)
CG->addModule(BitcodeFiles[I]->takeModule().get());
bool DisableVerify = true;
#ifdef NDEBUG
DisableVerify = false;
#endif
if (!CG->optimize(DisableVerify, false, false, false))
fatal(""); // optimize() should have emitted any error message.
Objs.resize(Config->LTOJobs);
// Use std::list to avoid invalidation of pointers in OSPtrs.
std::list<raw_svector_ostream> OSs;
std::vector<raw_pwrite_stream *> OSPtrs;
for (SmallString<0> &Obj : Objs) {
OSs.emplace_back(Obj);
OSPtrs.push_back(&OSs.back());
ObjectFiles.push_back(Obj);
}
if (!CG->compileOptimized(OSPtrs))
fatal(""); // compileOptimized() should have emitted any error message.
std::vector<ObjectFile *> ObjFiles;
for (SmallString<0> &Obj : Objs) {
auto *ObjFile = make<ObjectFile>(MemoryBufferRef(Obj, "<LTO object>"));
ObjectFiles.push_back(ObjFile);
ObjFiles.push_back(ObjFile);
}
return ObjFiles;
}
} // namespace coff

View file

@ -11,6 +11,7 @@
#define LLD_COFF_SYMBOL_TABLE_H
#include "InputFiles.h"
#include "LTO.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
@ -69,13 +70,11 @@ public:
void mangleMaybe(SymbolBody *B);
StringRef findMangle(StringRef Name);
// Print a layout map to OS.
void printMap(llvm::raw_ostream &OS);
// Build a set of COFF objects representing the combined contents of
// BitcodeFiles and add them to the symbol table. Called after all files are
// added and before the writer writes results to a file.
void addCombinedLTOObjects();
std::vector<StringRef> compileBitcodeFiles();
// The writer needs to handle DLL import libraries specially in
// order to create the import descriptor table.
@ -93,9 +92,12 @@ public:
Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias);
void addLazy(ArchiveFile *F, const Archive::Symbol Sym);
Symbol *addAbsolute(StringRef N, COFFSymbolRef S);
Symbol *addRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C);
Symbol *addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable);
Symbol *addCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C);
Symbol *addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
const llvm::object::coff_symbol_generic *S = nullptr,
SectionChunk *C = nullptr);
Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size,
const llvm::object::coff_symbol_generic *S = nullptr,
CommonChunk *C = nullptr);
Symbol *addImportData(StringRef N, ImportFile *F);
Symbol *addImportThunk(StringRef Name, DefinedImportData *S,
uint16_t Machine);
@ -113,12 +115,11 @@ private:
StringRef findByPrefix(StringRef Prefix);
void addCombinedLTOObject(ObjectFile *Obj);
std::vector<ObjectFile *> createLTOObjects(llvm::LTOCodeGenerator *CG);
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> Symtab;
std::vector<BitcodeFile *> BitcodeFiles;
std::vector<SmallString<0>> Objs;
std::unique_ptr<BitcodeCompiler> LTO;
};
extern SymbolTable *Symtab;

View file

@ -30,7 +30,7 @@ namespace lld {
namespace coff {
StringRef SymbolBody::getName() {
// DefinedCOFF names are read lazily for a performance reason.
// COFF symbol names are read lazily for a performance reason.
// Non-external symbol names are never used by the linker except for logging
// or debugging. Their internal references are resolved not by name but by
// symbol index. And because they are not external, no one can refer them by
@ -39,7 +39,7 @@ StringRef SymbolBody::getName() {
// is a waste of time.
if (Name.empty()) {
auto *D = cast<DefinedCOFF>(this);
D->File->getCOFFObj()->getSymbolName(D->Sym, Name);
cast<ObjectFile>(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name);
}
return Name;
}
@ -47,15 +47,14 @@ StringRef SymbolBody::getName() {
InputFile *SymbolBody::getFile() {
if (auto *Sym = dyn_cast<DefinedCOFF>(this))
return Sym->File;
if (auto *Sym = dyn_cast<DefinedBitcode>(this))
return Sym->File;
if (auto *Sym = dyn_cast<Lazy>(this))
return Sym->File;
return nullptr;
}
COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
size_t SymSize = File->getCOFFObj()->getSymbolTableEntrySize();
size_t SymSize =
cast<ObjectFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
if (SymSize == sizeof(coff_symbol16))
return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym));
assert(SymSize == sizeof(coff_symbol32));

View file

@ -30,7 +30,6 @@ using llvm::object::coff_import_header;
using llvm::object::coff_symbol_generic;
class ArchiveFile;
class BitcodeFile;
class InputFile;
class ObjectFile;
struct Symbol;
@ -52,13 +51,12 @@ public:
DefinedImportDataKind,
DefinedAbsoluteKind,
DefinedRelativeKind,
DefinedBitcodeKind,
UndefinedKind,
LazyKind,
LastDefinedCOFFKind = DefinedCommonKind,
LastDefinedKind = DefinedBitcodeKind,
LastDefinedKind = DefinedRelativeKind,
};
Kind kind() const { return static_cast<Kind>(SymbolKind); }
@ -81,7 +79,7 @@ protected:
friend SymbolTable;
explicit SymbolBody(Kind K, StringRef N = "")
: SymbolKind(K), IsExternal(true), IsCOMDAT(false),
IsReplaceable(false), WrittenToSymtab(false), Name(N) {}
WrittenToSymtab(false), Name(N) {}
const unsigned SymbolKind : 8;
unsigned IsExternal : 1;
@ -89,11 +87,9 @@ protected:
// This bit is used by the \c DefinedRegular subclass.
unsigned IsCOMDAT : 1;
// This bit is used by the \c DefinedBitcode subclass.
unsigned IsReplaceable : 1;
public:
// This bit is used by Writer::createSymbolAndStringTable().
// This bit is used by Writer::createSymbolAndStringTable() to prevent
// symbols from being written to the symbol table more than once.
unsigned WrittenToSymtab : 1;
protected:
@ -104,7 +100,7 @@ protected:
// etc.
class Defined : public SymbolBody {
public:
Defined(Kind K, StringRef N = "") : SymbolBody(K, N) {}
Defined(Kind K, StringRef N) : SymbolBody(K, N) {}
static bool classof(const SymbolBody *S) {
return S->kind() <= LastDefinedKind;
@ -127,22 +123,25 @@ public:
bool isExecutable();
};
// Symbols defined via a COFF object file.
// Symbols defined via a COFF object file or bitcode file. For COFF files, this
// stores a coff_symbol_generic*, and names of internal symbols are lazily
// loaded through that. For bitcode files, Sym is nullptr and the name is stored
// as a StringRef.
class DefinedCOFF : public Defined {
friend SymbolBody;
public:
DefinedCOFF(Kind K, ObjectFile *F, COFFSymbolRef S)
: Defined(K), File(F), Sym(S.getGeneric()) {}
DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S)
: Defined(K, N), File(F), Sym(S) {}
static bool classof(const SymbolBody *S) {
return S->kind() <= LastDefinedCOFFKind;
}
ObjectFile *getFile() { return File; }
InputFile *getFile() { return File; }
COFFSymbolRef getCOFFSymbol();
ObjectFile *File;
InputFile *File;
protected:
const coff_symbol_generic *Sym;
@ -151,10 +150,13 @@ protected:
// Regular defined symbols read from object file symbol tables.
class DefinedRegular : public DefinedCOFF {
public:
DefinedRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C)
: DefinedCOFF(DefinedRegularKind, F, S), Data(&C->Repl) {
IsExternal = S.isExternal();
IsCOMDAT = C->isCOMDAT();
DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT,
bool IsExternal = false,
const coff_symbol_generic *S = nullptr,
SectionChunk *C = nullptr)
: DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) {
this->IsExternal = IsExternal;
this->IsCOMDAT = IsCOMDAT;
}
static bool classof(const SymbolBody *S) {
@ -172,9 +174,11 @@ private:
class DefinedCommon : public DefinedCOFF {
public:
DefinedCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C)
: DefinedCOFF(DefinedCommonKind, F, S), Data(C) {
IsExternal = S.isExternal();
DefinedCommon(InputFile *F, StringRef N, uint64_t Size,
const coff_symbol_generic *S = nullptr,
CommonChunk *C = nullptr)
: DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) {
this->IsExternal = true;
}
static bool classof(const SymbolBody *S) {
@ -185,8 +189,9 @@ public:
private:
friend SymbolTable;
uint64_t getSize() { return Sym->Value; }
uint64_t getSize() const { return Size; }
CommonChunk *Data;
uint64_t Size;
};
// Absolute symbols.
@ -340,26 +345,6 @@ private:
LocalImportChunk *Data;
};
class DefinedBitcode : public Defined {
friend SymbolBody;
public:
DefinedBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable)
: Defined(DefinedBitcodeKind, N), File(F) {
// IsReplaceable tracks whether the bitcode symbol may be replaced with some
// other (defined, common or bitcode) symbol. This is the case for common,
// comdat and weak external symbols. We try to replace bitcode symbols with
// "real" symbols (see SymbolTable::add{Regular,Bitcode}), and resolve the
// result against the real symbol from the combined LTO object.
this->IsReplaceable = IsReplaceable;
}
static bool classof(const SymbolBody *S) {
return S->kind() == DefinedBitcodeKind;
}
BitcodeFile *File;
};
inline uint64_t Defined::getRVA() {
switch (kind()) {
case DefinedAbsoluteKind:
@ -376,8 +361,6 @@ inline uint64_t Defined::getRVA() {
return cast<DefinedCommon>(this)->getRVA();
case DefinedRegularKind:
return cast<DefinedRegular>(this)->getRVA();
case DefinedBitcodeKind:
llvm_unreachable("There is no address for a bitcode symbol.");
case LazyKind:
case UndefinedKind:
llvm_unreachable("Cannot get the address for an undefined symbol.");
@ -401,10 +384,9 @@ struct Symbol {
// This field is used to store the Symbol's SymbolBody. This instantiation of
// AlignedCharArrayUnion gives us a struct with a char array field that is
// large and aligned enough to store any derived class of SymbolBody.
llvm::AlignedCharArrayUnion<DefinedRegular, DefinedCommon, DefinedAbsolute,
DefinedRelative, Lazy, Undefined,
DefinedImportData, DefinedImportThunk,
DefinedLocalImport, DefinedBitcode>
llvm::AlignedCharArrayUnion<
DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedRelative, Lazy,
Undefined, DefinedImportData, DefinedImportThunk, DefinedLocalImport>
Body;
SymbolBody *body() {

View file

@ -12,6 +12,7 @@
#include "DLL.h"
#include "Error.h"
#include "InputFiles.h"
#include "MapFile.h"
#include "Memory.h"
#include "PDB.h"
#include "SymbolTable.h"
@ -39,7 +40,6 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::coff;
static const int PageSize = 4096;
static const int SectorSize = 512;
static const int DOSStubSize = 64;
static const int NumberfOfDataDirectory = 16;
@ -163,51 +163,6 @@ namespace coff {
void writeResult(SymbolTable *T) { Writer(T).run(); }
// OutputSection represents a section in an output file. It's a
// container of chunks. OutputSection and Chunk are 1:N relationship.
// Chunks cannot belong to more than one OutputSections. The writer
// creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and RVAs.
class OutputSection {
public:
OutputSection(StringRef N) : Name(N), Header({}) {}
void setRVA(uint64_t);
void setFileOffset(uint64_t);
void addChunk(Chunk *C);
StringRef getName() { return Name; }
std::vector<Chunk *> &getChunks() { return Chunks; }
void addPermissions(uint32_t C);
void setPermissions(uint32_t C);
uint32_t getPermissions() { return Header.Characteristics & PermMask; }
uint32_t getCharacteristics() { return Header.Characteristics; }
uint64_t getRVA() { return Header.VirtualAddress; }
uint64_t getFileOff() { return Header.PointerToRawData; }
void writeHeaderTo(uint8_t *Buf);
// Returns the size of this section in an executable memory image.
// This may be smaller than the raw size (the raw size is multiple
// of disk sector size, so there may be padding at end), or may be
// larger (if that's the case, the loader reserves spaces after end
// of raw data).
uint64_t getVirtualSize() { return Header.VirtualSize; }
// Returns the size of the section in the output file.
uint64_t getRawSize() { return Header.SizeOfRawData; }
// Set offset into the string table storing this section name.
// Used only when the name is longer than 8 bytes.
void setStringTableOff(uint32_t V) { StringTableOff = V; }
// N.B. The section index is one based.
uint32_t SectionIndex = 0;
private:
StringRef Name;
coff_section Header;
uint32_t StringTableOff = 0;
std::vector<Chunk *> Chunks;
};
void OutputSection::setRVA(uint64_t RVA) {
Header.VirtualAddress = RVA;
for (Chunk *C : Chunks)
@ -303,8 +258,14 @@ void Writer::run() {
sortExceptionTable();
writeBuildId();
if (!Config->PDBPath.empty())
createPDB(Config->PDBPath, Symtab, SectionTable, BuildId->DI);
if (!Config->PDBPath.empty()) {
const llvm::codeview::DebugInfo *DI = nullptr;
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV))
DI = BuildId->DI;
createPDB(Config->PDBPath, Symtab, SectionTable, DI);
}
writeMapFile(OutputSections);
if (auto EC = Buffer->commit())
fatal(EC, "failed to write the output file");
@ -641,6 +602,8 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
PE->SizeOfStackCommit = Config->StackCommit;
PE->SizeOfHeapReserve = Config->HeapReserve;
PE->SizeOfHeapCommit = Config->HeapCommit;
if (Config->AppContainer)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
if (Config->DynamicBase)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
if (Config->HighEntropyVA)
@ -830,7 +793,7 @@ void Writer::writeBuildId() {
"only PDB 7.0 is supported");
assert(sizeof(Res) == sizeof(BuildId->DI->PDB70.Signature) &&
"signature size mismatch");
memcpy(BuildId->DI->PDB70.Signature, Res,
memcpy(BuildId->DI->PDB70.Signature, Res.Bytes.data(),
sizeof(codeview::PDB70DebugInfo::Signature));
// TODO(compnerd) track the Age
BuildId->DI->PDB70.Age = 1;

View file

@ -10,14 +10,65 @@
#ifndef LLD_COFF_WRITER_H
#define LLD_COFF_WRITER_H
#include "Chunks.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/COFF.h"
#include <cstdint>
#include <vector>
namespace lld {
namespace coff {
class SymbolTable;
static const int PageSize = 4096;
void writeResult(SymbolTable *T);
// OutputSection represents a section in an output file. It's a
// container of chunks. OutputSection and Chunk are 1:N relationship.
// Chunks cannot belong to more than one OutputSections. The writer
// creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and RVAs.
class OutputSection {
public:
OutputSection(llvm::StringRef N) : Name(N), Header({}) {}
void setRVA(uint64_t);
void setFileOffset(uint64_t);
void addChunk(Chunk *C);
llvm::StringRef getName() { return Name; }
std::vector<Chunk *> &getChunks() { return Chunks; }
void addPermissions(uint32_t C);
void setPermissions(uint32_t C);
uint32_t getPermissions() { return Header.Characteristics & PermMask; }
uint32_t getCharacteristics() { return Header.Characteristics; }
uint64_t getRVA() { return Header.VirtualAddress; }
uint64_t getFileOff() { return Header.PointerToRawData; }
void writeHeaderTo(uint8_t *Buf);
// Returns the size of this section in an executable memory image.
// This may be smaller than the raw size (the raw size is multiple
// of disk sector size, so there may be padding at end), or may be
// larger (if that's the case, the loader reserves spaces after end
// of raw data).
uint64_t getVirtualSize() { return Header.VirtualSize; }
// Returns the size of the section in the output file.
uint64_t getRawSize() { return Header.SizeOfRawData; }
// Set offset into the string table storing this section name.
// Used only when the name is longer than 8 bytes.
void setStringTableOff(uint32_t V) { StringTableOff = V; }
// N.B. The section index is one based.
uint32_t SectionIndex = 0;
private:
llvm::StringRef Name;
llvm::object::coff_section Header;
uint32_t StringTableOff = 0;
std::vector<Chunk *> Chunks;
};
}
}

View file

@ -11,16 +11,19 @@ add_lld_library(lldELF
DriverUtils.cpp
EhFrame.cpp
Error.cpp
Filesystem.cpp
GdbIndex.cpp
ICF.cpp
InputFiles.cpp
InputSection.cpp
LTO.cpp
LinkerScript.cpp
MapFile.cpp
MarkLive.cpp
Mips.cpp
OutputSections.cpp
Relocations.cpp
ScriptLexer.cpp
ScriptParser.cpp
Strings.cpp
SymbolTable.cpp
@ -53,7 +56,7 @@ add_lld_library(lldELF
LINK_LIBS
lldConfig
lldCore
${PTHREAD_LIB}
${LLVM_PTHREAD_LIB}
DEPENDS
ELFOptionsTableGen

View file

@ -13,7 +13,10 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/CachePruning.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include <vector>
@ -34,14 +37,14 @@ enum ELFKind {
// For --build-id.
enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
// For --discard-{all,locals,none} and --retain-symbols-file.
enum class DiscardPolicy { Default, All, Locals, RetainFile, None };
// For --discard-{all,locals,none}.
enum class DiscardPolicy { Default, All, Locals, None };
// For --strip-{all,debug}.
enum class StripPolicy { None, All, Debug };
// For --unresolved-symbols.
enum class UnresolvedPolicy { NoUndef, ReportError, Warn, Ignore };
enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll };
// For --sort-section and linkerscript sorting rules.
enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
@ -58,11 +61,10 @@ struct SymbolVersion {
// This struct contains symbols version definition that
// can be found in version script if it is used for link.
struct VersionDefinition {
VersionDefinition(llvm::StringRef Name, uint16_t Id) : Name(Name), Id(Id) {}
llvm::StringRef Name;
uint16_t Id;
uint16_t Id = 0;
std::vector<SymbolVersion> Globals;
size_t NameOff; // Offset in string table.
size_t NameOff = 0; // Offset in the string table
};
// This struct contains the global configuration for the linker.
@ -72,6 +74,7 @@ struct VersionDefinition {
struct Configuration {
InputFile *FirstElf = nullptr;
uint8_t OSABI = 0;
llvm::CachePruningPolicy ThinLTOCachePolicy;
llvm::StringMap<uint64_t> SectionStartMap;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
@ -80,10 +83,12 @@ struct Configuration {
llvm::StringRef Init;
llvm::StringRef LTOAAPipeline;
llvm::StringRef LTONewPmPasses;
llvm::StringRef MapFile;
llvm::StringRef OutputFile;
llvm::StringRef OptRemarksFilename;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
llvm::StringSet<> RetainSymbolsFile;
llvm::StringRef ThinLTOCacheDir;
std::string RPath;
std::vector<VersionDefinition> VersionDefinitions;
std::vector<llvm::StringRef> AuxiliaryList;
@ -94,6 +99,7 @@ struct Configuration {
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
bool AllowMultipleDefinition;
bool ArchiveWithoutSymbolsSeen = false;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
@ -102,30 +108,29 @@ struct Configuration {
bool Demangle = true;
bool DisableVerify;
bool EhFrameHdr;
bool EmitRelocs;
bool EnableNewDtags;
bool ExportDynamic;
bool FatalWarnings;
bool GcSections;
bool GdbIndex;
bool GnuHash = false;
bool GnuHash;
bool ICF;
bool Mips64EL = false;
bool MipsN32Abi = false;
bool NoGnuUnique;
bool NoUndefinedVersion;
bool Nostdlib;
bool OFormatBinary;
bool OMagic;
bool Pic;
bool Omagic;
bool OptRemarksWithHotness;
bool Pie;
bool PrintGcSections;
bool Rela;
bool Relocatable;
bool SaveTemps;
bool SingleRoRx;
bool Shared;
bool Static = false;
bool SysvHash = true;
bool SysvHash;
bool Target1Rel;
bool Threads;
bool Trace;
@ -134,17 +139,20 @@ struct Configuration {
bool WarnMissingEntry;
bool ZCombreloc;
bool ZExecstack;
bool ZNocopyreloc;
bool ZNodelete;
bool ZNodlopen;
bool ZNow;
bool ZOrigin;
bool ZRelro;
bool ZText;
bool ExitEarly;
bool ZWxneeded;
DiscardPolicy Discard;
SortSectionPolicy SortSection;
StripPolicy Strip = StripPolicy::None;
StripPolicy Strip;
UnresolvedPolicy UnresolvedSymbols;
Target2Policy Target2 = Target2Policy::GotRel;
Target2Policy Target2;
BuildIdKind BuildId = BuildIdKind::None;
ELFKind EKind = ELFNoneKind;
uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
@ -157,6 +165,58 @@ struct Configuration {
unsigned LTOO;
unsigned Optimize;
unsigned ThinLTOJobs;
// The following config options do not directly correspond to any
// particualr command line options.
// True if we need to pass through relocations in input files to the
// output file. Usually false because we consume relocations.
bool CopyRelocs;
// True if the target is ELF64. False if ELF32.
bool Is64;
// True if the target is little-endian. False if big-endian.
bool IsLE;
// endianness::little if IsLE is true. endianness::big otherwise.
llvm::support::endianness Endianness;
// True if the target is the little-endian MIPS64.
//
// The reason why we have this variable only for the MIPS is because
// we use this often. Some ELF headers for MIPS64EL are in a
// mixed-endian (which is horrible and I'd say that's a serious spec
// bug), and we need to know whether we are reading MIPS ELF files or
// not in various places.
//
// (Note that MIPS64EL is not a typo for MIPS64LE. This is the official
// name whatever that means. A fun hypothesis is that "EL" is short for
// little-endian written in the little-endian order, but I don't know
// if that's true.)
bool IsMips64EL;
// The ELF spec defines two types of relocation table entries, RELA and
// REL. RELA is a triplet of (offset, info, addend) while REL is a
// tuple of (offset, info). Addends for REL are implicit and read from
// the location where the relocations are applied. So, REL is more
// compact than RELA but requires a bit of more work to process.
//
// (From the linker writer's view, this distinction is not necessary.
// If the ELF had chosen whichever and sticked with it, it would have
// been easier to write code to process relocations, but it's too late
// to change the spec.)
//
// Each ABI defines its relocation type. IsRela is true if target
// uses RELA. As far as we know, all 64-bit ABIs are using RELA. A
// few 32-bit ABIs are using RELA too.
bool IsRela;
// True if we are creating position-independent code.
bool Pic;
// 4 for ELF32, 8 for ELF64.
int Wordsize;
};
// The only instance of Configuration struct.

View file

@ -6,15 +6,34 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The driver drives the entire linking process. It is responsible for
// parsing command line options and doing whatever it is instructed to do.
//
// One notable thing in the LLD's driver when compared to other linkers is
// that the LLD's driver is agnostic on the host operating system.
// Other linkers usually have implicit default values (such as a dynamic
// linker path or library paths) for each host OS.
//
// I don't think implicit default values are useful because they are
// usually explicitly specified by the compiler driver. They can even
// be harmful when you are doing cross-linking. Therefore, in LLD, we
// simply trust the compiler driver to pass all required options and
// don't try to make effort on our side.
//
//===----------------------------------------------------------------------===//
#include "Driver.h"
#include "Config.h"
#include "Error.h"
#include "Filesystem.h"
#include "ICF.h"
#include "InputFiles.h"
#include "InputSection.h"
#include "LinkerScript.h"
#include "Memory.h"
#include "OutputSections.h"
#include "ScriptParser.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "Target.h"
@ -48,16 +67,19 @@ BumpPtrAllocator elf::BAlloc;
StringSaver elf::Saver{BAlloc};
std::vector<SpecificAllocBase *> elf::SpecificAllocBase::Instances;
static void setConfigs();
bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
ErrorCount = 0;
ErrorOS = &Error;
Argv0 = Args[0];
InputSections.clear();
Tar = nullptr;
Config = make<Configuration>();
Driver = make<LinkerDriver>();
ScriptConfig = make<ScriptConfiguration>();
Script = make<LinkerScript>();
Driver->main(Args, CanExitEarly);
freeArena();
@ -78,10 +100,8 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
.Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
.Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.Case("elf32btsmip", {ELF32BEKind, EM_MIPS})
.Case("elf32ltsmip", {ELF32LEKind, EM_MIPS})
.Case("elf32btsmipn32", {ELF32BEKind, EM_MIPS})
.Case("elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
.Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
.Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
.Case("elf32ppc", {ELF32BEKind, EM_PPC})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
@ -133,7 +153,7 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
// Opens and parses a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
void LinkerDriver::addFile(StringRef Path) {
void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
using namespace sys::fs;
Optional<MemoryBufferRef> Buffer = readFile(Path);
@ -164,6 +184,19 @@ void LinkerDriver::addFile(StringRef Path) {
return;
}
Files.push_back(createSharedFile(MBRef));
// DSOs usually have DT_SONAME tags in their ELF headers, and the
// sonames are used to identify DSOs. But if they are missing,
// they are identified by filenames. We don't know whether the new
// file has a DT_SONAME or not because we haven't parsed it yet.
// Here, we set the default soname for the file because we might
// need it later.
//
// If a file was specified by -lfoo, the directory part is not
// significant, as a user did not specify it. This behavior is
// compatible with GNU.
Files.back()->DefaultSoName =
WithLOption ? sys::path::filename(Path) : Path;
return;
default:
if (InLib)
@ -176,7 +209,7 @@ void LinkerDriver::addFile(StringRef Path) {
// Add a given library by searching it from input search paths.
void LinkerDriver::addLibrary(StringRef Name) {
if (Optional<std::string> Path = searchLibrary(Name))
addFile(*Path);
addFile(*Path, /*WithLOption=*/true);
else
error("unable to find library -l" + Name);
}
@ -281,11 +314,27 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
return;
}
// GNU linkers disagree here. Though both -version and -v are mentioned
// in help to print the version information, GNU ld just normally exits,
// while gold can continue linking. We are compatible with ld.bfd here.
if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v))
outs() << getLLDVersion() << "\n";
// Handle -v or -version.
//
// A note about "compatible with GNU linkers" message: this is a hack for
// scripts generated by GNU Libtool 2.4.6 (released in February 2014 and
// still the newest version in March 2017) or earlier to recognize LLD as
// a GNU compatible linker. As long as an output for the -v option
// contains "GNU" or "with BFD", they recognize us as GNU-compatible.
//
// This is somewhat ugly hack, but in reality, we had no choice other
// than doing this. Considering the very long release cycle of Libtool,
// it is not easy to improve it to recognize LLD as a GNU compatible
// linker in a timely manner. Even if we can make it, there are still a
// lot of "configure" scripts out there that are generated by old version
// of Libtool. We cannot convince every software developer to migrate to
// the latest version and re-generate scripts. So we have this hack.
if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
message(getLLDVersion() + " (compatible with GNU linkers)");
// ld.bfd always exits after printing out the version string.
// ld.gold proceeds if a given option is -v. Because gold's behavior
// is more permissive than ld.bfd, we chose what gold does here.
if (Args.hasArg(OPT_version))
return;
@ -311,6 +360,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
initLLVM(Args);
createFiles(Args);
inferMachineType();
setConfigs();
checkOptions(Args);
if (ErrorCount)
return;
@ -333,26 +383,68 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
}
}
static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) {
if (Args.hasArg(OPT_noinhibit_exec))
return UnresolvedPolicy::Warn;
if (Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs"))
return UnresolvedPolicy::NoUndef;
if (Config->Relocatable)
return UnresolvedPolicy::Ignore;
if (auto *Arg = Args.getLastArg(OPT_unresolved_symbols)) {
StringRef S = Arg->getValue();
if (S == "ignore-all" || S == "ignore-in-object-files")
return UnresolvedPolicy::Ignore;
if (S == "ignore-in-shared-libs" || S == "report-all")
return UnresolvedPolicy::ReportError;
error("unknown --unresolved-symbols value: " + S);
}
return UnresolvedPolicy::ReportError;
static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
bool Default) {
if (auto *Arg = Args.getLastArg(K1, K2))
return Arg->getOption().getID() == K1;
return Default;
}
static Target2Policy getTarget2Option(opt::InputArgList &Args) {
static std::vector<StringRef> getArgs(opt::InputArgList &Args, int Id) {
std::vector<StringRef> V;
for (auto *Arg : Args.filtered(Id))
V.push_back(Arg->getValue());
return V;
}
static std::string getRPath(opt::InputArgList &Args) {
std::vector<StringRef> V = getArgs(Args, OPT_rpath);
return llvm::join(V.begin(), V.end(), ":");
}
// Determines what we should do if there are remaining unresolved
// symbols after the name resolution.
static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) {
// -noinhibit-exec or -r imply some default values.
if (Args.hasArg(OPT_noinhibit_exec))
return UnresolvedPolicy::WarnAll;
if (Args.hasArg(OPT_relocatable))
return UnresolvedPolicy::IgnoreAll;
UnresolvedPolicy ErrorOrWarn = getArg(Args, OPT_error_unresolved_symbols,
OPT_warn_unresolved_symbols, true)
? UnresolvedPolicy::ReportError
: UnresolvedPolicy::Warn;
// Process the last of -unresolved-symbols, -no-undefined or -z defs.
for (auto *Arg : llvm::reverse(Args)) {
switch (Arg->getOption().getID()) {
case OPT_unresolved_symbols: {
StringRef S = Arg->getValue();
if (S == "ignore-all" || S == "ignore-in-object-files")
return UnresolvedPolicy::Ignore;
if (S == "ignore-in-shared-libs" || S == "report-all")
return ErrorOrWarn;
error("unknown --unresolved-symbols value: " + S);
continue;
}
case OPT_no_undefined:
return ErrorOrWarn;
case OPT_z:
if (StringRef(Arg->getValue()) == "defs")
return ErrorOrWarn;
continue;
}
}
// -shared implies -unresolved-symbols=ignore-all because missing
// symbols are likely to be resolved at runtime using other DSOs.
if (Config->Shared)
return UnresolvedPolicy::Ignore;
return ErrorOrWarn;
}
static Target2Policy getTarget2(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_target2)) {
StringRef S = Arg->getValue();
if (S == "rel")
@ -376,16 +468,10 @@ static bool isOutputFormatBinary(opt::InputArgList &Args) {
return false;
}
static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
bool Default) {
if (auto *Arg = Args.getLastArg(K1, K2))
return Arg->getOption().getID() == K1;
return Default;
}
static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
if (Config->Relocatable)
static DiscardPolicy getDiscard(opt::InputArgList &Args) {
if (Args.hasArg(OPT_relocatable))
return DiscardPolicy::None;
auto *Arg =
Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none);
if (!Arg)
@ -397,13 +483,23 @@ static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
return DiscardPolicy::None;
}
static StripPolicy getStripOption(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug)) {
if (Arg->getOption().getID() == OPT_strip_all)
return StripPolicy::All;
return StripPolicy::Debug;
}
return StripPolicy::None;
static StringRef getDynamicLinker(opt::InputArgList &Args) {
auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker)
return "";
return Arg->getValue();
}
static StripPolicy getStrip(opt::InputArgList &Args) {
if (Args.hasArg(OPT_relocatable))
return StripPolicy::None;
auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug);
if (!Arg)
return StripPolicy::None;
if (Arg->getOption().getID() == OPT_strip_all)
return StripPolicy::All;
return StripPolicy::Debug;
}
static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) {
@ -433,7 +529,7 @@ static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) {
return Ret;
}
static SortSectionPolicy getSortKind(opt::InputArgList &Args) {
static SortSectionPolicy getSortSection(opt::InputArgList &Args) {
StringRef S = getString(Args, OPT_sort_section);
if (S == "alignment")
return SortSectionPolicy::Alignment;
@ -444,6 +540,17 @@ static SortSectionPolicy getSortKind(opt::InputArgList &Args) {
return SortSectionPolicy::Default;
}
static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) {
StringRef S = getString(Args, OPT_hash_style, "sysv");
if (S == "sysv")
return {true, false};
if (S == "gnu")
return {false, true};
if (S != "both")
error("unknown -hash-style: " + S);
return {true, true};
}
static std::vector<StringRef> getLines(MemoryBufferRef MB) {
SmallVector<StringRef, 0> Arr;
MB.getBuffer().split(Arr, '\n');
@ -459,14 +566,87 @@ static std::vector<StringRef> getLines(MemoryBufferRef MB) {
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
for (auto *Arg : Args.filtered(OPT_L))
Config->SearchPaths.push_back(Arg->getValue());
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
Config->AuxiliaryList = getArgs(Args, OPT_auxiliary);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
!Args.hasArg(OPT_relocatable));
Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
Config->Discard = getDiscard(Args);
Config->DynamicLinker = getDynamicLinker(Args);
Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
Config->Entry = getString(Args, OPT_entry);
Config->ExportDynamic =
getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false);
Config->FatalWarnings =
getArg(Args, OPT_fatal_warnings, OPT_no_fatal_warnings, false);
Config->Fini = getString(Args, OPT_fini, "_fini");
Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false);
Config->GdbIndex = Args.hasArg(OPT_gdb_index);
Config->ICF = Args.hasArg(OPT_icf);
Config->Init = getString(Args, OPT_init, "_init");
Config->LTOAAPipeline = getString(Args, OPT_lto_aa_pipeline);
Config->LTONewPmPasses = getString(Args, OPT_lto_newpm_passes);
Config->LTOO = getInteger(Args, OPT_lto_O, 2);
Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
Config->MapFile = getString(Args, OPT_Map);
Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
Config->Nostdlib = Args.hasArg(OPT_nostdlib);
Config->OFormatBinary = isOutputFormatBinary(Args);
Config->Omagic = Args.hasArg(OPT_omagic);
Config->OptRemarksFilename = getString(Args, OPT_opt_remarks_filename);
Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness);
Config->Optimize = getInteger(Args, OPT_O, 1);
Config->OutputFile = getString(Args, OPT_o);
Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false);
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
Config->RPath = getRPath(Args);
Config->Relocatable = Args.hasArg(OPT_relocatable);
Config->SaveTemps = Args.hasArg(OPT_save_temps);
Config->SearchPaths = getArgs(Args, OPT_L);
Config->SectionStartMap = getSectionStartMap(Args);
Config->Shared = Args.hasArg(OPT_shared);
Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
Config->SoName = getString(Args, OPT_soname);
Config->SortSection = getSortSection(Args);
Config->Strip = getStrip(Args);
Config->Sysroot = getString(Args, OPT_sysroot);
Config->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false);
Config->Target2 = getTarget2(Args);
Config->ThinLTOCacheDir = getString(Args, OPT_thinlto_cache_dir);
Config->ThinLTOCachePolicy =
check(parseCachePruningPolicy(getString(Args, OPT_thinlto_cache_policy)),
"--thinlto-cache-policy: invalid cache policy");
Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true);
Config->Trace = Args.hasArg(OPT_trace);
Config->Undefined = getArgs(Args, OPT_undefined);
Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
Config->Verbose = Args.hasArg(OPT_verbose);
Config->WarnCommon = Args.hasArg(OPT_warn_common);
Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
Config->ZExecstack = hasZOption(Args, "execstack");
Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNodlopen = hasZOption(Args, "nodlopen");
Config->ZNow = hasZOption(Args, "now");
Config->ZOrigin = hasZOption(Args, "origin");
Config->ZRelro = !hasZOption(Args, "norelro");
Config->ZStackSize = getZOptionValue(Args, "stack-size", 0);
Config->ZText = !hasZOption(Args, "notext");
Config->ZWxneeded = hasZOption(Args, "wxneeded");
std::vector<StringRef> RPaths;
for (auto *Arg : Args.filtered(OPT_rpath))
RPaths.push_back(Arg->getValue());
if (!RPaths.empty())
Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":");
if (Config->LTOO > 3)
error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O));
if (Config->LTOPartitions == 0)
error("--lto-partitions: number of threads must be > 0");
if (Config->ThinLTOJobs == 0)
error("--thinlto-jobs: number of threads must be > 0");
if (auto *Arg = Args.getLastArg(OPT_m)) {
// Parse ELF{32,64}{LE,BE} and CPU type.
@ -477,98 +657,21 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->Emulation = S;
}
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);
Config->FatalWarnings = Args.hasArg(OPT_fatal_warnings);
Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false);
Config->GdbIndex = Args.hasArg(OPT_gdb_index);
Config->ICF = Args.hasArg(OPT_icf);
Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
Config->Nostdlib = Args.hasArg(OPT_nostdlib);
Config->OMagic = Args.hasArg(OPT_omagic);
Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false);
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
Config->Relocatable = Args.hasArg(OPT_relocatable);
Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
!Config->Relocatable);
Config->Discard = getDiscardOption(Args);
Config->SaveTemps = Args.hasArg(OPT_save_temps);
Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
Config->Shared = Args.hasArg(OPT_shared);
Config->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false);
Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true);
Config->Trace = Args.hasArg(OPT_trace);
Config->Verbose = Args.hasArg(OPT_verbose);
Config->WarnCommon = Args.hasArg(OPT_warn_common);
Config->DynamicLinker = getString(Args, OPT_dynamic_linker);
Config->Entry = getString(Args, OPT_entry);
Config->Fini = getString(Args, OPT_fini, "_fini");
Config->Init = getString(Args, OPT_init, "_init");
Config->LTOAAPipeline = getString(Args, OPT_lto_aa_pipeline);
Config->LTONewPmPasses = getString(Args, OPT_lto_newpm_passes);
Config->OutputFile = getString(Args, OPT_o);
Config->SoName = getString(Args, OPT_soname);
Config->Sysroot = getString(Args, OPT_sysroot);
Config->Optimize = getInteger(Args, OPT_O, 1);
Config->LTOO = getInteger(Args, OPT_lto_O, 2);
if (Config->LTOO > 3)
error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O));
Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
if (Config->LTOPartitions == 0)
error("--lto-partitions: number of threads must be > 0");
Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
if (Config->ThinLTOJobs == 0)
error("--thinlto-jobs: number of threads must be > 0");
Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
Config->ZExecstack = hasZOption(Args, "execstack");
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNow = hasZOption(Args, "now");
Config->ZOrigin = hasZOption(Args, "origin");
Config->ZRelro = !hasZOption(Args, "norelro");
Config->ZStackSize = getZOptionValue(Args, "stack-size", -1);
Config->ZWxneeded = hasZOption(Args, "wxneeded");
Config->OFormatBinary = isOutputFormatBinary(Args);
Config->SectionStartMap = getSectionStartMap(Args);
Config->SortSection = getSortKind(Args);
Config->Target2 = getTarget2Option(Args);
Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args);
if (Args.hasArg(OPT_print_map))
Config->MapFile = "-";
// --omagic is an option to create old-fashioned executables in which
// .text segments are writable. Today, the option is still in use to
// create special-purpose programs such as boot loaders. It doesn't
// make sense to create PT_GNU_RELRO for such executables.
if (Config->OMagic)
if (Config->Omagic)
Config->ZRelro = false;
if (!Config->Relocatable)
Config->Strip = getStripOption(Args);
std::tie(Config->SysvHash, Config->GnuHash) = getHashStyle(Args);
// Config->Pic is true if we are generating position-independent code.
Config->Pic = Config->Pie || Config->Shared;
if (auto *Arg = Args.getLastArg(OPT_hash_style)) {
StringRef S = Arg->getValue();
if (S == "gnu") {
Config->GnuHash = true;
Config->SysvHash = false;
} else if (S == "both") {
Config->GnuHash = true;
} else if (S != "sysv")
error("unknown hash style: " + S);
}
// Parse --build-id or --build-id=<style>.
// Parse --build-id or --build-id=<style>. We handle "tree" as a
// synonym for "sha1" because all of our hash functions including
// -build-id=sha1 are tree hashes for performance reasons.
if (Args.hasArg(OPT_build_id))
Config->BuildId = BuildIdKind::Fast;
if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {
@ -589,15 +692,10 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
}
}
for (auto *Arg : Args.filtered(OPT_auxiliary))
Config->AuxiliaryList.push_back(Arg->getValue());
if (!Config->Shared && !Config->AuxiliaryList.empty())
error("-f may not be used without -shared");
for (auto *Arg : Args.filtered(OPT_undefined))
Config->Undefined.push_back(Arg->getValue());
if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
for (auto *Arg : Args.filtered(OPT_dynamic_list))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
readDynamicList(*Buffer);
@ -605,13 +703,14 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
Config->SymbolOrderingFile = getLines(*Buffer);
// If --retain-symbol-file is used, we'll retail only the symbols listed in
// If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) {
Config->Discard = DiscardPolicy::RetainFile;
Config->DefaultSymbolVersion = VER_NDX_LOCAL;
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
for (StringRef S : getLines(*Buffer))
Config->RetainSymbolsFile.insert(S);
Config->VersionScriptGlobals.push_back(
{S, /*IsExternCpp*/ false, /*HasWildcard*/ false});
}
for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
@ -627,11 +726,37 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->DefaultSymbolVersion = VER_NDX_LOCAL;
}
if (getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false))
Config->DefaultSymbolVersion = VER_NDX_GLOBAL;
if (auto *Arg = Args.getLastArg(OPT_version_script))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
readVersionScript(*Buffer);
}
// Some Config members do not directly correspond to any particular
// command line options, but computed based on other Config values.
// This function initialize such members. See Config.h for the details
// of these values.
static void setConfigs() {
ELFKind Kind = Config->EKind;
uint16_t Machine = Config->EMachine;
// There is an ILP32 ABI for x86-64, although it's not very popular.
// It is called the x32 ABI.
bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);
Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind);
Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind);
Config->Endianness =
Config->IsLE ? support::endianness::little : support::endianness::big;
Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS);
Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi;
Config->Pic = Config->Pie || Config->Shared;
Config->Wordsize = Config->Is64 ? 8 : 4;
}
// Returns a value of "-format" option.
static bool getBinaryOption(StringRef S) {
if (S == "binary")
@ -650,7 +775,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
addLibrary(Arg->getValue());
break;
case OPT_INPUT:
addFile(Arg->getValue());
addFile(Arg->getValue(), /*WithLOption=*/false);
break;
case OPT_alias_script_T:
case OPT_script:
@ -744,12 +869,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
SymbolTable<ELFT> Symtab;
elf::Symtab<ELFT>::X = &Symtab;
Target = createTarget();
ScriptBase = Script<ELFT>::X = make<LinkerScript<ELFT>>();
Config->Rela =
ELFT::Is64Bits || Config->EMachine == EM_X86_64 || Config->MipsN32Abi;
Config->Mips64EL =
(Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind);
Config->MaxPageSize = getMaxPageSize(Args);
Config->ImageBase = getImageBase(Args);
@ -757,6 +877,14 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (Config->OutputFile.empty())
Config->OutputFile = "a.out";
// Fail early if the output file or map file is not writable. If a user has a
// long link, e.g. due to a large LTO link, they do not wish to run it and
// find that it failed because there was a mistake in their command-line.
if (!isFileWritable(Config->OutputFile, "output file"))
return;
if (!isFileWritable(Config->MapFile, "map file"))
return;
// Use default entry point name if no name was given via the command
// line nor linker scripts. For some reason, MIPS entry point name is
// different from others.
@ -792,6 +920,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (ErrorCount)
return;
// Some symbols (such as __ehdr_start) are defined lazily only when there
// are undefined symbols for them, so we add these to trigger that logic.
for (StringRef Sym : Script->Opt.ReferencedSymbols)
Symtab.addUndefined(Sym);
for (auto *Arg : Args.filtered(OPT_wrap))
Symtab.wrap(Arg->getValue());
@ -799,12 +932,12 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Beyond this point, no new files are added.
// Aggregate all input sections into one place.
for (elf::ObjectFile<ELFT> *F : Symtab.getObjectFiles())
for (InputSectionBase<ELFT> *S : F->getSections())
if (S && S != &InputSection<ELFT>::Discarded)
Symtab.Sections.push_back(S);
for (InputSectionBase *S : F->getSections())
if (S && S != &InputSection::Discarded)
InputSections.push_back(S);
for (BinaryFile *F : Symtab.getBinaryFiles())
for (InputSectionData *S : F->getSections())
Symtab.Sections.push_back(cast<InputSection<ELFT>>(S));
for (InputSectionBase *S : F->getSections())
InputSections.push_back(cast<InputSection>(S));
// Do size optimizations: garbage collection and identical code folding.
if (Config->GcSections)
@ -814,15 +947,15 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// MergeInputSection::splitIntoPieces needs to be called before
// any call of MergeInputSection::getOffset. Do that.
forEach(Symtab.Sections.begin(), Symtab.Sections.end(),
[](InputSectionBase<ELFT> *S) {
if (!S->Live)
return;
if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
S->uncompress();
if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S))
MS->splitIntoPieces();
});
parallelForEach(InputSections.begin(), InputSections.end(),
[](InputSectionBase *S) {
if (!S->Live)
return;
if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
S->uncompress();
if (auto *MS = dyn_cast<MergeInputSection>(S))
MS->splitIntoPieces();
});
// Write the result to the file.
writeResult<ELFT>();

View file

@ -27,7 +27,7 @@ extern class LinkerDriver *Driver;
class LinkerDriver {
public:
void main(ArrayRef<const char *> Args, bool CanExitEarly);
void addFile(StringRef Path);
void addFile(StringRef Path, bool WithLOption);
void addLibrary(StringRef Name);
private:

View file

@ -16,7 +16,6 @@
#include "Driver.h"
#include "Error.h"
#include "Memory.h"
#include "ScriptParser.h"
#include "lld/Config/Version.h"
#include "lld/Core/Reproduce.h"
#include "llvm/ADT/Optional.h"
@ -54,12 +53,10 @@ ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics.
static bool getColorDiagnostics(opt::InputArgList &Args) {
bool Default = (ErrorOS == &errs() && Process::StandardErrHasColors());
auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
OPT_no_color_diagnostics);
if (!Arg)
return Default;
return ErrorOS->has_colors();
if (Arg->getOption().getID() == OPT_color_diagnostics)
return true;
if (Arg->getOption().getID() == OPT_no_color_diagnostics)
@ -67,7 +64,7 @@ static bool getColorDiagnostics(opt::InputArgList &Args) {
StringRef S = Arg->getValue();
if (S == "auto")
return Default;
return ErrorOS->has_colors();
if (S == "always")
return true;
if (S != "never")
@ -120,6 +117,20 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
void elf::printHelp(const char *Argv0) {
ELFOptTable Table;
Table.PrintHelp(outs(), Argv0, "lld", false);
outs() << "\n";
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
// recent version as of March 2017) expect /: supported targets:.* elf/
// in a message for the -help option. If it doesn't match, the scripts
// assume that the linker doesn't support very basic features such as
// shared libraries. Therefore, we need to print out at least "elf".
// Here, we print out all the targets that we support.
outs() << Argv0 << ": supported targets: "
<< "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips "
<< "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips "
<< "elf32-tradlittlemips elf32-x86-64 "
<< "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips "
<< "elf64-tradlittlemips elf64-x86-64\n";
}
// Reconstructs command line arguments so that so that you can re-run
@ -136,6 +147,13 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) {
case OPT_INPUT:
OS << quote(rewritePath(Arg->getValue())) << "\n";
break;
case OPT_o:
// If -o path contains directories, "lld @response.txt" will likely
// fail because the archive we are creating doesn't contain empty
// directories for the output path (-o doesn't create directories).
// Strip directories to prevent the issue.
OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
break;
case OPT_L:
case OPT_dynamic_list:
case OPT_rpath:

View file

@ -38,13 +38,14 @@ using namespace lld::elf;
namespace {
template <class ELFT> class EhReader {
public:
EhReader(InputSectionBase<ELFT> *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
EhReader(InputSectionBase *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
size_t readEhRecordSize();
uint8_t getFdeEncoding();
private:
template <class P> void failOn(const P *Loc, const Twine &Msg) {
fatal(IS->getLocation((const uint8_t *)Loc - IS->Data.data()) + ": " + Msg);
fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " +
IS->getObjMsg<ELFT>((const uint8_t *)Loc - IS->Data.data()));
}
uint8_t readByte();
@ -53,15 +54,16 @@ private:
void skipLeb128();
void skipAugP();
InputSectionBase<ELFT> *IS;
InputSectionBase *IS;
ArrayRef<uint8_t> D;
};
}
template <class ELFT>
size_t elf::readEhRecordSize(InputSectionBase<ELFT> *S, size_t Off) {
size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) {
return EhReader<ELFT>(S, S->Data.slice(Off)).readEhRecordSize();
}
// .eh_frame section is a sequence of records. Each record starts with
// a 4 byte length field. This function reads the length.
template <class ELFT> size_t EhReader<ELFT>::readEhRecordSize() {
@ -121,11 +123,11 @@ template <class ELFT> void EhReader<ELFT>::skipLeb128() {
failOn(ErrPos, "corrupted CIE (failed to read LEB128)");
}
template <class ELFT> static size_t getAugPSize(unsigned Enc) {
static size_t getAugPSize(unsigned Enc) {
switch (Enc & 0x0f) {
case DW_EH_PE_absptr:
case DW_EH_PE_signed:
return ELFT::Is64Bits ? 8 : 4;
return Config->Wordsize;
case DW_EH_PE_udata2:
case DW_EH_PE_sdata2:
return 2;
@ -143,7 +145,7 @@ template <class ELFT> void EhReader<ELFT>::skipAugP() {
uint8_t Enc = readByte();
if ((Enc & 0xf0) == DW_EH_PE_aligned)
failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported");
size_t Size = getAugPSize<ELFT>(Enc);
size_t Size = getAugPSize(Enc);
if (Size == 0)
failOn(D.data() - 1, "unknown FDE encoding");
if (Size >= D.size())
@ -152,7 +154,7 @@ template <class ELFT> void EhReader<ELFT>::skipAugP() {
}
template <class ELFT> uint8_t elf::getFdeEncoding(EhSectionPiece *P) {
auto *IS = static_cast<InputSectionBase<ELFT> *>(P->ID);
auto *IS = static_cast<InputSectionBase *>(P->ID);
return EhReader<ELFT>(IS, P->data()).getFdeEncoding();
}
@ -199,14 +201,10 @@ template <class ELFT> uint8_t EhReader<ELFT>::getFdeEncoding() {
return DW_EH_PE_absptr;
}
template size_t elf::readEhRecordSize<ELF32LE>(InputSectionBase<ELF32LE> *S,
size_t Off);
template size_t elf::readEhRecordSize<ELF32BE>(InputSectionBase<ELF32BE> *S,
size_t Off);
template size_t elf::readEhRecordSize<ELF64LE>(InputSectionBase<ELF64LE> *S,
size_t Off);
template size_t elf::readEhRecordSize<ELF64BE>(InputSectionBase<ELF64BE> *S,
size_t Off);
template size_t elf::readEhRecordSize<ELF32LE>(InputSectionBase *S, size_t Off);
template size_t elf::readEhRecordSize<ELF32BE>(InputSectionBase *S, size_t Off);
template size_t elf::readEhRecordSize<ELF64LE>(InputSectionBase *S, size_t Off);
template size_t elf::readEhRecordSize<ELF64BE>(InputSectionBase *S, size_t Off);
template uint8_t elf::getFdeEncoding<ELF32LE>(EhSectionPiece *P);
template uint8_t elf::getFdeEncoding<ELF32BE>(EhSectionPiece *P);

View file

@ -14,11 +14,10 @@
namespace lld {
namespace elf {
template <class ELFT> class InputSectionBase;
class InputSectionBase;
struct EhSectionPiece;
template <class ELFT>
size_t readEhRecordSize(InputSectionBase<ELFT> *S, size_t Off);
template <class ELFT> size_t readEhRecordSize(InputSectionBase *S, size_t Off);
template <class ELFT> uint8_t getFdeEncoding(EhSectionPiece *P);
}
}

View file

@ -20,10 +20,10 @@
#include <unistd.h>
#endif
using namespace lld::elf;
using namespace llvm;
namespace lld {
using namespace lld;
using namespace lld::elf;
uint64_t elf::ErrorCount;
raw_ostream *elf::ErrorOS;
@ -33,6 +33,18 @@ StringRef elf::Argv0;
// but outs() or errs() are not thread-safe. We protect them using a mutex.
static std::mutex Mu;
// Prints "\n" or does nothing, depending on Msg contents of
// the previous call of this function.
static void newline(const Twine &Msg) {
// True if the previous error message contained "\n".
// We want to separate multi-line error messages with a newline.
static bool Flag;
if (Flag)
*ErrorOS << "\n";
Flag = (StringRef(Msg.str()).find('\n') != StringRef::npos);
}
static void print(StringRef S, raw_ostream::Colors C) {
*ErrorOS << Argv0 + ": ";
if (Config->ColorDiagnostics) {
@ -45,9 +57,16 @@ static void print(StringRef S, raw_ostream::Colors C) {
}
void elf::log(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
if (Config->Verbose)
if (Config->Verbose) {
std::lock_guard<std::mutex> Lock(Mu);
outs() << Argv0 << ": " << Msg << "\n";
}
}
void elf::message(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
outs() << Msg << "\n";
outs().flush();
}
void elf::warn(const Twine &Msg) {
@ -55,13 +74,16 @@ void elf::warn(const Twine &Msg) {
error(Msg);
return;
}
std::lock_guard<std::mutex> Lock(Mu);
newline(Msg);
print("warning: ", raw_ostream::MAGENTA);
*ErrorOS << Msg << "\n";
}
void elf::error(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
newline(Msg);
if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
print("error: ", raw_ostream::RED);
@ -77,10 +99,6 @@ void elf::error(const Twine &Msg) {
++ErrorCount;
}
void elf::error(std::error_code EC, const Twine &Prefix) {
error(Prefix + ": " + EC.message());
}
void elf::exitLld(int Val) {
// Dealloc/destroy ManagedStatic variables before calling
// _exit(). In a non-LTO build, this is a nop. In an LTO
@ -93,18 +111,6 @@ void elf::exitLld(int Val) {
}
void elf::fatal(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
print("error: ", raw_ostream::RED);
*ErrorOS << Msg << "\n";
error(Msg);
exitLld(1);
}
void elf::fatal(std::error_code EC, const Twine &Prefix) {
fatal(Prefix + ": " + EC.message());
}
void elf::fatal(Error &E, const Twine &Prefix) {
fatal(Prefix + ": " + llvm::toString(std::move(E)));
}
} // namespace lld

View file

@ -15,10 +15,14 @@
// Error prints out an error message and increment a global variable
// ErrorCount to record the fact that we met an error condition. It does
// not exit, so it is safe for a lld-as-a-library use case. It is generally
// useful because it can report more than one errors in a single run.
// useful because it can report more than one error in a single run.
//
// Warn doesn't do anything but printing out a given message.
//
// It is not recommended to use llvm::outs() or llvm::errs() directly
// in LLD because they are not thread-safe. The functions declared in
// this file are mutually excluded, so you want to use them instead.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_ERROR_H
@ -36,15 +40,12 @@ extern llvm::raw_ostream *ErrorOS;
extern llvm::StringRef Argv0;
void log(const Twine &Msg);
void message(const Twine &Msg);
void warn(const Twine &Msg);
void error(const Twine &Msg);
void error(std::error_code EC, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void fatal(Error &E, const Twine &Prefix);
// check() functions are convenient functions to strip errors
// from error-or-value objects.
@ -68,7 +69,7 @@ template <class T> T check(ErrorOr<T> E, const Twine &Prefix) {
template <class T> T check(Expected<T> E, const Twine &Prefix) {
if (!E)
fatal(Prefix + ": " + errorToErrorCode(E.takeError()).message());
fatal(Prefix + ": " + toString(E.takeError()));
return std::move(*E);
}

79
ELF/Filesystem.cpp Normal file
View file

@ -0,0 +1,79 @@
//===- Filesystem.cpp -----------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a few utility functions to handle files.
//
//===----------------------------------------------------------------------===//
#include "Filesystem.h"
#include "Config.h"
#include "Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileOutputBuffer.h"
#include <thread>
using namespace llvm;
using namespace lld;
using namespace lld::elf;
// Removes a given file asynchronously. This is a performance hack,
// so remove this when operating systems are improved.
//
// On Linux (and probably on other Unix-like systems), unlink(2) is a
// noticeably slow system call. As of 2016, unlink takes 250
// milliseconds to remove a 1 GB file on ext4 filesystem on my machine.
//
// To create a new result file, we first remove existing file. So, if
// you repeatedly link a 1 GB program in a regular compile-link-debug
// cycle, every cycle wastes 250 milliseconds only to remove a file.
// Since LLD can link a 1 GB binary in about 5 seconds, that waste
// actually counts.
//
// This function spawns a background thread to call unlink.
// The calling thread returns almost immediately.
void elf::unlinkAsync(StringRef Path) {
if (!Config->Threads || !sys::fs::exists(Config->OutputFile))
return;
// First, rename Path to avoid race condition. We cannot remove
// Path from a different thread because we are now going to create
// Path as a new file. If we do that in a different thread, the new
// thread can remove the new file.
SmallString<128> TempPath;
if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath))
return;
if (sys::fs::rename(Path, TempPath)) {
sys::fs::remove(TempPath);
return;
}
// Remove TempPath in background.
std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach();
}
// Returns true if a given file seems to be writable.
//
// Determining whether a file is writable or not is amazingly hard,
// and after all the only reliable way of doing that is to actually
// create a file. But we don't want to do that in this function
// because LLD shouldn't update any file if it will end in a failure.
// We also don't want to reimplement heuristics. So we'll let
// FileOutputBuffer do the work.
//
// FileOutputBuffer doesn't touch a desitnation file until commit()
// is called. We use that class without calling commit() to predict
// if the given file is writable.
bool elf::isFileWritable(StringRef Path, StringRef Desc) {
if (auto EC = FileOutputBuffer::create(Path, 1).getError()) {
error("cannot open " + Desc + " " + Path + ": " + EC.message());
return false;
}
return true;
}

22
ELF/Filesystem.h Normal file
View file

@ -0,0 +1,22 @@
//===- Filesystem.h ---------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_FILESYSTEM_H
#define LLD_ELF_FILESYSTEM_H
#include "lld/Core/LLVM.h"
namespace lld {
namespace elf {
void unlinkAsync(StringRef Path);
bool isFileWritable(StringRef Path, StringRef FileDescription);
}
}
#endif

View file

@ -7,199 +7,43 @@
//
//===----------------------------------------------------------------------===//
//
// File contains classes for implementation of --gdb-index command line option.
// The -gdb-index option instructs the linker to emit a .gdb_index section.
// The section contains information to make gdb startup faster.
// The format of the section is described at
// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html.
//
// If that option is used, linker should emit a .gdb_index section that allows
// debugger to locate and read .dwo files, containing neccessary debug
// information.
// More information about implementation can be found in DWARF specification,
// latest version is available at http://dwarfstd.org.
//
// .gdb_index section format:
// (Information is based on/taken from
// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html (*))
//
// A mapped index consists of several areas, laid out in order:
// 1) The file header.
// 2) "The CU (compilation unit) list. This is a sequence of pairs of 64-bit
// little-endian values, sorted by the CU offset. The first element in each
// pair is the offset of a CU in the .debug_info section. The second element
// in each pair is the length of that CU. References to a CU elsewhere in the
// map are done using a CU index, which is just the 0-based index into this
// table. Note that if there are type CUs, then conceptually CUs and type CUs
// form a single list for the purposes of CU indices."(*)
// 3) The types CU list. Depricated as .debug_types does not appear in the DWARF
// v5 specification.
// 4) The address area. The address area is a sequence of address
// entries, where each entrie contains low address, high address and CU
// index.
// 5) "The symbol table. This is an open-addressed hash table. The size of the
// hash table is always a power of 2. Each slot in the hash table consists of
// a pair of offset_type values. The first value is the offset of the
// symbol's name in the constant pool. The second value is the offset of the
// CU vector in the constant pool."(*)
// 6) "The constant pool. This is simply a bunch of bytes. It is organized so
// that alignment is correct: CU vectors are stored first, followed by
// strings." (*)
//
// For constructing the .gdb_index section following steps should be performed:
// 1) For file header nothing special should be done. It contains the offsets to
// the areas below.
// 2) Scan the compilation unit headers of the .debug_info sections to build a
// list of compilation units.
// 3) CU Types are no longer needed as DWARF skeleton type units never made it
// into the standard. lld does nothing to support parsing of .debug_types
// and generates empty types CU area in .gdb_index section.
// 4) Address area entries are extracted from DW_TAG_compile_unit DIEs of
// .debug_info sections.
// 5) For building the symbol table linker extracts the public names from the
// .debug_gnu_pubnames and .debug_gnu_pubtypes sections. Then it builds the
// hashtable in according to .gdb_index format specification.
// 6) Constant pool is populated at the same time as symbol table.
//===----------------------------------------------------------------------===//
#include "GdbIndex.h"
#include "Memory.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/ELFObjectFile.h"
using namespace llvm;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf;
template <class ELFT>
GdbIndexBuilder<ELFT>::GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec)
: DebugInfoSec(DebugInfoSec) {
if (Expected<std::unique_ptr<object::ObjectFile>> Obj =
object::ObjectFile::createObjectFile(DebugInfoSec->getFile()->MB))
Dwarf.reset(new DWARFContextInMemory(*Obj.get(), this));
else
error(toString(DebugInfoSec->getFile()) + ": error creating DWARF context");
}
template <class ELFT>
std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>>
GdbIndexBuilder<ELFT>::readCUList() {
std::vector<std::pair<uintX_t, uintX_t>> Ret;
for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units())
Ret.push_back(
{DebugInfoSec->OutSecOff + CU->getOffset(), CU->getLength() + 4});
return Ret;
}
template <class ELFT>
std::vector<std::pair<StringRef, uint8_t>>
GdbIndexBuilder<ELFT>::readPubNamesAndTypes() {
const bool IsLE = ELFT::TargetEndianness == llvm::support::little;
StringRef Data[] = {Dwarf->getGnuPubNamesSection(),
Dwarf->getGnuPubTypesSection()};
std::vector<std::pair<StringRef, uint8_t>> Ret;
for (StringRef D : Data) {
DWARFDebugPubTable PubTable(D, IsLE, true);
for (const DWARFDebugPubTable::Set &S : PubTable.getData())
for (const DWARFDebugPubTable::Entry &E : S.Entries)
Ret.push_back({E.Name, E.Descriptor.toBits()});
}
return Ret;
}
std::pair<bool, GdbSymbol *> GdbHashTab::add(uint32_t Hash, size_t Offset) {
if (Size * 4 / 3 >= Table.size())
expand();
GdbSymbol **Slot = findSlot(Hash, Offset);
bool New = false;
if (*Slot == nullptr) {
++Size;
*Slot = new (Alloc) GdbSymbol(Hash, Offset);
New = true;
}
return {New, *Slot};
GdbSymbol *&Sym = Map[Offset];
if (Sym)
return {false, Sym};
Sym = make<GdbSymbol>(Hash, Offset);
return {true, Sym};
}
void GdbHashTab::expand() {
if (Table.empty()) {
Table.resize(InitialSize);
return;
}
std::vector<GdbSymbol *> NewTable(Table.size() * 2);
NewTable.swap(Table);
void GdbHashTab::finalizeContents() {
uint32_t Size = std::max<uint32_t>(1024, NextPowerOf2(Map.size() * 4 / 3));
uint32_t Mask = Size - 1;
Table.resize(Size);
for (GdbSymbol *Sym : NewTable) {
if (!Sym)
continue;
GdbSymbol **Slot = findSlot(Sym->NameHash, Sym->NameOffset);
*Slot = Sym;
for (auto &P : Map) {
GdbSymbol *Sym = P.second;
uint32_t I = Sym->NameHash & Mask;
uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1;
while (Table[I])
I = (I + Step) & Mask;
Table[I] = Sym;
}
}
// Methods finds a slot for symbol with given hash. The step size used to find
// the next candidate slot when handling a hash collision is specified in
// .gdb_index section format. The hash value for a table entry is computed by
// applying an iterative hash function to the symbol's name.
GdbSymbol **GdbHashTab::findSlot(uint32_t Hash, size_t Offset) {
uint32_t Index = Hash & (Table.size() - 1);
uint32_t Step = ((Hash * 17) & (Table.size() - 1)) | 1;
for (;;) {
GdbSymbol *S = Table[Index];
if (!S || ((S->NameOffset == Offset) && (S->NameHash == Hash)))
return &Table[Index];
Index = (Index + Step) & (Table.size() - 1);
}
}
template <class ELFT>
static InputSectionBase<ELFT> *
findSection(ArrayRef<InputSectionBase<ELFT> *> Arr, uint64_t Offset) {
for (InputSectionBase<ELFT> *S : Arr)
if (S && S != &InputSection<ELFT>::Discarded)
if (Offset >= S->Offset && Offset < S->Offset + S->getSize())
return S;
return nullptr;
}
template <class ELFT>
std::vector<AddressEntry<ELFT>>
GdbIndexBuilder<ELFT>::readAddressArea(size_t CurrentCU) {
std::vector<AddressEntry<ELFT>> Ret;
for (const auto &CU : Dwarf->compile_units()) {
DWARFAddressRangesVector Ranges;
CU->collectAddressRanges(Ranges);
ArrayRef<InputSectionBase<ELFT> *> Sections =
DebugInfoSec->getFile()->getSections();
for (std::pair<uint64_t, uint64_t> &R : Ranges)
if (InputSectionBase<ELFT> *S = findSection(Sections, R.first))
Ret.push_back(
{S, R.first - S->Offset, R.second - S->Offset, CurrentCU});
++CurrentCU;
}
return Ret;
}
// We return file offset as load address for allocatable sections. That is
// currently used for collecting address ranges in readAddressArea(). We are
// able then to find section index that range belongs to.
template <class ELFT>
uint64_t GdbIndexBuilder<ELFT>::getSectionLoadAddress(
const object::SectionRef &Sec) const {
if (static_cast<const ELFSectionRef &>(Sec).getFlags() & ELF::SHF_ALLOC)
return static_cast<const ELFSectionRef &>(Sec).getOffset();
return 0;
}
template <class ELFT>
std::unique_ptr<LoadedObjectInfo> GdbIndexBuilder<ELFT>::clone() const {
return {};
}
namespace lld {
namespace elf {
template class GdbIndexBuilder<ELF32LE>;
template class GdbIndexBuilder<ELF32BE>;
template class GdbIndexBuilder<ELF64LE>;
template class GdbIndexBuilder<ELF64BE>;
}
}

View file

@ -17,48 +17,16 @@
namespace lld {
namespace elf {
template <class ELFT> class InputSection;
class InputSection;
// Struct represents single entry of address area of gdb index.
template <class ELFT> struct AddressEntry {
InputSectionBase<ELFT> *Section;
struct AddressEntry {
InputSectionBase *Section;
uint64_t LowAddress;
uint64_t HighAddress;
size_t CuIndex;
};
// GdbIndexBuilder is a helper class used for extracting data required
// for building .gdb_index section from objects.
template <class ELFT> class GdbIndexBuilder : public llvm::LoadedObjectInfo {
typedef typename ELFT::uint uintX_t;
InputSection<ELFT> *DebugInfoSec;
std::unique_ptr<llvm::DWARFContext> Dwarf;
public:
GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec);
// Extracts the compilation units. Each first element of pair is a offset of a
// CU in the .debug_info section and second is the length of that CU.
std::vector<std::pair<uintX_t, uintX_t>> readCUList();
// Extracts the vector of address area entries. Accepts global index of last
// parsed CU.
std::vector<AddressEntry<ELFT>> readAddressArea(size_t CurrentCU);
// Method extracts public names and types. It returns list of name and
// gnu_pub* kind pairs.
std::vector<std::pair<StringRef, uint8_t>> readPubNamesAndTypes();
private:
// Method returns section file offset as a load addres for DWARF parser. That
// allows to find the target section index for address ranges.
uint64_t
getSectionLoadAddress(const llvm::object::SectionRef &Sec) const override;
std::unique_ptr<llvm::LoadedObjectInfo> clone() const override;
};
// Element of GdbHashTab hash table.
struct GdbSymbol {
GdbSymbol(uint32_t Hash, size_t Offset)
@ -75,22 +43,13 @@ class GdbHashTab final {
public:
std::pair<bool, GdbSymbol *> add(uint32_t Hash, size_t Offset);
void finalizeContents();
size_t getCapacity() { return Table.size(); }
GdbSymbol *getSymbol(size_t I) { return Table[I]; }
private:
void expand();
GdbSymbol **findSlot(uint32_t Hash, size_t Offset);
llvm::BumpPtrAllocator Alloc;
llvm::DenseMap<size_t, GdbSymbol *> Map;
std::vector<GdbSymbol *> Table;
// Size keeps the amount of filled entries in Table.
size_t Size = 0;
// Initial size must be a power of 2.
static const int32_t InitialSize = 1024;
};
} // namespace elf

View file

@ -77,7 +77,6 @@
#include "Config.h"
#include "SymbolTable.h"
#include "Threads.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ELF.h"
@ -102,11 +101,11 @@ private:
bool constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB);
template <class RelTy>
bool variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
const InputSection<ELFT> *B, ArrayRef<RelTy> RelsB);
bool variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
const InputSection *B, ArrayRef<RelTy> RelsB);
bool equalsConstant(const InputSection<ELFT> *A, const InputSection<ELFT> *B);
bool equalsVariable(const InputSection<ELFT> *A, const InputSection<ELFT> *B);
bool equalsConstant(const InputSection *A, const InputSection *B);
bool equalsVariable(const InputSection *A, const InputSection *B);
size_t findBoundary(size_t Begin, size_t End);
@ -115,7 +114,7 @@ private:
void forEachClass(std::function<void(size_t, size_t)> Fn);
std::vector<InputSection<ELFT> *> Sections;
std::vector<InputSection *> Sections;
// We repeat the main loop while `Repeat` is true.
std::atomic<bool> Repeat;
@ -154,17 +153,17 @@ private:
// Returns a hash value for S. Note that the information about
// relocation targets is not included in the hash value.
template <class ELFT> static uint32_t getHash(InputSection<ELFT> *S) {
template <class ELFT> static uint32_t getHash(InputSection *S) {
return hash_combine(S->Flags, S->getSize(), S->NumRelocations);
}
// Returns true if section S is subject of ICF.
template <class ELFT> static bool isEligible(InputSection<ELFT> *S) {
static bool isEligible(InputSection *S) {
// .init and .fini contains instructions that must be executed to
// initialize and finalize the process. They cannot and should not
// be merged.
return S->Live && (S->Flags & SHF_ALLOC) && !(S->Flags & SHF_WRITE) &&
S->Name != ".init" && S->Name != ".fini";
return S->Live && (S->Flags & SHF_ALLOC) && (S->Flags & SHF_EXECINSTR) &&
!(S->Flags & SHF_WRITE) && S->Name != ".init" && S->Name != ".fini";
}
// Split an equivalence class into smaller classes.
@ -181,17 +180,17 @@ void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) {
while (Begin < End) {
// Divide [Begin, End) into two. Let Mid be the start index of the
// second group.
auto Bound = std::stable_partition(
Sections.begin() + Begin + 1, Sections.begin() + End,
[&](InputSection<ELFT> *S) {
if (Constant)
return equalsConstant(Sections[Begin], S);
return equalsVariable(Sections[Begin], S);
});
auto Bound =
std::stable_partition(Sections.begin() + Begin + 1,
Sections.begin() + End, [&](InputSection *S) {
if (Constant)
return equalsConstant(Sections[Begin], S);
return equalsVariable(Sections[Begin], S);
});
size_t Mid = Bound - Sections.begin();
// Now we split [Begin, End) into [Begin, Mid) and [Mid, End) by
// updating the sections in [Begin, End). We use Mid as an equivalence
// updating the sections in [Begin, Mid). We use Mid as an equivalence
// class ID because every group ends with a unique index.
for (size_t I = Begin; I < Mid; ++I)
Sections[I]->Class[Next] = Mid;
@ -210,7 +209,7 @@ template <class RelTy>
bool ICF<ELFT>::constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
auto Eq = [](const RelTy &A, const RelTy &B) {
return A.r_offset == B.r_offset &&
A.getType(Config->Mips64EL) == B.getType(Config->Mips64EL) &&
A.getType(Config->IsMips64EL) == B.getType(Config->IsMips64EL) &&
getAddend<ELFT>(A) == getAddend<ELFT>(B);
};
@ -221,40 +220,43 @@ bool ICF<ELFT>::constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
// Compare "non-moving" part of two InputSections, namely everything
// except relocation targets.
template <class ELFT>
bool ICF<ELFT>::equalsConstant(const InputSection<ELFT> *A,
const InputSection<ELFT> *B) {
bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) {
if (A->NumRelocations != B->NumRelocations || A->Flags != B->Flags ||
A->getSize() != B->getSize() || A->Data != B->Data)
return false;
if (A->AreRelocsRela)
return constantEq(A->relas(), B->relas());
return constantEq(A->rels(), B->rels());
return constantEq(A->template relas<ELFT>(), B->template relas<ELFT>());
return constantEq(A->template rels<ELFT>(), B->template rels<ELFT>());
}
// Compare two lists of relocations. Returns true if all pairs of
// relocations point to the same section in terms of ICF.
template <class ELFT>
template <class RelTy>
bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
const InputSection<ELFT> *B, ArrayRef<RelTy> RelsB) {
bool ICF<ELFT>::variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
const InputSection *B, ArrayRef<RelTy> RelsB) {
auto Eq = [&](const RelTy &RA, const RelTy &RB) {
// The two sections must be identical.
SymbolBody &SA = A->getFile()->getRelocTargetSym(RA);
SymbolBody &SB = B->getFile()->getRelocTargetSym(RB);
SymbolBody &SA = A->template getFile<ELFT>()->getRelocTargetSym(RA);
SymbolBody &SB = B->template getFile<ELFT>()->getRelocTargetSym(RB);
if (&SA == &SB)
return true;
// Or, the two sections must be in the same equivalence class.
auto *DA = dyn_cast<DefinedRegular<ELFT>>(&SA);
auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB);
auto *DA = dyn_cast<DefinedRegular>(&SA);
auto *DB = dyn_cast<DefinedRegular>(&SB);
if (!DA || !DB)
return false;
if (DA->Value != DB->Value)
return false;
auto *X = dyn_cast<InputSection<ELFT>>(DA->Section);
auto *Y = dyn_cast<InputSection<ELFT>>(DB->Section);
// Either both symbols must be absolute...
if (!DA->Section || !DB->Section)
return !DA->Section && !DB->Section;
// Or the two sections must be in the same equivalence class.
auto *X = dyn_cast<InputSection>(DA->Section);
auto *Y = dyn_cast<InputSection>(DB->Section);
if (!X || !Y)
return false;
@ -271,11 +273,11 @@ bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
// Compare "moving" part of two InputSections, namely relocation targets.
template <class ELFT>
bool ICF<ELFT>::equalsVariable(const InputSection<ELFT> *A,
const InputSection<ELFT> *B) {
bool ICF<ELFT>::equalsVariable(const InputSection *A, const InputSection *B) {
if (A->AreRelocsRela)
return variableEq(A, A->relas(), B, B->relas());
return variableEq(A, A->rels(), B, B->rels());
return variableEq(A, A->template relas<ELFT>(), B,
B->template relas<ELFT>());
return variableEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>());
}
template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
@ -291,7 +293,7 @@ template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
// groups of sections, grouped by the class.
//
// This function calls Fn on every group that starts within [Begin, End).
// Note that a group must starts in that range but doesn't necessarily
// Note that a group must start in that range but doesn't necessarily
// have to end before End.
template <class ELFT>
void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
@ -323,8 +325,9 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
// Split sections into 256 shards and call Fn in parallel.
size_t NumShards = 256;
size_t Step = Sections.size() / NumShards;
forLoop(0, NumShards,
[&](size_t I) { forEachClassRange(I * Step, (I + 1) * Step, Fn); });
parallelFor(0, NumShards, [&](size_t I) {
forEachClassRange(I * Step, (I + 1) * Step, Fn);
});
forEachClassRange(Step * NumShards, Sections.size(), Fn);
++Cnt;
}
@ -332,20 +335,20 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
// The main function of ICF.
template <class ELFT> void ICF<ELFT>::run() {
// Collect sections to merge.
for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections)
if (auto *S = dyn_cast<InputSection<ELFT>>(Sec))
for (InputSectionBase *Sec : InputSections)
if (auto *S = dyn_cast<InputSection>(Sec))
if (isEligible(S))
Sections.push_back(S);
// Initially, we use hash values to partition sections.
for (InputSection<ELFT> *S : Sections)
for (InputSection *S : Sections)
// Set MSB to 1 to avoid collisions with non-hash IDs.
S->Class[0] = getHash(S) | (1 << 31);
S->Class[0] = getHash<ELFT>(S) | (1 << 31);
// From now on, sections in Sections vector are ordered so that sections
// in the same equivalence class are consecutive in the vector.
std::stable_sort(Sections.begin(), Sections.end(),
[](InputSection<ELFT> *A, InputSection<ELFT> *B) {
[](InputSection *A, InputSection *B) {
return A->Class[0] < B->Class[0];
});
@ -372,6 +375,15 @@ template <class ELFT> void ICF<ELFT>::run() {
Sections[Begin]->replace(Sections[I]);
}
});
// Mark ARM Exception Index table sections that refer to folded code
// sections as not live. These sections have an implict dependency
// via the link order dependency.
if (Config->EMachine == EM_ARM)
for (InputSectionBase *Sec : InputSections)
if (auto *S = dyn_cast<InputSection>(Sec))
if (S->Flags & SHF_LINK_ORDER)
S->Live = S->getLinkOrderDep()->Live;
}
// ICF entry point function.

View file

@ -16,7 +16,6 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/IR/LLVMContext.h"
@ -38,6 +37,8 @@ using namespace lld::elf;
TarWriter *elf::Tar;
InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
namespace {
// In ELF object file all section addresses are zero. If we have multiple
// .text sections (when using -ffunction-section or comdat group) then
@ -56,14 +57,13 @@ public:
}
Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
if (Config->Verbose)
outs() << Path << "\n";
log(Path);
auto MBOrErr = MemoryBuffer::getFile(Path);
if (auto EC = MBOrErr.getError()) {
error(EC, "cannot open " + Path);
error("cannot open " + Path + ": " + EC.message());
return None;
}
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
MemoryBufferRef MBRef = MB->getMemBufferRef();
make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
@ -75,15 +75,13 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
std::unique_ptr<object::ObjectFile> Obj =
check(object::ObjectFile::createObjectFile(this->MB),
"createObjectFile failed");
check(object::ObjectFile::createObjectFile(this->MB), toString(this));
ObjectInfo ObjInfo;
DWARFContextInMemory Dwarf(*Obj, &ObjInfo);
DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs));
DataExtractor LineData(Dwarf.getLineSection().Data,
ELFT::TargetEndianness == support::little,
ELFT::Is64Bits ? 8 : 4);
DataExtractor LineData(Dwarf.getLineSection().Data, Config->IsLE,
Config->Wordsize);
// The second parameter is offset in .debug_line section
// for compilation unit (CU) of interest. We have only one
@ -94,34 +92,49 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
// Returns source line information for a given offset
// using DWARF debug info.
template <class ELFT>
std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase<ELFT> *S,
uintX_t Offset) {
Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S,
uint64_t Offset) {
if (!DwarfLine)
initializeDwarfLine();
// The offset to CU is 0.
const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
if (!Tbl)
return "";
return None;
// Use fake address calcuated by adding section file offset and offset in
// section. See comments for ObjectInfo class.
DILineInfo Info;
Tbl->getFileLineInfoForAddress(
S->Offset + Offset, nullptr,
S->getOffsetInFile() + Offset, nullptr,
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info);
if (Info.Line == 0)
return "";
return Info.FileName + ":" + std::to_string(Info.Line);
return None;
return Info;
}
// Returns source line information for a given offset
// using DWARF debug info.
template <class ELFT>
std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S,
uint64_t Offset) {
if (Optional<DILineInfo> Info = getDILineInfo(S, Offset))
return Info->FileName + ":" + std::to_string(Info->Line);
return "";
}
// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
std::string lld::toString(const InputFile *F) {
if (!F)
return "(internal)";
if (!F->ArchiveName.empty())
return (F->ArchiveName + "(" + F->getName() + ")").str();
return F->getName();
if (F->ToStringCache.empty()) {
if (F->ArchiveName.empty())
F->ToStringCache = F->getName();
else
F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str();
}
return F->ToStringCache;
}
template <class ELFT> static ELFKind getELFKind() {
@ -144,29 +157,26 @@ typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalSymbols() {
template <class ELFT>
uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX));
return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX),
toString(this));
}
template <class ELFT>
void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr *Symtab) {
FirstNonLocal = Symtab->sh_info;
Symbols = check(getObj().symbols(Symtab));
Symbols = check(getObj().symbols(Symtab), toString(this));
if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size())
fatal(toString(this) + ": invalid sh_info in symbol table");
StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections));
StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections),
toString(this));
}
template <class ELFT>
elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
: ELFFileBase<ELFT>(Base::ObjectKind, M) {}
template <class ELFT>
ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getNonLocalSymbols() {
return makeArrayRef(this->SymbolBodies).slice(this->FirstNonLocal);
}
template <class ELFT>
ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() {
if (this->SymbolBodies.empty())
@ -196,19 +206,20 @@ StringRef
elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec) {
if (this->Symbols.empty())
this->initSymtab(Sections,
check(object::getSection<ELFT>(Sections, Sec.sh_link)));
const Elf_Sym *Sym =
check(object::getSymbol<ELFT>(this->Symbols, Sec.sh_info));
return check(Sym->getName(this->StringTable));
this->initSymtab(
Sections,
check(object::getSection<ELFT>(Sections, Sec.sh_link), toString(this)));
const Elf_Sym *Sym = check(
object::getSymbol<ELFT>(this->Symbols, Sec.sh_info), toString(this));
return check(Sym->getName(this->StringTable), toString(this));
}
template <class ELFT>
ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word>
elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
const ELFFile<ELFT> &Obj = this->getObj();
ArrayRef<Elf_Word> Entries =
check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec));
ArrayRef<Elf_Word> Entries = check(
Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), toString(this));
if (Entries.empty() || Entries[0] != GRP_COMDAT)
fatal(toString(this) + ": unsupported SHT_GROUP format");
return Entries.slice(1);
@ -242,14 +253,14 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
// the section does not hold a table of fixed-size entries". We know
// that Rust 1.13 produces a string mergeable section with a zero
// sh_entsize. Here we just accept it rather than being picky about it.
uintX_t EntSize = Sec.sh_entsize;
uint64_t EntSize = Sec.sh_entsize;
if (EntSize == 0)
return false;
if (Sec.sh_size % EntSize)
fatal(toString(this) +
": SHF_MERGE section size must be a multiple of sh_entsize");
uintX_t Flags = Sec.sh_flags;
uint64_t Flags = Sec.sh_flags;
if (!(Flags & SHF_MERGE))
return false;
if (Flags & SHF_WRITE)
@ -270,76 +281,79 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
template <class ELFT>
void elf::ObjectFile<ELFT>::initializeSections(
DenseSet<CachedHashStringRef> &ComdatGroups) {
ArrayRef<Elf_Shdr> ObjSections = check(this->getObj().sections());
ArrayRef<Elf_Shdr> ObjSections =
check(this->getObj().sections(), toString(this));
const ELFFile<ELFT> &Obj = this->getObj();
uint64_t Size = ObjSections.size();
Sections.resize(Size);
this->Sections.resize(Size);
unsigned I = -1;
StringRef SectionStringTable = check(Obj.getSectionStringTable(ObjSections));
StringRef SectionStringTable =
check(Obj.getSectionStringTable(ObjSections), toString(this));
for (const Elf_Shdr &Sec : ObjSections) {
++I;
if (Sections[I] == &InputSection<ELFT>::Discarded)
if (this->Sections[I] == &InputSection::Discarded)
continue;
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) {
Sections[I] = &InputSection<ELFT>::Discarded;
this->Sections[I] = &InputSection::Discarded;
continue;
}
switch (Sec.sh_type) {
case SHT_GROUP:
Sections[I] = &InputSection<ELFT>::Discarded;
if (ComdatGroups.insert(CachedHashStringRef(
getShtGroupSignature(ObjSections, Sec)))
this->Sections[I] = &InputSection::Discarded;
if (ComdatGroups
.insert(
CachedHashStringRef(getShtGroupSignature(ObjSections, Sec)))
.second)
continue;
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
if (SecIndex >= Size)
fatal(toString(this) + ": invalid section index in group: " +
Twine(SecIndex));
Sections[SecIndex] = &InputSection<ELFT>::Discarded;
fatal(toString(this) +
": invalid section index in group: " + Twine(SecIndex));
this->Sections[SecIndex] = &InputSection::Discarded;
}
break;
case SHT_SYMTAB:
this->initSymtab(ObjSections, &Sec);
break;
case SHT_SYMTAB_SHNDX:
this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, ObjSections));
this->SymtabSHNDX =
check(Obj.getSHNDXTable(Sec, ObjSections), toString(this));
break;
case SHT_STRTAB:
case SHT_NULL:
break;
default:
Sections[I] = createInputSection(Sec, SectionStringTable);
this->Sections[I] = createInputSection(Sec, SectionStringTable);
}
// .ARM.exidx sections have a reverse dependency on the InputSection they
// have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
if (Sec.sh_flags & SHF_LINK_ORDER) {
if (Sec.sh_link >= Sections.size())
if (Sec.sh_link >= this->Sections.size())
fatal(toString(this) + ": invalid sh_link index: " +
Twine(Sec.sh_link));
auto *IS = cast<InputSection<ELFT>>(Sections[Sec.sh_link]);
IS->DependentSection = Sections[I];
this->Sections[Sec.sh_link]->DependentSections.push_back(
this->Sections[I]);
}
}
}
template <class ELFT>
InputSectionBase<ELFT> *
elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
uint32_t Idx = Sec.sh_info;
if (Idx >= Sections.size())
if (Idx >= this->Sections.size())
fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx));
InputSectionBase<ELFT> *Target = Sections[Idx];
InputSectionBase *Target = this->Sections[Idx];
// Strictly speaking, a relocation section must be included in the
// group of the section it relocates. However, LLVM 3.3 and earlier
// would fail to do so, so we gracefully handle that case.
if (Target == &InputSection<ELFT>::Discarded)
if (Target == &InputSection::Discarded)
return nullptr;
if (!Target)
@ -348,11 +362,11 @@ elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
}
template <class ELFT>
InputSectionBase<ELFT> *
InputSectionBase *
elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
StringRef SectionStringTable) {
StringRef Name =
check(this->getObj().getSectionName(&Sec, SectionStringTable));
StringRef Name = check(
this->getObj().getSectionName(&Sec, SectionStringTable), toString(this));
switch (Sec.sh_type) {
case SHT_ARM_ATTRIBUTES:
@ -361,62 +375,91 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
// attribute section for dlopen to work.
// In a full implementation we would merge all attribute sections.
if (In<ELFT>::ARMAttributes == nullptr) {
In<ELFT>::ARMAttributes = make<InputSection<ELFT>>(this, &Sec, Name);
In<ELFT>::ARMAttributes = make<InputSection>(this, &Sec, Name);
return In<ELFT>::ARMAttributes;
}
return &InputSection<ELFT>::Discarded;
return &InputSection::Discarded;
case SHT_RELA:
case SHT_REL: {
// Find the relocation target section and associate this
// section with it. Target can be discarded, for example
// if it is a duplicated member of SHT_GROUP section, we
// do not create or proccess relocatable sections then.
InputSectionBase *Target = getRelocTarget(Sec);
if (!Target)
return nullptr;
// This section contains relocation information.
// If -r is given, we do not interpret or apply relocation
// but just copy relocation sections to output.
if (Config->Relocatable)
return make<InputSection<ELFT>>(this, &Sec, Name);
return make<InputSection>(this, &Sec, Name);
// Find the relocation target section and associate this
// section with it.
InputSectionBase<ELFT> *Target = getRelocTarget(Sec);
if (!Target)
return nullptr;
if (Target->FirstRelocation)
fatal(toString(this) +
": multiple relocation sections to one section are not supported");
if (!isa<InputSection<ELFT>>(Target) && !isa<EhInputSection<ELFT>>(Target))
if (isa<MergeInputSection>(Target))
fatal(toString(this) +
": relocations pointing to SHF_MERGE are not supported");
size_t NumRelocations;
if (Sec.sh_type == SHT_RELA) {
ArrayRef<Elf_Rela> Rels = check(this->getObj().relas(&Sec));
ArrayRef<Elf_Rela> Rels =
check(this->getObj().relas(&Sec), toString(this));
Target->FirstRelocation = Rels.begin();
NumRelocations = Rels.size();
Target->AreRelocsRela = true;
} else {
ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec));
ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec), toString(this));
Target->FirstRelocation = Rels.begin();
NumRelocations = Rels.size();
Target->AreRelocsRela = false;
}
assert(isUInt<31>(NumRelocations));
Target->NumRelocations = NumRelocations;
// Relocation sections processed by the linker are usually removed
// from the output, so returning `nullptr` for the normal case.
// However, if -emit-relocs is given, we need to leave them in the output.
// (Some post link analysis tools need this information.)
if (Config->EmitRelocs) {
InputSection *RelocSec = make<InputSection>(this, &Sec, Name);
// We will not emit relocation section if target was discarded.
Target->DependentSections.push_back(RelocSec);
return RelocSec;
}
return nullptr;
}
}
// .note.GNU-stack is a marker section to control the presence of
// PT_GNU_STACK segment in outputs. Since the presence of the segment
// is controlled only by the command line option (-z execstack) in LLD,
// .note.GNU-stack is ignored.
// The GNU linker uses .note.GNU-stack section as a marker indicating
// that the code in the object file does not expect that the stack is
// executable (in terms of NX bit). If all input files have the marker,
// the GNU linker adds a PT_GNU_STACK segment to tells the loader to
// make the stack non-executable. Most object files have this section as
// of 2017.
//
// But making the stack non-executable is a norm today for security
// reasons. Failure to do so may result in a serious security issue.
// Therefore, we make LLD always add PT_GNU_STACK unless it is
// explicitly told to do otherwise (by -z execstack). Because the stack
// executable-ness is controlled solely by command line options,
// .note.GNU-stack sections are simply ignored.
if (Name == ".note.GNU-stack")
return &InputSection<ELFT>::Discarded;
return &InputSection::Discarded;
// Split stacks is a feature to support a discontiguous stack. At least
// as of 2017, it seems that the feature is not being used widely.
// Only GNU gold supports that. We don't. For the details about that,
// see https://gcc.gnu.org/wiki/SplitStacks
if (Name == ".note.GNU-split-stack") {
error("objects using splitstacks are not supported");
return &InputSection<ELFT>::Discarded;
error(toString(this) +
": object file compiled with -fsplit-stack is not supported");
return &InputSection::Discarded;
}
if (Config->Strip != StripPolicy::None && Name.startswith(".debug"))
return &InputSection<ELFT>::Discarded;
return &InputSection::Discarded;
// The linkonce feature is a sort of proto-comdat. Some glibc i386 object
// files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce
@ -424,17 +467,17 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
// FIXME: This is glibc PR20543, we should remove this hack once that has been
// fixed for a while.
if (Name.startswith(".gnu.linkonce."))
return &InputSection<ELFT>::Discarded;
return &InputSection::Discarded;
// The linker merges EH (exception handling) frames and creates a
// .eh_frame_hdr section for runtime. So we handle them with a special
// class. For relocatable outputs, they are just passed through.
if (Name == ".eh_frame" && !Config->Relocatable)
return make<EhInputSection<ELFT>>(this, &Sec, Name);
return make<EhInputSection>(this, &Sec, Name);
if (shouldMerge(Sec))
return make<MergeInputSection<ELFT>>(this, &Sec, Name);
return make<InputSection<ELFT>>(this, &Sec, Name);
return make<MergeInputSection>(this, &Sec, Name);
return make<InputSection>(this, &Sec, Name);
}
template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
@ -444,12 +487,11 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
}
template <class ELFT>
InputSectionBase<ELFT> *
elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
InputSectionBase *elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
uint32_t Index = this->getSectionIndex(Sym);
if (Index >= Sections.size())
if (Index >= this->Sections.size())
fatal(toString(this) + ": invalid section index: " + Twine(Index));
InputSectionBase<ELFT> *S = Sections[Index];
InputSectionBase *S = this->Sections[Index];
// We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could
// generate broken objects. STT_SECTION/STT_NOTYPE symbols can be
@ -463,7 +505,7 @@ elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
fatal(toString(this) + ": invalid section index: " + Twine(Index));
}
if (S == &InputSection<ELFT>::Discarded)
if (S == &InputSection::Discarded)
return S;
return S->Repl;
}
@ -471,30 +513,29 @@ elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
template <class ELFT>
SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
int Binding = Sym->getBinding();
InputSectionBase<ELFT> *Sec = getSection(*Sym);
InputSectionBase *Sec = getSection(*Sym);
uint8_t StOther = Sym->st_other;
uint8_t Type = Sym->getType();
uintX_t Value = Sym->st_value;
uintX_t Size = Sym->st_size;
uint64_t Value = Sym->st_value;
uint64_t Size = Sym->st_size;
if (Binding == STB_LOCAL) {
if (Sym->getType() == STT_FILE)
SourceFile = check(Sym->getName(this->StringTable));
SourceFile = check(Sym->getName(this->StringTable), toString(this));
if (this->StringTable.size() <= Sym->st_name)
fatal(toString(this) + ": invalid symbol name offset");
StringRefZ Name = this->StringTable.data() + Sym->st_name;
if (Sym->st_shndx == SHN_UNDEF)
return new (BAlloc)
Undefined<ELFT>(Name, /*IsLocal=*/true, StOther, Type, this);
return make<Undefined>(Name, /*IsLocal=*/true, StOther, Type, this);
return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther,
Type, Value, Size, Sec, this);
return make<DefinedRegular>(Name, /*IsLocal=*/true, StOther, Type, Value,
Size, Sec, this);
}
StringRef Name = check(Sym->getName(this->StringTable));
StringRef Name = check(Sym->getName(this->StringTable), toString(this));
switch (Sym->st_shndx) {
case SHN_UNDEF:
@ -517,7 +558,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
case STB_GLOBAL:
case STB_WEAK:
case STB_GNU_UNIQUE:
if (Sec == &InputSection<ELFT>::Discarded)
if (Sec == &InputSection::Discarded)
return elf::Symtab<ELFT>::X
->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type,
/*CanOmitFromDynSym=*/false, this)
@ -533,27 +574,34 @@ template <class ELFT> void ArchiveFile::parse() {
MB.getBufferIdentifier() + ": failed to parse archive");
// Read the symbol table to construct Lazy objects.
for (const Archive::Symbol &Sym : File->symbols())
for (const Archive::Symbol &Sym : File->symbols()) {
Symtab<ELFT>::X->addLazyArchive(this, Sym);
}
if (File->symbols().begin() == File->symbols().end())
Config->ArchiveWithoutSymbolsSeen = true;
}
// Returns a buffer pointing to a member file containing a given symbol.
std::pair<MemoryBufferRef, uint64_t>
ArchiveFile::getMember(const Archive::Symbol *Sym) {
Archive::Child C =
check(Sym->getMember(),
"could not get the member for symbol " + Sym->getName());
check(Sym->getMember(), toString(this) +
": could not get the member for symbol " +
Sym->getName());
if (!Seen.insert(C.getChildOffset()).second)
return {MemoryBufferRef(), 0};
MemoryBufferRef Ret =
check(C.getMemoryBufferRef(),
"could not get the buffer for the member defining symbol " +
toString(this) +
": could not get the buffer for the member defining symbol " +
Sym->getName());
if (C.getParent()->isThin() && Tar)
Tar->append(relativeToRoot(check(C.getFullName())), Ret.getBuffer());
Tar->append(relativeToRoot(check(C.getFullName(), toString(this))),
Ret.getBuffer());
if (C.getParent()->isThin())
return {Ret, 0};
return {Ret, C.getChildOffset()};
@ -567,16 +615,24 @@ template <class ELFT>
const typename ELFT::Shdr *
SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
return check(
this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX));
this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX),
toString(this));
}
template <class ELFT> StringRef SharedFile<ELFT>::getSoName() const {
if (SoName.empty())
return this->DefaultSoName;
return SoName;
}
// Partially parse the shared object file so that we can call
// getSoName on this object.
template <class ELFT> void SharedFile<ELFT>::parseSoName() {
const Elf_Shdr *DynamicSec = nullptr;
const ELFFile<ELFT> Obj = this->getObj();
ArrayRef<Elf_Shdr> Sections = check(Obj.sections());
ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
// Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d.
for (const Elf_Shdr &Sec : Sections) {
switch (Sec.sh_type) {
default:
@ -588,7 +644,8 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
DynamicSec = &Sec;
break;
case SHT_SYMTAB_SHNDX:
this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, Sections));
this->SymtabSHNDX =
check(Obj.getSHNDXTable(Sec, Sections), toString(this));
break;
case SHT_GNU_versym:
this->VersymSec = &Sec;
@ -602,20 +659,15 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
if (this->VersymSec && this->Symbols.empty())
error("SHT_GNU_versym should be associated with symbol table");
// DSOs are identified by soname, and they usually contain
// DT_SONAME tag in their header. But if they are missing,
// filenames are used as default sonames.
SoName = sys::path::filename(this->getName());
// Search for a DT_SONAME tag to initialize this->SoName.
if (!DynamicSec)
return;
ArrayRef<Elf_Dyn> Arr =
check(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec),
toString(this) + ": getSectionContentsAsArray failed");
toString(this));
for (const Elf_Dyn &Dyn : Arr) {
if (Dyn.d_tag == DT_SONAME) {
uintX_t Val = Dyn.getVal();
uint64_t Val = Dyn.getVal();
if (Val >= this->StringTable.size())
fatal(toString(this) + ": invalid DT_SONAME entry");
SoName = StringRef(this->StringTable.data() + Val);
@ -681,7 +733,7 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
bool Hidden = VersymIndex & VERSYM_HIDDEN;
VersymIndex = VersymIndex & ~VERSYM_HIDDEN;
StringRef Name = check(Sym.getName(this->StringTable));
StringRef Name = check(Sym.getName(this->StringTable), toString(this));
if (Sym.isUndefined()) {
Undefs.push_back(Name);
continue;
@ -707,19 +759,18 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
}
}
static ELFKind getBitcodeELFKind(MemoryBufferRef MB) {
Triple T(check(getBitcodeTargetTriple(MB)));
static ELFKind getBitcodeELFKind(const Triple &T) {
if (T.isLittleEndian())
return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind;
return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind;
}
static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) {
Triple T(check(getBitcodeTargetTriple(MB)));
static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
switch (T.getArch()) {
case Triple::aarch64:
return EM_AARCH64;
case Triple::arm:
case Triple::thumb:
return EM_ARM;
case Triple::mips:
case Triple::mipsel:
@ -735,14 +786,32 @@ static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) {
case Triple::x86_64:
return EM_X86_64;
default:
fatal(MB.getBufferIdentifier() +
": could not infer e_machine from bitcode target triple " + T.str());
fatal(Path + ": could not infer e_machine from bitcode target triple " +
T.str());
}
}
BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) {
EKind = getBitcodeELFKind(MB);
EMachine = getBitcodeMachineKind(MB);
BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
uint64_t OffsetInArchive)
: InputFile(BitcodeKind, MB) {
this->ArchiveName = ArchiveName;
// Here we pass a new MemoryBufferRef which is identified by ArchiveName
// (the fully resolved path of the archive) + member name + offset of the
// member in the archive.
// ThinLTO uses the MemoryBufferRef identifier to access its internal
// data structures and if two archives define two members with the same name,
// this causes a collision which result in only one of the objects being
// taken into consideration at LTO time (which very likely causes undefined
// symbols later in the link stage).
MemoryBufferRef MBRef(MB.getBuffer(),
Saver.save(ArchiveName + MB.getBufferIdentifier() +
utostr(OffsetInArchive)));
Obj = check(lto::InputFile::create(MBRef), toString(this));
Triple T(Obj->getTargetTriple());
EKind = getBitcodeELFKind(T);
EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T);
}
static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
@ -762,25 +831,24 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
const lto::InputFile::Symbol &ObjSym,
BitcodeFile *F) {
StringRef NameRef = Saver.save(ObjSym.getName());
uint32_t Flags = ObjSym.getFlags();
uint32_t Binding = (Flags & BasicSymbolRef::SF_Weak) ? STB_WEAK : STB_GLOBAL;
uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL;
uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
uint8_t Visibility = mapVisibility(ObjSym.getVisibility());
bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable();
int C = check(ObjSym.getComdatIndex());
int C = ObjSym.getComdatIndex();
if (C != -1 && !KeptComdats[C])
return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
Visibility, Type, CanOmitFromDynSym,
F);
if (Flags & BasicSymbolRef::SF_Undefined)
if (ObjSym.isUndefined())
return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
Visibility, Type, CanOmitFromDynSym,
F);
if (Flags & BasicSymbolRef::SF_Common)
if (ObjSym.isCommon())
return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(),
ObjSym.getCommonAlignment(), Binding,
Visibility, STT_OBJECT, F);
@ -791,24 +859,9 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
template <class ELFT>
void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
// Here we pass a new MemoryBufferRef which is identified by ArchiveName
// (the fully resolved path of the archive) + member name + offset of the
// member in the archive.
// ThinLTO uses the MemoryBufferRef identifier to access its internal
// data structures and if two archives define two members with the same name,
// this causes a collision which result in only one of the objects being
// taken into consideration at LTO time (which very likely causes undefined
// symbols later in the link stage).
Obj = check(lto::InputFile::create(MemoryBufferRef(
MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() +
utostr(OffsetInArchive)))));
std::vector<bool> KeptComdats;
for (StringRef S : Obj->getComdatTable()) {
StringRef N = Saver.save(S);
KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(N)).second);
}
for (StringRef S : Obj->getComdatTable())
KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second);
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this));
@ -857,8 +910,8 @@ template <class ELFT> void BinaryFile::parse() {
StringRef EndName = Saver.save(Twine(Filename) + "_end");
StringRef SizeName = Saver.save(Twine(Filename) + "_size");
auto *Section = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
8, Data, ".data");
auto *Section =
make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data");
Sections.push_back(Section);
elf::Symtab<ELFT>::X->addRegular(StartName, STV_DEFAULT, STT_OBJECT, 0, 0,
@ -878,10 +931,10 @@ static bool isBitcode(MemoryBufferRef MB) {
InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
uint64_t OffsetInArchive) {
InputFile *F =
isBitcode(MB) ? make<BitcodeFile>(MB) : createELFFile<ObjectFile>(MB);
InputFile *F = isBitcode(MB)
? make<BitcodeFile>(MB, ArchiveName, OffsetInArchive)
: createELFFile<ObjectFile>(MB);
F->ArchiveName = ArchiveName;
F->OffsetInArchive = OffsetInArchive;
return F;
}
@ -907,27 +960,31 @@ template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
typedef typename ELFT::SymRange Elf_Sym_Range;
const ELFFile<ELFT> Obj(this->MB.getBuffer());
ArrayRef<Elf_Shdr> Sections = check(Obj.sections());
ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
for (const Elf_Shdr &Sec : Sections) {
if (Sec.sh_type != SHT_SYMTAB)
continue;
Elf_Sym_Range Syms = check(Obj.symbols(&Sec));
Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this));
uint32_t FirstNonLocal = Sec.sh_info;
StringRef StringTable = check(Obj.getStringTableForSymtab(Sec, Sections));
StringRef StringTable =
check(Obj.getStringTableForSymtab(Sec, Sections), toString(this));
std::vector<StringRef> V;
for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
if (Sym.st_shndx != SHN_UNDEF)
V.push_back(check(Sym.getName(StringTable)));
V.push_back(check(Sym.getName(StringTable), toString(this)));
return V;
}
return {};
}
std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
std::unique_ptr<lto::InputFile> Obj = check(lto::InputFile::create(this->MB));
std::unique_ptr<lto::InputFile> Obj =
check(lto::InputFile::create(this->MB), toString(this));
std::vector<StringRef> V;
for (const lto::InputFile::Symbol &Sym : Obj->symbols())
if (!(Sym.getFlags() & BasicSymbolRef::SF_Undefined))
if (!Sym.isUndefined())
V.push_back(Saver.save(Sym.getName()));
return V;
}

View file

@ -30,6 +30,7 @@
namespace llvm {
class DWARFDebugLine;
class TarWriter;
struct DILineInfo;
namespace lto {
class InputFile;
}
@ -74,25 +75,34 @@ public:
StringRef getName() const { return MB.getBufferIdentifier(); }
MemoryBufferRef MB;
// Returns sections. It is a runtime error to call this function
// on files that don't have the notion of sections.
ArrayRef<InputSectionBase *> getSections() const {
assert(FileKind == ObjectKind || FileKind == BinaryKind);
return Sections;
}
// Filename of .a which contained this file. If this file was
// not in an archive file, it is the empty string. We use this
// string for creating error messages.
StringRef ArchiveName;
// If this file is in an archive, the member contains the offset of
// the file in the archive. Otherwise, it's just zero. We store this
// field so that we can pass it to lib/LTO in order to disambiguate
// between objects.
uint64_t OffsetInArchive;
// If this is an architecture-specific file, the following members
// have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
ELFKind EKind = ELFNoneKind;
uint16_t EMachine = llvm::ELF::EM_NONE;
uint8_t OSABI = 0;
// For SharedKind inputs, the string to use in DT_NEEDED when the library
// has no soname.
std::string DefaultSoName;
// Cache for toString(). Only toString() should use this member.
mutable std::string ToStringCache;
protected:
InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
InputFile(Kind K, MemoryBufferRef M);
std::vector<InputSectionBase *> Sections;
private:
const Kind FileKind;
@ -136,9 +146,7 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::Word Elf_Word;
typedef typename ELFT::uint uintX_t;
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec);
@ -151,13 +159,11 @@ public:
ArrayRef<SymbolBody *> getSymbols();
ArrayRef<SymbolBody *> getLocalSymbols();
ArrayRef<SymbolBody *> getNonLocalSymbols();
explicit ObjectFile(MemoryBufferRef M);
void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
InputSectionBase *getSection(const Elf_Sym &Sym) const;
SymbolBody &getSymbolBody(uint32_t SymbolIndex) const {
if (SymbolIndex >= SymbolBodies.size())
@ -167,13 +173,14 @@ public:
template <typename RelT>
SymbolBody &getRelocTargetSym(const RelT &Rel) const {
uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL);
uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
return getSymbolBody(SymIndex);
}
// Returns source line information for a given offset.
// If no information is available, returns "".
std::string getLineInfo(InputSectionBase<ELFT> *S, uintX_t Offset);
std::string getLineInfo(InputSectionBase *S, uint64_t Offset);
llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
// MIPS GP0 value defined by this file. This value represents the gp value
// used to create the relocatable object and required to support
@ -190,16 +197,13 @@ private:
initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
void initializeSymbols();
void initializeDwarfLine();
InputSectionBase<ELFT> *getRelocTarget(const Elf_Shdr &Sec);
InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec,
StringRef SectionStringTable);
InputSectionBase *getRelocTarget(const Elf_Shdr &Sec);
InputSectionBase *createInputSection(const Elf_Shdr &Sec,
StringRef SectionStringTable);
bool shouldMerge(const Elf_Shdr &Sec);
SymbolBody *createSymbolBody(const Elf_Sym *Sym);
// List of all sections defined by this file.
std::vector<InputSectionBase<ELFT> *> Sections;
// List of all symbols referenced or defined by this file.
std::vector<SymbolBody *> SymbolBodies;
@ -256,7 +260,8 @@ private:
class BitcodeFile : public InputFile {
public:
explicit BitcodeFile(MemoryBufferRef M);
BitcodeFile(MemoryBufferRef M, StringRef ArchiveName,
uint64_t OffsetInArchive);
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
template <class ELFT>
void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
@ -276,8 +281,6 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Versym Elf_Versym;
typedef typename ELFT::Word Elf_Word;
typedef typename ELFT::uint uintX_t;
std::vector<StringRef> Undefs;
StringRef SoName;
@ -285,7 +288,7 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
const Elf_Shdr *VerdefSec = nullptr;
public:
StringRef getSoName() const { return SoName; }
StringRef getSoName() const;
const Elf_Shdr *getSection(const Elf_Sym &Sym) const;
llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; }
@ -322,10 +325,6 @@ public:
explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == BinaryKind; }
template <class ELFT> void parse();
ArrayRef<InputSectionData *> getSections() const { return Sections; }
private:
std::vector<InputSectionData *> Sections;
};
InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "",

File diff suppressed because it is too large Load diff

View file

@ -27,97 +27,115 @@ class DefinedCommon;
class SymbolBody;
struct SectionPiece;
template <class ELFT> class DefinedRegular;
class DefinedRegular;
class SyntheticSection;
template <class ELFT> class EhFrameSection;
class MergeSyntheticSection;
template <class ELFT> class ObjectFile;
template <class ELFT> class OutputSection;
class OutputSectionBase;
class OutputSection;
// We need non-template input section class to store symbol layout
// in linker script parser structures, where we do not have ELFT
// template parameter. For each scripted output section symbol we
// store pointer to preceding InputSectionData object or nullptr,
// if symbol should be placed at the very beginning of the output
// section
class InputSectionData {
// This is the base class of all sections that lld handles. Some are sections in
// input files, some are sections in the produced output file and some exist
// just as a convenience for implementing special ways of combining some
// sections.
class SectionBase {
public:
enum Kind { Regular, EHFrame, Merge, Synthetic, };
enum Kind { Regular, EHFrame, Merge, Synthetic, Output };
Kind kind() const { return (Kind)SectionKind; }
StringRef Name;
unsigned SectionKind : 3;
// The next two bit fields are only used by InputSectionBase, but we
// put them here so the struct packs better.
// The garbage collector sets sections' Live bits.
// If GC is disabled, all sections are considered live by default.
InputSectionData(Kind SectionKind, StringRef Name, ArrayRef<uint8_t> Data,
bool Live)
: SectionKind(SectionKind), Live(Live), Assigned(false), Name(Name),
Data(Data) {}
unsigned Live : 1; // for garbage collection
unsigned Assigned : 1; // for linker script
private:
unsigned SectionKind : 3;
public:
Kind kind() const { return (Kind)SectionKind; }
unsigned Live : 1; // for garbage collection
unsigned Assigned : 1; // for linker script
uint32_t Alignment;
StringRef Name;
ArrayRef<uint8_t> Data;
template <typename T> llvm::ArrayRef<T> getDataAs() const {
size_t S = Data.size();
assert(S % sizeof(T) == 0);
return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
}
std::vector<Relocation> Relocations;
};
// This corresponds to a section of an input file.
template <class ELFT> class InputSectionBase : public InputSectionData {
protected:
typedef typename ELFT::Chdr Elf_Chdr;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::uint uintX_t;
// The file this section is from.
ObjectFile<ELFT> *File;
public:
// These corresponds to the fields in Elf_Shdr.
uintX_t Flags;
uintX_t Offset = 0;
uintX_t Entsize;
uint64_t Flags;
uint64_t Entsize;
uint32_t Type;
uint32_t Link;
uint32_t Info;
OutputSection *getOutputSection();
const OutputSection *getOutputSection() const {
return const_cast<SectionBase *>(this)->getOutputSection();
}
// Translate an offset in the input section to an offset in the output
// section.
uint64_t getOffset(uint64_t Offset) const;
uint64_t getOffset(const DefinedRegular &Sym) const;
protected:
SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags,
uint64_t Entsize, uint64_t Alignment, uint32_t Type,
uint32_t Info, uint32_t Link)
: Name(Name), SectionKind(SectionKind), Alignment(Alignment),
Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) {
Live = false;
Assigned = false;
}
};
// This corresponds to a section of an input file.
class InputSectionBase : public SectionBase {
public:
static bool classof(const SectionBase *S);
// The file this section is from.
InputFile *File;
ArrayRef<uint8_t> Data;
uint64_t getOffsetInFile() const;
static InputSectionBase Discarded;
InputSectionBase()
: InputSectionData(Regular, "", ArrayRef<uint8_t>(), false), Repl(this) {
: SectionBase(Regular, "", /*Flags*/ 0, /*Entsize*/ 0, /*Alignment*/ 0,
/*Type*/ 0,
/*Info*/ 0, /*Link*/ 0),
Repl(this) {
Live = false;
Assigned = false;
NumRelocations = 0;
AreRelocsRela = false;
}
InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
template <class ELFT>
InputSectionBase(ObjectFile<ELFT> *File, const typename ELFT::Shdr *Header,
StringRef Name, Kind SectionKind);
InputSectionBase(ObjectFile<ELFT> *File, uintX_t Flags, uint32_t Type,
uintX_t Entsize, uint32_t Link, uint32_t Info,
uintX_t Addralign, ArrayRef<uint8_t> Data, StringRef Name,
InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type,
uint64_t Entsize, uint32_t Link, uint32_t Info,
uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name,
Kind SectionKind);
OutputSectionBase *OutSec = nullptr;
OutputSection *OutSec = nullptr;
// Relocations that refer to this section.
const Elf_Rel *FirstRelocation = nullptr;
const void *FirstRelocation = nullptr;
unsigned NumRelocations : 31;
unsigned AreRelocsRela : 1;
ArrayRef<Elf_Rel> rels() const {
template <class ELFT> ArrayRef<typename ELFT::Rel> rels() const {
assert(!AreRelocsRela);
return llvm::makeArrayRef(FirstRelocation, NumRelocations);
return llvm::makeArrayRef(
static_cast<const typename ELFT::Rel *>(FirstRelocation),
NumRelocations);
}
ArrayRef<Elf_Rela> relas() const {
template <class ELFT> ArrayRef<typename ELFT::Rela> relas() const {
assert(AreRelocsRela);
return llvm::makeArrayRef(static_cast<const Elf_Rela *>(FirstRelocation),
NumRelocations);
return llvm::makeArrayRef(
static_cast<const typename ELFT::Rela *>(FirstRelocation),
NumRelocations);
}
// This pointer points to the "real" instance of this instance.
@ -125,25 +143,38 @@ public:
// Repl pointer of one section points to another section. So,
// if you need to get a pointer to this instance, do not use
// this but instead this->Repl.
InputSectionBase<ELFT> *Repl;
InputSectionBase *Repl;
// InputSections that are dependent on us (reverse dependency for GC)
llvm::TinyPtrVector<InputSectionBase *> DependentSections;
// Returns the size of this section (even if this is a common or BSS.)
size_t getSize() const;
ObjectFile<ELFT> *getFile() const { return File; }
llvm::object::ELFFile<ELFT> getObj() const { return File->getObj(); }
uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
template <class ELFT> ObjectFile<ELFT> *getFile() const;
template <class ELFT> llvm::object::ELFFile<ELFT> getObj() const {
return getFile<ELFT>()->getObj();
}
InputSectionBase *getLinkOrderDep() const;
// Translate an offset in the input section to an offset in the output
// section.
uintX_t getOffset(uintX_t Offset) const;
void uncompress();
// Returns a source location string. Used to construct an error message.
std::string getLocation(uintX_t Offset);
template <class ELFT> std::string getLocation(uint64_t Offset);
template <class ELFT> std::string getSrcMsg(uint64_t Offset);
template <class ELFT> std::string getObjMsg(uint64_t Offset);
void relocate(uint8_t *Buf, uint8_t *BufEnd);
template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd);
std::vector<Relocation> Relocations;
template <typename T> llvm::ArrayRef<T> getDataAs() const {
size_t S = Data.size();
assert(S % sizeof(T) == 0);
return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
}
};
// SectionPiece represents a piece of splittable section contents.
@ -162,26 +193,23 @@ static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t),
"SectionPiece is too big");
// This corresponds to a SHF_MERGE section of an input file.
template <class ELFT> class MergeInputSection : public InputSectionBase<ELFT> {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Shdr Elf_Shdr;
class MergeInputSection : public InputSectionBase {
public:
MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header,
template <class ELFT>
MergeInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
StringRef Name);
static bool classof(const InputSectionData *S);
static bool classof(const SectionBase *S);
void splitIntoPieces();
// Mark the piece at a given offset live. Used by GC.
void markLiveAt(uintX_t Offset) {
void markLiveAt(uint64_t Offset) {
assert(this->Flags & llvm::ELF::SHF_ALLOC);
LiveOffsets.insert(Offset);
}
// Translate an offset in the input section to an offset
// in the output section.
uintX_t getOffset(uintX_t Offset) const;
uint64_t getOffset(uint64_t Offset) const;
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
@ -203,8 +231,13 @@ public:
}
// Returns the SectionPiece at a given input section offset.
SectionPiece *getSectionPiece(uintX_t Offset);
const SectionPiece *getSectionPiece(uintX_t Offset) const;
SectionPiece *getSectionPiece(uint64_t Offset);
const SectionPiece *getSectionPiece(uint64_t Offset) const;
// MergeInputSections are aggregated to a synthetic input sections,
// and then added to an OutputSection. This pointer points to a
// synthetic MergeSyntheticSection which this section belongs to.
MergeSyntheticSection *MergeSec = nullptr;
private:
void splitStrings(ArrayRef<uint8_t> A, size_t Size);
@ -212,18 +245,18 @@ private:
std::vector<uint32_t> Hashes;
mutable llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap;
mutable std::once_flag InitOffsetMap;
llvm::DenseSet<uintX_t> LiveOffsets;
llvm::DenseSet<uint64_t> LiveOffsets;
};
struct EhSectionPiece : public SectionPiece {
EhSectionPiece(size_t Off, InputSectionData *ID, uint32_t Size,
EhSectionPiece(size_t Off, InputSectionBase *ID, uint32_t Size,
unsigned FirstRelocation)
: SectionPiece(Off, false), ID(ID), Size(Size),
FirstRelocation(FirstRelocation) {}
InputSectionData *ID;
InputSectionBase *ID;
uint32_t Size;
uint32_t size() const { return Size; }
@ -232,85 +265,65 @@ struct EhSectionPiece : public SectionPiece {
};
// This corresponds to a .eh_frame section of an input file.
template <class ELFT> class EhInputSection : public InputSectionBase<ELFT> {
class EhInputSection : public InputSectionBase {
public:
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::uint uintX_t;
EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name);
static bool classof(const InputSectionData *S);
void split();
template <class RelTy> void split(ArrayRef<RelTy> Rels);
template <class ELFT>
EhInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
StringRef Name);
static bool classof(const SectionBase *S);
template <class ELFT> void split();
template <class ELFT, class RelTy> void split(ArrayRef<RelTy> Rels);
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
std::vector<EhSectionPiece> Pieces;
SyntheticSection *EHSec = nullptr;
};
// This corresponds to a non SHF_MERGE section of an input file.
template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
typedef InputSectionBase<ELFT> Base;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::uint uintX_t;
typedef InputSectionData::Kind Kind;
// This is a section that is added directly to an output section
// instead of needing special combination via a synthetic section. This
// includes all input sections with the exceptions of SHF_MERGE and
// .eh_frame. It also includes the synthetic sections themselves.
class InputSection : public InputSectionBase {
public:
InputSection();
InputSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
ArrayRef<uint8_t> Data, StringRef Name,
Kind K = InputSectionData::Regular);
InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name);
static InputSection<ELFT> Discarded;
InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular);
template <class ELFT>
InputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
StringRef Name);
// Write this section to a mmap'ed file, assuming Buf is pointing to
// beginning of the output section.
void writeTo(uint8_t *Buf);
template <class ELFT> void writeTo(uint8_t *Buf);
// The offset from beginning of the output sections this section was assigned
// to. The writer sets a value.
uint64_t OutSecOff = 0;
// InputSection that is dependent on us (reverse dependency for GC)
InputSectionBase<ELFT> *DependentSection = nullptr;
static bool classof(const SectionBase *S);
static bool classof(const InputSectionData *S);
InputSectionBase *getRelocatedSection();
InputSectionBase<ELFT> *getRelocatedSection();
// Register thunk related to the symbol. When the section is written
// to a mmap'ed file, target is requested to write an actual thunk code.
// Now thunks is supported for MIPS and ARM target only.
void addThunk(const Thunk<ELFT> *T);
// The offset of synthetic thunk code from beginning of this section.
uint64_t getThunkOff() const;
// Size of chunk with thunks code.
uint64_t getThunksSize() const;
template <class RelTy>
template <class ELFT, class RelTy>
void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
// Used by ICF.
uint32_t Class[2] = {0, 0};
// Called by ICF to merge two input sections.
void replace(InputSection<ELFT> *Other);
void replace(InputSection *Other);
private:
template <class RelTy>
template <class ELFT, class RelTy>
void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks;
};
template <class ELFT> InputSection<ELFT> InputSection<ELFT>::Discarded;
// The list of all input sections.
extern std::vector<InputSectionBase *> InputSections;
} // namespace elf
template <class ELFT> std::string toString(const elf::InputSectionBase<ELFT> *);
std::string toString(const elf::InputSectionBase *);
} // namespace lld
#endif

View file

@ -12,12 +12,13 @@
#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
#include "lld/Core/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/LTO/Caching.h"
#include "llvm/LTO/Config.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/SymbolicFile.h"
@ -46,7 +47,7 @@ static void saveBuffer(StringRef Buffer, const Twine &Path) {
std::error_code EC;
raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
if (EC)
error(EC, "cannot create " + Path);
error("cannot create " + Path + ": " + EC.message());
OS << Buffer;
}
@ -73,6 +74,7 @@ static std::unique_ptr<lto::LTO> createLTO() {
Conf.Options.RelaxELFRelocations = true;
Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static;
Conf.CodeModel = GetCodeModelFromCMModel();
Conf.DisableVerify = Config->DisableVerify;
Conf.DiagHandler = diagnosticHandler;
Conf.OptLevel = Config->LTOO;
@ -81,6 +83,10 @@ static std::unique_ptr<lto::LTO> createLTO() {
Conf.OptPipeline = Config->LTONewPmPasses;
Conf.AAPipeline = Config->LTOAAPipeline;
// Set up optimization remarks if we've been asked to.
Conf.RemarksFilename = Config->OptRemarksFilename;
Conf.RemarksWithHotness = Config->OptRemarksWithHotness;
if (Config->SaveTemps)
checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
/*UseInputModulePath*/ true));
@ -96,12 +102,12 @@ BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
template <class ELFT> static void undefine(Symbol *S) {
replaceBody<Undefined<ELFT>>(S, S->body()->getName(), /*IsLocal=*/false,
STV_DEFAULT, S->body()->Type, nullptr);
static void undefine(Symbol *S) {
replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
STV_DEFAULT, S->body()->Type, nullptr);
}
template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
unsigned SymNum = 0;
std::vector<Symbol *> Syms = F.getSymbols();
@ -119,14 +125,12 @@ template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
// flags an undefined in IR with a definition in ASM as prevailing.
// Once IRObjectFile is fixed to report only one symbol this hack can
// be removed.
R.Prevailing =
!(ObjSym.getFlags() & object::BasicSymbolRef::SF_Undefined) &&
B->File == &F;
R.Prevailing = !ObjSym.isUndefined() && B->File == &F;
R.VisibleToRegularObj =
Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
if (R.Prevailing)
undefine<ELFT>(Sym);
undefine(Sym);
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
@ -137,17 +141,34 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
std::vector<InputFile *> Ret;
unsigned MaxTasks = LTOObj->getMaxTasks();
Buff.resize(MaxTasks);
Files.resize(MaxTasks);
checkError(LTOObj->run([&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
llvm::make_unique<raw_svector_ostream>(Buff[Task]));
}));
// The --thinlto-cache-dir option specifies the path to a directory in which
// to cache native object files for ThinLTO incremental builds. If a path was
// specified, configure LTO to use it as the cache directory.
lto::NativeObjectCache Cache;
if (!Config->ThinLTOCacheDir.empty())
Cache = check(
lto::localCache(Config->ThinLTOCacheDir,
[&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
Files[Task] = std::move(MB);
}));
checkError(LTOObj->run(
[&](size_t Task) {
return llvm::make_unique<lto::NativeObjectStream>(
llvm::make_unique<raw_svector_ostream>(Buff[Task]));
},
Cache));
if (!Config->ThinLTOCacheDir.empty())
pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
for (unsigned I = 0; I != MaxTasks; ++I) {
if (Buff[I].empty())
continue;
if (Config->SaveTemps) {
if (MaxTasks == 1)
if (I == 0)
saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
else
saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
@ -155,10 +176,10 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp"));
Ret.push_back(Obj);
}
for (std::unique_ptr<MemoryBuffer> &File : Files)
if (File)
Ret.push_back(createObjectFile(*File));
return Ret;
}
template void BitcodeCompiler::template add<ELF32LE>(BitcodeFile &);
template void BitcodeCompiler::template add<ELF32BE>(BitcodeFile &);
template void BitcodeCompiler::template add<ELF64LE>(BitcodeFile &);
template void BitcodeCompiler::template add<ELF64BE>(BitcodeFile &);

View file

@ -43,12 +43,13 @@ public:
BitcodeCompiler();
~BitcodeCompiler();
template <class ELFT> void add(BitcodeFile &F);
void add(BitcodeFile &F);
std::vector<InputFile *> compile();
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
std::vector<SmallString<0>> Buff;
std::vector<std::unique_ptr<MemoryBuffer>> Files;
};
}
}

File diff suppressed because it is too large Load diff

View file

@ -15,6 +15,7 @@
#include "Writer.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
@ -28,45 +29,32 @@ namespace lld {
namespace elf {
class DefinedCommon;
class ScriptParser;
class SymbolBody;
template <class ELFT> class InputSectionBase;
template <class ELFT> class InputSection;
class OutputSectionBase;
template <class ELFT> class OutputSectionFactory;
class InputSectionData;
class InputSectionBase;
class InputSection;
class OutputSection;
class OutputSectionFactory;
class InputSectionBase;
class SectionBase;
struct ExprValue {
SectionBase *Sec;
uint64_t Val;
bool ForceAbsolute;
ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val)
: Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute) {}
ExprValue(SectionBase *Sec, uint64_t Val) : ExprValue(Sec, false, Val) {}
ExprValue(uint64_t Val) : ExprValue(nullptr, Val) {}
bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; }
uint64_t getValue() const;
uint64_t getSecAddr() const;
};
// This represents an expression in the linker script.
// ScriptParser::readExpr reads an expression and returns an Expr.
// Later, we evaluate the expression by calling the function
// with the value of special context variable ".".
struct Expr {
std::function<uint64_t(uint64_t)> Val;
std::function<bool()> IsAbsolute;
// If expression is section-relative the function below is used
// to get the output section pointer.
std::function<const OutputSectionBase *()> Section;
uint64_t operator()(uint64_t Dot) const { return Val(Dot); }
operator bool() const { return (bool)Val; }
Expr(std::function<uint64_t(uint64_t)> Val, std::function<bool()> IsAbsolute,
std::function<const OutputSectionBase *()> Section)
: Val(Val), IsAbsolute(IsAbsolute), Section(Section) {}
template <typename T>
Expr(T V) : Expr(V, [] { return true; }, [] { return nullptr; }) {}
Expr() : Expr(nullptr) {}
};
// Parses a linker script. Calling this function updates
// Config and ScriptConfig.
void readLinkerScript(MemoryBufferRef MB);
// Parses a version script.
void readVersionScript(MemoryBufferRef MB);
void readDynamicList(MemoryBufferRef MB);
// Later, we evaluate the expression by calling the function.
typedef std::function<ExprValue()> Expr;
// This enum is used to implement linker script SECTIONS command.
// https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
@ -80,16 +68,13 @@ enum SectionsCommandKind {
struct BaseCommand {
BaseCommand(int K) : Kind(K) {}
virtual ~BaseCommand() = default;
int Kind;
};
// This represents ". = <expr>" or "<symbol> = <expr>".
struct SymbolAssignment : BaseCommand {
SymbolAssignment(StringRef Name, Expr E)
: BaseCommand(AssignmentKind), Name(Name), Expression(E) {}
SymbolAssignment(StringRef Name, Expr E, std::string Loc)
: BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {}
static bool classof(const BaseCommand *C);
@ -103,6 +88,9 @@ struct SymbolAssignment : BaseCommand {
// Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN.
bool Provide = false;
bool Hidden = false;
// Holds file name and line number for error reporting.
std::string Location;
};
// Linker scripts allow additional constraints to be put on ouput sections.
@ -111,22 +99,37 @@ struct SymbolAssignment : BaseCommand {
// with ONLY_IF_RW is created if all input sections are RW.
enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
// This struct is used to represent the location and size of regions of
// target memory. Instances of the struct are created by parsing the
// MEMORY command.
struct MemoryRegion {
std::string Name;
uint64_t Origin;
uint64_t Length;
uint64_t Offset;
uint32_t Flags;
uint32_t NegFlags;
};
struct OutputSectionCommand : BaseCommand {
OutputSectionCommand(StringRef Name)
: BaseCommand(OutputSectionKind), Name(Name) {}
static bool classof(const BaseCommand *C);
OutputSection *Sec = nullptr;
MemoryRegion *MemRegion = nullptr;
StringRef Name;
Expr AddrExpr;
Expr AlignExpr;
Expr LMAExpr;
Expr SubalignExpr;
std::vector<std::unique_ptr<BaseCommand>> Commands;
std::vector<BaseCommand *> Commands;
std::vector<StringRef> Phdrs;
uint32_t Filler = 0;
llvm::Optional<uint32_t> Filler;
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
};
// This struct represents one section match pattern in SECTIONS() command.
@ -154,7 +157,7 @@ struct InputSectionDescription : BaseCommand {
// will be associated with this InputSectionDescription.
std::vector<SectionPattern> SectionPatterns;
std::vector<InputSectionData *> Sections;
std::vector<InputSectionBase *> Sections;
};
// Represents an ASSERT().
@ -187,25 +190,10 @@ struct PhdrsCommand {
Expr LMAExpr;
};
class LinkerScriptBase {
protected:
~LinkerScriptBase() = default;
public:
virtual uint64_t getHeaderSize() = 0;
virtual uint64_t getSymbolValue(const Twine &Loc, StringRef S) = 0;
virtual bool isDefined(StringRef S) = 0;
virtual bool isAbsolute(StringRef S) = 0;
virtual const OutputSectionBase *getSymbolSection(StringRef S) = 0;
virtual const OutputSectionBase *getOutputSection(const Twine &Loc,
StringRef S) = 0;
virtual uint64_t getOutputSectionSize(StringRef S) = 0;
};
// ScriptConfiguration holds linker script parse results.
struct ScriptConfiguration {
// Used to assign addresses to sections.
std::vector<std::unique_ptr<BaseCommand>> Commands;
std::vector<BaseCommand *> Commands;
// Used to assign sections to headers.
std::vector<PhdrsCommand> PhdrsCommands;
@ -215,20 +203,60 @@ struct ScriptConfiguration {
// List of section patterns specified with KEEP commands. They will
// be kept even if they are unused and --gc-sections is specified.
std::vector<InputSectionDescription *> KeptSections;
// A map from memory region name to a memory region descriptor.
llvm::DenseMap<llvm::StringRef, MemoryRegion> MemoryRegions;
// A list of symbols referenced by the script.
std::vector<llvm::StringRef> ReferencedSymbols;
};
extern ScriptConfiguration *ScriptConfig;
class LinkerScript {
protected:
void assignSymbol(SymbolAssignment *Cmd, bool InSec);
void setDot(Expr E, const Twine &Loc, bool InSec);
// This is a runner of the linker script.
template <class ELFT> class LinkerScript final : public LinkerScriptBase {
typedef typename ELFT::uint uintX_t;
std::vector<InputSectionBase *>
computeInputSections(const InputSectionDescription *);
std::vector<InputSectionBase *>
createInputSectionList(OutputSectionCommand &Cmd);
std::vector<size_t> getPhdrIndices(StringRef SectionName);
size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
void switchTo(OutputSection *Sec);
void flush();
void output(InputSection *Sec);
void process(BaseCommand &Base);
OutputSection *Aether;
bool ErrorOnMissingSection = false;
uint64_t Dot;
uint64_t ThreadBssOffset = 0;
std::function<uint64_t()> LMAOffset;
OutputSection *CurOutSec = nullptr;
MemoryRegion *CurMemRegion = nullptr;
llvm::DenseSet<OutputSection *> AlreadyOutputOS;
llvm::DenseSet<InputSectionBase *> AlreadyOutputIS;
public:
LinkerScript();
~LinkerScript();
bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
uint64_t getDot() { return Dot; }
OutputSection *getOutputSection(const Twine &Loc, StringRef S);
uint64_t getOutputSectionSize(StringRef S);
void discard(ArrayRef<InputSectionBase *> V);
void processCommands(OutputSectionFactory<ELFT> &Factory);
void addOrphanSections(OutputSectionFactory<ELFT> &Factory);
ExprValue getSymbolValue(const Twine &Loc, StringRef S);
bool isDefined(StringRef S);
std::vector<OutputSection *> *OutputSections;
void addOrphanSections(OutputSectionFactory &Factory);
void removeEmptyCommands();
void adjustSectionsBeforeSorting();
void adjustSectionsAfterSorting();
@ -236,61 +264,24 @@ public:
std::vector<PhdrEntry> createPhdrs();
bool ignoreInterpSection();
uint32_t getFiller(StringRef Name);
void writeDataBytes(StringRef Name, uint8_t *Buf);
llvm::Optional<uint32_t> getFiller(StringRef Name);
bool hasLMA(StringRef Name);
bool shouldKeep(InputSectionBase<ELFT> *S);
bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd);
void placeOrphanSections();
void processNonSectionCommands();
void assignAddresses(std::vector<PhdrEntry> &Phdrs);
bool hasPhdrsCommands();
uint64_t getHeaderSize() override;
uint64_t getSymbolValue(const Twine &Loc, StringRef S) override;
bool isDefined(StringRef S) override;
bool isAbsolute(StringRef S) override;
const OutputSectionBase *getSymbolSection(StringRef S) override;
const OutputSectionBase *getOutputSection(const Twine &Loc,
StringRef S) override;
uint64_t getOutputSectionSize(StringRef S) override;
std::vector<OutputSectionBase *> *OutputSections;
int getSectionIndex(StringRef Name);
private:
void computeInputSections(InputSectionDescription *);
void writeDataBytes(StringRef Name, uint8_t *Buf);
void addSymbol(SymbolAssignment *Cmd);
void processCommands(OutputSectionFactory &Factory);
void addSection(OutputSectionFactory<ELFT> &Factory,
InputSectionBase<ELFT> *Sec, StringRef Name);
void discard(ArrayRef<InputSectionBase<ELFT> *> V);
std::vector<InputSectionBase<ELFT> *>
createInputSectionList(OutputSectionCommand &Cmd);
// "ScriptConfig" is a bit too long, so define a short name for it.
ScriptConfiguration &Opt = *ScriptConfig;
std::vector<size_t> getPhdrIndices(StringRef SectionName);
size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
uintX_t Dot;
uintX_t LMAOffset = 0;
OutputSectionBase *CurOutSec = nullptr;
uintX_t ThreadBssOffset = 0;
void switchTo(OutputSectionBase *Sec);
void flush();
void output(InputSection<ELFT> *Sec);
void process(BaseCommand &Base);
llvm::DenseSet<OutputSectionBase *> AlreadyOutputOS;
llvm::DenseSet<InputSectionData *> AlreadyOutputIS;
// Parsed linker script configurations are set to this struct.
ScriptConfiguration Opt;
};
// Variable template is a C++14 feature, so we can't template
// a global variable. Use a struct to workaround.
template <class ELFT> struct Script { static LinkerScript<ELFT> *X; };
template <class ELFT> LinkerScript<ELFT> *Script<ELFT>::X;
extern LinkerScriptBase *ScriptBase;
extern LinkerScript *Script;
} // end namespace elf
} // end namespace lld

131
ELF/MapFile.cpp Normal file
View file

@ -0,0 +1,131 @@
//===- MapFile.cpp --------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the -Map option. It shows lists in order and
// hierarchically the output sections, input sections, input files and
// symbol:
//
// Address Size Align Out In File Symbol
// =================================================================
// 00201000 00000015 4 .text
// 00201000 0000000e 4 .text
// 00201000 0000000e 4 test.o
// 0020100e 00000000 0 local
// 00201005 00000000 0 f(int)
//
//===----------------------------------------------------------------------===//
#include "MapFile.h"
#include "InputFiles.h"
#include "Strings.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf;
static void writeOutSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
uint64_t Size, uint64_t Align, StringRef Name) {
OS << format("%0*llx %0*llx %5lld ", Width, Address, Width, Size, Align)
<< left_justify(Name, 7);
}
static void writeInSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
uint64_t Size, uint64_t Align, StringRef Name) {
// Pass an empty name to align the text to the correct column.
writeOutSecLine(OS, Width, Address, Size, Align, "");
OS << ' ' << left_justify(Name, 7);
}
static void writeFileLine(raw_fd_ostream &OS, int Width, uint64_t Address,
uint64_t Size, uint64_t Align, StringRef Name) {
// Pass an empty name to align the text to the correct column.
writeInSecLine(OS, Width, Address, Size, Align, "");
OS << ' ' << left_justify(Name, 7);
}
static void writeSymbolLine(raw_fd_ostream &OS, int Width, uint64_t Address,
uint64_t Size, StringRef Name) {
// Pass an empty name to align the text to the correct column.
writeFileLine(OS, Width, Address, Size, 0, "");
OS << ' ' << left_justify(Name, 7);
}
template <class ELFT>
static void writeInputSection(raw_fd_ostream &OS, const InputSection *IS,
StringRef &PrevName) {
int Width = ELFT::Is64Bits ? 16 : 8;
StringRef Name = IS->Name;
if (Name != PrevName) {
writeInSecLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
IS->Alignment, Name);
OS << '\n';
PrevName = Name;
}
elf::ObjectFile<ELFT> *File = IS->template getFile<ELFT>();
if (!File)
return;
writeFileLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
IS->Alignment, toString(File));
OS << '\n';
for (SymbolBody *Sym : File->getSymbols()) {
auto *DR = dyn_cast<DefinedRegular>(Sym);
if (!DR)
continue;
if (DR->Section != IS)
continue;
if (DR->isSection())
continue;
writeSymbolLine(OS, Width, Sym->getVA(), Sym->getSize<ELFT>(),
toString(*Sym));
OS << '\n';
}
}
template <class ELFT>
static void writeMapFile2(raw_fd_ostream &OS,
ArrayRef<OutputSection *> OutputSections) {
int Width = ELFT::Is64Bits ? 16 : 8;
OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width)
<< " Align Out In File Symbol\n";
for (OutputSection *Sec : OutputSections) {
writeOutSecLine(OS, Width, Sec->Addr, Sec->Size, Sec->Alignment, Sec->Name);
OS << '\n';
StringRef PrevName = "";
for (InputSection *IS : Sec->Sections) {
writeInputSection<ELFT>(OS, IS, PrevName);
}
}
}
template <class ELFT>
void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
if (Config->MapFile.empty())
return;
std::error_code EC;
raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
if (EC)
error("cannot open " + Config->MapFile + ": " + EC.message());
else
writeMapFile2<ELFT>(OS, OutputSections);
}
template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSection *>);
template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSection *>);
template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSection *>);
template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSection *>);

22
ELF/MapFile.h Normal file
View file

@ -0,0 +1,22 @@
//===- MapFile.h ------------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_MAPFILE_H
#define LLD_ELF_MAPFILE_H
#include "OutputSections.h"
namespace lld {
namespace elf {
template <class ELFT>
void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
}
}
#endif

View file

@ -22,6 +22,7 @@
#include "InputSection.h"
#include "LinkerScript.h"
#include "Memory.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
@ -44,51 +45,59 @@ using namespace lld::elf;
namespace {
// A resolved relocation. The Sec and Offset fields are set if the relocation
// was resolved to an offset within a section.
template <class ELFT> struct ResolvedReloc {
InputSectionBase<ELFT> *Sec;
typename ELFT::uint Offset;
struct ResolvedReloc {
InputSectionBase *Sec;
uint64_t Offset;
};
} // end anonymous namespace
template <class ELFT>
static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
static typename ELFT::uint getAddend(InputSectionBase &Sec,
const typename ELFT::Rel &Rel) {
return Target->getImplicitAddend(Sec.Data.begin() + Rel.r_offset,
Rel.getType(Config->Mips64EL));
Rel.getType(Config->IsMips64EL));
}
template <class ELFT>
static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
static typename ELFT::uint getAddend(InputSectionBase &Sec,
const typename ELFT::Rela &Rel) {
return Rel.r_addend;
}
// There are normally few input sections whose names are valid C
// identifiers, so we just store a std::vector instead of a multimap.
static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections;
template <class ELFT, class RelT>
static ResolvedReloc<ELFT> resolveReloc(InputSectionBase<ELFT> &Sec,
RelT &Rel) {
SymbolBody &B = Sec.getFile()->getRelocTargetSym(Rel);
auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
if (!D || !D->Section)
return {nullptr, 0};
typename ELFT::uint Offset = D->Value;
if (D->isSection())
Offset += getAddend(Sec, Rel);
return {D->Section->Repl, Offset};
static void resolveReloc(InputSectionBase &Sec, RelT &Rel,
std::function<void(ResolvedReloc)> Fn) {
SymbolBody &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
if (auto *D = dyn_cast<DefinedRegular>(&B)) {
if (!D->Section)
return;
typename ELFT::uint Offset = D->Value;
if (D->isSection())
Offset += getAddend<ELFT>(Sec, Rel);
Fn({cast<InputSectionBase>(D->Section)->Repl, Offset});
} else if (auto *U = dyn_cast<Undefined>(&B)) {
for (InputSectionBase *Sec : CNamedSections.lookup(U->getName()))
Fn({Sec, 0});
}
}
// Calls Fn for each section that Sec refers to via relocations.
template <class ELFT>
static void forEachSuccessor(InputSection<ELFT> &Sec,
std::function<void(ResolvedReloc<ELFT>)> Fn) {
static void forEachSuccessor(InputSection &Sec,
std::function<void(ResolvedReloc)> Fn) {
if (Sec.AreRelocsRela) {
for (const typename ELFT::Rela &Rel : Sec.relas())
Fn(resolveReloc(Sec, Rel));
for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>())
resolveReloc<ELFT>(Sec, Rel, Fn);
} else {
for (const typename ELFT::Rel &Rel : Sec.rels())
Fn(resolveReloc(Sec, Rel));
for (const typename ELFT::Rel &Rel : Sec.template rels<ELFT>())
resolveReloc<ELFT>(Sec, Rel, Fn);
}
if (Sec.DependentSection)
Fn({Sec.DependentSection, 0});
for (InputSectionBase *IS : Sec.DependentSections)
Fn({IS, 0});
}
// The .eh_frame section is an unfortunate special case.
@ -106,9 +115,8 @@ static void forEachSuccessor(InputSection<ELFT> &Sec,
// the gc pass. With that we would be able to also gc some sections holding
// LSDAs and personality functions if we found that they were unused.
template <class ELFT, class RelTy>
static void
scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
static void scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
std::function<void(ResolvedReloc)> Enqueue) {
const endianness E = ELFT::TargetEndianness;
for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
EhSectionPiece &Piece = EH.Pieces[I];
@ -118,7 +126,7 @@ scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
if (read32<E>(Piece.data().data() + 4) == 0) {
// This is a CIE, we only need to worry about the first relocation. It is
// known to point to the personality function.
Enqueue(resolveReloc(EH, Rels[FirstRelI]));
resolveReloc<ELFT>(EH, Rels[FirstRelI], Enqueue);
continue;
}
// This is a FDE. The relocations point to the described function or to
@ -129,37 +137,37 @@ scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
const RelTy &Rel = Rels[I2];
if (Rel.r_offset >= PieceEnd)
break;
ResolvedReloc<ELFT> R = resolveReloc(EH, Rels[I2]);
if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
continue;
if (R.Sec->Flags & SHF_EXECINSTR)
continue;
Enqueue({R.Sec, 0});
resolveReloc<ELFT>(EH, Rels[I2], [&](ResolvedReloc R) {
if (!R.Sec || R.Sec == &InputSection::Discarded)
return;
if (R.Sec->Flags & SHF_EXECINSTR)
return;
Enqueue({R.Sec, 0});
});
}
}
}
template <class ELFT>
static void
scanEhFrameSection(EhInputSection<ELFT> &EH,
std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
static void scanEhFrameSection(EhInputSection &EH,
std::function<void(ResolvedReloc)> Enqueue) {
if (!EH.NumRelocations)
return;
// Unfortunately we need to split .eh_frame early since some relocations in
// .eh_frame keep other section alive and some don't.
EH.split();
EH.split<ELFT>();
if (EH.AreRelocsRela)
scanEhFrameSection(EH, EH.relas(), Enqueue);
scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Enqueue);
else
scanEhFrameSection(EH, EH.rels(), Enqueue);
scanEhFrameSection<ELFT>(EH, EH.template rels<ELFT>(), Enqueue);
}
// We do not garbage-collect two types of sections:
// 1) Sections used by the loader (.init, .fini, .ctors, .dtors or .jcr)
// 2) Non-allocatable sections which typically contain debugging information
template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
template <class ELFT> static bool isReserved(InputSectionBase *Sec) {
switch (Sec->Type) {
case SHT_FINI_ARRAY:
case SHT_INIT_ARRAY:
@ -170,12 +178,7 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
if (!(Sec->Flags & SHF_ALLOC))
return true;
// We do not want to reclaim sections if they can be referred
// by __start_* and __stop_* symbols.
StringRef S = Sec->Name;
if (isValidCIdentifier(S))
return true;
return S.startswith(".ctors") || S.startswith(".dtors") ||
S.startswith(".init") || S.startswith(".fini") ||
S.startswith(".jcr");
@ -186,14 +189,15 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
// Starting from GC-root sections, this function visits all reachable
// sections to set their "Live" bits.
template <class ELFT> void elf::markLive() {
SmallVector<InputSection<ELFT> *, 256> Q;
SmallVector<InputSection *, 256> Q;
CNamedSections.clear();
auto Enqueue = [&](ResolvedReloc<ELFT> R) {
auto Enqueue = [&](ResolvedReloc R) {
// Skip over discarded sections. This in theory shouldn't happen, because
// the ELF spec doesn't allow a relocation to point to a deduplicated
// COMDAT section directly. Unfortunately this happens in practice (e.g.
// .eh_frame) so we need to add a check.
if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
if (R.Sec == &InputSection::Discarded)
return;
// We don't gc non alloc sections.
@ -203,20 +207,20 @@ template <class ELFT> void elf::markLive() {
// Usually, a whole section is marked as live or dead, but in mergeable
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(R.Sec))
if (auto *MS = dyn_cast<MergeInputSection>(R.Sec))
MS->markLiveAt(R.Offset);
if (R.Sec->Live)
return;
R.Sec->Live = true;
// Add input section to the queue.
if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(R.Sec))
if (InputSection *S = dyn_cast<InputSection>(R.Sec))
Q.push_back(S);
};
auto MarkSymbol = [&](const SymbolBody *Sym) {
if (auto *D = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym))
Enqueue({D->Section, D->Value});
if (auto *D = dyn_cast_or_null<DefinedRegular>(Sym))
Enqueue({cast<InputSectionBase>(D->Section), D->Value});
};
// Add GC root symbols.
@ -234,14 +238,20 @@ template <class ELFT> void elf::markLive() {
// Preserve special sections and those which are specified in linker
// script KEEP command.
for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
for (InputSectionBase *Sec : InputSections) {
// .eh_frame is always marked as live now, but also it can reference to
// sections that contain personality. We preserve all non-text sections
// referred by .eh_frame here.
if (auto *EH = dyn_cast_or_null<EhInputSection<ELFT>>(Sec))
if (auto *EH = dyn_cast_or_null<EhInputSection>(Sec))
scanEhFrameSection<ELFT>(*EH, Enqueue);
if (isReserved(Sec) || Script<ELFT>::X->shouldKeep(Sec))
if (Sec->Flags & SHF_LINK_ORDER)
continue;
if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec))
Enqueue({Sec, 0});
else if (isValidCIdentifier(Sec->Name)) {
CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec);
CNamedSections[Saver.save("__end_" + Sec->Name)].push_back(Sec);
}
}
// Mark all reachable sections.

View file

@ -48,6 +48,8 @@ def color_diagnostics_eq: J<"color-diagnostics=">,
def define_common: F<"define-common">,
HelpText<"Assign space to common symbols">;
def demangle: F<"demangle">, HelpText<"Demangle symbol names">;
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@ -68,6 +70,8 @@ def dynamic_list: S<"dynamic-list">,
def eh_frame_hdr: F<"eh-frame-hdr">,
HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
def enable_new_dtags: F<"enable-new-dtags">,
HelpText<"Enable new dynamic tags">;
@ -80,6 +84,9 @@ def entry: S<"entry">, MetaVarName<"<entry>">,
def error_limit: S<"error-limit">,
HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
def error_unresolved_symbols: F<"error-unresolved-symbols">,
HelpText<"Report unresolved symbols as errors">;
def export_dynamic: F<"export-dynamic">,
HelpText<"Put symbols in the dynamic symbol table">;
@ -124,6 +131,8 @@ def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
def Map: JS<"Map">, HelpText<"Print a link map to the specified file">;
def nostdlib: F<"nostdlib">,
HelpText<"Only search directories specified on the command line">;
@ -139,6 +148,12 @@ def no_define_common: F<"no-define-common">,
def no_demangle: F<"no-demangle">,
HelpText<"Do not demangle symbol names">;
def no_dynamic_linker: F<"no-dynamic-linker">,
HelpText<"Inhibit output of .interp section">;
def no_export_dynamic: F<"no-export-dynamic">;
def no_fatal_warnings: F<"no-fatal-warnings">;
def no_gc_sections: F<"no-gc-sections">,
HelpText<"Disable garbage collection of unused sections">;
@ -170,7 +185,7 @@ def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
HelpText<"Specify the binary format for the output object file">;
def omagic: F<"omagic">, MetaVarName<"<magic>">,
def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
HelpText<"Set the text and data sections to be readable and writable">;
def pie: F<"pie">, HelpText<"Create a position independent executable">;
@ -178,6 +193,9 @@ def pie: F<"pie">, HelpText<"Create a position independent executable">;
def print_gc_sections: F<"print-gc-sections">,
HelpText<"List removed unused sections">;
def print_map: F<"print-map">,
HelpText<"Print a link map to the standard output">;
def reproduce: S<"reproduce">,
HelpText<"Dump linker invocation and input files for debugging">;
@ -221,7 +239,7 @@ def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">;
def trace_symbol : S<"trace-symbol">, HelpText<"Trace references to symbols">;
def undefined: S<"undefined">,
HelpText<"Force undefined symbol during linking">;
@ -244,6 +262,9 @@ def version_script: S<"version-script">,
def warn_common: F<"warn-common">,
HelpText<"Warn about duplicate common symbols">;
def warn_unresolved_symbols: F<"warn-unresolved-symbols">,
HelpText<"Report unresolved symbols as warnings">;
def whole_archive: F<"whole-archive">,
HelpText<"Force load of all members in a static library">;
@ -267,6 +288,7 @@ def alias_define_common_dp: F<"dp">, Alias<define_common>;
def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_entry_entry: J<"entry=">, Alias<entry>;
def alias_error_limit: J<"error-limit=">, Alias<error_limit>;
@ -278,10 +300,12 @@ def alias_format_b: S<"b">, Alias<format>;
def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>;
def alias_init_init: J<"init=">, Alias<init>;
def alias_l__library: J<"library=">, Alias<l>;
def alias_Map_eq: J<"Map=">, Alias<Map>;
def alias_omagic: Flag<["-"], "N">, Alias<omagic>;
def alias_o_output: Joined<["--"], "output=">, Alias<o>;
def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;
def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>;
def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;
@ -297,6 +321,7 @@ def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
def alias_Tbss: J<"Tbss=">, Alias<Tbss>;
def alias_Tdata: J<"Tdata=">, Alias<Tdata>;
def alias_trace: Flag<["-"], "t">, Alias<trace>;
def trace_trace_symbol_eq : J<"trace-symbol=">, Alias<trace_symbol>;
def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
def alias_Ttext: J<"Ttext=">, Alias<Ttext>;
def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>;
@ -329,17 +354,12 @@ def plugin_opt_eq: J<"plugin-opt=">;
// Options listed below are silently ignored for now for compatibility.
def allow_shlib_undefined: F<"allow-shlib-undefined">;
def cref: Flag<["--"], "cref">;
def demangle: F<"demangle">;
def detect_odr_violations: F<"detect-odr-violations">;
def g: Flag<["-"], "g">;
def M: Flag<["-"], "M">;
def Map: JS<"Map">;
def no_add_needed: F<"no-add-needed">;
def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">,
Alias<no_add_needed>;
def no_dynamic_linker: F<"no-dynamic-linker">;
def no_fatal_warnings: F<"no-fatal-warnings">;
def no_mmap_output_file: F<"no-mmap-output-file">;
def no_warn_common: F<"no-warn-common">;
def no_warn_mismatch: F<"no-warn-mismatch">;
@ -355,7 +375,6 @@ def G: JoinedOrSeparate<["-"], "G">;
def Qy : F<"Qy">;
// Aliases for ignored options
def alias_Map_eq: J<"Map=">, Alias<Map>;
def alias_version_script_version_script: J<"version-script=">,
Alias<version_script>;
@ -368,5 +387,13 @@ def lto_partitions: J<"lto-partitions=">,
HelpText<"Number of LTO codegen partitions">;
def disable_verify: F<"disable-verify">;
def mllvm: S<"mllvm">;
def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
HelpText<"YAML output file for optimization remarks">;
def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
HelpText<"Include hotness informations in the optimization remarks file">;
def save_temps: F<"save-temps">;
def thinlto_cache_dir: J<"thinlto-cache-dir=">,
HelpText<"Path to ThinLTO cached object file directory">;
def thinlto_cache_policy: S<"thinlto-cache-policy">,
HelpText<"Pruning policy for the ThinLTO cache">;
def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;

View file

@ -9,7 +9,6 @@
#include "OutputSections.h"
#include "Config.h"
#include "EhFrame.h"
#include "LinkerScript.h"
#include "Memory.h"
#include "Strings.h"
@ -31,15 +30,18 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
OutputSectionBase::OutputSectionBase(StringRef Name, uint32_t Type,
uint64_t Flags)
: Name(Name) {
this->Type = Type;
this->Flags = Flags;
this->Addralign = 1;
}
uint8_t Out::First;
OutputSection *Out::Opd;
uint8_t *Out::OpdBuf;
PhdrEntry *Out::TlsPhdr;
OutputSection *Out::DebugInfo;
OutputSection *Out::ElfHeader;
OutputSection *Out::ProgramHeaders;
OutputSection *Out::PreinitArray;
OutputSection *Out::InitArray;
OutputSection *Out::FiniArray;
uint32_t OutputSectionBase::getPhdrFlags() const {
uint32_t OutputSection::getPhdrFlags() const {
uint32_t Ret = PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
@ -49,9 +51,9 @@ uint32_t OutputSectionBase::getPhdrFlags() const {
}
template <class ELFT>
void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
Shdr->sh_entsize = Entsize;
Shdr->sh_addralign = Addralign;
Shdr->sh_addralign = Alignment;
Shdr->sh_type = Type;
Shdr->sh_offset = Offset;
Shdr->sh_flags = Flags;
@ -62,49 +64,28 @@ void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
Shdr->sh_name = ShName;
}
template <class ELFT> static uint64_t getEntsize(uint32_t Type) {
switch (Type) {
case SHT_RELA:
return sizeof(typename ELFT::Rela);
case SHT_REL:
return sizeof(typename ELFT::Rel);
case SHT_MIPS_REGINFO:
return sizeof(Elf_Mips_RegInfo<ELFT>);
case SHT_MIPS_OPTIONS:
return sizeof(Elf_Mips_Options<ELFT>) + sizeof(Elf_Mips_RegInfo<ELFT>);
case SHT_MIPS_ABIFLAGS:
return sizeof(Elf_Mips_ABIFlags<ELFT>);
default:
return 0;
}
}
OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
: SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
/*Info*/ 0,
/*Link*/ 0) {}
template <class ELFT>
OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
: OutputSectionBase(Name, Type, Flags) {
this->Entsize = getEntsize<ELFT>(Type);
}
template <typename ELFT>
static bool compareByFilePosition(InputSection<ELFT> *A,
InputSection<ELFT> *B) {
static bool compareByFilePosition(InputSection *A, InputSection *B) {
// Synthetic doesn't have link order dependecy, stable_sort will keep it last
if (A->kind() == InputSectionData::Synthetic ||
B->kind() == InputSectionData::Synthetic)
if (A->kind() == InputSectionBase::Synthetic ||
B->kind() == InputSectionBase::Synthetic)
return false;
auto *LA = cast<InputSection<ELFT>>(A->getLinkOrderDep());
auto *LB = cast<InputSection<ELFT>>(B->getLinkOrderDep());
OutputSectionBase *AOut = LA->OutSec;
OutputSectionBase *BOut = LB->OutSec;
auto *LA = cast<InputSection>(A->getLinkOrderDep());
auto *LB = cast<InputSection>(B->getLinkOrderDep());
OutputSection *AOut = LA->OutSec;
OutputSection *BOut = LB->OutSec;
if (AOut != BOut)
return AOut->SectionIndex < BOut->SectionIndex;
return LA->OutSecOff < LB->OutSecOff;
}
template <class ELFT> void OutputSection<ELFT>::finalize() {
template <class ELFT> void OutputSection::finalize() {
if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
std::sort(Sections.begin(), Sections.end(), compareByFilePosition<ELFT>);
Size = 0;
std::sort(Sections.begin(), Sections.end(), compareByFilePosition);
assignOffsets();
// We must preserve the link order dependency of sections with the
@ -116,34 +97,41 @@ template <class ELFT> void OutputSection<ELFT>::finalize() {
}
uint32_t Type = this->Type;
if (!Config->Relocatable || (Type != SHT_RELA && Type != SHT_REL))
if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
return;
InputSection *First = Sections[0];
if (isa<SyntheticSection>(First))
return;
this->Link = In<ELFT>::SymTab->OutSec->SectionIndex;
// sh_info for SHT_REL[A] sections should contain the section header index of
// the section to which the relocation applies.
InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection();
InputSectionBase *S = First->getRelocatedSection();
this->Info = S->OutSec->SectionIndex;
}
template <class ELFT>
void OutputSection<ELFT>::addSection(InputSectionData *C) {
assert(C->Live);
auto *S = cast<InputSection<ELFT>>(C);
void OutputSection::addSection(InputSection *S) {
assert(S->Live);
Sections.push_back(S);
S->OutSec = this;
this->updateAlignment(S->Alignment);
// Keep sh_entsize value of the input section to be able to perform merging
// later during a final linking using the generated relocatable object.
if (Config->Relocatable && (S->Flags & SHF_MERGE))
this->Entsize = S->Entsize;
// If this section contains a table of fixed-size entries, sh_entsize
// holds the element size. Consequently, if this contains two or more
// input sections, all of them must have the same sh_entsize. However,
// you can put different types of input sections into one output
// sectin by using linker scripts. I don't know what to do here.
// Probably we sholuld handle that as an error. But for now we just
// pick the largest sh_entsize.
this->Entsize = std::max(this->Entsize, S->Entsize);
}
// This function is called after we sort input sections
// and scan relocations to setup sections' offsets.
template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
uintX_t Off = this->Size;
for (InputSection<ELFT> *S : Sections) {
void OutputSection::assignOffsets() {
uint64_t Off = 0;
for (InputSection *S : Sections) {
Off = alignTo(Off, S->Alignment);
S->OutSecOff = Off;
Off += S->getSize();
@ -151,14 +139,12 @@ template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
this->Size = Off;
}
template <class ELFT>
void OutputSection<ELFT>::sort(
std::function<int(InputSection<ELFT> *S)> Order) {
typedef std::pair<unsigned, InputSection<ELFT> *> Pair;
void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) {
typedef std::pair<unsigned, InputSection *> Pair;
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
std::vector<Pair> V;
for (InputSection<ELFT> *S : Sections)
for (InputSection *S : Sections)
V.push_back({Order(S), S});
std::stable_sort(V.begin(), V.end(), Comp);
Sections.clear();
@ -172,9 +158,9 @@ void OutputSection<ELFT>::sort(
// because the compiler keeps the original initialization order in a
// translation unit and we need to respect that.
// For more detail, read the section of the GCC's manual about init_priority.
template <class ELFT> void OutputSection<ELFT>::sortInitFini() {
void OutputSection::sortInitFini() {
// Sort sections by priority.
sort([](InputSection<ELFT> *S) { return getPriority(S->Name); });
sort([](InputSectionBase *S) { return getPriority(S->Name); });
}
// Returns true if S matches /Filename.?\.o$/.
@ -208,15 +194,13 @@ static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
// .ctors are duplicate features (and .init_array is newer.) However, there
// are too many real-world use cases of .ctors, so we had no choice to
// support that with this rather ad-hoc semantics.
template <class ELFT>
static bool compCtors(const InputSection<ELFT> *A,
const InputSection<ELFT> *B) {
bool BeginA = isCrtbegin(A->getFile()->getName());
bool BeginB = isCrtbegin(B->getFile()->getName());
static bool compCtors(const InputSection *A, const InputSection *B) {
bool BeginA = isCrtbegin(A->File->getName());
bool BeginB = isCrtbegin(B->File->getName());
if (BeginA != BeginB)
return BeginA;
bool EndA = isCrtend(A->getFile()->getName());
bool EndB = isCrtend(B->getFile()->getName());
bool EndA = isCrtend(A->File->getName());
bool EndB = isCrtend(B->File->getName());
if (EndA != EndB)
return EndB;
StringRef X = A->Name;
@ -233,319 +217,65 @@ static bool compCtors(const InputSection<ELFT> *A,
// Sorts input sections by the special rules for .ctors and .dtors.
// Unfortunately, the rules are different from the one for .{init,fini}_array.
// Read the comment above.
template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
void OutputSection::sortCtorsDtors() {
std::stable_sort(Sections.begin(), Sections.end(), compCtors);
}
// Fill [Buf, Buf + Size) with Filler. Filler is written in big
// endian order. This is used for linker script "=fillexp" command.
void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
uint8_t V[4];
write32be(V, Filler);
// Fill [Buf, Buf + Size) with Filler.
// This is used for linker script "=fillexp" command.
static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
size_t I = 0;
for (; I + 4 < Size; I += 4)
memcpy(Buf + I, V, 4);
memcpy(Buf + I, V, Size - I);
memcpy(Buf + I, &Filler, 4);
memcpy(Buf + I, &Filler, Size - I);
}
template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
Loc = Buf;
if (uint32_t Filler = Script<ELFT>::X->getFiller(this->Name))
fill(Buf, this->Size, Filler);
uint32_t OutputSection::getFiller() {
// Determine what to fill gaps between InputSections with, as specified by the
// linker script. If nothing is specified and this is an executable section,
// fall back to trap instructions to prevent bad diassembly and detect invalid
// jumps to padding.
if (Optional<uint32_t> Filler = Script->getFiller(Name))
return *Filler;
if (Flags & SHF_EXECINSTR)
return Target->TrapInstr;
return 0;
}
auto Fn = [=](InputSection<ELFT> *IS) { IS->writeTo(Buf); };
forEach(Sections.begin(), Sections.end(), Fn);
template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
Loc = Buf;
// Write leading padding.
uint32_t Filler = getFiller();
if (Filler)
fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
parallelFor(0, Sections.size(), [=](size_t I) {
InputSection *Sec = Sections[I];
Sec->writeTo<ELFT>(Buf);
// Fill gaps between sections.
if (Filler) {
uint8_t *Start = Buf + Sec->OutSecOff + Sec->getSize();
uint8_t *End;
if (I + 1 == Sections.size())
End = Buf + Size;
else
End = Buf + Sections[I + 1]->OutSecOff;
fill(Start, End - Start, Filler);
}
});
// Linker scripts may have BYTE()-family commands with which you
// can write arbitrary bytes to the output. Process them if any.
Script<ELFT>::X->writeDataBytes(this->Name, Buf);
Script->writeDataBytes(Name, Buf);
}
template <class ELFT>
EhOutputSection<ELFT>::EhOutputSection()
: OutputSectionBase(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
// Search for an existing CIE record or create a new one.
// CIE records from input object files are uniquified by their contents
// and where their relocations point to.
template <class ELFT>
template <class RelTy>
CieRecord *EhOutputSection<ELFT>::addCie(EhSectionPiece &Piece,
ArrayRef<RelTy> Rels) {
auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
const endianness E = ELFT::TargetEndianness;
if (read32<E>(Piece.data().data() + 4) != 0)
fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
SymbolBody *Personality = nullptr;
unsigned FirstRelI = Piece.FirstRelocation;
if (FirstRelI != (unsigned)-1)
Personality = &Sec->getFile()->getRelocTargetSym(Rels[FirstRelI]);
// Search for an existing CIE by CIE contents/relocation target pair.
CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
// If not found, create a new one.
if (Cie->Piece == nullptr) {
Cie->Piece = &Piece;
Cies.push_back(Cie);
}
return Cie;
}
// There is one FDE per function. Returns true if a given FDE
// points to a live function.
template <class ELFT>
template <class RelTy>
bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
ArrayRef<RelTy> Rels) {
auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
unsigned FirstRelI = Piece.FirstRelocation;
if (FirstRelI == (unsigned)-1)
fatal(toString(Sec) + ": FDE doesn't reference another section");
const RelTy &Rel = Rels[FirstRelI];
SymbolBody &B = Sec->getFile()->getRelocTargetSym(Rel);
auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
if (!D || !D->Section)
return false;
InputSectionBase<ELFT> *Target = D->Section->Repl;
return Target && Target->Live;
}
// .eh_frame is a sequence of CIE or FDE records. In general, there
// is one CIE record per input object file which is followed by
// a list of FDEs. This function searches an existing CIE or create a new
// one and associates FDEs to the CIE.
template <class ELFT>
template <class RelTy>
void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
ArrayRef<RelTy> Rels) {
const endianness E = ELFT::TargetEndianness;
DenseMap<size_t, CieRecord *> OffsetToCie;
for (EhSectionPiece &Piece : Sec->Pieces) {
// The empty record is the end marker.
if (Piece.size() == 4)
return;
size_t Offset = Piece.InputOff;
uint32_t ID = read32<E>(Piece.data().data() + 4);
if (ID == 0) {
OffsetToCie[Offset] = addCie(Piece, Rels);
continue;
}
uint32_t CieOffset = Offset + 4 - ID;
CieRecord *Cie = OffsetToCie[CieOffset];
if (!Cie)
fatal(toString(Sec) + ": invalid CIE reference");
if (!isFdeLive(Piece, Rels))
continue;
Cie->FdePieces.push_back(&Piece);
NumFdes++;
}
}
template <class ELFT>
void EhOutputSection<ELFT>::addSection(InputSectionData *C) {
auto *Sec = cast<EhInputSection<ELFT>>(C);
Sec->OutSec = this;
this->updateAlignment(Sec->Alignment);
Sections.push_back(Sec);
// .eh_frame is a sequence of CIE or FDE records. This function
// splits it into pieces so that we can call
// SplitInputSection::getSectionPiece on the section.
Sec->split();
if (Sec->Pieces.empty())
return;
if (Sec->NumRelocations) {
if (Sec->AreRelocsRela)
addSectionAux(Sec, Sec->relas());
else
addSectionAux(Sec, Sec->rels());
return;
}
addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
}
template <class ELFT>
static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
memcpy(Buf, D.data(), D.size());
// Fix the size field. -4 since size does not include the size field itself.
const endianness E = ELFT::TargetEndianness;
write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
}
template <class ELFT> void EhOutputSection<ELFT>::finalize() {
if (this->Size)
return; // Already finalized.
size_t Off = 0;
for (CieRecord *Cie : Cies) {
Cie->Piece->OutputOff = Off;
Off += alignTo(Cie->Piece->size(), sizeof(uintX_t));
for (EhSectionPiece *Fde : Cie->FdePieces) {
Fde->OutputOff = Off;
Off += alignTo(Fde->size(), sizeof(uintX_t));
}
}
this->Size = Off;
}
template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
const endianness E = ELFT::TargetEndianness;
switch (Size) {
case DW_EH_PE_udata2:
return read16<E>(Buf);
case DW_EH_PE_udata4:
return read32<E>(Buf);
case DW_EH_PE_udata8:
return read64<E>(Buf);
case DW_EH_PE_absptr:
if (ELFT::Is64Bits)
return read64<E>(Buf);
return read32<E>(Buf);
}
fatal("unknown FDE size encoding");
}
// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
// We need it to create .eh_frame_hdr section.
template <class ELFT>
typename ELFT::uint EhOutputSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
uint8_t Enc) {
// The starting address to which this FDE applies is
// stored at FDE + 8 byte.
size_t Off = FdeOff + 8;
uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
if ((Enc & 0x70) == DW_EH_PE_absptr)
return Addr;
if ((Enc & 0x70) == DW_EH_PE_pcrel)
return Addr + this->Addr + Off;
fatal("unknown FDE size relative encoding");
}
template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
const endianness E = ELFT::TargetEndianness;
for (CieRecord *Cie : Cies) {
size_t CieOffset = Cie->Piece->OutputOff;
writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
for (EhSectionPiece *Fde : Cie->FdePieces) {
size_t Off = Fde->OutputOff;
writeCieFde<ELFT>(Buf + Off, Fde->data());
// FDE's second word should have the offset to an associated CIE.
// Write it.
write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
}
}
for (EhInputSection<ELFT> *S : Sections)
S->relocate(Buf, nullptr);
// Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
// to get a FDE from an address to which FDE is applied. So here
// we obtain two addresses and pass them to EhFrameHdr object.
if (In<ELFT>::EhFrameHdr) {
for (CieRecord *Cie : Cies) {
uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
for (SectionPiece *Fde : Cie->FdePieces) {
uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
uintX_t FdeVA = this->Addr + Fde->OutputOff;
In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
}
}
}
}
template <class ELFT>
MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
uintX_t Flags, uintX_t Alignment)
: OutputSectionBase(Name, Type, Flags),
Builder(StringTableBuilder::RAW, Alignment) {}
template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
Builder.write(Buf);
}
template <class ELFT>
void MergeOutputSection<ELFT>::addSection(InputSectionData *C) {
auto *Sec = cast<MergeInputSection<ELFT>>(C);
Sec->OutSec = this;
this->updateAlignment(Sec->Alignment);
this->Entsize = Sec->Entsize;
Sections.push_back(Sec);
}
template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
}
template <class ELFT> void MergeOutputSection<ELFT>::finalizeTailMerge() {
// Add all string pieces to the string table builder to create section
// contents.
for (MergeInputSection<ELFT> *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Builder.add(Sec->getData(I));
// Fix the string table content. After this, the contents will never change.
Builder.finalize();
this->Size = Builder.getSize();
// finalize() fixed tail-optimized strings, so we can now get
// offsets of strings. Get an offset for each string and save it
// to a corresponding StringPiece for easy access.
for (MergeInputSection<ELFT> *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
}
template <class ELFT> void MergeOutputSection<ELFT>::finalizeNoTailMerge() {
// Add all string pieces to the string table builder to create section
// contents. Because we are not tail-optimizing, offsets of strings are
// fixed when they are added to the builder (string table builder contains
// a hash table from strings to offsets).
for (MergeInputSection<ELFT> *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
Builder.finalizeInOrder();
this->Size = Builder.getSize();
}
template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
if (shouldTailMerge())
finalizeTailMerge();
else
finalizeNoTailMerge();
}
template <class ELFT>
static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
static uint64_t getOutFlags(InputSectionBase *S) {
return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
}
namespace llvm {
template <> struct DenseMapInfo<lld::elf::SectionKey> {
static lld::elf::SectionKey getEmptyKey();
static lld::elf::SectionKey getTombstoneKey();
static unsigned getHashValue(const lld::elf::SectionKey &Val);
static bool isEqual(const lld::elf::SectionKey &LHS,
const lld::elf::SectionKey &RHS);
};
}
template <class ELFT>
static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
// The ELF spec just says
// ----------------------------------------------------------------
// In the first phase, input sections that match in name, type and
@ -588,81 +318,76 @@ static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
//
// Given the above issues, we instead merge sections by name and error on
// incompatible types and flags.
//
// The exception being SHF_MERGE, where we create different output sections
// for each alignment. This makes each output section simple. In case of
// relocatable object generation we do not try to perform merging and treat
// SHF_MERGE sections as regular ones, but also create different output
// sections for them to allow merging at final linking stage.
//
// Fortunately, creating symbols in the middle of a merge section is not
// supported by bfd or gold, so the SHF_MERGE exception should not cause
// problems with most linker scripts.
typedef typename ELFT::uint uintX_t;
uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
uintX_t Alignment = 0;
if (isa<MergeInputSection<ELFT>>(C) ||
(Config->Relocatable && (C->Flags & SHF_MERGE)))
Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
uint32_t Alignment = 0;
uint64_t Flags = 0;
if (Config->Relocatable && (C->Flags & SHF_MERGE)) {
Alignment = std::max<uint64_t>(C->Alignment, C->Entsize);
Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
}
return SectionKey{OutsecName, Flags, Alignment};
}
template <class ELFT> OutputSectionFactory<ELFT>::OutputSectionFactory() {}
template <class ELFT> OutputSectionFactory<ELFT>::~OutputSectionFactory() {}
template <class ELFT>
std::pair<OutputSectionBase *, bool>
OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
StringRef OutsecName) {
SectionKey Key = createKey(C, OutsecName);
return create(Key, C);
}
OutputSectionFactory::OutputSectionFactory(
std::vector<OutputSection *> &OutputSections)
: OutputSections(OutputSections) {}
static uint64_t getIncompatibleFlags(uint64_t Flags) {
return Flags & (SHF_ALLOC | SHF_TLS);
}
template <class ELFT>
std::pair<OutputSectionBase *, bool>
OutputSectionFactory<ELFT>::create(const SectionKey &Key,
InputSectionBase<ELFT> *C) {
uintX_t Flags = getOutFlags(C);
OutputSectionBase *&Sec = Map[Key];
if (Sec) {
if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(C->Flags))
error("Section has flags incompatible with others with the same name " +
toString(C));
// Convert notbits to progbits if they are mixed. This happens is some
// linker scripts.
if (Sec->Type == SHT_NOBITS && C->Type == SHT_PROGBITS)
Sec->Type = SHT_PROGBITS;
if (Sec->Type != C->Type &&
!(Sec->Type == SHT_PROGBITS && C->Type == SHT_NOBITS))
error("Section has different type from others with the same name " +
toString(C));
Sec->Flags |= Flags;
return {Sec, false};
// We allow sections of types listed below to merged into a
// single progbits section. This is typically done by linker
// scripts. Merging nobits and progbits will force disk space
// to be allocated for nobits sections. Other ones don't require
// any special treatment on top of progbits, so there doesn't
// seem to be a harm in merging them.
static bool canMergeToProgbits(unsigned Type) {
return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY ||
Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY ||
Type == SHT_NOTE;
}
static void reportDiscarded(InputSectionBase *IS) {
if (!Config->PrintGcSections)
return;
message("removing unused section from '" + IS->Name + "' in file '" +
IS->File->getName());
}
void OutputSectionFactory::addInputSec(InputSectionBase *IS,
StringRef OutsecName) {
if (!IS->Live) {
reportDiscarded(IS);
return;
}
uint32_t Type = C->Type;
switch (C->kind()) {
case InputSectionBase<ELFT>::Regular:
case InputSectionBase<ELFT>::Synthetic:
Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
break;
case InputSectionBase<ELFT>::EHFrame:
return {Out<ELFT>::EhFrame, false};
case InputSectionBase<ELFT>::Merge:
Sec = make<MergeOutputSection<ELFT>>(Key.Name, Type, Flags, Key.Alignment);
break;
SectionKey Key = createKey(IS, OutsecName);
uint64_t Flags = getOutFlags(IS);
OutputSection *&Sec = Map[Key];
if (Sec) {
if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))
error("Section has flags incompatible with others with the same name " +
toString(IS));
if (Sec->Type != IS->Type) {
if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type))
Sec->Type = SHT_PROGBITS;
else
error("Section has different type from others with the same name " +
toString(IS));
}
Sec->Flags |= Flags;
} else {
Sec = make<OutputSection>(Key.Name, IS->Type, Flags);
OutputSections.push_back(Sec);
}
return {Sec, true};
Sec->addSection(cast<InputSection>(IS));
}
OutputSectionFactory::~OutputSectionFactory() {}
SectionKey DenseMapInfo<SectionKey>::getEmptyKey() {
return SectionKey{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
}
@ -681,32 +406,23 @@ bool DenseMapInfo<SectionKey>::isEqual(const SectionKey &LHS,
LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment;
}
namespace lld {
namespace elf {
template void OutputSectionBase::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
template void OutputSectionBase::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
template void OutputSectionBase::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
template void OutputSectionBase::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
template class OutputSection<ELF32LE>;
template class OutputSection<ELF32BE>;
template class OutputSection<ELF64LE>;
template class OutputSection<ELF64BE>;
template class EhOutputSection<ELF32LE>;
template class EhOutputSection<ELF32BE>;
template class EhOutputSection<ELF64LE>;
template class EhOutputSection<ELF64BE>;
template class MergeOutputSection<ELF32LE>;
template class MergeOutputSection<ELF32BE>;
template class MergeOutputSection<ELF64LE>;
template class MergeOutputSection<ELF64BE>;
template class OutputSectionFactory<ELF32LE>;
template class OutputSectionFactory<ELF32BE>;
template class OutputSectionFactory<ELF64LE>;
template class OutputSectionFactory<ELF64BE>;
}
uint64_t elf::getHeaderSize() {
if (Config->OFormatBinary)
return 0;
return Out::ElfHeader->Size + Out::ProgramHeaders->Size;
}
template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
template void OutputSection::finalize<ELF32LE>();
template void OutputSection::finalize<ELF32BE>();
template void OutputSection::finalize<ELF64LE>();
template void OutputSection::finalize<ELF64BE>();
template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf);
template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf);
template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf);
template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf);

View file

@ -11,6 +11,7 @@
#define LLD_ELF_OUTPUT_SECTIONS_H
#include "Config.h"
#include "InputSection.h"
#include "Relocations.h"
#include "lld/Core/LLVM.h"
@ -23,49 +24,38 @@ namespace elf {
struct PhdrEntry;
class SymbolBody;
struct EhSectionPiece;
template <class ELFT> class EhInputSection;
template <class ELFT> class InputSection;
template <class ELFT> class InputSectionBase;
template <class ELFT> class MergeInputSection;
template <class ELFT> class OutputSection;
class EhInputSection;
class InputSection;
class InputSectionBase;
class MergeInputSection;
class OutputSection;
template <class ELFT> class ObjectFile;
template <class ELFT> class SharedFile;
template <class ELFT> class SharedSymbol;
template <class ELFT> class DefinedRegular;
class SharedSymbol;
class DefinedRegular;
// This represents a section in an output file.
// Different sub classes represent different types of sections. Some contain
// input sections, others are created by the linker.
// It is composed of multiple InputSections.
// The writer creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
class OutputSectionBase {
class OutputSection final : public SectionBase {
public:
enum Kind {
Base,
EHFrame,
Merge,
Regular,
};
OutputSection(StringRef Name, uint32_t Type, uint64_t Flags);
static bool classof(const SectionBase *S) {
return S->kind() == SectionBase::Output;
}
OutputSectionBase(StringRef Name, uint32_t Type, uint64_t Flags);
void setLMAOffset(uint64_t LMAOff) { LMAOffset = LMAOff; }
uint64_t getLMA() const { return Addr + LMAOffset; }
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
StringRef getName() const { return Name; }
virtual void addSection(InputSectionData *C) {}
virtual Kind getKind() const { return Base; }
static bool classof(const OutputSectionBase *B) {
return B->getKind() == Base;
}
unsigned SectionIndex;
uint32_t getPhdrFlags() const;
void updateAlignment(uint64_t Alignment) {
if (Alignment > Addralign)
Addralign = Alignment;
void updateAlignment(uint32_t Val) {
if (Val > Alignment)
Alignment = Val;
}
// If true, this section will be page aligned on disk.
@ -78,191 +68,82 @@ public:
// between their file offsets should be equal to difference between their
// virtual addresses. To compute some section offset we use the following
// formula: Off = Off_first + VA - VA_first.
OutputSectionBase *FirstInPtLoad = nullptr;
virtual void finalize() {}
virtual void assignOffsets() {}
virtual void writeTo(uint8_t *Buf) {}
virtual ~OutputSectionBase() = default;
StringRef Name;
OutputSection *FirstInPtLoad = nullptr;
// The following fields correspond to Elf_Shdr members.
uint64_t Size = 0;
uint64_t Entsize = 0;
uint64_t Addralign = 0;
uint64_t Offset = 0;
uint64_t Flags = 0;
uint64_t LMAOffset = 0;
uint64_t Addr = 0;
uint32_t ShName = 0;
uint32_t Type = 0;
uint32_t Info = 0;
uint32_t Link = 0;
};
template <class ELFT> class OutputSection final : public OutputSectionBase {
public:
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::uint uintX_t;
OutputSection(StringRef Name, uint32_t Type, uintX_t Flags);
void addSection(InputSectionData *C) override;
void sort(std::function<int(InputSection<ELFT> *S)> Order);
void addSection(InputSection *S);
void sort(std::function<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
void writeTo(uint8_t *Buf) override;
void finalize() override;
void assignOffsets() override;
Kind getKind() const override { return Regular; }
static bool classof(const OutputSectionBase *B) {
return B->getKind() == Regular;
}
std::vector<InputSection<ELFT> *> Sections;
uint32_t getFiller();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void finalize();
void assignOffsets();
std::vector<InputSection *> Sections;
// Location in the output buffer.
uint8_t *Loc = nullptr;
};
template <class ELFT>
class MergeOutputSection final : public OutputSectionBase {
typedef typename ELFT::uint uintX_t;
public:
MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
uintX_t Alignment);
void addSection(InputSectionData *S) override;
void writeTo(uint8_t *Buf) override;
void finalize() override;
bool shouldTailMerge() const;
Kind getKind() const override { return Merge; }
static bool classof(const OutputSectionBase *B) {
return B->getKind() == Merge;
}
private:
void finalizeTailMerge();
void finalizeNoTailMerge();
llvm::StringTableBuilder Builder;
std::vector<MergeInputSection<ELFT> *> Sections;
};
struct CieRecord {
EhSectionPiece *Piece = nullptr;
std::vector<EhSectionPiece *> FdePieces;
};
// Output section for .eh_frame.
template <class ELFT> class EhOutputSection final : public OutputSectionBase {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
public:
EhOutputSection();
void writeTo(uint8_t *Buf) override;
void finalize() override;
bool empty() const { return Sections.empty(); }
void addSection(InputSectionData *S) override;
Kind getKind() const override { return EHFrame; }
static bool classof(const OutputSectionBase *B) {
return B->getKind() == EHFrame;
}
size_t NumFdes = 0;
private:
template <class RelTy>
void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
template <class RelTy>
CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
template <class RelTy>
bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
std::vector<EhInputSection<ELFT> *> Sections;
std::vector<CieRecord *> Cies;
// CIE records are uniquified by their contents and personality functions.
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
};
// All output sections that are hadnled by the linker specially are
// All output sections that are handled by the linker specially are
// globally accessible. Writer initializes them, so don't use them
// until Writer is initialized.
template <class ELFT> struct Out {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Phdr Elf_Phdr;
struct Out {
static uint8_t First;
static EhOutputSection<ELFT> *EhFrame;
static OutputSection<ELFT> *Bss;
static OutputSection<ELFT> *BssRelRo;
static OutputSectionBase *Opd;
static OutputSection *Opd;
static uint8_t *OpdBuf;
static PhdrEntry *TlsPhdr;
static OutputSectionBase *DebugInfo;
static OutputSectionBase *ElfHeader;
static OutputSectionBase *ProgramHeaders;
static OutputSectionBase *PreinitArray;
static OutputSectionBase *InitArray;
static OutputSectionBase *FiniArray;
static OutputSection *DebugInfo;
static OutputSection *ElfHeader;
static OutputSection *ProgramHeaders;
static OutputSection *PreinitArray;
static OutputSection *InitArray;
static OutputSection *FiniArray;
};
struct SectionKey {
StringRef Name;
uint64_t Flags;
uint64_t Alignment;
uint32_t Alignment;
};
}
}
namespace llvm {
template <> struct DenseMapInfo<lld::elf::SectionKey> {
static lld::elf::SectionKey getEmptyKey();
static lld::elf::SectionKey getTombstoneKey();
static unsigned getHashValue(const lld::elf::SectionKey &Val);
static bool isEqual(const lld::elf::SectionKey &LHS,
const lld::elf::SectionKey &RHS);
};
}
namespace lld {
namespace elf {
// This class knows how to create an output section for a given
// input section. Output section type is determined by various
// factors, including input section's sh_flags, sh_type and
// linker scripts.
template <class ELFT> class OutputSectionFactory {
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::uint uintX_t;
class OutputSectionFactory {
public:
OutputSectionFactory();
OutputSectionFactory(std::vector<OutputSection *> &OutputSections);
~OutputSectionFactory();
std::pair<OutputSectionBase *, bool> create(InputSectionBase<ELFT> *C,
StringRef OutsecName);
std::pair<OutputSectionBase *, bool> create(const SectionKey &Key,
InputSectionBase<ELFT> *C);
void addInputSec(InputSectionBase *IS, StringRef OutsecName);
private:
llvm::SmallDenseMap<SectionKey, OutputSectionBase *> Map;
llvm::SmallDenseMap<SectionKey, OutputSection *> Map;
std::vector<OutputSection *> &OutputSections;
};
template <class ELFT> uint64_t getHeaderSize() {
if (Config->OFormatBinary)
return 0;
return Out<ELFT>::ElfHeader->Size + Out<ELFT>::ProgramHeaders->Size;
}
uint64_t getHeaderSize();
template <class ELFT> uint8_t Out<ELFT>::First;
template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::BssRelRo;
template <class ELFT> OutputSectionBase *Out<ELFT>::Opd;
template <class ELFT> uint8_t *Out<ELFT>::OpdBuf;
template <class ELFT> PhdrEntry *Out<ELFT>::TlsPhdr;
template <class ELFT> OutputSectionBase *Out<ELFT>::DebugInfo;
template <class ELFT> OutputSectionBase *Out<ELFT>::ElfHeader;
template <class ELFT> OutputSectionBase *Out<ELFT>::ProgramHeaders;
template <class ELFT> OutputSectionBase *Out<ELFT>::PreinitArray;
template <class ELFT> OutputSectionBase *Out<ELFT>::InitArray;
template <class ELFT> OutputSectionBase *Out<ELFT>::FiniArray;
} // namespace elf
} // namespace lld

File diff suppressed because it is too large Load diff

View file

@ -11,13 +11,16 @@
#define LLD_ELF_RELOCATIONS_H
#include "lld/Core/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include <map>
#include <vector>
namespace lld {
namespace elf {
class SymbolBody;
class InputSectionData;
template <class ELFT> class InputSection;
template <class ELFT> class InputSectionBase;
class InputSection;
class InputSectionBase;
class OutputSection;
// List of target-independent relocation types. Relocations read
// from files are converted to these types so that the main code
@ -34,39 +37,39 @@ enum RelExpr {
R_GOT_PAGE_PC,
R_GOT_PC,
R_HINT,
R_MIPS_GOTREL,
R_MIPS_GOT_GP,
R_MIPS_GOT_GP_PC,
R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOT_OFF,
R_MIPS_GOT_OFF32,
R_MIPS_GOTREL,
R_MIPS_TLSGD,
R_MIPS_TLSLD,
R_NEG_TLS,
R_NONE,
R_PAGE_PC,
R_PC,
R_PLT,
R_PLT_PC,
R_PLT_PAGE_PC,
R_PLT_PC,
R_PPC_OPD,
R_PPC_PLT_OPD,
R_PPC_TOC,
R_RELAX_GOT_PC,
R_RELAX_GOT_PC_NOPIC,
R_RELAX_TLS_GD_TO_IE,
R_RELAX_TLS_GD_TO_IE_END,
R_RELAX_TLS_GD_TO_IE_ABS,
R_RELAX_TLS_GD_TO_IE_END,
R_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_RELAX_TLS_GD_TO_LE,
R_RELAX_TLS_GD_TO_LE_NEG,
R_RELAX_TLS_IE_TO_LE,
R_RELAX_TLS_LD_TO_LE,
R_SIZE,
R_THUNK_ABS,
R_THUNK_PC,
R_THUNK_PLT_PC,
R_TLS,
R_TLSDESC,
R_TLSDESC_PAGE,
R_TLSDESC_CALL,
R_TLSDESC_PAGE,
R_TLSGD,
R_TLSGD_PC,
R_TLSLD,
@ -107,21 +110,44 @@ struct Relocation {
RelExpr Expr;
uint32_t Type;
uint64_t Offset;
uint64_t Addend;
int64_t Addend;
SymbolBody *Sym;
};
template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &);
template <class ELFT> void scanRelocations(InputSectionBase &);
template <class ELFT> void createThunks(InputSectionBase<ELFT> &);
class ThunkSection;
class Thunk;
template <class ELFT> class ThunkCreator {
public:
// Return true if Thunks have been added to OutputSections
bool createThunks(ArrayRef<OutputSection *> OutputSections);
private:
void mergeThunks(OutputSection *OS, std::vector<ThunkSection *> &Thunks);
ThunkSection *getOSThunkSec(ThunkSection *&TS, OutputSection *OS);
ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS);
std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type);
// Track Symbols that already have a Thunk
llvm::DenseMap<SymbolBody *, Thunk *> ThunkedSymbols;
// Track InputSections that have a ThunkSection placed in front
llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections;
// Track the ThunksSections that need to be inserted into an OutputSection
std::map<OutputSection *, std::vector<ThunkSection *>> ThunkSections;
};
// Return a int64_t to make sure we get the sign extension out of the way as
// early as possible.
template <class ELFT>
static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) {
static inline int64_t getAddend(const typename ELFT::Rel &Rel) {
return 0;
}
template <class ELFT>
static inline typename ELFT::uint getAddend(const typename ELFT::Rela &Rel) {
static inline int64_t getAddend(const typename ELFT::Rela &Rel) {
return Rel.r_addend;
}
}

285
ELF/ScriptLexer.cpp Normal file
View file

@ -0,0 +1,285 @@
//===- ScriptLexer.cpp ----------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a lexer for the linker script.
//
// The linker script's grammar is not complex but ambiguous due to the
// lack of the formal specification of the language. What we are trying to
// do in this and other files in LLD is to make a "reasonable" linker
// script processor.
//
// Among simplicity, compatibility and efficiency, we put the most
// emphasis on simplicity when we wrote this lexer. Compatibility with the
// GNU linkers is important, but we did not try to clone every tiny corner
// case of their lexers, as even ld.bfd and ld.gold are subtly different
// in various corner cases. We do not care much about efficiency because
// the time spent in parsing linker scripts is usually negligible.
//
// Our grammar of the linker script is LL(2), meaning that it needs at
// most two-token lookahead to parse. The only place we need two-token
// lookahead is labels in version scripts, where we need to parse "local :"
// as if "local:".
//
// Overall, this lexer works fine for most linker scripts. There might
// be room for improving compatibility, but that's probably not at the
// top of our todo list.
//
//===----------------------------------------------------------------------===//
#include "ScriptLexer.h"
#include "Error.h"
#include "llvm/ADT/Twine.h"
using namespace llvm;
using namespace lld;
using namespace lld::elf;
// Returns a whole line containing the current token.
StringRef ScriptLexer::getLine() {
StringRef S = getCurrentMB().getBuffer();
StringRef Tok = Tokens[Pos - 1];
size_t Pos = S.rfind('\n', Tok.data() - S.data());
if (Pos != StringRef::npos)
S = S.substr(Pos + 1);
return S.substr(0, S.find_first_of("\r\n"));
}
// Returns 1-based line number of the current token.
size_t ScriptLexer::getLineNumber() {
StringRef S = getCurrentMB().getBuffer();
StringRef Tok = Tokens[Pos - 1];
return S.substr(0, Tok.data() - S.data()).count('\n') + 1;
}
// Returns 0-based column number of the current token.
size_t ScriptLexer::getColumnNumber() {
StringRef Tok = Tokens[Pos - 1];
return Tok.data() - getLine().data();
}
std::string ScriptLexer::getCurrentLocation() {
std::string Filename = getCurrentMB().getBufferIdentifier();
if (!Pos)
return Filename;
return (Filename + ":" + Twine(getLineNumber())).str();
}
ScriptLexer::ScriptLexer(MemoryBufferRef MB) { tokenize(MB); }
// We don't want to record cascading errors. Keep only the first one.
void ScriptLexer::setError(const Twine &Msg) {
if (Error)
return;
Error = true;
if (!Pos) {
error(getCurrentLocation() + ": " + Msg);
return;
}
std::string S = getCurrentLocation() + ": ";
error(S + Msg);
error(S + getLine());
error(S + std::string(getColumnNumber(), ' ') + "^");
}
// Split S into linker script tokens.
void ScriptLexer::tokenize(MemoryBufferRef MB) {
std::vector<StringRef> Vec;
MBs.push_back(MB);
StringRef S = MB.getBuffer();
StringRef Begin = S;
for (;;) {
S = skipSpace(S);
if (S.empty())
break;
// Quoted token. Note that double-quote characters are parts of a token
// because, in a glob match context, only unquoted tokens are interpreted
// as glob patterns. Double-quoted tokens are literal patterns in that
// context.
if (S.startswith("\"")) {
size_t E = S.find("\"", 1);
if (E == StringRef::npos) {
StringRef Filename = MB.getBufferIdentifier();
size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n');
error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote");
return;
}
Vec.push_back(S.take_front(E + 1));
S = S.substr(E + 1);
continue;
}
// Unquoted token. This is more relaxed than tokens in C-like language,
// so that you can write "file-name.cpp" as one bare token, for example.
size_t Pos = S.find_first_not_of(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
"0123456789_.$/\\~=+[]*?-!<>^:");
// A character that cannot start a word (which is usually a
// punctuation) forms a single character token.
if (Pos == 0)
Pos = 1;
Vec.push_back(S.substr(0, Pos));
S = S.substr(Pos);
}
Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end());
}
// Skip leading whitespace characters or comments.
StringRef ScriptLexer::skipSpace(StringRef S) {
for (;;) {
if (S.startswith("/*")) {
size_t E = S.find("*/", 2);
if (E == StringRef::npos) {
error("unclosed comment in a linker script");
return "";
}
S = S.substr(E + 2);
continue;
}
if (S.startswith("#")) {
size_t E = S.find('\n', 1);
if (E == StringRef::npos)
E = S.size() - 1;
S = S.substr(E + 1);
continue;
}
size_t Size = S.size();
S = S.ltrim();
if (S.size() == Size)
return S;
}
}
// An erroneous token is handled as if it were the last token before EOF.
bool ScriptLexer::atEOF() { return Error || Tokens.size() == Pos; }
// Split a given string as an expression.
// This function returns "3", "*" and "5" for "3*5" for example.
static std::vector<StringRef> tokenizeExpr(StringRef S) {
StringRef Ops = "+-*/:"; // List of operators
// Quoted strings are literal strings, so we don't want to split it.
if (S.startswith("\""))
return {S};
// Split S with +-*/ as separators.
std::vector<StringRef> Ret;
while (!S.empty()) {
size_t E = S.find_first_of(Ops);
// No need to split if there is no operator.
if (E == StringRef::npos) {
Ret.push_back(S);
break;
}
// Get a token before the opreator.
if (E != 0)
Ret.push_back(S.substr(0, E));
// Get the operator as a token.
Ret.push_back(S.substr(E, 1));
S = S.substr(E + 1);
}
return Ret;
}
// In contexts where expressions are expected, the lexer should apply
// different tokenization rules than the default one. By default,
// arithmetic operator characters are regular characters, but in the
// expression context, they should be independent tokens.
//
// For example, "foo*3" should be tokenized to "foo", "*" and "3" only
// in the expression context.
//
// This function may split the current token into multiple tokens.
void ScriptLexer::maybeSplitExpr() {
if (!InExpr || Error || atEOF())
return;
std::vector<StringRef> V = tokenizeExpr(Tokens[Pos]);
if (V.size() == 1)
return;
Tokens.erase(Tokens.begin() + Pos);
Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
}
StringRef ScriptLexer::next() {
maybeSplitExpr();
if (Error)
return "";
if (atEOF()) {
setError("unexpected EOF");
return "";
}
return Tokens[Pos++];
}
StringRef ScriptLexer::peek() {
StringRef Tok = next();
if (Error)
return "";
Pos = Pos - 1;
return Tok;
}
bool ScriptLexer::consume(StringRef Tok) {
if (peek() == Tok) {
skip();
return true;
}
return false;
}
// Consumes Tok followed by ":". Space is allowed between Tok and ":".
bool ScriptLexer::consumeLabel(StringRef Tok) {
if (consume((Tok + ":").str()))
return true;
if (Tokens.size() >= Pos + 2 && Tokens[Pos] == Tok &&
Tokens[Pos + 1] == ":") {
Pos += 2;
return true;
}
return false;
}
void ScriptLexer::skip() { (void)next(); }
void ScriptLexer::expect(StringRef Expect) {
if (Error)
return;
StringRef Tok = next();
if (Tok != Expect)
setError(Expect + " expected, but got " + Tok);
}
// Returns true if S encloses T.
static bool encloses(StringRef S, StringRef T) {
return S.bytes_begin() <= T.bytes_begin() && T.bytes_end() <= S.bytes_end();
}
MemoryBufferRef ScriptLexer::getCurrentMB() {
// Find input buffer containing the current token.
assert(!MBs.empty());
if (!Pos)
return MBs[0];
for (MemoryBufferRef MB : MBs)
if (encloses(MB.getBuffer(), Tokens[Pos - 1]))
return MB;
llvm_unreachable("getCurrentMB: failed to find a token");
}

56
ELF/ScriptLexer.h Normal file
View file

@ -0,0 +1,56 @@
//===- ScriptLexer.h --------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_SCRIPT_LEXER_H
#define LLD_ELF_SCRIPT_LEXER_H
#include "lld/Core/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
#include <utility>
#include <vector>
namespace lld {
namespace elf {
class ScriptLexer {
public:
explicit ScriptLexer(MemoryBufferRef MB);
void setError(const Twine &Msg);
void tokenize(MemoryBufferRef MB);
static StringRef skipSpace(StringRef S);
bool atEOF();
StringRef next();
StringRef peek();
void skip();
bool consume(StringRef Tok);
void expect(StringRef Expect);
bool consumeLabel(StringRef Tok);
std::string getCurrentLocation();
std::vector<MemoryBufferRef> MBs;
std::vector<StringRef> Tokens;
bool InExpr = false;
size_t Pos = 0;
bool Error = false;
private:
void maybeSplitExpr();
StringRef getLine();
size_t getLineNumber();
size_t getColumnNumber();
MemoryBufferRef getCurrentMB();
};
} // namespace elf
} // namespace lld
#endif

File diff suppressed because it is too large Load diff

View file

@ -11,41 +11,19 @@
#define LLD_ELF_SCRIPT_PARSER_H
#include "lld/Core/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
#include <utility>
#include <vector>
namespace lld {
namespace elf {
class ScriptParserBase {
public:
explicit ScriptParserBase(MemoryBufferRef MB);
// Parses a linker script. Calling this function updates
// Config and ScriptConfig.
void readLinkerScript(MemoryBufferRef MB);
void setError(const Twine &Msg);
void tokenize(MemoryBufferRef MB);
static StringRef skipSpace(StringRef S);
bool atEOF();
StringRef next();
StringRef peek();
void skip();
bool consume(StringRef Tok);
void expect(StringRef Expect);
std::string getCurrentLocation();
// Parses a version script.
void readVersionScript(MemoryBufferRef MB);
std::vector<MemoryBufferRef> MBs;
std::vector<StringRef> Tokens;
size_t Pos = 0;
bool Error = false;
private:
StringRef getLine();
size_t getLineNumber();
size_t getColumnNumber();
MemoryBufferRef getCurrentMB();
};
void readDynamicList(MemoryBufferRef MB);
} // namespace elf
} // namespace lld

View file

@ -91,9 +91,9 @@ bool elf::isValidCIdentifier(StringRef S) {
// Returns the demangled C++ symbol name for Name.
Optional<std::string> elf::demangle(StringRef Name) {
// __cxa_demangle can be used to demangle strings other than symbol
// itaniumDemangle can be used to demangle strings other than symbol
// names which do not necessarily start with "_Z". Name can be
// either a C or C++ symbol. Don't call __cxa_demangle if the name
// either a C or C++ symbol. Don't call itaniumDemangle if the name
// does not look like a C++ symbol name to avoid getting unexpected
// result for a C symbol that happens to match a mangled type name.
if (!Name.startswith("_Z"))

View file

@ -75,7 +75,7 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
}
if (Config->Trace)
outs() << toString(File) << "\n";
message(toString(File));
// .so file
if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
@ -115,7 +115,7 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
// Compile bitcode files and replace bitcode symbols.
LTO.reset(new BitcodeCompiler);
for (BitcodeFile *F : BitcodeFiles)
LTO->add<ELFT>(*F);
LTO->add(*F);
for (InputFile *File : LTO->compile()) {
ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File);
@ -126,19 +126,19 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
}
template <class ELFT>
DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name,
uint8_t Visibility,
uint8_t Binding) {
DefinedRegular *SymbolTable<ELFT>::addAbsolute(StringRef Name,
uint8_t Visibility,
uint8_t Binding) {
Symbol *Sym =
addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr);
return cast<DefinedRegular<ELFT>>(Sym->body());
return cast<DefinedRegular>(Sym->body());
}
// Add Name as an "ignored" symbol. An ignored symbol is a regular
// linker-synthesized defined symbol, but is only defined if needed.
template <class ELFT>
DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name,
uint8_t Visibility) {
DefinedRegular *SymbolTable<ELFT>::addIgnored(StringRef Name,
uint8_t Visibility) {
SymbolBody *S = find(Name);
if (!S || S->isInCurrentDSO())
return nullptr;
@ -191,7 +191,7 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
Symbol *Sym;
if (IsNew) {
Sym = new (BAlloc) Symbol;
Sym = make<Symbol>();
Sym->InVersionScript = false;
Sym->Binding = STB_WEAK;
Sym->Visibility = STV_DEFAULT;
@ -206,13 +206,6 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
return {Sym, IsNew};
}
// Construct a string in the form of "Sym in File1 and File2".
// Used to construct an error message.
static std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile) {
return "'" + toString(*Existing) + "' in " + toString(Existing->File) +
" and " + toString(NewFile);
}
// Find an existing symbol or create and insert a new one, then apply the given
// attributes.
template <class ELFT>
@ -226,13 +219,19 @@ SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
// Merge in the new symbol's visibility.
S->Visibility = getMinVisibility(S->Visibility, Visibility);
if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic))
S->ExportDynamic = true;
if (IsUsedInRegularObj)
S->IsUsedInRegularObj = true;
if (!WasInserted && S->body()->Type != SymbolBody::UnknownType &&
((Type == STT_TLS) != S->body()->isTls()))
error("TLS attribute mismatch for symbol " + conflictMsg(S->body(), File));
((Type == STT_TLS) != S->body()->isTls())) {
error("TLS attribute mismatch: " + toString(*S->body()) +
"\n>>> defined in " + toString(S->body()->File) +
"\n>>> defined in " + toString(File));
}
return {S, WasInserted};
}
@ -252,18 +251,22 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
InputFile *File) {
Symbol *S;
bool WasInserted;
uint8_t Visibility = getVisibility(StOther);
std::tie(S, WasInserted) =
insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File);
if (WasInserted) {
insert(Name, Type, Visibility, CanOmitFromDynSym, File);
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
if (WasInserted ||
(isa<SharedSymbol>(S->body()) && Visibility != STV_DEFAULT)) {
S->Binding = Binding;
replaceBody<Undefined<ELFT>>(S, Name, IsLocal, StOther, Type, File);
replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File);
return S;
}
if (Binding != STB_WEAK) {
if (S->body()->isShared() || S->body()->isLazy())
S->Binding = Binding;
if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(S->body()))
SS->file()->IsUsed = true;
if (auto *SS = dyn_cast<SharedSymbol>(S->body()))
cast<SharedFile<ELFT>>(SS->File)->IsUsed = true;
}
if (auto *L = dyn_cast<Lazy>(S->body())) {
// An undefined weak will not fetch archive members, but we have to remember
@ -309,7 +312,7 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
if (Config->WarnCommon)
warn("common " + S->body()->getName() + " is overridden");
return 1;
} else if (auto *R = dyn_cast<DefinedRegular<ELFT>>(B)) {
} else if (auto *R = dyn_cast<DefinedRegular>(B)) {
if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute &&
R->Value == Value)
return -1;
@ -319,7 +322,7 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
template <class ELFT>
Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
uint64_t Alignment, uint8_t Binding,
uint32_t Alignment, uint8_t Binding,
uint8_t StOther, uint8_t Type,
InputFile *File) {
Symbol *S;
@ -349,40 +352,56 @@ Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
return S;
}
static void print(const Twine &Msg) {
static void warnOrError(const Twine &Msg) {
if (Config->AllowMultipleDefinition)
warn(Msg);
else
error(Msg);
}
static void reportDuplicate(SymbolBody *Existing, InputFile *NewFile) {
print("duplicate symbol " + conflictMsg(Existing, NewFile));
static void reportDuplicate(SymbolBody *Sym, InputFile *NewFile) {
warnOrError("duplicate symbol: " + toString(*Sym) +
"\n>>> defined in " + toString(Sym->File) +
"\n>>> defined in " + toString(NewFile));
}
template <class ELFT>
static void reportDuplicate(SymbolBody *Existing,
InputSectionBase<ELFT> *ErrSec,
static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec,
typename ELFT::uint ErrOffset) {
DefinedRegular<ELFT> *D = dyn_cast<DefinedRegular<ELFT>>(Existing);
DefinedRegular *D = dyn_cast<DefinedRegular>(Sym);
if (!D || !D->Section || !ErrSec) {
reportDuplicate(Existing, ErrSec ? ErrSec->getFile() : nullptr);
reportDuplicate(Sym, ErrSec ? ErrSec->getFile<ELFT>() : nullptr);
return;
}
std::string OldLoc = D->Section->getLocation(D->Value);
std::string NewLoc = ErrSec->getLocation(ErrOffset);
// Construct and print an error message in the form of:
//
// ld.lld: error: duplicate symbol: foo
// >>> defined at bar.c:30
// >>> bar.o (/home/alice/src/bar.o)
// >>> defined at baz.c:563
// >>> baz.o in archive libbaz.a
auto *Sec1 = cast<InputSectionBase>(D->Section);
std::string Src1 = Sec1->getSrcMsg<ELFT>(D->Value);
std::string Obj1 = Sec1->getObjMsg<ELFT>(D->Value);
std::string Src2 = ErrSec->getSrcMsg<ELFT>(ErrOffset);
std::string Obj2 = ErrSec->getObjMsg<ELFT>(ErrOffset);
print(NewLoc + ": duplicate symbol '" + toString(*Existing) + "'");
print(OldLoc + ": previous definition was here");
std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at ";
if (!Src1.empty())
Msg += Src1 + "\n>>> ";
Msg += Obj1 + "\n>>> defined at ";
if (!Src2.empty())
Msg += Src2 + "\n>>> ";
Msg += Obj2;
warnOrError(Msg);
}
template <typename ELFT>
Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t StOther,
uint8_t Type, uintX_t Value, uintX_t Size,
uint8_t Binding,
InputSectionBase<ELFT> *Section,
InputFile *File) {
uint8_t Type, uint64_t Value,
uint64_t Size, uint8_t Binding,
SectionBase *Section, InputFile *File) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther),
@ -390,32 +409,16 @@ Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t StOther,
int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
Section == nullptr, Value);
if (Cmp > 0)
replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type,
Value, Size, Section, File);
replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type,
Value, Size, Section, File);
else if (Cmp == 0)
reportDuplicate(S->body(), Section, Value);
reportDuplicate<ELFT>(S->body(),
dyn_cast_or_null<InputSectionBase>(Section), Value);
return S;
}
template <typename ELFT>
Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N,
const OutputSectionBase *Section,
uintX_t Value, uint8_t StOther) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, STT_NOTYPE, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, nullptr);
int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, STB_GLOBAL,
/*IsAbsolute*/ false, /*Value*/ 0);
if (Cmp > 0)
replaceBody<DefinedSynthetic>(S, N, Value, Section);
else if (Cmp == 0)
reportDuplicate(S->body(), nullptr);
return S;
}
template <typename ELFT>
void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *File, StringRef Name,
const Elf_Sym &Sym,
const typename ELFT::Verdef *Verdef) {
// DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
@ -423,15 +426,21 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
// unchanged.
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) =
insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, F);
std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT,
/*CanOmitFromDynSym*/ true, File);
// Make sure we preempt DSO symbols with default visibility.
if (Sym.getVisibility() == STV_DEFAULT)
S->ExportDynamic = true;
if (WasInserted || isa<Undefined<ELFT>>(S->body())) {
replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
SymbolBody *Body = S->body();
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
if (WasInserted ||
(isa<Undefined>(Body) && Body->getVisibility() == STV_DEFAULT)) {
replaceBody<SharedSymbol>(S, File, Name, Sym.st_other, Sym.getType(), &Sym,
Verdef);
if (!S->isWeak())
F->IsUsed = true;
File->IsUsed = true;
}
}
@ -446,8 +455,8 @@ Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, uint8_t Binding,
int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
/*IsAbs*/ false, /*Value*/ 0);
if (Cmp > 0)
replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type,
0, 0, nullptr, F);
replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0,
nullptr, F);
else if (Cmp == 0)
reportDuplicate(S->body(), F);
return S;

View file

@ -19,7 +19,6 @@
namespace lld {
namespace elf {
class Lazy;
class OutputSectionBase;
struct Symbol;
// SymbolTable is a bucket of all known symbols, including defined,
@ -36,7 +35,6 @@ struct Symbol;
// is one add* function per symbol type.
template <class ELFT> class SymbolTable {
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::uint uintX_t;
public:
void addFile(InputFile *File);
@ -47,11 +45,11 @@ public:
ArrayRef<BinaryFile *> getBinaryFiles() const { return BinaryFiles; }
ArrayRef<SharedFile<ELFT> *> getSharedFiles() const { return SharedFiles; }
DefinedRegular<ELFT> *addAbsolute(StringRef Name,
uint8_t Visibility = llvm::ELF::STV_HIDDEN,
uint8_t Binding = llvm::ELF::STB_GLOBAL);
DefinedRegular<ELFT> *addIgnored(StringRef Name,
uint8_t Visibility = llvm::ELF::STV_HIDDEN);
DefinedRegular *addAbsolute(StringRef Name,
uint8_t Visibility = llvm::ELF::STV_HIDDEN,
uint8_t Binding = llvm::ELF::STB_GLOBAL);
DefinedRegular *addIgnored(StringRef Name,
uint8_t Visibility = llvm::ELF::STV_HIDDEN);
Symbol *addUndefined(StringRef Name);
Symbol *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding,
@ -59,11 +57,8 @@ public:
InputFile *File);
Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
uintX_t Value, uintX_t Size, uint8_t Binding,
InputSectionBase<ELFT> *Section, InputFile *File);
Symbol *addSynthetic(StringRef N, const OutputSectionBase *Section,
uintX_t Value, uint8_t StOther);
uint64_t Value, uint64_t Size, uint8_t Binding,
SectionBase *Section, InputFile *File);
void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
const typename ELFT::Verdef *Verdef);
@ -73,10 +68,15 @@ public:
Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File);
Symbol *addCommon(StringRef N, uint64_t Size, uint64_t Alignment,
Symbol *addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
uint8_t Binding, uint8_t StOther, uint8_t Type,
InputFile *File);
std::pair<Symbol *, bool> insert(StringRef Name);
std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
uint8_t Visibility, bool CanOmitFromDynSym,
InputFile *File);
void scanUndefinedFlags();
void scanShlibUndefined();
void scanVersionScript();
@ -87,14 +87,7 @@ public:
void trace(StringRef Name);
void wrap(StringRef Name);
std::vector<InputSectionBase<ELFT> *> Sections;
private:
std::pair<Symbol *, bool> insert(StringRef Name);
std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
uint8_t Visibility, bool CanOmitFromDynSym,
InputFile *File);
std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);
std::vector<SymbolBody *> findAllByVersion(SymbolVersion Ver);

View file

@ -28,62 +28,89 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
template <class ELFT>
static typename ELFT::uint getSymVA(const SymbolBody &Body,
typename ELFT::uint &Addend) {
typedef typename ELFT::uint uintX_t;
DefinedRegular *ElfSym::Bss;
DefinedRegular *ElfSym::Etext1;
DefinedRegular *ElfSym::Etext2;
DefinedRegular *ElfSym::Edata1;
DefinedRegular *ElfSym::Edata2;
DefinedRegular *ElfSym::End1;
DefinedRegular *ElfSym::End2;
DefinedRegular *ElfSym::MipsGp;
DefinedRegular *ElfSym::MipsGpDisp;
DefinedRegular *ElfSym::MipsLocalGp;
static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) {
switch (Body.kind()) {
case SymbolBody::DefinedSyntheticKind: {
auto &D = cast<DefinedSynthetic>(Body);
const OutputSectionBase *Sec = D.Section;
if (!Sec)
return D.Value;
if (D.Value == uintX_t(-1))
return Sec->Addr + Sec->Size;
return Sec->Addr + D.Value;
}
case SymbolBody::DefinedRegularKind: {
auto &D = cast<DefinedRegular<ELFT>>(Body);
InputSectionBase<ELFT> *IS = D.Section;
auto &D = cast<DefinedRegular>(Body);
SectionBase *IS = D.Section;
if (auto *ISB = dyn_cast_or_null<InputSectionBase>(IS))
IS = ISB->Repl;
// According to the ELF spec reference to a local symbol from outside
// the group are not allowed. Unfortunately .eh_frame breaks that rule
// and must be treated specially. For now we just replace the symbol with
// 0.
if (IS == &InputSection<ELFT>::Discarded)
if (IS == &InputSection::Discarded)
return 0;
// This is an absolute symbol.
if (!IS)
return D.Value;
uintX_t Offset = D.Value;
uint64_t Offset = D.Value;
// An object in an SHF_MERGE section might be referenced via a
// section symbol (as a hack for reducing the number of local
// symbols).
// Depending on the addend, the reference via a section symbol
// refers to a different object in the merge section.
// Since the objects in the merge section are not necessarily
// contiguous in the output, the addend can thus affect the final
// VA in a non-linear way.
// To make this work, we incorporate the addend into the section
// offset (and zero out the addend for later processing) so that
// we find the right object in the section.
if (D.isSection()) {
Offset += Addend;
Addend = 0;
}
uintX_t VA = (IS->OutSec ? IS->OutSec->Addr : 0) + IS->getOffset(Offset);
const OutputSection *OutSec = IS->getOutputSection();
// In the typical case, this is actually very simple and boils
// down to adding together 3 numbers:
// 1. The address of the output section.
// 2. The offset of the input section within the output section.
// 3. The offset within the input section (this addition happens
// inside InputSection::getOffset).
//
// If you understand the data structures involved with this next
// line (and how they get built), then you have a pretty good
// understanding of the linker.
uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset);
if (D.isTls() && !Config->Relocatable) {
if (!Out<ELFT>::TlsPhdr)
if (!Out::TlsPhdr)
fatal(toString(D.File) +
" has a STT_TLS symbol but doesn't have a PT_TLS section");
return VA - Out<ELFT>::TlsPhdr->p_vaddr;
return VA - Out::TlsPhdr->p_vaddr;
}
return VA;
}
case SymbolBody::DefinedCommonKind:
if (!Config->DefineCommon)
return 0;
return In<ELFT>::Common->OutSec->Addr + In<ELFT>::Common->OutSecOff +
return InX::Common->OutSec->Addr + InX::Common->OutSecOff +
cast<DefinedCommon>(Body).Offset;
case SymbolBody::SharedKind: {
auto &SS = cast<SharedSymbol<ELFT>>(Body);
if (!SS.NeedsCopyOrPltAddr)
return 0;
if (SS.isFunc())
return Body.getPltVA<ELFT>();
return SS.getBssSectionForCopy()->Addr + SS.CopyOffset;
auto &SS = cast<SharedSymbol>(Body);
if (SS.NeedsCopy)
return SS.CopyRelSec->OutSec->Addr + SS.CopyRelSec->OutSecOff +
SS.CopyRelSecOff;
if (SS.NeedsPltAddr)
return Body.getPltVA();
return 0;
}
case SymbolBody::UndefinedKind:
return 0;
@ -97,10 +124,9 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type)
: SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal),
: SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal),
IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
IsInIgot(false), CopyIsInBssRelRo(false), Type(Type), StOther(StOther),
Name(Name) {}
IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {}
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
@ -112,7 +138,7 @@ bool SymbolBody::isPreemptible() const {
// symbols with copy relocations (which resolve to .bss) or preempt plt
// entries (which resolve to that plt entry).
if (isShared())
return !NeedsCopyOrPltAddr;
return !NeedsCopy && !NeedsPltAddr;
// That's all that can be preempted in a non-DSO.
if (!Config->Shared)
@ -132,65 +158,68 @@ bool SymbolBody::isPreemptible() const {
return true;
}
template <class ELFT> bool SymbolBody::hasThunk() const {
if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
return DR->ThunkData != nullptr;
if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
return S->ThunkData != nullptr;
return false;
}
template <class ELFT>
typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend);
uint64_t SymbolBody::getVA(int64_t Addend) const {
uint64_t OutVA = getSymVA(*this, Addend);
return OutVA + Addend;
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
return In<ELFT>::Got->getVA() + getGotOffset<ELFT>();
return In<ELFT>::Got->getVA() + getGotOffset();
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
uint64_t SymbolBody::getGotOffset() const {
return GotIndex * Target->GotEntrySize;
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
uint64_t SymbolBody::getGotPltVA() const {
if (this->IsInIgot)
return In<ELFT>::IgotPlt->getVA() + getGotPltOffset<ELFT>();
return In<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
return InX::IgotPlt->getVA() + getGotPltOffset();
return InX::GotPlt->getVA() + getGotPltOffset();
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
uint64_t SymbolBody::getGotPltOffset() const {
return GotPltIndex * Target->GotPltEntrySize;
}
template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
uint64_t SymbolBody::getPltVA() const {
if (this->IsInIplt)
return In<ELFT>::Iplt->getVA() + PltIndex * Target->PltEntrySize;
return In<ELFT>::Plt->getVA() + Target->PltHeaderSize +
return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
return InX::Plt->getVA() + Target->PltHeaderSize +
PltIndex * Target->PltEntrySize;
}
template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
return DR->ThunkData->getVA();
if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
return S->ThunkData->getVA();
if (const auto *S = dyn_cast<Undefined<ELFT>>(this))
return S->ThunkData->getVA();
fatal("getThunkVA() not supported for Symbol class\n");
}
template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
if (const auto *C = dyn_cast<DefinedCommon>(this))
return C->Size;
if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
if (const auto *DR = dyn_cast<DefinedRegular>(this))
return DR->Size;
if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
return S->Sym.st_size;
if (const auto *S = dyn_cast<SharedSymbol>(this))
return S->getSize<ELFT>();
return 0;
}
OutputSection *SymbolBody::getOutputSection() const {
if (auto *S = dyn_cast<DefinedRegular>(this)) {
if (S->Section)
return S->Section->getOutputSection();
return nullptr;
}
if (auto *S = dyn_cast<SharedSymbol>(this)) {
if (S->NeedsCopy)
return S->CopyRelSec->OutSec;
return nullptr;
}
if (isa<DefinedCommon>(this)) {
if (Config->DefineCommon)
return InX::Common->OutSec;
return nullptr;
}
return nullptr;
}
// If a symbol name contains '@', the characters after that is
// a symbol version name. This function parses that.
void SymbolBody::parseSymbolVersion() {
@ -234,27 +263,25 @@ Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type)
: SymbolBody(K, Name, IsLocal, StOther, Type) {}
template <class ELFT> bool DefinedRegular<ELFT>::isMipsPIC() const {
template <class ELFT> bool DefinedRegular::isMipsPIC() const {
if (!Section || !isFunc())
return false;
return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
(Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC);
(cast<InputSectionBase>(Section)
->template getFile<ELFT>()
->getObj()
.getHeader()
->e_flags &
EF_MIPS_PIC);
}
template <typename ELFT>
Undefined<ELFT>::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type, InputFile *File)
Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type, InputFile *File)
: SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
this->File = File;
}
template <typename ELFT>
OutputSection<ELFT> *SharedSymbol<ELFT>::getBssSectionForCopy() const {
assert(needsCopy());
return CopyIsInBssRelRo ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss;
}
DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment,
DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment,
uint8_t StOther, uint8_t Type, InputFile *File)
: Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther,
Type),
@ -262,6 +289,17 @@ DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment,
this->File = File;
}
// If a shared symbol is referred via a copy relocation, its alignment
// becomes part of the ABI. This function returns a symbol alignment.
// Because symbols don't have alignment attributes, we need to infer that.
template <class ELFT> uint32_t SharedSymbol::getAlignment() const {
auto *File = cast<SharedFile<ELFT>>(this->File);
uint32_t SecAlign = File->getSection(getSym<ELFT>())->sh_addralign;
uint64_t SymValue = getSym<ELFT>().st_value;
uint32_t SymAlign = uint32_t(1) << countTrailingZeros(SymValue);
return std::min(SecAlign, SymAlign);
}
InputFile *Lazy::fetch() {
if (auto *S = dyn_cast<LazyArchive>(this))
return S->fetch();
@ -319,15 +357,15 @@ bool Symbol::includeInDynsym() const {
// Print out a log message for --trace-symbol.
void elf::printTraceSymbol(Symbol *Sym) {
SymbolBody *B = Sym->body();
outs() << toString(B->File);
std::string S;
if (B->isUndefined())
outs() << ": reference to ";
S = ": reference to ";
else if (B->isCommon())
outs() << ": common definition of ";
S = ": common definition of ";
else
outs() << ": definition of ";
outs() << B->getName() << "\n";
S = ": definition of ";
message(toString(B->File) + S + B->getName());
}
// Returns a symbol for an error message.
@ -338,62 +376,22 @@ std::string lld::toString(const SymbolBody &B) {
return B.getName();
}
template bool SymbolBody::hasThunk<ELF32LE>() const;
template bool SymbolBody::hasThunk<ELF32BE>() const;
template bool SymbolBody::hasThunk<ELF64LE>() const;
template bool SymbolBody::hasThunk<ELF64BE>() const;
template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
template uint64_t SymbolBody::template getVA<ELF64BE>(uint64_t) const;
template uint32_t SymbolBody::template getGotVA<ELF32LE>() const;
template uint32_t SymbolBody::template getGotVA<ELF32BE>() const;
template uint64_t SymbolBody::template getGotVA<ELF64LE>() const;
template uint64_t SymbolBody::template getGotVA<ELF64BE>() const;
template uint32_t SymbolBody::template getGotOffset<ELF32LE>() const;
template uint32_t SymbolBody::template getGotOffset<ELF32BE>() const;
template uint64_t SymbolBody::template getGotOffset<ELF64LE>() const;
template uint64_t SymbolBody::template getGotOffset<ELF64BE>() const;
template uint32_t SymbolBody::template getGotPltVA<ELF32LE>() const;
template uint32_t SymbolBody::template getGotPltVA<ELF32BE>() const;
template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const;
template uint64_t SymbolBody::template getGotPltVA<ELF64BE>() const;
template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const;
template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const;
template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const;
template uint64_t SymbolBody::template getThunkVA<ELF64BE>() const;
template uint32_t SymbolBody::template getGotPltOffset<ELF32LE>() const;
template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const;
template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const;
template uint64_t SymbolBody::template getGotPltOffset<ELF64BE>() const;
template uint32_t SymbolBody::template getPltVA<ELF32LE>() const;
template uint32_t SymbolBody::template getPltVA<ELF32BE>() const;
template uint64_t SymbolBody::template getPltVA<ELF64LE>() const;
template uint64_t SymbolBody::template getPltVA<ELF64BE>() const;
template uint32_t SymbolBody::template getSize<ELF32LE>() const;
template uint32_t SymbolBody::template getSize<ELF32BE>() const;
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
template uint64_t SymbolBody::template getSize<ELF64BE>() const;
template class elf::Undefined<ELF32LE>;
template class elf::Undefined<ELF32BE>;
template class elf::Undefined<ELF64LE>;
template class elf::Undefined<ELF64BE>;
template bool DefinedRegular::template isMipsPIC<ELF32LE>() const;
template bool DefinedRegular::template isMipsPIC<ELF32BE>() const;
template bool DefinedRegular::template isMipsPIC<ELF64LE>() const;
template bool DefinedRegular::template isMipsPIC<ELF64BE>() const;
template class elf::SharedSymbol<ELF32LE>;
template class elf::SharedSymbol<ELF32BE>;
template class elf::SharedSymbol<ELF64LE>;
template class elf::SharedSymbol<ELF64BE>;
template class elf::DefinedRegular<ELF32LE>;
template class elf::DefinedRegular<ELF32BE>;
template class elf::DefinedRegular<ELF64LE>;
template class elf::DefinedRegular<ELF64BE>;
template uint32_t SharedSymbol::template getAlignment<ELF32LE>() const;
template uint32_t SharedSymbol::template getAlignment<ELF32BE>() const;
template uint32_t SharedSymbol::template getAlignment<ELF64LE>() const;
template uint32_t SharedSymbol::template getAlignment<ELF64BE>() const;

View file

@ -30,8 +30,7 @@ class BitcodeFile;
class InputFile;
class LazyObjectFile;
template <class ELFT> class ObjectFile;
template <class ELFT> class OutputSection;
class OutputSectionBase;
class OutputSection;
template <class ELFT> class SharedFile;
struct Symbol;
@ -44,8 +43,7 @@ public:
DefinedRegularKind = DefinedFirst,
SharedKind,
DefinedCommonKind,
DefinedSyntheticKind,
DefinedLast = DefinedSyntheticKind,
DefinedLast = DefinedCommonKind,
UndefinedKind,
LazyArchiveKind,
LazyObjectKind,
@ -76,18 +74,16 @@ public:
bool isInGot() const { return GotIndex != -1U; }
bool isInPlt() const { return PltIndex != -1U; }
template <class ELFT> bool hasThunk() const;
template <class ELFT>
typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const;
uint64_t getVA(int64_t Addend = 0) const;
template <class ELFT> typename ELFT::uint getGotOffset() const;
uint64_t getGotOffset() const;
template <class ELFT> typename ELFT::uint getGotVA() const;
template <class ELFT> typename ELFT::uint getGotPltOffset() const;
template <class ELFT> typename ELFT::uint getGotPltVA() const;
template <class ELFT> typename ELFT::uint getPltVA() const;
template <class ELFT> typename ELFT::uint getThunkVA() const;
uint64_t getGotPltOffset() const;
uint64_t getGotPltVA() const;
uint64_t getPltVA() const;
template <class ELFT> typename ELFT::uint getSize() const;
OutputSection *getOutputSection() const;
// The file from which this symbol was created.
InputFile *File = nullptr;
@ -105,9 +101,13 @@ protected:
const unsigned SymbolKind : 8;
public:
// True if the linker has to generate a copy relocation for this shared
// symbol or if the symbol should point to its plt entry.
unsigned NeedsCopyOrPltAddr : 1;
// True if the linker has to generate a copy relocation.
// For SharedSymbol only.
unsigned NeedsCopy : 1;
// True the symbol should point to its PLT entry.
// For SharedSymbol only.
unsigned NeedsPltAddr : 1;
// True if this is a local symbol.
unsigned IsLocal : 1;
@ -124,11 +124,6 @@ public:
// True if this symbol is in the Igot sub-section of the .got.plt or .got.
unsigned IsInIgot : 1;
// True if this is a shared symbol in a read-only segment which requires a
// copy relocation. This causes space for the symbol to be allocated in the
// .bss.rel.ro section.
unsigned CopyIsInBssRelRo : 1;
// The following fields have the same meaning as the ELF symbol attributes.
uint8_t Type; // symbol type
uint8_t StOther; // st_other field value
@ -160,7 +155,7 @@ public:
class DefinedCommon : public Defined {
public:
DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t StOther,
DefinedCommon(StringRef N, uint64_t Size, uint32_t Alignment, uint8_t StOther,
uint8_t Type, InputFile *File);
static bool classof(const SymbolBody *S) {
@ -172,77 +167,35 @@ public:
uint64_t Offset;
// The maximum alignment we have seen for this symbol.
uint64_t Alignment;
uint32_t Alignment;
uint64_t Size;
};
// Regular defined symbols read from object file symbol tables.
template <class ELFT> class DefinedRegular : public Defined {
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::uint uintX_t;
class DefinedRegular : public Defined {
public:
DefinedRegular(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
uintX_t Value, uintX_t Size, InputSectionBase<ELFT> *Section,
uint64_t Value, uint64_t Size, SectionBase *Section,
InputFile *File)
: Defined(SymbolBody::DefinedRegularKind, Name, IsLocal, StOther, Type),
Value(Value), Size(Size),
Section(Section ? Section->Repl : NullInputSection) {
Value(Value), Size(Size), Section(Section) {
this->File = File;
}
// Return true if the symbol is a PIC function.
bool isMipsPIC() const;
template <class ELFT> bool isMipsPIC() const;
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedRegularKind;
}
uintX_t Value;
uintX_t Size;
// The input section this symbol belongs to. Notice that this is
// a reference to a pointer. We are using two levels of indirections
// because of ICF. If ICF decides two sections need to be merged, it
// manipulates this Section pointers so that they point to the same
// section. This is a bit tricky, so be careful to not be confused.
// If this is null, the symbol is an absolute symbol.
InputSectionBase<ELFT> *&Section;
// If non-null the symbol has a Thunk that may be used as an alternative
// destination for callers of this Symbol.
Thunk<ELFT> *ThunkData = nullptr;
private:
static InputSectionBase<ELFT> *NullInputSection;
};
template <class ELFT>
InputSectionBase<ELFT> *DefinedRegular<ELFT>::NullInputSection;
// DefinedSynthetic is a class to represent linker-generated ELF symbols.
// The difference from the regular symbol is that DefinedSynthetic symbols
// don't belong to any input files or sections. Thus, its constructor
// takes an output section to calculate output VA, etc.
// If Section is null, this symbol is relative to the image base.
class DefinedSynthetic : public Defined {
public:
DefinedSynthetic(StringRef Name, uint64_t Value,
const OutputSectionBase *Section)
: Defined(SymbolBody::DefinedSyntheticKind, Name, /*IsLocal=*/false,
llvm::ELF::STV_HIDDEN, 0 /* Type */),
Value(Value), Section(Section) {}
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedSyntheticKind;
}
uint64_t Value;
const OutputSectionBase *Section;
uint64_t Size;
SectionBase *Section;
};
template <class ELFT> class Undefined : public SymbolBody {
class Undefined : public SymbolBody {
public:
Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
InputFile *F);
@ -250,53 +203,51 @@ public:
static bool classof(const SymbolBody *S) {
return S->kind() == UndefinedKind;
}
// If non-null the symbol has a Thunk that may be used as an alternative
// destination for callers of this Symbol. When linking a DSO undefined
// symbols are implicitly imported, the symbol lookup will be performed by
// the dynamic loader. A call to an undefined symbol will be given a PLT
// entry and on ARM this may need a Thunk if the caller is in Thumb state.
Thunk<ELFT> *ThunkData = nullptr;
InputFile *file() { return this->File; }
};
template <class ELFT> class SharedSymbol : public Defined {
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::uint uintX_t;
class SharedSymbol : public Defined {
public:
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::SharedKind;
}
SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
const Elf_Verdef *Verdef)
: Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, Sym.st_other,
Sym.getType()),
Sym(Sym), Verdef(Verdef) {
SharedSymbol(InputFile *File, StringRef Name, uint8_t StOther, uint8_t Type,
const void *ElfSym, const void *Verdef)
: Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, StOther, Type),
Verdef(Verdef), ElfSym(ElfSym) {
// IFuncs defined in DSOs are treated as functions by the static linker.
if (isGnuIFunc())
Type = llvm::ELF::STT_FUNC;
this->File = F;
this->File = File;
}
SharedFile<ELFT> *file() { return (SharedFile<ELFT> *)this->File; }
template <class ELFT> uint64_t getShndx() const {
return getSym<ELFT>().st_shndx;
}
const Elf_Sym &Sym;
template <class ELFT> uint64_t getValue() const {
return getSym<ELFT>().st_value;
}
template <class ELFT> uint64_t getSize() const {
return getSym<ELFT>().st_size;
}
template <class ELFT> uint32_t getAlignment() const;
// This field is a pointer to the symbol's version definition.
const Elf_Verdef *Verdef;
const void *Verdef;
// CopyOffset is significant only when needsCopy() is true.
uintX_t CopyOffset = 0;
// CopyRelSec and CopyRelSecOff are significant only when NeedsCopy is true.
InputSection *CopyRelSec;
uint64_t CopyRelSecOff;
// If non-null the symbol has a Thunk that may be used as an alternative
// destination for callers of this Symbol.
Thunk<ELFT> *ThunkData = nullptr;
bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); }
private:
template <class ELFT> const typename ELFT::Sym &getSym() const {
return *(const typename ELFT::Sym *)ElfSym;
}
OutputSection<ELFT> *getBssSectionForCopy() const;
const void *ElfSym;
};
// This class represents a symbol defined in an archive file. It is
@ -350,39 +301,28 @@ public:
// Some linker-generated symbols need to be created as
// DefinedRegular symbols.
template <class ELFT> struct ElfSym {
// The content for __ehdr_start symbol.
static DefinedRegular<ELFT> *EhdrStart;
struct ElfSym {
// __bss_start
static DefinedRegular *Bss;
// The content for _etext and etext symbols.
static DefinedRegular<ELFT> *Etext;
static DefinedRegular<ELFT> *Etext2;
// etext and _etext
static DefinedRegular *Etext1;
static DefinedRegular *Etext2;
// The content for _edata and edata symbols.
static DefinedRegular<ELFT> *Edata;
static DefinedRegular<ELFT> *Edata2;
// edata and _edata
static DefinedRegular *Edata1;
static DefinedRegular *Edata2;
// The content for _end and end symbols.
static DefinedRegular<ELFT> *End;
static DefinedRegular<ELFT> *End2;
// end and _end
static DefinedRegular *End1;
static DefinedRegular *End2;
// The content for _gp_disp/__gnu_local_gp symbols for MIPS target.
static DefinedRegular<ELFT> *MipsGpDisp;
static DefinedRegular<ELFT> *MipsLocalGp;
static DefinedRegular<ELFT> *MipsGp;
// _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS.
static DefinedRegular *MipsGp;
static DefinedRegular *MipsGpDisp;
static DefinedRegular *MipsLocalGp;
};
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::EhdrStart;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext2;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGpDisp;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsLocalGp;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGp;
// A real symbol object, SymbolBody, is usually stored within a Symbol. There's
// always one Symbol for each symbol name. The resolver updates the SymbolBody
// stored in the Body field of this object as it resolves symbols. Symbol also
@ -426,13 +366,9 @@ struct Symbol {
// This field is used to store the Symbol's SymbolBody. This instantiation of
// AlignedCharArrayUnion gives us a struct with a char array field that is
// large and aligned enough to store any derived class of SymbolBody. We
// assume that the size and alignment of ELF64LE symbols is sufficient for any
// ELFT, and we verify this with the static_asserts in replaceBody.
llvm::AlignedCharArrayUnion<
DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic,
Undefined<llvm::object::ELF64LE>, SharedSymbol<llvm::object::ELF64LE>,
LazyArchive, LazyObject>
// large and aligned enough to store any derived class of SymbolBody.
llvm::AlignedCharArrayUnion<DefinedCommon, DefinedRegular, Undefined,
SharedSymbol, LazyArchive, LazyObject>
Body;
SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }

File diff suppressed because it is too large Load diff

View file

@ -6,10 +6,22 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Synthetic sections represent chunks of linker-created data. If you
// need to create a chunk of data that to be included in some section
// in the result, you probably want to create that as a synthetic section.
//
// Synthetic sections are designed as input sections as opposed to
// output sections because we want to allow them to be manipulated
// using linker scripts just like other input sections from regular
// files.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_SYNTHETIC_SECTION_H
#define LLD_ELF_SYNTHETIC_SECTION_H
#include "EhFrame.h"
#include "GdbIndex.h"
#include "InputSection.h"
#include "llvm/ADT/MapVector.h"
@ -18,49 +30,95 @@
namespace lld {
namespace elf {
template <class ELFT> class SyntheticSection : public InputSection<ELFT> {
typedef typename ELFT::uint uintX_t;
class SyntheticSection : public InputSection {
public:
SyntheticSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
SyntheticSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
StringRef Name)
: InputSection<ELFT>(Flags, Type, Addralign, ArrayRef<uint8_t>(), Name,
InputSectionData::Synthetic) {
: InputSection(Flags, Type, Alignment, {}, Name,
InputSectionBase::Synthetic) {
this->Live = true;
}
virtual ~SyntheticSection() = default;
virtual void writeTo(uint8_t *Buf) = 0;
virtual size_t getSize() const = 0;
virtual void finalize() {}
virtual void finalizeContents() {}
// If the section has the SHF_ALLOC flag and the size may be changed if
// thunks are added, update the section size.
virtual void updateAllocSize() {}
// If any additional finalization of contents are needed post thunk creation.
virtual void postThunkContents() {}
virtual bool empty() const { return false; }
uint64_t getVA() const;
uintX_t getVA() const {
return this->OutSec ? this->OutSec->Addr + this->OutSecOff : 0;
}
static bool classof(const InputSectionData *D) {
return D->kind() == InputSectionData::Synthetic;
static bool classof(const InputSectionBase *D) {
return D->kind() == InputSectionBase::Synthetic;
}
};
template <class ELFT> class GotSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::uint uintX_t;
struct CieRecord {
EhSectionPiece *Piece = nullptr;
std::vector<EhSectionPiece *> FdePieces;
};
// Section for .eh_frame.
template <class ELFT> class EhFrameSection final : public SyntheticSection {
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
void updateAlignment(uint64_t Val) {
if (Val > this->Alignment)
this->Alignment = Val;
}
public:
EhFrameSection();
void writeTo(uint8_t *Buf) override;
void finalizeContents() override;
bool empty() const override { return Sections.empty(); }
size_t getSize() const override { return Size; }
void addSection(InputSectionBase *S);
size_t NumFdes = 0;
std::vector<EhInputSection *> Sections;
private:
uint64_t Size = 0;
template <class RelTy>
void addSectionAux(EhInputSection *S, llvm::ArrayRef<RelTy> Rels);
template <class RelTy>
CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
template <class RelTy>
bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
uint64_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
std::vector<CieRecord *> Cies;
// CIE records are uniquified by their contents and personality functions.
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
};
template <class ELFT> class GotSection final : public SyntheticSection {
public:
GotSection();
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return Size; }
void finalize() override;
void finalizeContents() override;
bool empty() const override;
void addEntry(SymbolBody &Sym);
bool addDynTlsEntry(SymbolBody &Sym);
bool addTlsIndex();
uintX_t getGlobalDynAddr(const SymbolBody &B) const;
uintX_t getGlobalDynOffset(const SymbolBody &B) const;
uint64_t getGlobalDynAddr(const SymbolBody &B) const;
uint64_t getGlobalDynOffset(const SymbolBody &B) const;
uintX_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; }
uint64_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; }
uint32_t getTlsIndexOff() const { return TlsIndexOff; }
// Flag to force GOT to be in output if we have relocations
@ -70,11 +128,11 @@ public:
private:
size_t NumEntries = 0;
uint32_t TlsIndexOff = -1;
uintX_t Size = 0;
uint64_t Size = 0;
};
// .note.gnu.build-id section.
template <class ELFT> class BuildIdSection : public SyntheticSection<ELFT> {
class BuildIdSection : public SyntheticSection {
// First 16 bytes are a header.
static const unsigned HeaderSize = 16;
@ -92,22 +150,36 @@ private:
uint8_t *HashBuf;
};
template <class ELFT>
class MipsGotSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::uint uintX_t;
// BssSection is used to reserve space for copy relocations and common symbols.
// We create three instances of this class for .bss, .bss.rel.ro and "COMMON",
// that are used for writable symbols, read-only symbols and common symbols,
// respectively.
class BssSection final : public SyntheticSection {
public:
BssSection(StringRef Name);
void writeTo(uint8_t *) override {}
bool empty() const override { return getSize() == 0; }
size_t reserveSpace(uint64_t Size, uint32_t Alignment);
size_t getSize() const override { return Size; }
private:
uint64_t Size = 0;
};
class MipsGotSection final : public SyntheticSection {
public:
MipsGotSection();
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return Size; }
void finalize() override;
void updateAllocSize() override;
void finalizeContents() override;
bool empty() const override;
void addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr);
bool addDynTlsEntry(SymbolBody &Sym);
bool addTlsIndex();
uintX_t getPageEntryOffset(const SymbolBody &B, uintX_t Addend) const;
uintX_t getBodyEntryOffset(const SymbolBody &B, uintX_t Addend) const;
uintX_t getGlobalDynOffset(const SymbolBody &B) const;
uint64_t getPageEntryOffset(const SymbolBody &B, int64_t Addend) const;
uint64_t getBodyEntryOffset(const SymbolBody &B, int64_t Addend) const;
uint64_t getGlobalDynOffset(const SymbolBody &B) const;
// Returns the symbol which corresponds to the first entry of the global part
// of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
@ -121,11 +193,11 @@ public:
// Returns offset of TLS part of the MIPS GOT table. This part goes
// after 'local' and 'global' entries.
uintX_t getTlsOffset() const;
uint64_t getTlsOffset() const;
uint32_t getTlsIndexOff() const { return TlsIndexOff; }
uintX_t getGp() const;
uint64_t getGp() const;
private:
// MIPS GOT consists of three parts: local, global and tls. Each part
@ -171,9 +243,9 @@ private:
uint32_t PageEntriesNum = 0;
// Map output sections referenced by MIPS GOT relocations
// to the first index of "Page" entries allocated for this section.
llvm::SmallMapVector<const OutputSectionBase *, size_t, 16> PageIndexMap;
llvm::SmallMapVector<const OutputSection *, size_t, 16> PageIndexMap;
typedef std::pair<const SymbolBody *, uintX_t> GotEntry;
typedef std::pair<const SymbolBody *, uint64_t> GotEntry;
typedef std::vector<GotEntry> GotEntries;
// Map from Symbol-Addend pair to the GOT index.
llvm::DenseMap<GotEntry, size_t> EntryIndexMap;
@ -189,13 +261,10 @@ private:
std::vector<const SymbolBody *> TlsEntries;
uint32_t TlsIndexOff = -1;
uintX_t Size = 0;
uint64_t Size = 0;
};
template <class ELFT>
class GotPltSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::uint uintX_t;
class GotPltSection final : public SyntheticSection {
public:
GotPltSection();
void addEntry(SymbolBody &Sym);
@ -207,14 +276,11 @@ private:
std::vector<const SymbolBody *> Entries;
};
// The IgotPltSection is a Got associated with the IpltSection for GNU Ifunc
// The IgotPltSection is a Got associated with the PltSection for GNU Ifunc
// Symbols that will be relocated by Target->IRelativeRel.
// On most Targets the IgotPltSection will immediately follow the GotPltSection
// on ARM the IgotPltSection will immediately follow the GotSection.
template <class ELFT>
class IgotPltSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::uint uintX_t;
class IgotPltSection final : public SyntheticSection {
public:
IgotPltSection();
void addEntry(SymbolBody &Sym);
@ -226,10 +292,8 @@ private:
std::vector<const SymbolBody *> Entries;
};
template <class ELFT>
class StringTableSection final : public SyntheticSection<ELFT> {
class StringTableSection final : public SyntheticSection {
public:
typedef typename ELFT::uint uintX_t;
StringTableSection(StringRef Name, bool Dynamic);
unsigned addString(StringRef S, bool HashIt = true);
void writeTo(uint8_t *Buf) override;
@ -239,54 +303,41 @@ public:
private:
const bool Dynamic;
// ELF string tables start with a NUL byte, so 1.
uintX_t Size = 1;
uint64_t Size = 0;
llvm::DenseMap<StringRef, unsigned> StringMap;
std::vector<StringRef> Strings;
};
template <class ELFT> class DynamicReloc {
typedef typename ELFT::uint uintX_t;
class DynamicReloc {
public:
DynamicReloc(uint32_t Type, const InputSectionBase<ELFT> *InputSec,
uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
uintX_t Addend)
DynamicReloc(uint32_t Type, const InputSectionBase *InputSec,
uint64_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
int64_t Addend)
: Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
UseSymVA(UseSymVA), Addend(Addend) {}
DynamicReloc(uint32_t Type, const OutputSectionBase *OutputSec,
uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
uintX_t Addend)
: Type(Type), Sym(Sym), OutputSec(OutputSec), OffsetInSec(OffsetInSec),
UseSymVA(UseSymVA), Addend(Addend) {}
uintX_t getOffset() const;
uintX_t getAddend() const;
uint64_t getOffset() const;
int64_t getAddend() const;
uint32_t getSymIndex() const;
const OutputSectionBase *getOutputSec() const { return OutputSec; }
const InputSectionBase<ELFT> *getInputSec() const { return InputSec; }
const InputSectionBase *getInputSec() const { return InputSec; }
uint32_t Type;
private:
SymbolBody *Sym;
const InputSectionBase<ELFT> *InputSec = nullptr;
const OutputSectionBase *OutputSec = nullptr;
uintX_t OffsetInSec;
const InputSectionBase *InputSec = nullptr;
uint64_t OffsetInSec;
bool UseSymVA;
uintX_t Addend;
int64_t Addend;
};
template <class ELFT>
class DynamicSection final : public SyntheticSection<ELFT> {
template <class ELFT> class DynamicSection final : public SyntheticSection {
typedef typename ELFT::Dyn Elf_Dyn;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::uint uintX_t;
// The .dynamic section contains information for the dynamic linker.
// The section consists of fixed size entries, which consist of
@ -295,49 +346,45 @@ class DynamicSection final : public SyntheticSection<ELFT> {
struct Entry {
int32_t Tag;
union {
OutputSectionBase *OutSec;
InputSection<ELFT> *InSec;
OutputSection *OutSec;
InputSection *InSec;
uint64_t Val;
const SymbolBody *Sym;
};
enum KindT { SecAddr, SecSize, SymAddr, PlainInt, InSecAddr } Kind;
Entry(int32_t Tag, OutputSectionBase *OutSec, KindT Kind = SecAddr)
Entry(int32_t Tag, OutputSection *OutSec, KindT Kind = SecAddr)
: Tag(Tag), OutSec(OutSec), Kind(Kind) {}
Entry(int32_t Tag, InputSection<ELFT> *Sec)
Entry(int32_t Tag, InputSection *Sec)
: Tag(Tag), InSec(Sec), Kind(InSecAddr) {}
Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {}
Entry(int32_t Tag, const SymbolBody *Sym)
: Tag(Tag), Sym(Sym), Kind(SymAddr) {}
};
// finalize() fills this vector with the section contents. finalize()
// cannot directly create final section contents because when the
// function is called, symbol or section addresses are not fixed yet.
// finalizeContents() fills this vector with the section contents.
std::vector<Entry> Entries;
public:
DynamicSection();
void finalize() override;
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return Size; }
private:
void addEntries();
void add(Entry E) { Entries.push_back(E); }
uintX_t Size = 0;
uint64_t Size = 0;
};
template <class ELFT>
class RelocationSection final : public SyntheticSection<ELFT> {
template <class ELFT> class RelocationSection final : public SyntheticSection {
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::uint uintX_t;
public:
RelocationSection(StringRef Name, bool Sort);
void addReloc(const DynamicReloc<ELFT> &Reloc);
void addReloc(const DynamicReloc &Reloc);
unsigned getRelocOffset();
void finalize() override;
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
bool empty() const override { return Relocs.empty(); }
size_t getSize() const override { return Relocs.size() * this->Entsize; }
@ -346,7 +393,7 @@ public:
private:
bool Sort;
size_t NumRelativeRelocs = 0;
std::vector<DynamicReloc<ELFT>> Relocs;
std::vector<DynamicReloc> Relocs;
};
struct SymbolTableEntry {
@ -354,125 +401,95 @@ struct SymbolTableEntry {
size_t StrTabOffset;
};
template <class ELFT>
class SymbolTableSection final : public SyntheticSection<ELFT> {
template <class ELFT> class SymbolTableSection final : public SyntheticSection {
public:
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::uint uintX_t;
SymbolTableSection(StringTableSection<ELFT> &StrTabSec);
void finalize() override;
SymbolTableSection(StringTableSection &StrTabSec);
void finalizeContents() override;
void postThunkContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return getNumSymbols() * sizeof(Elf_Sym); }
void addGlobal(SymbolBody *Body);
void addLocal(SymbolBody *Body);
StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
void addSymbol(SymbolBody *Body);
unsigned getNumSymbols() const { return Symbols.size() + 1; }
size_t getSymbolIndex(SymbolBody *Body);
ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
static const OutputSectionBase *getOutputSection(SymbolBody *Sym);
private:
void writeLocalSymbols(uint8_t *&Buf);
void writeGlobalSymbols(uint8_t *Buf);
// A vector of symbols and their string table offsets.
std::vector<SymbolTableEntry> Symbols;
StringTableSection<ELFT> &StrTabSec;
unsigned NumLocals = 0;
StringTableSection &StrTabSec;
};
// Outputs GNU Hash section. For detailed explanation see:
// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
template <class ELFT>
class GnuHashTableSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::Off Elf_Off;
typedef typename ELFT::Word Elf_Word;
typedef typename ELFT::uint uintX_t;
class GnuHashTableSection final : public SyntheticSection {
public:
GnuHashTableSection();
void finalize() override;
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return this->Size; }
size_t getSize() const override { return Size; }
// Adds symbols to the hash table.
// Sorts the input to satisfy GNU hash section requirements.
void addSymbols(std::vector<SymbolTableEntry> &Symbols);
private:
static unsigned calcNBuckets(unsigned NumHashed);
static unsigned calcMaskWords(unsigned NumHashed);
size_t getShift2() const { return Config->Is64 ? 6 : 5; }
void writeHeader(uint8_t *&Buf);
void writeBloomFilter(uint8_t *&Buf);
void writeBloomFilter(uint8_t *Buf);
void writeHashTable(uint8_t *Buf);
struct SymbolData {
struct Entry {
SymbolBody *Body;
size_t STName;
size_t StrTabOffset;
uint32_t Hash;
};
std::vector<SymbolData> Symbols;
unsigned MaskWords;
unsigned NBuckets;
unsigned Shift2;
uintX_t Size = 0;
std::vector<Entry> Symbols;
size_t MaskWords;
size_t NBuckets = 0;
size_t Size = 0;
};
template <class ELFT>
class HashTableSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::Word Elf_Word;
template <class ELFT> class HashTableSection final : public SyntheticSection {
public:
HashTableSection();
void finalize() override;
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return this->Size; }
size_t getSize() const override { return Size; }
private:
size_t Size = 0;
};
template <class ELFT> class PltSection final : public SyntheticSection<ELFT> {
// The PltSection is used for both the Plt and Iplt. The former always has a
// header as its first entry that is used at run-time to resolve lazy binding.
// The latter is used for GNU Ifunc symbols, that will be subject to a
// Target->IRelativeRel.
class PltSection : public SyntheticSection {
public:
PltSection();
PltSection(size_t HeaderSize);
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
void addEntry(SymbolBody &Sym);
bool empty() const override { return Entries.empty(); }
void addSymbols();
template <class ELFT> void addEntry(SymbolBody &Sym);
private:
void writeHeader(uint8_t *Buf){};
void addHeaderSymbols(){};
unsigned getPltRelocOff() const;
std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
// Iplt always has HeaderSize of 0, the Plt HeaderSize is always non-zero
size_t HeaderSize;
};
// The IpltSection is a variant of Plt for recording entries for GNU Ifunc
// symbols that will be subject to a Target->IRelativeRel
// The IpltSection immediately follows the Plt section in the Output Section
template <class ELFT> class IpltSection final : public SyntheticSection<ELFT> {
public:
IpltSection();
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
void addEntry(SymbolBody &Sym);
bool empty() const override { return Entries.empty(); }
private:
std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
};
template <class ELFT>
class GdbIndexSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::uint uintX_t;
class GdbIndexSection final : public SyntheticSection {
const unsigned OffsetTypeSize = 4;
const unsigned CuListOffset = 6 * OffsetTypeSize;
const unsigned CompilationUnitSize = 16;
@ -481,13 +498,13 @@ class GdbIndexSection final : public SyntheticSection<ELFT> {
public:
GdbIndexSection();
void finalize() override;
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
bool empty() const override;
// Pairs of [CU Offset, CU length].
std::vector<std::pair<uintX_t, uintX_t>> CompilationUnits;
std::vector<std::pair<uint64_t, uint64_t>> CompilationUnits;
llvm::StringTableBuilder StringPool;
@ -496,11 +513,10 @@ public:
// The CU vector portion of the constant pool.
std::vector<std::vector<std::pair<uint32_t, uint8_t>>> CuVectors;
std::vector<AddressEntry<ELFT>> AddressArea;
std::vector<AddressEntry> AddressArea;
private:
void parseDebugSections();
void readDwarf(InputSection<ELFT> *I);
void readDwarf(InputSection *Sec);
uint32_t CuTypesOffset;
uint32_t SymTabOffset;
@ -522,10 +538,7 @@ private:
// Detailed info about internals can be found in Ian Lance Taylor's blog:
// http://www.airs.com/blog/archives/460 (".eh_frame")
// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
template <class ELFT>
class EhFrameHeader final : public SyntheticSection<ELFT> {
typedef typename ELFT::uint uintX_t;
template <class ELFT> class EhFrameHeader final : public SyntheticSection {
public:
EhFrameHeader();
void writeTo(uint8_t *Buf) override;
@ -551,13 +564,13 @@ private:
// The section shall contain an array of Elf_Verdef structures, optionally
// followed by an array of Elf_Verdaux structures.
template <class ELFT>
class VersionDefinitionSection final : public SyntheticSection<ELFT> {
class VersionDefinitionSection final : public SyntheticSection {
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Verdaux Elf_Verdaux;
public:
VersionDefinitionSection();
void finalize() override;
void finalizeContents() override;
size_t getSize() const override;
void writeTo(uint8_t *Buf) override;
@ -574,12 +587,12 @@ private:
// The values 0 and 1 are reserved. All other values are used for versions in
// the own object or in any of the dependencies.
template <class ELFT>
class VersionTableSection final : public SyntheticSection<ELFT> {
class VersionTableSection final : public SyntheticSection {
typedef typename ELFT::Versym Elf_Versym;
public:
VersionTableSection();
void finalize() override;
void finalizeContents() override;
size_t getSize() const override;
void writeTo(uint8_t *Buf) override;
bool empty() const override;
@ -590,8 +603,7 @@ public:
// Elf_Verneed specifies the version requirements for a single DSO, and contains
// a reference to a linked list of Elf_Vernaux data structures which define the
// mapping from version identifiers to version names.
template <class ELFT>
class VersionNeedSection final : public SyntheticSection<ELFT> {
template <class ELFT> class VersionNeedSection final : public SyntheticSection {
typedef typename ELFT::Verneed Elf_Verneed;
typedef typename ELFT::Vernaux Elf_Vernaux;
@ -604,17 +616,40 @@ class VersionNeedSection final : public SyntheticSection<ELFT> {
public:
VersionNeedSection();
void addSymbol(SharedSymbol<ELFT> *SS);
void finalize() override;
void addSymbol(SharedSymbol *SS);
void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
size_t getNeedNum() const { return Needed.size(); }
bool empty() const override;
};
// MergeSyntheticSection is a class that allows us to put mergeable sections
// with different attributes in a single output sections. To do that
// we put them into MergeSyntheticSection synthetic input sections which are
// attached to regular output sections.
class MergeSyntheticSection final : public SyntheticSection {
public:
MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags,
uint32_t Alignment);
void addSection(MergeInputSection *MS);
void writeTo(uint8_t *Buf) override;
void finalizeContents() override;
bool shouldTailMerge() const;
size_t getSize() const override;
private:
void finalizeTailMerge();
void finalizeNoTailMerge();
bool Finalized = false;
llvm::StringTableBuilder Builder;
std::vector<MergeInputSection *> Sections;
};
// .MIPS.abiflags section.
template <class ELFT>
class MipsAbiFlagsSection final : public SyntheticSection<ELFT> {
class MipsAbiFlagsSection final : public SyntheticSection {
typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags;
public:
@ -629,8 +664,7 @@ private:
};
// .MIPS.options section.
template <class ELFT>
class MipsOptionsSection final : public SyntheticSection<ELFT> {
template <class ELFT> class MipsOptionsSection final : public SyntheticSection {
typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
@ -649,8 +683,7 @@ private:
};
// MIPS .reginfo section.
template <class ELFT>
class MipsReginfoSection final : public SyntheticSection<ELFT> {
template <class ELFT> class MipsReginfoSection final : public SyntheticSection {
typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
public:
@ -668,78 +701,95 @@ private:
// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
// See "Dynamic section" in Chapter 5 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
template <class ELFT> class MipsRldMapSection : public SyntheticSection<ELFT> {
class MipsRldMapSection : public SyntheticSection {
public:
MipsRldMapSection();
size_t getSize() const override { return sizeof(typename ELFT::uint); }
size_t getSize() const override { return Config->Wordsize; }
void writeTo(uint8_t *Buf) override;
};
template <class ELFT> class ARMExidxSentinelSection : public SyntheticSection<ELFT> {
class ARMExidxSentinelSection : public SyntheticSection {
public:
ARMExidxSentinelSection();
size_t getSize() const override { return 8; }
void writeTo(uint8_t *Buf) override;
};
template <class ELFT> InputSection<ELFT> *createCommonSection();
template <class ELFT> InputSection<ELFT> *createInterpSection();
template <class ELFT> MergeInputSection<ELFT> *createCommentSection();
// A container for one or more linker generated thunks. Instances of these
// thunks including ARM interworking and Mips LA25 PI to non-PI thunks.
class ThunkSection : public SyntheticSection {
public:
// ThunkSection in OS, with desired OutSecOff of Off
ThunkSection(OutputSection *OS, uint64_t Off);
// Add a newly created Thunk to this container:
// Thunk is given offset from start of this InputSection
// Thunk defines a symbol in this InputSection that can be used as target
// of a relocation
void addThunk(Thunk *T);
size_t getSize() const override { return Size; }
void writeTo(uint8_t *Buf) override;
InputSection *getTargetInputSection() const;
private:
std::vector<const Thunk *> Thunks;
size_t Size = 0;
};
template <class ELFT> InputSection *createCommonSection();
InputSection *createInterpSection();
template <class ELFT> MergeInputSection *createCommentSection();
template <class ELFT>
SymbolBody *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
uint64_t Size, InputSectionBase *Section);
// Linker generated sections which can be used as inputs.
template <class ELFT> struct In {
static InputSection<ELFT> *ARMAttributes;
static BuildIdSection<ELFT> *BuildId;
static InputSection<ELFT> *Common;
struct InX {
static InputSection *ARMAttributes;
static BssSection *Bss;
static BssSection *BssRelRo;
static BuildIdSection *BuildId;
static InputSection *Common;
static StringTableSection *DynStrTab;
static InputSection *Interp;
static GdbIndexSection *GdbIndex;
static GotPltSection *GotPlt;
static IgotPltSection *IgotPlt;
static MipsGotSection *MipsGot;
static MipsRldMapSection *MipsRldMap;
static PltSection *Plt;
static PltSection *Iplt;
static StringTableSection *ShStrTab;
static StringTableSection *StrTab;
};
template <class ELFT> struct In : public InX {
static DynamicSection<ELFT> *Dynamic;
static StringTableSection<ELFT> *DynStrTab;
static SymbolTableSection<ELFT> *DynSymTab;
static EhFrameHeader<ELFT> *EhFrameHdr;
static GnuHashTableSection<ELFT> *GnuHashTab;
static GdbIndexSection<ELFT> *GdbIndex;
static GotSection<ELFT> *Got;
static MipsGotSection<ELFT> *MipsGot;
static GotPltSection<ELFT> *GotPlt;
static IgotPltSection<ELFT> *IgotPlt;
static EhFrameSection<ELFT> *EhFrame;
static HashTableSection<ELFT> *HashTab;
static InputSection<ELFT> *Interp;
static MipsRldMapSection<ELFT> *MipsRldMap;
static PltSection<ELFT> *Plt;
static IpltSection<ELFT> *Iplt;
static RelocationSection<ELFT> *RelaDyn;
static RelocationSection<ELFT> *RelaPlt;
static RelocationSection<ELFT> *RelaIplt;
static StringTableSection<ELFT> *ShStrTab;
static StringTableSection<ELFT> *StrTab;
static SymbolTableSection<ELFT> *SymTab;
static VersionDefinitionSection<ELFT> *VerDef;
static VersionTableSection<ELFT> *VerSym;
static VersionNeedSection<ELFT> *VerNeed;
};
template <class ELFT> InputSection<ELFT> *In<ELFT>::ARMAttributes;
template <class ELFT> BuildIdSection<ELFT> *In<ELFT>::BuildId;
template <class ELFT> InputSection<ELFT> *In<ELFT>::Common;
template <class ELFT> DynamicSection<ELFT> *In<ELFT>::Dynamic;
template <class ELFT> StringTableSection<ELFT> *In<ELFT>::DynStrTab;
template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::DynSymTab;
template <class ELFT> EhFrameHeader<ELFT> *In<ELFT>::EhFrameHdr;
template <class ELFT> GdbIndexSection<ELFT> *In<ELFT>::GdbIndex;
template <class ELFT> GnuHashTableSection<ELFT> *In<ELFT>::GnuHashTab;
template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
template <class ELFT> MipsGotSection<ELFT> *In<ELFT>::MipsGot;
template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt;
template <class ELFT> IgotPltSection<ELFT> *In<ELFT>::IgotPlt;
template <class ELFT> EhFrameSection<ELFT> *In<ELFT>::EhFrame;
template <class ELFT> HashTableSection<ELFT> *In<ELFT>::HashTab;
template <class ELFT> InputSection<ELFT> *In<ELFT>::Interp;
template <class ELFT> MipsRldMapSection<ELFT> *In<ELFT>::MipsRldMap;
template <class ELFT> PltSection<ELFT> *In<ELFT>::Plt;
template <class ELFT> IpltSection<ELFT> *In<ELFT>::Iplt;
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaDyn;
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaPlt;
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaIplt;
template <class ELFT> StringTableSection<ELFT> *In<ELFT>::ShStrTab;
template <class ELFT> StringTableSection<ELFT> *In<ELFT>::StrTab;
template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::SymTab;
template <class ELFT> VersionDefinitionSection<ELFT> *In<ELFT>::VerDef;
template <class ELFT> VersionTableSection<ELFT> *In<ELFT>::VerSym;

View file

@ -45,7 +45,10 @@ using namespace llvm::support::endian;
using namespace llvm::ELF;
std::string lld::toString(uint32_t Type) {
return getELFRelocationTypeName(elf::Config->EMachine, Type);
StringRef S = getELFRelocationTypeName(elf::Config->EMachine, Type);
if (S == "Unknown")
return ("Unknown (" + Twine(Type) + ")").str();
return S;
}
namespace lld {
@ -56,20 +59,20 @@ TargetInfo *Target;
static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); }
template <class ELFT> static std::string getErrorLoc(uint8_t *Loc) {
for (InputSectionData *D : Symtab<ELFT>::X->Sections) {
auto *IS = dyn_cast_or_null<InputSection<ELFT>>(D);
template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) {
for (InputSectionBase *D : InputSections) {
auto *IS = dyn_cast_or_null<InputSection>(D);
if (!IS || !IS->OutSec)
continue;
uint8_t *ISLoc = cast<OutputSection<ELFT>>(IS->OutSec)->Loc + IS->OutSecOff;
uint8_t *ISLoc = cast<OutputSection>(IS->OutSec)->Loc + IS->OutSecOff;
if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
return IS->getLocation(Loc - ISLoc) + ": ";
return IS->template getLocation<ELFT>(Loc - ISLoc) + ": ";
}
return "";
}
static std::string getErrorLocation(uint8_t *Loc) {
static std::string getErrorLocation(const uint8_t *Loc) {
switch (Config->EKind) {
case ELF32LEKind:
return getErrorLoc<ELF32LE>(Loc);
@ -116,17 +119,17 @@ namespace {
class X86TargetInfo final : public TargetInfo {
public:
X86TargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const override;
int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
void writeGotPltHeader(uint8_t *Buf) const override;
uint32_t getDynRel(uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
@ -141,15 +144,15 @@ public:
template <class ELFT> class X86_64TargetInfo final : public TargetInfo {
public:
X86_64TargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const override;
bool isPicRel(uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPltHeader(uint8_t *Buf) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
@ -170,14 +173,16 @@ class PPCTargetInfo final : public TargetInfo {
public:
PPCTargetInfo();
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const override;
};
class PPC64TargetInfo final : public TargetInfo {
public:
PPC64TargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
@ -185,12 +190,13 @@ public:
class AArch64TargetInfo final : public TargetInfo {
public:
AArch64TargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const override;
bool isPicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
bool usesOnlyLowPageBits(uint32_t Type) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
@ -205,44 +211,47 @@ class AMDGPUTargetInfo final : public TargetInfo {
public:
AMDGPUTargetInfo();
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const override;
};
class ARMTargetInfo final : public TargetInfo {
public:
ARMTargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const override;
bool isPicRel(uint32_t Type) const override;
uint32_t getDynRel(uint32_t Type) const override;
uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
const SymbolBody &S) const override;
void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override;
void addPltHeaderSymbols(InputSectionBase *ISD) const override;
bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
template <class ELFT> class MipsTargetInfo final : public TargetInfo {
public:
MipsTargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const override;
int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
bool isPicRel(uint32_t Type) const override;
uint32_t getDynRel(uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
bool isTlsGlobalDynamicRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
const SymbolBody &S) const override;
bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
bool usesOnlyLowPageBits(uint32_t Type) const override;
};
@ -286,25 +295,21 @@ TargetInfo *createTarget() {
TargetInfo::~TargetInfo() {}
uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf,
uint32_t Type) const {
int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
return 0;
}
bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
const InputFile &File,
const SymbolBody &S) const {
return Expr;
bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
const InputFile *File, const SymbolBody &S) const {
return false;
}
bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
bool TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return false; }
bool TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const { return false; }
void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
writeGotPlt(Buf, S);
}
@ -352,10 +357,14 @@ X86TargetInfo::X86TargetInfo() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
// 0xCC is the "int3" (call debug exception handler) instruction.
TrapInstr = 0xcccccccc;
}
RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const {
switch (Type) {
case R_386_8:
case R_386_16:
case R_386_32:
case R_386_TLS_LDO_32:
@ -366,6 +375,7 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
return R_TLSLD;
case R_386_PLT32:
return R_PLT_PC;
case R_386_PC8:
case R_386_PC16:
case R_386_PC32:
return R_PC;
@ -375,6 +385,24 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
return R_GOT;
case R_386_GOT32:
case R_386_GOT32X:
// These relocations can be calculated in two different ways.
// Usual calculation is G + A - GOT what means an offset in GOT table
// (R_GOT_FROM_END). When instruction pointed by relocation has no base
// register, then relocations can be used when PIC code is disabled. In that
// case calculation is G + A, it resolves to an address of entry in GOT
// (R_GOT) and not an offset.
//
// To check that instruction has no base register we scan ModR/M byte.
// See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte"
// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
if ((Loc[-1] & 0xc7) != 0x5)
return R_GOT_FROM_END;
if (Config->Pic)
error(toString(S.File) + ": relocation " + toString(Type) + " against '" +
S.getName() +
"' without base register can not be used when PIC enabled");
return R_GOT;
case R_386_TLS_GOTIE:
return R_GOT_FROM_END;
case R_386_GOTOFF:
@ -384,10 +412,9 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
case R_386_TLS_LE_32:
return R_NEG_TLS;
case R_386_NONE:
return R_HINT;
return R_NONE;
default:
error("do not know how to handle relocation '" + toString(Type) + "' (" +
Twine(Type) + ")");
error(toString(S.File) + ": unknown relocation type: " + toString(Type));
return R_HINT;
}
}
@ -411,12 +438,12 @@ void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
// Entries in .got.plt initially points back to the corresponding
// PLT entries with a fixed offset to skip the first instruction.
write32le(Buf, S.getPltVA<ELF32LE>() + 6);
write32le(Buf, S.getPltVA() + 6);
}
void X86TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
// An x86 entry is the address of the ifunc resolver function.
write32le(Buf, S.getVA<ELF32LE>());
write32le(Buf, S.getVA());
}
uint32_t X86TargetInfo::getDynRel(uint32_t Type) const {
@ -427,10 +454,6 @@ uint32_t X86TargetInfo::getDynRel(uint32_t Type) const {
return Type;
}
bool X86TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
return Type == R_386_TLS_GD;
}
bool X86TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const {
return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM;
}
@ -440,30 +463,33 @@ bool X86TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
}
void X86TargetInfo::writePltHeader(uint8_t *Buf) const {
// Executable files and shared object files have
// separate procedure linkage tables.
if (Config->Pic) {
const uint8_t V[] = {
0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx)
0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx)
0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx)
0x90, 0x90, 0x90, 0x90 // nop
};
memcpy(Buf, V, sizeof(V));
uint32_t Ebx = In<ELF32LE>::Got->getVA() + In<ELF32LE>::Got->getSize();
uint32_t GotPlt = In<ELF32LE>::GotPlt->getVA() - Ebx;
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
return;
}
const uint8_t PltData[] = {
0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOT+4)
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOT+8)
0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOTPLT+4)
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOTPLT+8)
0x90, 0x90, 0x90, 0x90 // nop
};
memcpy(Buf, PltData, sizeof(PltData));
uint32_t Got = In<ELF32LE>::GotPlt->getVA();
write32le(Buf + 2, Got + 4);
write32le(Buf + 8, Got + 8);
uint32_t GotPlt = In<ELF32LE>::GotPlt->getVA();
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
}
void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Inst[] = {
@ -473,22 +499,32 @@ void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
};
memcpy(Buf, Inst, sizeof(Inst));
// jmp *foo@GOT(%ebx) or jmp *foo_in_GOT
Buf[1] = Config->Pic ? 0xa3 : 0x25;
uint32_t Got = In<ELF32LE>::GotPlt->getVA();
write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
if (Config->Pic) {
// jmp *foo@GOT(%ebx)
uint32_t Ebx = In<ELF32LE>::Got->getVA() + In<ELF32LE>::Got->getSize();
Buf[1] = 0xa3;
write32le(Buf + 2, GotPltEntryAddr - Ebx);
} else {
// jmp *foo_in_GOT
Buf[1] = 0x25;
write32le(Buf + 2, GotPltEntryAddr);
}
write32le(Buf + 7, RelOff);
write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
}
uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
uint32_t Type) const {
int64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
uint32_t Type) const {
switch (Type) {
default:
return 0;
case R_386_8:
case R_386_PC8:
return SignExtend64<8>(*Buf);
case R_386_16:
case R_386_PC16:
return read16le(Buf);
return SignExtend64<16>(read16le(Buf));
case R_386_32:
case R_386_GOT32:
case R_386_GOT32X:
@ -497,21 +533,36 @@ uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
case R_386_PC32:
case R_386_PLT32:
case R_386_TLS_LE:
return read32le(Buf);
return SignExtend64<32>(read32le(Buf));
}
}
void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
checkInt<32>(Loc, Val, Type);
// R_386_PC16 and R_386_16 are not part of the current i386 psABI. They are
// used by 16-bit x86 objects, like boot loaders.
if (Type == R_386_16 || Type == R_386_PC16) {
// R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
// being used for some 16-bit programs such as boot loaders, so
// we want to support them.
switch (Type) {
case R_386_8:
checkUInt<8>(Loc, Val, Type);
*Loc = Val;
break;
case R_386_PC8:
checkInt<8>(Loc, Val, Type);
*Loc = Val;
break;
case R_386_16:
checkUInt<16>(Loc, Val, Type);
write16le(Loc, Val);
return;
break;
case R_386_PC16:
checkInt<16>(Loc, Val, Type);
write16le(Loc, Val);
break;
default:
checkInt<32>(Loc, Val, Type);
write32le(Loc, Val);
}
write32le(Loc, Val);
}
void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
@ -527,7 +578,7 @@ void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax
};
memcpy(Loc - 3, Inst, sizeof(Inst));
relocateOne(Loc + 5, R_386_32, Val);
write32le(Loc + 5, Val);
}
void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
@ -543,7 +594,7 @@ void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax
};
memcpy(Loc - 3, Inst, sizeof(Inst));
relocateOne(Loc + 5, R_386_32, Val);
write32le(Loc + 5, Val);
}
// In some conditions, relocations can be optimized to avoid using GOT.
@ -583,13 +634,13 @@ void X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
Loc[-1] = 0x80 | (Reg << 3) | Reg;
}
}
relocateOne(Loc, R_386_TLS_LE, Val);
write32le(Loc, Val);
}
void X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
if (Type == R_386_TLS_LDO_32) {
relocateOne(Loc, R_386_TLS_LE, Val);
write32le(Loc, Val);
return;
}
@ -625,12 +676,16 @@ template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() {
// Align to the large page size (known as a superpage or huge page).
// FreeBSD automatically promotes large, superpage-aligned allocations.
DefaultImageBase = 0x200000;
// 0xCC is the "int3" (call debug exception handler) instruction.
TrapInstr = 0xcccccccc;
}
template <class ELFT>
RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
const SymbolBody &S) const {
RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const {
switch (Type) {
case R_X86_64_8:
case R_X86_64_16:
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
@ -660,10 +715,9 @@ RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
case R_X86_64_GOTTPOFF:
return R_GOT_PC;
case R_X86_64_NONE:
return R_HINT;
return R_NONE;
default:
error("do not know how to handle relocation '" + toString(Type) + "' (" +
Twine(Type) + ")");
error(toString(S.File) + ": unknown relocation type: " + toString(Type));
return R_HINT;
}
}
@ -681,25 +735,25 @@ template <class ELFT>
void X86_64TargetInfo<ELFT>::writeGotPlt(uint8_t *Buf,
const SymbolBody &S) const {
// See comments in X86TargetInfo::writeGotPlt.
write32le(Buf, S.getPltVA<ELFT>() + 6);
write32le(Buf, S.getPltVA() + 6);
}
template <class ELFT>
void X86_64TargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
const uint8_t PltData[] = {
0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
0x0f, 0x1f, 0x40, 0x00 // nopl 0x0(rax)
0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOTPLT+8(%rip)
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOTPLT+16(%rip)
0x0f, 0x1f, 0x40, 0x00 // nop
};
memcpy(Buf, PltData, sizeof(PltData));
uint64_t Got = In<ELFT>::GotPlt->getVA();
uint64_t GotPlt = In<ELFT>::GotPlt->getVA();
uint64_t Plt = In<ELFT>::Plt->getVA();
write32le(Buf + 2, Got - Plt + 2); // GOT+8
write32le(Buf + 8, Got - Plt + 4); // GOT+16
write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8
write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16
}
template <class ELFT>
void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Inst[] = {
@ -709,7 +763,7 @@ void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
};
memcpy(Buf, Inst, sizeof(Inst));
write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6);
write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6);
write32le(Buf + 7, Index);
write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
}
@ -724,11 +778,6 @@ bool X86_64TargetInfo<ELFT>::isTlsInitialExecRel(uint32_t Type) const {
return Type == R_X86_64_GOTTPOFF;
}
template <class ELFT>
bool X86_64TargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
return Type == R_X86_64_TLSGD;
}
template <class ELFT>
bool X86_64TargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
return Type == R_X86_64_DTPOFF32 || Type == R_X86_64_DTPOFF64 ||
@ -752,9 +801,10 @@ void X86_64TargetInfo<ELFT>::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax
};
memcpy(Loc - 4, Inst, sizeof(Inst));
// The original code used a pc relative relocation and so we have to
// compensate for the -4 in had in the addend.
relocateOne(Loc + 8, R_X86_64_TPOFF32, Val + 4);
write32le(Loc + 8, Val + 4);
}
template <class ELFT>
@ -774,9 +824,10 @@ void X86_64TargetInfo<ELFT>::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax
};
memcpy(Loc - 4, Inst, sizeof(Inst));
// Both code sequences are PC relatives, but since we are moving the constant
// forward by 8 bytes we have to subtract the value by 8.
relocateOne(Loc + 8, R_X86_64_PC32, Val - 8);
write32le(Loc + 8, Val - 8);
}
// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
@ -821,7 +872,7 @@ void X86_64TargetInfo<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
// The original code used a PC relative relocation.
// Need to compensate for the -4 it had in the addend.
relocateOne(Loc, R_X86_64_TPOFF32, Val + 4);
write32le(Loc, Val + 4);
}
template <class ELFT>
@ -841,7 +892,7 @@ void X86_64TargetInfo<ELFT>::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
return;
}
if (Type == R_X86_64_DTPOFF32) {
relocateOne(Loc, R_X86_64_TPOFF32, Val);
write32le(Loc, Val);
return;
}
@ -857,6 +908,14 @@ template <class ELFT>
void X86_64TargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
switch (Type) {
case R_X86_64_8:
checkUInt<8>(Loc, Val, Type);
*Loc = Val;
break;
case R_X86_64_16:
checkUInt<16>(Loc, Val, Type);
write16le(Loc, Val);
break;
case R_X86_64_32:
checkUInt<32>(Loc, Val, Type);
write32le(Loc, Val);
@ -898,12 +957,14 @@ RelExpr X86_64TargetInfo<ELFT>::adjustRelaxExpr(uint32_t Type,
return RelExpr;
const uint8_t Op = Data[-2];
const uint8_t ModRm = Data[-1];
// FIXME: When PIC is disabled and foo is defined locally in the
// lower 32 bit address space, memory operand in mov can be converted into
// immediate operand. Otherwise, mov must be changed to lea. We support only
// latter relaxation at this moment.
if (Op == 0x8b)
return R_RELAX_GOT_PC;
// Relax call and jmp.
if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25))
return R_RELAX_GOT_PC;
@ -961,7 +1022,7 @@ void X86_64TargetInfo<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val,
// SIB.base field.
// See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A).
Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
relocateOne(Loc, R_X86_64_PC32, Val);
write32le(Loc, Val);
return;
}
@ -982,7 +1043,7 @@ void X86_64TargetInfo<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val,
// descriptions about each operation.
Loc[-2] = 0x81;
Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
relocateOne(Loc, R_X86_64_PC32, Val);
write32le(Loc, Val);
}
template <class ELFT>
@ -993,7 +1054,7 @@ void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
// Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg".
if (Op == 0x8b) {
Loc[-2] = 0x8d;
relocateOne(Loc, R_X86_64_PC32, Val);
write32le(Loc, Val);
return;
}
@ -1012,7 +1073,7 @@ void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
// prefix. That makes result expression to be a single instruction.
Loc[-2] = 0x67; // addr32 prefix
Loc[-1] = 0xe8; // call
relocateOne(Loc, R_X86_64_PC32, Val);
write32le(Loc, Val);
return;
}
@ -1021,7 +1082,7 @@ void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
assert(ModRm == 0x25);
Loc[-2] = 0xe9; // jmp
Loc[3] = 0x90; // nop
relocateOne(Loc - 1, R_X86_64_PC32, Val + 1);
write32le(Loc - 1, Val + 1);
}
// Relocation masks following the #lo(value), #hi(value), #ha(value),
@ -1059,7 +1120,8 @@ void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
}
}
RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const {
switch (Type) {
case R_PPC_REL24:
case R_PPC_REL32:
@ -1108,7 +1170,8 @@ uint64_t getPPC64TocBase() {
return TocVA + PPC64TocOffset;
}
RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const {
switch (Type) {
default:
return R_ABS;
@ -1126,10 +1189,10 @@ RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
}
}
void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
uint64_t Off = GotEntryAddr - getPPC64TocBase();
uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
// FIXME: What we should do, in theory, is get the offset of the function
// descriptor in the .opd section, and use that as the offset from %r2 (the
@ -1256,8 +1319,8 @@ AArch64TargetInfo::AArch64TargetInfo() {
TcbSize = 16;
}
RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
const SymbolBody &S) const {
RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const {
switch (Type) {
default:
return R_ABS;
@ -1289,6 +1352,8 @@ RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
return R_GOT_PAGE_PC;
case R_AARCH64_NONE:
return R_NONE;
}
}
@ -1361,7 +1426,7 @@ void AArch64TargetInfo::writePltHeader(uint8_t *Buf) const {
relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
}
void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Inst[] = {
@ -1373,9 +1438,9 @@ void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
memcpy(Buf, Inst, sizeof(Inst));
relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(GotEntryAddr) - getAArch64Page(PltEntryAddr));
relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotEntryAddr);
relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotEntryAddr);
getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr));
relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr);
relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr);
}
static void write32AArch64Addr(uint8_t *L, uint64_t Imm) {
@ -1598,7 +1663,8 @@ void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
}
}
RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const {
switch (Type) {
case R_AMDGPU_ABS32:
case R_AMDGPU_ABS64:
@ -1612,7 +1678,8 @@ RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
case R_AMDGPU_GOTPCREL32_HI:
return R_GOT_PC;
default:
fatal("do not know how to handle relocation " + Twine(Type));
error(toString(S.File) + ": unknown relocation type: " + toString(Type));
return R_HINT;
}
}
@ -1634,7 +1701,8 @@ ARMTargetInfo::ARMTargetInfo() {
NeedsThunks = true;
}
RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const {
switch (Type) {
default:
return R_ABS;
@ -1683,7 +1751,7 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
case R_ARM_THM_MOVT_PREL:
return R_PC;
case R_ARM_NONE:
return R_HINT;
return R_NONE;
case R_ARM_TLS_LE32:
return R_TLS;
}
@ -1709,7 +1777,7 @@ void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
void ARMTargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
// An ARM entry is the address of the ifunc resolver function.
write32le(Buf, S.getVA<ELF32LE>());
write32le(Buf, S.getVA());
}
void ARMTargetInfo::writePltHeader(uint8_t *Buf) const {
@ -1726,7 +1794,13 @@ void ARMTargetInfo::writePltHeader(uint8_t *Buf) const {
write32le(Buf + 16, GotPlt - L1 - 8);
}
void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
void ARMTargetInfo::addPltHeaderSymbols(InputSectionBase *ISD) const {
auto *IS = cast<InputSection>(ISD);
addSyntheticLocal<ELF32LE>("$a", STT_NOTYPE, 0, 0, IS);
addSyntheticLocal<ELF32LE>("$d", STT_NOTYPE, 16, 0, IS);
}
void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
// FIXME: Using simple code sequence with simple relocations.
@ -1740,18 +1814,24 @@ void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
};
memcpy(Buf, PltData, sizeof(PltData));
uint64_t L1 = PltEntryAddr + 4;
write32le(Buf + 12, GotEntryAddr - L1 - 8);
write32le(Buf + 12, GotPltEntryAddr - L1 - 8);
}
RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
const InputFile &File,
const SymbolBody &S) const {
void ARMTargetInfo::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const {
auto *IS = cast<InputSection>(ISD);
addSyntheticLocal<ELF32LE>("$a", STT_NOTYPE, Off, 0, IS);
addSyntheticLocal<ELF32LE>("$d", STT_NOTYPE, Off + 12, 0, IS);
}
bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
const InputFile *File,
const SymbolBody &S) const {
// If S is an undefined weak symbol in an executable we don't need a Thunk.
// In a DSO calls to undefined symbols, including weak ones get PLT entries
// which may need a thunk.
if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak()
&& !Config->Shared)
return Expr;
if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() &&
!Config->Shared)
return false;
// A state change from ARM to Thumb and vice versa must go through an
// interworking thunk if the relocation type is not R_ARM_CALL or
// R_ARM_THM_CALL.
@ -1761,20 +1841,18 @@ RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
case R_ARM_JUMP24:
// Source is ARM, all PLT entries are ARM so no interworking required.
// Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
if (Expr == R_PC && ((S.getVA<ELF32LE>() & 1) == 1))
return R_THUNK_PC;
if (Expr == R_PC && ((S.getVA() & 1) == 1))
return true;
break;
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
// Source is Thumb, all PLT entries are ARM so interworking is required.
// Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
if (Expr == R_PLT_PC)
return R_THUNK_PLT_PC;
if ((S.getVA<ELF32LE>() & 1) == 0)
return R_THUNK_PC;
if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0))
return true;
break;
}
return Expr;
return false;
}
void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
@ -1796,6 +1874,7 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
case R_ARM_TLS_LDO32:
case R_ARM_TLS_LE32:
case R_ARM_TLS_TPOFF32:
case R_ARM_TLS_DTPOFF32:
write32le(Loc, Val);
break;
case R_ARM_TLS_DTPMOD32:
@ -1911,8 +1990,8 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
}
}
uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
uint32_t Type) const {
int64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
uint32_t Type) const {
switch (Type) {
default:
return 0;
@ -1990,10 +2069,6 @@ bool ARMTargetInfo::isTlsLocalDynamicRel(uint32_t Type) const {
return Type == R_ARM_TLS_LDO32 || Type == R_ARM_TLS_LDM32;
}
bool ARMTargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
return Type == R_ARM_TLS_GD32;
}
bool ARMTargetInfo::isTlsInitialExecRel(uint32_t Type) const {
return Type == R_ARM_TLS_IE32;
}
@ -2022,8 +2097,8 @@ template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
}
template <class ELFT>
RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
const SymbolBody &S) const {
RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const {
// See comment in the calculateMipsRelChain.
if (ELFT::Is64Bits || Config->MipsN32Abi)
Type &= 0xff;
@ -2039,13 +2114,16 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
return R_PLT;
case R_MIPS_HI16:
case R_MIPS_LO16:
case R_MIPS_GOT_OFST:
// R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
// offset between start of function and 'gp' value which by default
// equal to the start of .got section. In that case we consider these
// relocations as relative.
if (&S == ElfSym<ELFT>::MipsGpDisp)
return R_PC;
if (&S == ElfSym::MipsGpDisp)
return R_MIPS_GOT_GP_PC;
if (&S == ElfSym::MipsLocalGp)
return R_MIPS_GOT_GP;
// fallthrough
case R_MIPS_GOT_OFST:
return R_ABS;
case R_MIPS_PC32:
case R_MIPS_PC16:
@ -2091,11 +2169,6 @@ bool MipsTargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
return Type == R_MIPS_TLS_LDM;
}
template <class ELFT>
bool MipsTargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
return Type == R_MIPS_TLS_GD;
}
template <class ELFT>
void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
write32<ELFT::TargetEndianness>(Buf, In<ELFT>::Plt->getVA());
@ -2161,18 +2234,20 @@ void MipsTargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28
}
write32<E>(Buf + 16, 0x03e07825); // move $15, $31
write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
write32<E>(Buf + 24, 0x0320f809); // jalr $25
write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
uint64_t Got = In<ELFT>::GotPlt->getVA();
writeMipsHi16<E>(Buf, Got);
writeMipsLo16<E>(Buf + 4, Got);
writeMipsLo16<E>(Buf + 8, Got);
uint64_t GotPlt = In<ELFT>::GotPlt->getVA();
writeMipsHi16<E>(Buf, GotPlt);
writeMipsLo16<E>(Buf + 4, GotPlt);
writeMipsLo16<E>(Buf + 8, GotPlt);
}
template <class ELFT>
void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const endianness E = ELFT::TargetEndianness;
@ -2181,37 +2256,37 @@ void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
// jr $25
write32<E>(Buf + 8, isMipsR6<ELFT>() ? 0x03200009 : 0x03200008);
write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
writeMipsHi16<E>(Buf, GotEntryAddr);
writeMipsLo16<E>(Buf + 4, GotEntryAddr);
writeMipsLo16<E>(Buf + 12, GotEntryAddr);
writeMipsHi16<E>(Buf, GotPltEntryAddr);
writeMipsLo16<E>(Buf + 4, GotPltEntryAddr);
writeMipsLo16<E>(Buf + 12, GotPltEntryAddr);
}
template <class ELFT>
RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type,
const InputFile &File,
const SymbolBody &S) const {
bool MipsTargetInfo<ELFT>::needsThunk(RelExpr Expr, uint32_t Type,
const InputFile *File,
const SymbolBody &S) const {
// Any MIPS PIC code function is invoked with its address in register $t9.
// So if we have a branch instruction from non-PIC code to the PIC one
// we cannot make the jump directly and need to create a small stubs
// to save the target function address.
// See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (Type != R_MIPS_26)
return Expr;
auto *F = dyn_cast<ELFFileBase<ELFT>>(&File);
return false;
auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
if (!F)
return Expr;
return false;
// If current file has PIC code, LA25 stub is not required.
if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
return Expr;
auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
return false;
auto *D = dyn_cast<DefinedRegular>(&S);
// LA25 is required if target file has PIC code
// or target symbol is a PIC symbol.
return D && D->isMipsPIC() ? R_THUNK_ABS : Expr;
return D && D->isMipsPIC<ELFT>();
}
template <class ELFT>
uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
uint32_t Type) const {
int64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
uint32_t Type) const {
const endianness E = ELFT::TargetEndianness;
switch (Type) {
default:
@ -2220,7 +2295,7 @@ uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
case R_MIPS_GPREL32:
case R_MIPS_TLS_DTPREL32:
case R_MIPS_TLS_TPREL32:
return read32<E>(Buf);
return SignExtend64<32>(read32<E>(Buf));
case R_MIPS_26:
// FIXME (simon): If the relocation target symbol is not a PLT entry
// we should use another expression for calculation:
@ -2303,9 +2378,19 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
case R_MIPS_26:
write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff));
break;
case R_MIPS_GOT16:
// The R_MIPS_GOT16 relocation's value in "relocatable" linking mode
// is updated addend (not a GOT index). In that case write high 16 bits
// to store a correct addend value.
if (Config->Relocatable)
writeMipsHi16<E>(Loc, Val);
else {
checkInt<16>(Loc, Val, Type);
writeMipsLo16<E>(Loc, Val);
}
break;
case R_MIPS_GOT_DISP:
case R_MIPS_GOT_PAGE:
case R_MIPS_GOT16:
case R_MIPS_GPREL16:
case R_MIPS_TLS_GD:
case R_MIPS_TLS_LDM:

View file

@ -25,13 +25,12 @@ class TargetInfo {
public:
virtual bool isTlsInitialExecRel(uint32_t Type) const;
virtual bool isTlsLocalDynamicRel(uint32_t Type) const;
virtual bool isTlsGlobalDynamicRel(uint32_t Type) const;
virtual bool isPicRel(uint32_t Type) const { return true; }
virtual uint32_t getDynRel(uint32_t Type) const { return Type; }
virtual void writeGotPltHeader(uint8_t *Buf) const {}
virtual void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {};
virtual void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const;
virtual uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const;
virtual int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const;
// If lazy binding is supported, the first entry of the PLT has code
// to call the dynamic linker to resolve PLT entries the first time
@ -41,7 +40,8 @@ public:
virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {}
virtual void addPltHeaderSymbols(InputSectionBase *IS) const {}
virtual void addPltSymbols(InputSectionBase *IS, uint64_t Off) const {}
// Returns true if a relocation only uses the low bits of a value such that
// all those bits are in in the same page. For example, if the relocation
// only uses the low 12 bits in a system with 4k pages. If this is true, the
@ -50,15 +50,11 @@ public:
virtual bool usesOnlyLowPageBits(uint32_t Type) const;
// Decide whether a Thunk is needed for the relocation from File
// targeting S. Returns one of:
// Expr if there is no Thunk required
// R_THUNK_ABS if thunk is required and expression is absolute
// R_THUNK_PC if thunk is required and expression is pc rel
// R_THUNK_PLT_PC if thunk is required to PLT entry and expression is pc rel
virtual RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType,
const InputFile &File,
const SymbolBody &S) const;
virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0;
// targeting S.
virtual bool needsThunk(RelExpr Expr, uint32_t RelocType,
const InputFile *File, const SymbolBody &S) const;
virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const = 0;
virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
virtual ~TargetInfo();
@ -95,6 +91,10 @@ public:
bool NeedsThunks = false;
// A 4-byte field corresponding to one or more trap instructions, used to pad
// executable OutputSections.
uint32_t TrapInstr = 0;
virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
RelExpr Expr) const;
virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;

View file

@ -15,7 +15,7 @@
//
// That said, we don't want to do "too clever" things using threads.
// Complex multi-threaded algorithms are sometimes extremely hard to
// justify the correctness and can easily mess up the entire design.
// reason about and can easily mess up the entire design.
//
// Fortunately, when a linker links large programs (when the link time is
// most critical), it spends most of the time to work on massive number of
@ -34,7 +34,7 @@
// instead of std::for_each (or a plain for loop). Because tasks are
// completely independent from each other, we can run them in parallel
// without any coordination between them. That's very easy to understand
// and justify.
// and reason about.
//
// For the cases such as the latter, we can use parallel algorithms to
// deal with massive data. We have to write code for a tailored algorithm
@ -69,14 +69,15 @@ namespace lld {
namespace elf {
template <class IterTy, class FuncTy>
void forEach(IterTy Begin, IterTy End, FuncTy Fn) {
void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn) {
if (Config->Threads)
parallel_for_each(Begin, End, Fn);
else
std::for_each(Begin, End, Fn);
}
inline void forLoop(size_t Begin, size_t End, std::function<void(size_t)> Fn) {
inline void parallelFor(size_t Begin, size_t End,
std::function<void(size_t)> Fn) {
if (Config->Threads) {
parallel_for(Begin, End, Fn);
} else {

View file

@ -28,6 +28,7 @@
#include "Memory.h"
#include "OutputSections.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ELF.h"
@ -49,127 +50,159 @@ namespace {
// Specific ARM Thunk implementations. The naming convention is:
// Source State, TargetState, Target Requirement, ABS or PI, Range
template <class ELFT>
class ARMToThumbV7ABSLongThunk final : public Thunk<ELFT> {
template <class ELFT> class ARMV7ABSLongThunk final : public Thunk {
public:
ARMToThumbV7ABSLongThunk(const SymbolBody &Dest,
const InputSection<ELFT> &Owner)
: Thunk<ELFT>(Dest, Owner) {}
ARMV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) {}
uint32_t size() const override { return 12; }
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
};
template <class ELFT> class ARMToThumbV7PILongThunk final : public Thunk<ELFT> {
template <class ELFT> class ARMV7PILongThunk final : public Thunk {
public:
ARMToThumbV7PILongThunk(const SymbolBody &Dest,
const InputSection<ELFT> &Owner)
: Thunk<ELFT>(Dest, Owner) {}
ARMV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) {}
uint32_t size() const override { return 16; }
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
};
template <class ELFT>
class ThumbToARMV7ABSLongThunk final : public Thunk<ELFT> {
template <class ELFT> class ThumbV7ABSLongThunk final : public Thunk {
public:
ThumbToARMV7ABSLongThunk(const SymbolBody &Dest,
const InputSection<ELFT> &Owner)
: Thunk<ELFT>(Dest, Owner) {}
ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) {
this->alignment = 2;
}
uint32_t size() const override { return 10; }
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
};
template <class ELFT> class ThumbToARMV7PILongThunk final : public Thunk<ELFT> {
template <class ELFT> class ThumbV7PILongThunk final : public Thunk {
public:
ThumbToARMV7PILongThunk(const SymbolBody &Dest,
const InputSection<ELFT> &Owner)
: Thunk<ELFT>(Dest, Owner) {}
ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) {
this->alignment = 2;
}
uint32_t size() const override { return 12; }
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
};
// MIPS LA25 thunk
template <class ELFT> class MipsThunk final : public Thunk<ELFT> {
template <class ELFT> class MipsThunk final : public Thunk {
public:
MipsThunk(const SymbolBody &Dest, const InputSection<ELFT> &Owner)
: Thunk<ELFT>(Dest, Owner) {}
MipsThunk(const SymbolBody &Dest) : Thunk(Dest) {}
uint32_t size() const override { return 16; }
void writeTo(uint8_t *Buf) const override;
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
InputSection *getTargetInputSection() const override;
};
} // end anonymous namespace
// ARM Target Thunks
template <class ELFT> static uint64_t getARMThunkDestVA(const SymbolBody &S) {
uint64_t V = S.isInPlt() ? S.getPltVA<ELFT>() : S.getVA<ELFT>();
static uint64_t getARMThunkDestVA(const SymbolBody &S) {
uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA();
return SignExtend64<32>(V);
}
template <class ELFT>
void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
void ARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
0x1c, 0xff, 0x2f, 0xe1, // bx ip
};
uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
uint64_t S = getARMThunkDestVA(this->Destination);
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S);
Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S);
}
template <class ELFT>
void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
void ARMV7ABSLongThunk<ELFT>::addSymbols(ThunkSection &IS) {
this->ThunkSym = addSyntheticLocal<ELFT>(
Saver.save("__ARMv7ABSLongThunk_" + this->Destination.getName()),
STT_FUNC, this->Offset, size(), &IS);
addSyntheticLocal<ELFT>("$a", STT_NOTYPE, this->Offset, 0, &IS);
}
template <class ELFT>
void ThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
0x60, 0x47, // bx ip
};
uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
uint64_t S = getARMThunkDestVA(this->Destination);
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S);
Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S);
}
template <class ELFT>
void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
void ThumbV7ABSLongThunk<ELFT>::addSymbols(ThunkSection &IS) {
this->ThunkSym = addSyntheticLocal<ELFT>(
Saver.save("__Thumbv7ABSLongThunk_" + this->Destination.getName()),
STT_FUNC, this->Offset, size(), &IS);
addSyntheticLocal<ELFT>("$t", STT_NOTYPE, this->Offset, 0, &IS);
}
template <class ELFT>
void ARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8)
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P+4) +8)
0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
0x1c, 0xff, 0x2f, 0xe1, // bx r12
};
uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
uint64_t P = this->getVA();
uint64_t S = getARMThunkDestVA(this->Destination);
uint64_t P = this->ThunkSym->getVA();
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16);
Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12);
}
template <class ELFT>
void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
void ARMV7PILongThunk<ELFT>::addSymbols(ThunkSection &IS) {
this->ThunkSym = addSyntheticLocal<ELFT>(
Saver.save("__ARMV7PILongThunk_" + this->Destination.getName()), STT_FUNC,
this->Offset, size(), &IS);
addSyntheticLocal<ELFT>("$a", STT_NOTYPE, this->Offset, 0, &IS);
}
template <class ELFT>
void ThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P+4) + 4)
0xfc, 0x44, // L1: add r12, pc
0x60, 0x47, // bx r12
};
uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
uint64_t P = this->getVA();
uint64_t S = getARMThunkDestVA(this->Destination);
uint64_t P = this->ThunkSym->getVA();
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12);
Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8);
}
template <class ELFT>
void ThumbV7PILongThunk<ELFT>::addSymbols(ThunkSection &IS) {
this->ThunkSym = addSyntheticLocal<ELFT>(
Saver.save("__ThumbV7PILongThunk_" + this->Destination.getName()),
STT_FUNC, this->Offset, size(), &IS);
addSyntheticLocal<ELFT>("$t", STT_NOTYPE, this->Offset, 0, &IS);
}
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const {
template <class ELFT>
void MipsThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &) const {
const endianness E = ELFT::TargetEndianness;
uint64_t S = this->Destination.template getVA<ELFT>();
uint64_t S = this->Destination.getVA();
write32<E>(Buf, 0x3c190000); // lui $25, %hi(func)
write32<E>(Buf + 4, 0x08000000 | (S >> 2)); // j func
write32<E>(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
@ -178,20 +211,24 @@ template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const {
Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
}
template <class ELFT>
Thunk<ELFT>::Thunk(const SymbolBody &D, const InputSection<ELFT> &O)
: Destination(D), Owner(O), Offset(O.getThunkOff() + O.getThunksSize()) {}
template <class ELFT> typename ELFT::uint Thunk<ELFT>::getVA() const {
return Owner.OutSec->Addr + Owner.OutSecOff + Offset;
template <class ELFT> void MipsThunk<ELFT>::addSymbols(ThunkSection &IS) {
this->ThunkSym = addSyntheticLocal<ELFT>(
Saver.save("__LA25Thunk_" + this->Destination.getName()), STT_FUNC,
this->Offset, size(), &IS);
}
template <class ELFT> Thunk<ELFT>::~Thunk() = default;
template <class ELFT>
InputSection *MipsThunk<ELFT>::getTargetInputSection() const {
auto *DR = dyn_cast<DefinedRegular>(&this->Destination);
return dyn_cast<InputSection>(DR->Section);
}
Thunk::Thunk(const SymbolBody &D) : Destination(D), Offset(0) {}
Thunk::~Thunk() = default;
// Creates a thunk for Thumb-ARM interworking.
template <class ELFT>
static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S,
InputSection<ELFT> &IS) {
template <class ELFT> static Thunk *addThunkArm(uint32_t Reloc, SymbolBody &S) {
// ARM relocations need ARM to Thumb interworking Thunks.
// Thumb relocations need Thumb to ARM relocations.
// Use position independent Thunks if we require position independent code.
@ -200,76 +237,33 @@ static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S,
case R_ARM_PLT32:
case R_ARM_JUMP24:
if (Config->Pic)
return new (BAlloc) ARMToThumbV7PILongThunk<ELFT>(S, IS);
return new (BAlloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS);
return make<ARMV7PILongThunk<ELFT>>(S);
return make<ARMV7ABSLongThunk<ELFT>>(S);
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
if (Config->Pic)
return new (BAlloc) ThumbToARMV7PILongThunk<ELFT>(S, IS);
return new (BAlloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS);
return make<ThumbV7PILongThunk<ELFT>>(S);
return make<ThumbV7ABSLongThunk<ELFT>>(S);
}
fatal("unrecognized relocation type");
}
template <class ELFT>
static void addThunkARM(uint32_t Reloc, SymbolBody &S, InputSection<ELFT> &IS) {
// Only one Thunk supported per symbol.
if (S.hasThunk<ELFT>())
return;
// ARM Thunks are added to the same InputSection as the relocation. This
// isn't strictly necessary but it makes it more likely that a limited range
// branch can reach the Thunk, and it makes Thunks to the PLT section easier
Thunk<ELFT> *T = createThunkArm(Reloc, S, IS);
IS.addThunk(T);
if (auto *Sym = dyn_cast<DefinedRegular<ELFT>>(&S))
Sym->ThunkData = T;
else if (auto *Sym = dyn_cast<SharedSymbol<ELFT>>(&S))
Sym->ThunkData = T;
else if (auto *Sym = dyn_cast<Undefined<ELFT>>(&S))
Sym->ThunkData = T;
else
fatal("symbol not DefinedRegular or Shared");
template <class ELFT> static Thunk *addThunkMips(SymbolBody &S) {
return make<MipsThunk<ELFT>>(S);
}
template <class ELFT>
static void addThunkMips(uint32_t RelocType, SymbolBody &S,
InputSection<ELFT> &IS) {
// Only one Thunk supported per symbol.
if (S.hasThunk<ELFT>())
return;
// Mips Thunks are added to the InputSection defining S.
auto *R = cast<DefinedRegular<ELFT>>(&S);
auto *Sec = cast<InputSection<ELFT>>(R->Section);
auto *T = new (BAlloc) MipsThunk<ELFT>(S, *Sec);
Sec->addThunk(T);
R->ThunkData = T;
}
template <class ELFT>
void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &IS) {
template <class ELFT> Thunk *addThunk(uint32_t RelocType, SymbolBody &S) {
if (Config->EMachine == EM_ARM)
addThunkARM<ELFT>(RelocType, S, IS);
return addThunkArm<ELFT>(RelocType, S);
else if (Config->EMachine == EM_MIPS)
addThunkMips<ELFT>(RelocType, S, IS);
else
llvm_unreachable("add Thunk only supported for ARM and Mips");
return addThunkMips<ELFT>(S);
llvm_unreachable("add Thunk only supported for ARM and Mips");
return nullptr;
}
template void addThunk<ELF32LE>(uint32_t, SymbolBody &,
InputSection<ELF32LE> &);
template void addThunk<ELF32BE>(uint32_t, SymbolBody &,
InputSection<ELF32BE> &);
template void addThunk<ELF64LE>(uint32_t, SymbolBody &,
InputSection<ELF64LE> &);
template void addThunk<ELF64BE>(uint32_t, SymbolBody &,
InputSection<ELF64BE> &);
template class Thunk<ELF32LE>;
template class Thunk<ELF32BE>;
template class Thunk<ELF64LE>;
template class Thunk<ELF64BE>;
template Thunk *addThunk<ELF32LE>(uint32_t, SymbolBody &);
template Thunk *addThunk<ELF32BE>(uint32_t, SymbolBody &);
template Thunk *addThunk<ELF64LE>(uint32_t, SymbolBody &);
template Thunk *addThunk<ELF64BE>(uint32_t, SymbolBody &);
} // end namespace elf
} // end namespace lld

View file

@ -15,8 +15,7 @@
namespace lld {
namespace elf {
class SymbolBody;
template <class ELFT> class InputSection;
class ThunkSection;
// Class to describe an instance of a Thunk.
// A Thunk is a code-sequence inserted by the linker in between a caller and
// the callee. The relocation to the callee is redirected to the Thunk, which
@ -24,31 +23,35 @@ template <class ELFT> class InputSection;
// include transferring control from non-pi to pi and changing state on
// targets like ARM.
//
// Thunks can be created for DefinedRegular and Shared Symbols. The Thunk
// is stored in a field of the Symbol Destination.
// Thunks to be written to an InputSection are recorded by the InputSection.
template <class ELFT> class Thunk {
typedef typename ELFT::uint uintX_t;
// Thunks can be created for DefinedRegular, Shared and Undefined Symbols.
// Thunks are assigned to synthetic ThunkSections
class Thunk {
public:
Thunk(const SymbolBody &Destination, const InputSection<ELFT> &Owner);
Thunk(const SymbolBody &Destination);
virtual ~Thunk();
virtual uint32_t size() const { return 0; }
virtual void writeTo(uint8_t *Buf) const {}
uintX_t getVA() const;
virtual void writeTo(uint8_t *Buf, ThunkSection &IS) const {}
protected:
// All Thunks must define at least one symbol ThunkSym so that we can
// redirect relocations to it.
virtual void addSymbols(ThunkSection &IS) {}
// Some Thunks must be placed immediately before their Target as they elide
// a branch and fall through to the first Symbol in the Target.
virtual InputSection *getTargetInputSection() const { return nullptr; }
// The alignment requirement for this Thunk, defaults to the size of the
// typical code section alignment.
const SymbolBody &Destination;
const InputSection<ELFT> &Owner;
SymbolBody *ThunkSym;
uint64_t Offset;
uint32_t alignment = 4;
};
// For a Relocation to symbol S from InputSection Src, create a Thunk and
// update the fields of S and the InputSection that the Thunk body will be
// written to. At present there are implementations for ARM and Mips Thunks.
template <class ELFT>
void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &Src);
// For a Relocation to symbol S create a Thunk to be added to a synthetic
// ThunkSection. At present there are implementations for ARM and Mips Thunks.
template <class ELFT> Thunk *addThunk(uint32_t RelocType, SymbolBody &S);
} // namespace elf
} // namespace lld

File diff suppressed because it is too large Load diff

View file

@ -18,41 +18,39 @@
namespace lld {
namespace elf {
class InputFile;
class OutputSectionBase;
template <class ELFT> class InputSectionBase;
class OutputSection;
class InputSectionBase;
template <class ELFT> class ObjectFile;
template <class ELFT> class SymbolTable;
template <class ELFT> void writeResult();
template <class ELFT> void markLive();
template <class ELFT> bool isRelroSection(const OutputSectionBase *Sec);
template <class ELFT> bool isRelroSection(const OutputSection *Sec);
// This describes a program header entry.
// Each contains type, access flags and range of output sections that will be
// placed in it.
struct PhdrEntry {
PhdrEntry(unsigned Type, unsigned Flags);
void add(OutputSectionBase *Sec);
void add(OutputSection *Sec);
uint64_t p_paddr = 0;
uint64_t p_vaddr = 0;
uint64_t p_align = 0;
uint64_t p_memsz = 0;
uint64_t p_filesz = 0;
uint64_t p_offset = 0;
uint32_t p_align = 0;
uint32_t p_type = 0;
uint32_t p_flags = 0;
OutputSectionBase *First = nullptr;
OutputSectionBase *Last = nullptr;
OutputSection *First = nullptr;
OutputSection *Last = nullptr;
bool HasLMA = false;
};
llvm::StringRef getOutputSectionName(llvm::StringRef Name);
template <class ELFT>
void allocateHeaders(llvm::MutableArrayRef<PhdrEntry>,
llvm::ArrayRef<OutputSectionBase *>);
template <class ELFT> void reportDiscarded(InputSectionBase<ELFT> *IS);
bool allocateHeaders(std::vector<PhdrEntry> &, llvm::ArrayRef<OutputSection *>,
uint64_t Min);
template <class ELFT> uint32_t getMipsEFlags();

View file

@ -1,6 +1,9 @@
ATOM-based lld
==============
Note: this document discuss Mach-O port of LLD. For ELF and COFF,
see :doc:`index`.
ATOM-based lld is a new set of modular code for creating linker tools.
Currently it supports Mach-O.
@ -46,9 +49,7 @@ Contents
design
getting_started
ReleaseNotes
development
windows_support
open_projects
sphinx_intro

View file

@ -1,9 +0,0 @@
C++11
=====
Originally, LLD was developed in C++11 unlike the rest of LLVM. Now, all of
LLVM, LLD, and Clang are developed using C++11. See the `LLVM Coding
Standards`_ for details on the precise subset of C++11 supported by the various
host compilers.
.. _LLVM Coding Standards: http://llvm.org/docs/CodingStandards.html

View file

@ -2,6 +2,9 @@
Driver
======
Note: this document discuss Mach-O port of LLD. For ELF and COFF,
see :doc:`index`.
.. contents::
:local:

View file

@ -1,42 +1,6 @@
The ELF and COFF Linkers
========================
We started rewriting the ELF (Unix) and COFF (Windows) linkers in May 2015.
Since then, we have been making a steady progress towards providing
drop-in replacements for the system linkers.
Currently, the Windows support is mostly complete and is about 2x faster
than the linker that comes as a part of Micrsoft Visual Studio toolchain.
The ELF support is in progress and is able to link large programs
such as Clang or LLD itself. Unless your program depends on linker scripts,
you can expect it to be linkable with LLD.
It is currently about 1.2x to 2x faster than GNU gold linker.
We aim to make it a drop-in replacement for the GNU linker.
We expect that FreeBSD is going to be the first large system
to adopt LLD as the system linker.
We are working on it in collaboration with the FreeBSD project.
The linkers are notably small; as of October 2016,
the COFF linker is about 7k lines and the ELF linker is about 18k lines,
while gold is 165K lines.
The linkers are designed to be as fast and simple as possible.
Because it is simple, it is easy to extend to support new features.
It already supports several advanced features such section garbage
collection and identical code folding.
The COFF linker supports i386, x86-64 and ARM. The ELF linker supports
i386, x86-64, x32, MIPS32, MIPS64, PowerPC, AMDGPU, ARM and Aarch64,
although the quality varies depending on platform. By default, LLD
provides support for all targets because the amount of code we have for
each target is so small. We do not even provide a way to disable
targets at compile time.
There are a few key design choices that we made to achieve these goals.
We will describe them in this document.
The ELF Linker as a Library
---------------------------
@ -126,7 +90,7 @@ between speed, simplicity and extensibility.
Visiting the same archive files multiple makes the linker slower.
Here is how LLD approached the problem. Instead of memorizing only undefined symbols,
Here is how LLD approaches the problem. Instead of memorizing only undefined symbols,
we program LLD so that it memorizes all symbols.
When it sees an undefined symbol that can be resolved by extracting an object file
from an archive file it previously visited, it immediately extracts the file and link it.
@ -169,7 +133,7 @@ it would slow down the linker by 10%. So, don't do that.
On the other hand, you don't have to pursue efficiency
when handling files.
Important Data Strcutures
Important Data Structures
-------------------------
We will describe the key data structures in LLD in this section.
@ -216,7 +180,7 @@ Once you understand their functions, the code of the linker should look obvious
* SymbolTable
SymbolTable is basically a hash table from strings to Symbols
with a logic to resolve symbol conflicts. It resolves conflicts by symbol type.
with logic to resolve symbol conflicts. It resolves conflicts by symbol type.
- If we add Defined and Undefined symbols, the symbol table will keep the former.
- If we add Defined and Lazy symbols, it will keep the former.
@ -269,11 +233,11 @@ There are mainly three actors in this linker.
* Driver
The linking process is driven by the driver. The driver
The linking process is driven by the driver. The driver:
- processes command line options,
- creates a symbol table,
- creates an InputFile for each input file and put all symbols in it into the symbol table,
- creates an InputFile for each input file and puts all symbols within into the symbol table,
- checks if there's no remaining undefined symbols,
- creates a writer,
- and passes the symbol table to the writer to write the result to a file.

View file

@ -3,6 +3,9 @@
Developing lld Readers
======================
Note: this document discuss Mach-O port of LLD. For ELF and COFF,
see :doc:`index`.
Introduction
------------

View file

@ -1,101 +1,37 @@
=======================
LLD 4.0.0 Release Notes
LLD 5.0.0 Release Notes
=======================
.. contents::
:local:
.. warning::
These are in-progress notes for the upcoming LLVM 5.0.0 release.
Release notes for previous releases can be found on
`the Download Page <http://releases.llvm.org/download.html>`_.
Introduction
============
LLD is a linker which supports ELF (Unix), COFF (Windows) and Mach-O
(macOS). It is generally faster than the GNU BFD/gold linkers or the
MSVC linker.
LLD is designed to be a drop-in replacement for the system linkers, so
that users don't need to change their build systems other than swapping
the linker command.
This document contains the release notes for LLD 4.0.0.
This document contains the release notes for the LLD linker, release 5.0.0.
Here we describe the status of LLD, including major improvements
from the previous release. All LLD releases may be downloaded
from the `LLVM releases web site <http://llvm.org/releases/>`_.
What's New in LLD 4.0?
======================
Non-comprehensive list of changes in this release
=================================================
ELF Improvements
----------------
LLD provides much better compatibility with the GNU linker than before.
Now it is able to link the entire FreeBSD base system including the kernel
out of the box. We are working closely with the FreeBSD project to
make it usable as the system linker in a future release of the operating
system.
Multi-threading performance has been improved, and multi-threading
is now enabled by default. Combined with other optimizations, LLD 4.0
is about 1.5 times faster than LLD 3.9 when linking large programs
in our test environment.
Other notable changes are listed below:
* Error messages contain more information than before. If debug info
is available, the linker prints out not only the object file name
but the source location of unresolved symbols.
* Error messages are printed in red just like Clang by default. You
can disable it by passing ``-no-color-diagnostics``.
* LLD's version string is now embedded in a .comment section in the
result output file. You can dump it with this command: ``objdump -j -s
.comment <file>``.
* The ``-Map`` option is supported. With that, you can print out section
and symbol information to a specified file. This feature is useful
for analyzing link results.
* The file format for the ``-reproduce`` option has changed from cpio to
tar.
* When creating a copy relocation for a symbol, LLD now scans the
DSO's header to see if the symbol is in a read-only segment. If so,
space for the copy relocation is reserved in .bss.rel.ro instead of
.bss. This fixes a security issue that read-only data in a DSO
becomes writable if it is copied by a copy relocation. This issue
was disclosed originally on the
`binutils mailing list <https://sourceware.org/ml/libc-alpha/2016-12/msg00914.html>`_.
* Compressed input sections are supported.
* ``--oformat binary``, ``--section-start``, ``-Tbss``, ``-Tdata``,
``-Ttext``, ``-b binary``, ``-build-id=uuid``, ``-no-rosegment``,
``-nopie``, ``-nostdlib``, ``-omagic``, ``-retain-symbols-file``,
``-sort-section``, ``-z max-page-size`` and ``-z wxneeded`` are
supported.
* A lot of linker script directives have been added.
* Default image base address for x86-64 has changed from 0x10000 to
0x200000 to make it huge-page friendly.
* ARM port now supports GNU ifunc, the ARM C++ exceptions ABI, TLS
relocations and static linking. Problems with ``dlopen()`` on systems
using eglibc fixed.
* MIPS port now supports input files in new R6 revision of MIPS ABIs
or N32 ABI. Generated file now contains .MIPS.abiflags section and
complete set of ELF headers flags.
* Relocations produced by the ``-mxgot`` compiler flag is supported
for MIPS. Now it is possible to generate "large" GOT that exceeds the 64K
limit.
* Item 1.
COFF Improvements
-----------------
* Performance on Windows has been improved by parallelizing parts of the
linker and optimizing file system operations. As a result of these
improvements, LLD 4.0 has been measured to be about 2.5 times faster
than LLD 3.9 when linking a large Chromium DLL.
* Item 1.
MachO Improvements
------------------
* Item 1.

View file

@ -47,10 +47,10 @@ copyright = u'2011-%d, LLVM Project' % date.today().year
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '4'
# The short version.
version = '5'
# The full version, including alpha/beta/rc tags.
release = '4'
release = '5'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View file

@ -3,6 +3,9 @@
Linker Design
=============
Note: this document discuss Mach-O port of LLD. For ELF and COFF,
see :doc:`index`.
Introduction
------------

View file

@ -3,13 +3,11 @@
Development
===========
Note: this document discuss Mach-O port of LLD. For ELF and COFF,
see :doc:`index`.
lld is developed as part of the `LLVM <http://llvm.org>`_ project.
Using C++11 in lld
------------------
:doc:`C++11`.
Creating a Reader
-----------------
@ -43,6 +41,5 @@ information on writing documentation for the project, see the
.. toctree::
:hidden:
C++11
Readers
Driver

View file

@ -1,25 +1,179 @@
.. _index:
lld - The LLVM Linker
LLD - The LLVM Linker
=====================
lld contains two linkers whose architectures are different from each other.
LLD is a linker from the LLVM project. That is a drop-in replacement
for system linkers and runs much faster than them. It also provides
features that are useful for toolchain developers.
The linker supports ELF (Unix), PE/COFF (Windows) and Mach-O (macOS)
in descending order of completeness. Internally, LLD consists of three
different linkers. The ELF port is the one that will be described in
this document. The PE/COFF port is almost complete except the lack of
the Windows debug info (PDB) support. The Mach-O port is built based
on a different architecture than the ELF or COFF ports. For the
details about Mach-O, please read :doc:`AtomLLD`.
Features
--------
- LLD is a drop-in replacement for the GNU linkers. That accepts the
same command line arguments and linker scripts as GNU.
We are currently working closely with the FreeBSD project to make
LLD default system linker in future versions of the operating
system, so we are serious about addressing compatibility issues. As
of February 2017, LLD is able to link the entire FreeBSD/amd64 base
system including the kernel. With a few work-in-progress patches it
can link approximately 95% of the ports collection on AMD64. For the
details, see `FreeBSD quarterly status report
<https://www.freebsd.org/news/status/report-2016-10-2016-12.html#Using-LLVM%27s-LLD-Linker-as-FreeBSD%27s-System-Linker>`_.
- LLD is very fast. When you link a large program on a multicore
machine, you can expect that LLD runs more than twice as fast as GNU
gold linker. Your milage may vary, though.
- It supports various CPUs/ABIs including x86-64, x86, x32, AArch64,
ARM, MIPS 32/64 big/little-endian, PowerPC, PowerPC 64 and AMDGPU.
Among these, x86-64 is the most well-supported target and have
reached production quality. AArch64 and MIPS seem decent too. x86
should be OK but not well tested yet. ARM support is being developed
actively.
- It is always a cross-linker, meaning that it always supports all the
above targets however it was built. In fact, we don't provide a
build-time option to enable/disable each target. This should make it
easy to use our linker as part of a cross-compile toolchain.
- You can embed LLD to your program to eliminate dependency to
external linkers. All you have to do is to construct object files
and command line arguments just like you would do to invoke an
external linker and then call the linker's main function,
``lld::elf::link``, from your code.
- It is small. We are using LLVM libObject library to read from object
files, so it is not completely a fair comparison, but as of February
2017, LLD/ELF consists only of 21k lines of C++ code while GNU gold
consists of 198k lines of C++ code.
- Link-time optimization (LTO) is supported by default. Essentially,
all you have to do to do LTO is to pass the ``-flto`` option to clang.
Then clang creates object files not in the native object file format
but in LLVM bitcode format. LLD reads bitcode object files, compile
them using LLVM and emit an output file. Because in this way LLD can
see the entire program, it can do the whole program optimization.
- Some very old features for ancient Unix systems (pre-90s or even
before that) have been removed. Some default settings have been
tuned for the 21st century. For example, the stack is marked as
non-executable by default to tighten security.
Performance
-----------
This is a link time comparison on a 2-socket 20-core 40-thread Xeon
E5-2680 2.80 GHz machine with an SSD drive.
LLD is much faster than the GNU linkers for large programs. That's
fast for small programs too, but because the link time is short
anyway, the difference is not very noticeable in that case.
Note that this is just a benchmark result of our environment.
Depending on number of available cores, available amount of memory or
disk latency/throughput, your results may vary.
============ =========== ============ ============= ======
Program Output size GNU ld GNU gold [1]_ LLD
ffmpeg dbg 91 MiB 1.59s 1.15s 0.78s
mysqld dbg 157 MiB 7.09s 2.49s 1.31s
clang dbg 1.45 GiB 86.76s 21.93s 8.38s
chromium dbg 1.52 GiB 142.30s [2]_ 40.86s 12.69s
============ =========== ============ ============= ======
.. [1] With the ``--threads`` option to enable multi-threading support.
.. [2] Since GNU ld doesn't support the ``-icf=all`` option, we
removed that from the command line for GNU ld. GNU ld would be
slower than this if it had that option support. For gold and
LLD, we use ``-icf=all``.
Build
-----
If you have already checked out LLVM using SVN, you can check out LLD
under ``tools`` directory just like you probably did for clang. For the
details, see `Getting Started with the LLVM System
<http://llvm.org/docs/GettingStarted.html>`_.
If you haven't checkout out LLVM, the easiest way to build LLD is to
checkout the entire LLVM projects/sub-projects from a git mirror and
build that tree. You need `cmake` and of course a C++ compiler.
.. code-block:: console
$ git clone https://github.com/llvm-project/llvm-project/
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=lld -DCMAKE_INSTALL_PREFIX=/usr/local ../llvm-project/llvm
$ make install
Using LLD
---------
LLD is installed as ``ld.lld``. On Unix, linkers are invoked by
compiler drivers, so you are not expected to use that command
directly. There are a few ways to tell compiler drivers to use ld.lld
instead of the default linker.
The easiest way to do that is to overwrite the default linker. After
installing LLD to somewhere on your disk, you can create a symbolic
link by doing ``ln -s /path/to/ld.lld /usr/bin/ld`` so that
``/usr/bin/ld`` is resolved to LLD.
If you don't want to change the system setting, you can use clang's
``-fuse-ld`` option. In this way, you want to set ``-fuse-ld=lld`` to
LDFLAGS when building your programs.
LLD leaves its name and version number to a ``.comment`` section in an
output. If you are in doubt whether you are successfully using LLD or
not, run ``objdump -s -j .comment <output-file>`` and examine the
output. If the string "Linker: LLD" is included in the output, you are
using LLD.
History
-------
Here is a brief project history of the ELF and COFF ports.
- May 2015: We decided to rewrite the COFF linker and did that.
Noticed that the new linker is much faster than the MSVC linker.
- July 2015: The new ELF port was developed based on the COFF linker
architecture.
- September 2015: The first patches to support MIPS and AArch64 landed.
- October 2015: Succeeded to self-host the ELF port. We have noticed
that the linker was faster than the GNU linkers, but we weren't sure
at the time if we would be able to keep the gap as we would add more
features to the linker.
- July 2016: Started working on improving the linker script support.
- December 2016: Succeeded to build the entire FreeBSD base system
including the kernel. We had widen the performance gap against the
GNU linkers.
Internals
---------
For the internals of the linker, please read :doc:`NewLLD`. It is a bit
outdated but the fundamental concepts remain valid. We'll update the
document soon.
.. toctree::
:maxdepth: 1
NewLLD
AtomLLD
Source
------
lld is available in the LLVM SVN repository::
svn co http://llvm.org/svn/llvm-project/lld/trunk lld
lld is also available via the read-only git mirror::
git clone http://llvm.org/git/lld.git
Put it in llvm's tools/ directory, rerun cmake, then build target lld.
windows_support
ReleaseNotes

View file

@ -318,12 +318,11 @@ void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) {
TaskGroup Tg;
IndexTy I = Begin;
for (; I < End; I += TaskSize) {
for (; I + TaskSize < End; I += TaskSize) {
Tg.spawn([=, &Fn] {
for (IndexTy J = I, E = I + TaskSize; J != E; ++J)
Fn(J);
});
Begin += TaskSize;
}
Tg.spawn([=, &Fn] {
for (IndexTy J = I; J < End; ++J)

View file

@ -0,0 +1,20 @@
//===-- TargetOptionsCommandFlags.h ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Helper to create TargetOptions from command line flags.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/CodeGen.h"
#include "llvm/Target/TargetOptions.h"
namespace lld {
llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
llvm::CodeModel::Model GetCodeModelFromCMModel();
}

View file

@ -15,7 +15,8 @@
namespace lld {
namespace coff {
bool link(llvm::ArrayRef<const char *> Args);
bool link(llvm::ArrayRef<const char *> Args,
llvm::raw_ostream &Diag = llvm::errs());
}
namespace elf {

View file

@ -1,3 +1,7 @@
if(NOT LLD_BUILT_STANDALONE)
set(tablegen_deps intrinsics_gen)
endif()
add_lld_library(lldCore
DefinedAtom.cpp
Error.cpp
@ -7,11 +11,16 @@ add_lld_library(lldCore
Reproduce.cpp
Resolver.cpp
SymbolTable.cpp
TargetOptionsCommandFlags.cpp
Writer.cpp
ADDITIONAL_HEADER_DIRS
${LLD_INCLUDE_DIR}/lld/Core
LINK_COMPONENTS
MC
Support
DEPENDS
${tablegen_deps}
)

View file

@ -0,0 +1,32 @@
//===-- TargetOptionsCommandFlags.cpp ---------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file exists as a place for global variables defined in LLVM's
// CodeGen/CommandFlags.h. By putting the resulting object file in
// an archive and linking with it, the definitions will automatically be
// included when needed and skipped when already present.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/TargetOptionsCommandFlags.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/Target/TargetOptions.h"
// Define an externally visible version of
// InitTargetOptionsFromCodeGenFlags, so that its functionality can be
// used without having to include llvm/CodeGen/CommandFlags.h, which
// would lead to multiple definitions of the command line flags.
llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() {
return ::InitTargetOptionsFromCodeGenFlags();
}
llvm::CodeModel::Model lld::GetCodeModelFromCMModel() {
return CMModel;
}

View file

@ -51,11 +51,7 @@ public:
canBypassGOT = true;
return true;
case delta32ToGOT:
canBypassGOT = false;
return true;
case unwindCIEToPersonalityFunction:
canBypassGOT = false;
return true;
case imageOffsetGot:
canBypassGOT = false;
return true;

View file

@ -118,14 +118,7 @@ public:
normalized::Relocations &relocs) override;
bool isDataInCodeTransition(Reference::KindValue refKind) override {
switch (refKind) {
case modeCode:
case modeData:
return true;
default:
return false;
break;
}
return refKind == modeCode || refKind == modeData;
}
Reference::KindValue dataInCodeTransitionStart(

View file

@ -28,7 +28,7 @@ add_lld_library(lldMachO
LINK_LIBS
lldCore
lldYAML
${PTHREAD_LIB}
${LLVM_PTHREAD_LIB}
)
include_directories(.)

View file

@ -3,13 +3,18 @@ set(LLVM_BINARY_DIR "${LLVM_BINARY_DIR}")
set(LLVM_BUILD_MODE "%(build_mode)s")
set(LLVM_TOOLS_DIR "${LLVM_TOOLS_BINARY_DIR}/%(build_config)s")
set(LLVM_LIBS_DIR "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/%(build_config)s")
set(CLANG_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
set(CLANG_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/..")
if(BUILD_SHARED_LIBS)
set(ENABLE_SHARED 1)
else()
set(ENABLE_SHARED 0)
endif(BUILD_SHARED_LIBS)
if(LLD_BUILT_STANDALONE)
# Set HAVE_LIBZ according to recorded LLVM_ENABLE_ZLIB value. This
# value is forced to 0 if zlib was not found, so it is fine to use it
# instead of HAVE_LIBZ (not recorded).
if(LLVM_ENABLE_ZLIB)
set(HAVE_LIBZ 1)
endif()
endif()
llvm_canonicalize_cmake_booleans(
HAVE_LIBZ)
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
@ -19,13 +24,17 @@ configure_lit_site_cfg(
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
)
set(LLD_TEST_DEPS
FileCheck not llvm-ar llvm-as llvm-dis llvm-dwarfdump llvm-nm
llc lld llvm-config llvm-objdump llvm-readobj yaml2obj obj2yaml
llvm-mc llvm-lib llvm-pdbdump opt
)
set(LLD_TEST_DEPS lld)
if (NOT LLD_BUILT_STANDALONE)
list(APPEND LLD_TEST_DEPS
FileCheck count not llvm-ar llvm-as llvm-dis llvm-dwarfdump llvm-nm
llc llvm-config llvm-objdump llvm-readobj yaml2obj obj2yaml
llvm-mc llvm-lib llvm-pdbdump opt
)
endif()
if (LLVM_INCLUDE_TESTS)
set(LLD_TEST_DEPS ${LLD_TEST_DEPS} LLDUnitTests)
list(APPEND LLD_TEST_DEPS LLDUnitTests)
endif()
set(LLD_TEST_PARAMS

6
test/COFF/Inputs/bar.ll Normal file
View file

@ -0,0 +1,6 @@
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
define void @bar() {
ret void
}

View file

@ -0,0 +1,3 @@
.globl foo
foo:
ret

View file

@ -0,0 +1,28 @@
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.0.24215"
%class.baz = type { %class.bar }
%class.bar = type { i32 (...)** }
$"\01?x@bar@@UEBA_NXZ" = comdat any
$"\01??_7baz@@6B@" = comdat any
$"\01??_Gbaz@@UEAAPEAXI@Z" = comdat any
@"\01??_7baz@@6B@" = linkonce_odr unnamed_addr constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (i8* (%class.baz*, i32)* @"\01??_Gbaz@@UEAAPEAXI@Z" to i8*), i8* bitcast (i1 (%class.bar*)* @"\01?x@bar@@UEBA_NXZ" to i8*)] }, comdat, !type !0, !type !1
define void @"\01?qux@@YAXXZ"() local_unnamed_addr {
ret void
}
define linkonce_odr i8* @"\01??_Gbaz@@UEAAPEAXI@Z"(%class.baz* %this, i32 %should_call_delete) unnamed_addr comdat {
ret i8* null
}
define linkonce_odr zeroext i1 @"\01?x@bar@@UEBA_NXZ"(%class.bar* %this) unnamed_addr comdat {
ret i1 false
}
!0 = !{i64 0, !"?AVbar@@"}
!1 = !{i64 0, !"?AVbaz@@"}

28
test/COFF/def-name.test Normal file
View file

@ -0,0 +1,28 @@
# REQUIRES: winres
# RUN: rm -rf %t
# RUN: mkdir -p %t
# RUN: cd %t
# RUN: yaml2obj < %p/Inputs/ret42.yaml > in.obj
# RUN: lld-link /entry:main in.obj
# RUN: lld-link /entry:main /dll in.obj
# RUN: echo -e "NAME foo\n" > fooexe.def
# RUN: echo -e "LIBRARY foo\n" > foodll.def
# RUN: lld-link /entry:main /def:fooexe.def in.obj
# RUN: lld-link /entry:main /def:foodll.def /dll in.obj
# RUN: lld-link /entry:main /out:bar.exe /def:fooexe.def in.obj
# RUN: lld-link /entry:main /out:bar.dll /def:foodll.def /dll in.obj
# RUN: llvm-readobj in.exe | FileCheck %s
# RUN: llvm-readobj in.dll | FileCheck %s
# RUN: llvm-readobj foo.exe | FileCheck %s
# RUN: llvm-readobj foo.dll | FileCheck %s
# RUN: llvm-readobj bar.exe | FileCheck %s
# RUN: llvm-readobj bar.dll | FileCheck %s
CHECK: File:

View file

@ -0,0 +1,3 @@
# REQUIRES: system-windows
# RUN: not LLD-LINK 2>&1 | FileCheck %s
CHECK: no input files

View file

@ -0,0 +1,29 @@
RUN: not lld-link 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 \
RUN: 21 22 2>&1 | FileCheck -check-prefix=DEFAULT %s
DEFAULT: could not open 01
DEFAULT: could not open 20
DEFAULT-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors)
DEFAULT-NOT: could not open 21
RUN: not lld-link /ERRORLIMIT:5 01 02 03 04 05 06 07 08 09 10 2>&1 \
RUN: | FileCheck -check-prefix=LIMIT5 %s
LIMIT5: could not open 01
LIMIT5: could not open 05
LIMIT5-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors)
LIMIT5-NOT: could not open 06
RUN: not lld-link /ERRORLIMIT:0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \
RUN: 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=UNLIMITED %s
UNLIMITED: could not open 01
UNLIMITED: could not open 20
UNLIMITED: could not open 21
UNLIMITED: could not open 22
UNLIMITED-NOT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors)
RUN: not lld-link /ERRORLIMIT:XYZ 01 02 03 04 05 06 07 08 09 10 11 12 13 14 \
RUN: 15 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=WRONG %s
WRONG: /ERRORLIMIT: number expected, but got XYZ

Some files were not shown because too many files have changed in this diff Show more