aboutsummaryrefslogtreecommitdiffstats
path: root/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:48:50 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:48:50 +0000
commit1c98619801a5705c688e683be3ef9d70169a0686 (patch)
tree8422105cd1a94c368315f2db16b9ac746cf7c000 /ELF
parentf4f3ce4613680903220815690ad79fc7ba0a2e26 (diff)
downloadsrc-1c98619801a5705c688e683be3ef9d70169a0686.tar.gz
src-1c98619801a5705c688e683be3ef9d70169a0686.zip
Vendor import of lld release_39 branch r276489:vendor/lld/lld-release_39-r276489
Notes
Notes: svn path=/vendor/lld/dist/; revision=303239 svn path=/vendor/lld/lld-release_39-r276489/; revision=303240; tag=vendor/lld/lld-release_39-r276489
Diffstat (limited to 'ELF')
-rw-r--r--ELF/CMakeLists.txt28
-rw-r--r--ELF/Config.h63
-rw-r--r--ELF/Driver.cpp463
-rw-r--r--ELF/Driver.h65
-rw-r--r--ELF/DriverUtils.cpp234
-rw-r--r--ELF/EhFrame.cpp167
-rw-r--r--ELF/EhFrame.h22
-rw-r--r--ELF/Error.cpp49
-rw-r--r--ELF/Error.h39
-rw-r--r--ELF/ICF.cpp345
-rw-r--r--ELF/ICF.h19
-rw-r--r--ELF/InputFiles.cpp775
-rw-r--r--ELF/InputFiles.h187
-rw-r--r--ELF/InputSection.cpp779
-rw-r--r--ELF/InputSection.h206
-rw-r--r--ELF/LTO.cpp325
-rw-r--r--ELF/LTO.h54
-rw-r--r--ELF/LinkerScript.cpp566
-rw-r--r--ELF/LinkerScript.h103
-rw-r--r--ELF/MarkLive.cpp167
-rw-r--r--ELF/Options.td283
-rw-r--r--ELF/OutputSections.cpp2176
-rw-r--r--ELF/OutputSections.h596
-rw-r--r--ELF/README.md22
-rw-r--r--ELF/Relocations.cpp704
-rw-r--r--ELF/Relocations.h93
-rw-r--r--ELF/ScriptParser.cpp163
-rw-r--r--ELF/ScriptParser.h49
-rw-r--r--ELF/Strings.cpp98
-rw-r--r--ELF/Strings.h29
-rw-r--r--ELF/SymbolListFile.cpp168
-rw-r--r--ELF/SymbolListFile.h27
-rw-r--r--ELF/SymbolTable.cpp717
-rw-r--r--ELF/SymbolTable.h99
-rw-r--r--ELF/Symbols.cpp369
-rw-r--r--ELF/Symbols.h470
-rw-r--r--ELF/Target.cpp2678
-rw-r--r--ELF/Target.h151
-rw-r--r--ELF/Thunks.cpp268
-rw-r--r--ELF/Thunks.h56
-rw-r--r--ELF/Writer.cpp1564
-rw-r--r--ELF/Writer.h20
42 files changed, 10971 insertions, 4485 deletions
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
index 3dcb65ff8957..a1b65adc7400 100644
--- a/ELF/CMakeLists.txt
+++ b/ELF/CMakeLists.txt
@@ -2,25 +2,49 @@ set(LLVM_TARGET_DEFINITIONS Options.td)
tablegen(LLVM Options.inc -gen-opt-parser-defs)
add_public_tablegen_target(ELFOptionsTableGen)
-add_lld_library(lldELF2
+add_lld_library(lldELF
Driver.cpp
DriverUtils.cpp
+ EhFrame.cpp
Error.cpp
+ ICF.cpp
InputFiles.cpp
InputSection.cpp
+ LTO.cpp
LinkerScript.cpp
MarkLive.cpp
OutputSections.cpp
+ Relocations.cpp
+ ScriptParser.cpp
+ Strings.cpp
+ SymbolListFile.cpp
SymbolTable.cpp
Symbols.cpp
Target.cpp
+ Thunks.cpp
Writer.cpp
LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ Analysis
+ BitReader
+ BitWriter
+ Codegen
+ Core
+ IPO
+ Linker
+ LTO
Object
Option
+ Passes
MC
Support
+ Target
+ TransformUtils
+
+ LINK_LIBS
+ lldConfig
+ ${PTHREAD_LIB}
)
-add_dependencies(lldELF2 ELFOptionsTableGen)
+add_dependencies(lldELF intrinsics_gen ELFOptionsTableGen)
diff --git a/ELF/Config.h b/ELF/Config.h
index c279b99b43c1..2ccd95e88775 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -17,10 +17,10 @@
#include <vector>
namespace lld {
-namespace elf2 {
+namespace elf {
class InputFile;
-class SymbolBody;
+struct Symbol;
enum ELFKind {
ELFNoneKind,
@@ -30,60 +30,105 @@ enum ELFKind {
ELF64BEKind
};
+enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring };
+
+enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore };
+
+struct SymbolVersion {
+ llvm::StringRef Name;
+ bool IsExternCpp;
+};
+
+// 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, size_t Id) : Name(Name), Id(Id) {}
+ llvm::StringRef Name;
+ size_t Id;
+ std::vector<SymbolVersion> Globals;
+ size_t NameOff; // Offset in string table.
+};
+
// This struct contains the global configuration for the linker.
// Most fields are direct mapping from the command line options
// and such fields have the same name as the corresponding options.
// Most fields are initialized by the driver.
struct Configuration {
- SymbolBody *EntrySym = nullptr;
- SymbolBody *MipsGpDisp = nullptr;
+ Symbol *EntrySym = nullptr;
InputFile *FirstElf = nullptr;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
llvm::StringRef Emulation;
llvm::StringRef Fini;
llvm::StringRef Init;
+ llvm::StringRef LtoAAPipeline;
+ llvm::StringRef LtoNewPmPasses;
llvm::StringRef OutputFile;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
std::string RPath;
- llvm::MapVector<llvm::StringRef, std::vector<llvm::StringRef>> OutputSections;
+ std::vector<VersionDefinition> VersionDefinitions;
+ std::vector<llvm::StringRef> DynamicList;
std::vector<llvm::StringRef> SearchPaths;
std::vector<llvm::StringRef> Undefined;
+ std::vector<SymbolVersion> VersionScriptGlobals;
+ std::vector<uint8_t> BuildIdVector;
bool AllowMultipleDefinition;
bool AsNeeded = false;
bool Bsymbolic;
+ bool BsymbolicFunctions;
+ bool Demangle = true;
+ bool DisableVerify;
bool DiscardAll;
bool DiscardLocals;
bool DiscardNone;
+ bool EhFrameHdr;
bool EnableNewDtags;
bool ExportDynamic;
+ bool FatalWarnings;
bool GcSections;
bool GnuHash = false;
+ bool ICF;
bool Mips64EL = false;
- bool NoInhibitExec;
- bool NoUndefined;
+ bool NoGnuUnique;
+ bool NoUndefinedVersion;
+ bool Pic;
+ bool Pie;
bool PrintGcSections;
+ bool Rela;
+ bool Relocatable;
+ bool SaveTemps;
bool Shared;
bool Static = false;
bool StripAll;
+ bool StripDebug;
bool SysvHash = true;
+ bool Threads;
+ bool Trace;
bool Verbose;
+ bool WarnCommon;
+ bool ZCombreloc;
bool ZExecStack;
bool ZNodelete;
bool ZNow;
bool ZOrigin;
bool ZRelro;
+ UnresolvedPolicy UnresolvedSymbols;
+ BuildIdKind BuildId = BuildIdKind::None;
ELFKind EKind = ELFNoneKind;
+ uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
uint16_t EMachine = llvm::ELF::EM_NONE;
uint64_t EntryAddr = -1;
- unsigned Optimize = 0;
+ uint64_t ImageBase;
+ unsigned LtoJobs;
+ unsigned LtoO;
+ unsigned Optimize;
};
// The only instance of Configuration struct.
extern Configuration *Config;
-} // namespace elf2
+} // namespace elf
} // namespace lld
#endif
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index f00d97851e4a..c6ca2639236f 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -10,119 +10,218 @@
#include "Driver.h"
#include "Config.h"
#include "Error.h"
+#include "ICF.h"
#include "InputFiles.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Strings.h"
+#include "SymbolListFile.h"
#include "SymbolTable.h"
#include "Target.h"
#include "Writer.h"
-#include "llvm/ADT/STLExtras.h"
+#include "lld/Driver/Driver.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
#include <utility>
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
+using namespace llvm::sys;
using namespace lld;
-using namespace lld::elf2;
+using namespace lld::elf;
-Configuration *elf2::Config;
-LinkerDriver *elf2::Driver;
+Configuration *elf::Config;
+LinkerDriver *elf::Driver;
+
+bool elf::link(ArrayRef<const char *> Args, raw_ostream &Error) {
+ HasError = false;
+ ErrorOS = &Error;
-void elf2::link(ArrayRef<const char *> Args) {
Configuration C;
LinkerDriver D;
+ ScriptConfiguration SC;
Config = &C;
Driver = &D;
- Driver->main(Args.slice(1));
+ ScriptConfig = &SC;
+
+ Driver->main(Args);
+ return !HasError;
}
+// Parses a linker -m option.
static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) {
- if (S == "elf32btsmip")
- return {ELF32BEKind, EM_MIPS};
- if (S == "elf32ltsmip")
- return {ELF32LEKind, EM_MIPS};
- if (S == "elf32ppc" || S == "elf32ppc_fbsd")
- return {ELF32BEKind, EM_PPC};
- if (S == "elf64ppc" || S == "elf64ppc_fbsd")
- return {ELF64BEKind, EM_PPC64};
- if (S == "elf_i386")
- return {ELF32LEKind, EM_386};
- if (S == "elf_x86_64")
- return {ELF64LEKind, EM_X86_64};
- if (S == "aarch64linux")
- return {ELF64LEKind, EM_AARCH64};
- if (S == "i386pe" || S == "i386pep" || S == "thumb2pe")
- error("Windows targets are not supported on the ELF frontend: " + S);
- error("Unknown emulation: " + S);
+ if (S.endswith("_fbsd"))
+ S = S.drop_back(5);
+
+ std::pair<ELFKind, uint16_t> Ret =
+ StringSwitch<std::pair<ELFKind, uint16_t>>(S)
+ .Case("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("elf32ppc", {ELF32BEKind, EM_PPC})
+ .Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
+ .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
+ .Case("elf64ppc", {ELF64BEKind, EM_PPC64})
+ .Case("elf_i386", {ELF32LEKind, EM_386})
+ .Case("elf_x86_64", {ELF64LEKind, EM_X86_64})
+ .Default({ELFNoneKind, EM_NONE});
+
+ if (Ret.first == ELFNoneKind) {
+ if (S == "i386pe" || S == "i386pep" || S == "thumb2pe")
+ error("Windows targets are not supported on the ELF frontend: " + S);
+ else
+ error("unknown emulation: " + S);
+ }
+ return Ret;
}
// Returns slices of MB by parsing MB as an archive file.
// Each slice consists of a member file in the archive.
-static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB) {
- ErrorOr<std::unique_ptr<Archive>> FileOrErr = Archive::create(MB);
- error(FileOrErr, "Failed to parse archive");
- std::unique_ptr<Archive> File = std::move(*FileOrErr);
+std::vector<MemoryBufferRef>
+LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
+ std::unique_ptr<Archive> File =
+ check(Archive::create(MB), "failed to parse archive");
std::vector<MemoryBufferRef> V;
- for (const ErrorOr<Archive::Child> &C : File->children()) {
- error(C, "Could not get the child of the archive " + File->getFileName());
- ErrorOr<MemoryBufferRef> MbOrErr = C->getMemoryBufferRef();
- error(MbOrErr, "Could not get the buffer for a child of the archive " +
- File->getFileName());
- V.push_back(*MbOrErr);
+ Error Err;
+ for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
+ Archive::Child C = check(COrErr, "could not get the child of the archive " +
+ File->getFileName());
+ MemoryBufferRef MBRef =
+ check(C.getMemoryBufferRef(),
+ "could not get the buffer for a child of the archive " +
+ File->getFileName());
+ V.push_back(MBRef);
}
+ if (Err)
+ Error(Err);
+
+ // Take ownership of memory buffers created for members of thin archives.
+ for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers())
+ OwningMBs.push_back(std::move(MB));
+
return V;
}
// 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) {
- using namespace llvm::sys::fs;
+ using namespace sys::fs;
if (Config->Verbose)
- llvm::outs() << Path << "\n";
- auto MBOrErr = MemoryBuffer::getFile(Path);
- error(MBOrErr, "cannot open " + Path);
- std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
- MemoryBufferRef MBRef = MB->getMemBufferRef();
- OwningMBs.push_back(std::move(MB)); // take MB ownership
+ outs() << Path << "\n";
+
+ Optional<MemoryBufferRef> Buffer = readFile(Path);
+ if (!Buffer.hasValue())
+ return;
+ MemoryBufferRef MBRef = *Buffer;
switch (identify_magic(MBRef.getBuffer())) {
case file_magic::unknown:
- readLinkerScript(&Alloc, MBRef);
+ readLinkerScript(MBRef);
return;
case file_magic::archive:
if (WholeArchive) {
for (MemoryBufferRef MB : getArchiveMembers(MBRef))
- Files.push_back(createObjectFile(MB));
+ Files.push_back(createObjectFile(MB, Path));
return;
}
Files.push_back(make_unique<ArchiveFile>(MBRef));
return;
case file_magic::elf_shared_object:
+ if (Config->Relocatable) {
+ error("attempted static link of dynamic object " + Path);
+ return;
+ }
Files.push_back(createSharedFile(MBRef));
return;
default:
- Files.push_back(createObjectFile(MBRef));
+ if (InLib)
+ Files.push_back(make_unique<LazyObjectFile>(MBRef));
+ else
+ Files.push_back(createObjectFile(MBRef));
+ }
+}
+
+Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) {
+ auto MBOrErr = MemoryBuffer::getFile(Path);
+ if (auto EC = MBOrErr.getError()) {
+ error(EC, "cannot open " + Path);
+ return None;
}
+ std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
+ MemoryBufferRef MBRef = MB->getMemBufferRef();
+ OwningMBs.push_back(std::move(MB)); // take MB ownership
+
+ if (Cpio)
+ Cpio->append(relativeToRoot(Path), MBRef.getBuffer());
+
+ return MBRef;
+}
+
+// Add a given library by searching it from input search paths.
+void LinkerDriver::addLibrary(StringRef Name) {
+ std::string Path = searchLibrary(Name);
+ if (Path.empty())
+ error("unable to find library -l" + Name);
+ else
+ addFile(Path);
+}
+
+// This function is called on startup. We need this for LTO since
+// LTO calls LLVM functions to compile bitcode files to native code.
+// Technically this can be delayed until we read bitcode files, but
+// we don't bother to do lazily because the initialization is fast.
+static void initLLVM(opt::InputArgList &Args) {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+
+ // This is a flag to discard all but GlobalValue names.
+ // We want to enable it by default because it saves memory.
+ // Disable it only when a developer option (-save-temps) is given.
+ Driver->Context.setDiscardValueNames(!Config->SaveTemps);
+ Driver->Context.enableDebugTypeODRUniquing();
+
+ // Parse and evaluate -mllvm options.
+ std::vector<const char *> V;
+ V.push_back("lld (LLVM option parsing)");
+ for (auto *Arg : Args.filtered(OPT_mllvm))
+ V.push_back(Arg->getValue());
+ cl::ParseCommandLineOptions(V.size(), V.data());
}
// Some command line options or some combinations of them are not allowed.
// This function checks for such errors.
static void checkOptions(opt::InputArgList &Args) {
- // Traditional linkers can generate re-linkable object files instead
- // of executables or DSOs. We don't support that since the feature
- // does not seem to provide more value than the static archiver.
- if (Args.hasArg(OPT_relocatable))
- error("-r option is not supported. Use 'ar' command instead.");
-
// The MIPS ABI as of 2016 does not support the GNU-style symbol lookup
// table which is a relatively new feature.
if (Config->EMachine == EM_MIPS && Config->GnuHash)
- error("The .gnu.hash section is not compatible with the MIPS target.");
+ error("the .gnu.hash section is not compatible with the MIPS target.");
if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty())
error("-e option is not valid for AMDGPU.");
+
+ if (Config->Pie && Config->Shared)
+ error("-shared and -pie may not be used together");
+
+ if (Config->Relocatable) {
+ if (Config->Shared)
+ error("-r and -shared may not be used together");
+ if (Config->GcSections)
+ error("-r and --gc-sections may not be used together");
+ if (Config->ICF)
+ error("-r and --icf may not be used together");
+ if (Config->Pie)
+ error("-r and -pie may not be used together");
+ }
}
static StringRef
@@ -132,6 +231,22 @@ getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") {
return Default;
}
+static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
+ int V = Default;
+ if (auto *Arg = Args.getLastArg(Key)) {
+ StringRef S = Arg->getValue();
+ if (S.getAsInteger(10, V))
+ error(Arg->getSpelling() + ": number expected, but got " + S);
+ }
+ return V;
+}
+
+static const char *getReproduceOption(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_reproduce))
+ return Arg->getValue();
+ return getenv("LLD_REPRODUCE");
+}
+
static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
for (auto *Arg : Args.filtered(OPT_z))
if (Key == Arg->getValue())
@@ -140,12 +255,33 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
}
void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
- initSymbols();
+ ELFOptTable Parser;
+ opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
+ if (Args.hasArg(OPT_help)) {
+ printHelp(ArgsArr[0]);
+ return;
+ }
+ if (Args.hasArg(OPT_version)) {
+ outs() << getVersionString();
+ return;
+ }
+
+ if (const char *Path = getReproduceOption(Args)) {
+ // Note that --reproduce is a debug option so you can ignore it
+ // if you are trying to understand the whole picture of the code.
+ Cpio.reset(CpioFile::create(Path));
+ if (Cpio) {
+ Cpio->append("response.txt", createResponseFile(Args));
+ Cpio->append("version.txt", getVersionString());
+ }
+ }
- opt::InputArgList Args = parseArgs(&Alloc, ArgsArr);
readConfigs(Args);
+ initLLVM(Args);
createFiles(Args);
checkOptions(Args);
+ if (HasError)
+ return;
switch (Config->EKind) {
case ELF32LEKind:
@@ -165,6 +301,25 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
}
}
+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::Error;
+ error("unknown --unresolved-symbols value: " + S);
+ }
+ return UnresolvedPolicy::Error;
+}
+
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
for (auto *Arg : Args.filtered(OPT_L))
@@ -185,38 +340,66 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
+ Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ Config->Demangle = !Args.hasArg(OPT_no_demangle);
+ Config->DisableVerify = Args.hasArg(OPT_disable_verify);
Config->DiscardAll = Args.hasArg(OPT_discard_all);
Config->DiscardLocals = Args.hasArg(OPT_discard_locals);
Config->DiscardNone = Args.hasArg(OPT_discard_none);
+ 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 = Args.hasArg(OPT_gc_sections);
- Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec);
- Config->NoUndefined = Args.hasArg(OPT_no_undefined);
+ Config->ICF = Args.hasArg(OPT_icf);
+ Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
+ Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
+ Config->Pie = Args.hasArg(OPT_pie);
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
+ Config->Relocatable = Args.hasArg(OPT_relocatable);
+ Config->SaveTemps = Args.hasArg(OPT_save_temps);
Config->Shared = Args.hasArg(OPT_shared);
Config->StripAll = Args.hasArg(OPT_strip_all);
+ Config->StripDebug = Args.hasArg(OPT_strip_debug);
+ Config->Threads = Args.hasArg(OPT_threads);
+ 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->LtoJobs = getInteger(Args, OPT_lto_jobs, 1);
+ if (Config->LtoJobs == 0)
+ error("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");
- if (auto *Arg = Args.getLastArg(OPT_O)) {
- StringRef Val = Arg->getValue();
- if (Val.getAsInteger(10, Config->Optimize))
- error("Invalid optimization level");
- }
+ if (Config->Relocatable)
+ Config->StripAll = false;
+
+ // --strip-all implies --strip-debug.
+ if (Config->StripAll)
+ Config->StripDebug = true;
+
+ // 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();
@@ -226,19 +409,52 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
} else if (S == "both") {
Config->GnuHash = true;
} else if (S != "sysv")
- error("Unknown hash style: " + S);
+ error("unknown hash style: " + S);
+ }
+
+ // Parse --build-id or --build-id=<style>.
+ if (Args.hasArg(OPT_build_id))
+ Config->BuildId = BuildIdKind::Fnv1;
+ if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {
+ StringRef S = Arg->getValue();
+ if (S == "md5") {
+ Config->BuildId = BuildIdKind::Md5;
+ } else if (S == "sha1") {
+ Config->BuildId = BuildIdKind::Sha1;
+ } else if (S == "none") {
+ Config->BuildId = BuildIdKind::None;
+ } else if (S.startswith("0x")) {
+ Config->BuildId = BuildIdKind::Hexstring;
+ Config->BuildIdVector = parseHex(S.substr(2));
+ } else {
+ error("unknown --build-id style: " + S);
+ }
}
for (auto *Arg : Args.filtered(OPT_undefined))
Config->Undefined.push_back(Arg->getValue());
+
+ Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args);
+
+ if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ parseDynamicList(*Buffer);
+
+ for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+ Config->DynamicList.push_back(Arg->getValue());
+
+ if (auto *Arg = Args.getLastArg(OPT_version_script))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ parseVersionScript(*Buffer);
}
void LinkerDriver::createFiles(opt::InputArgList &Args) {
for (auto *Arg : Args) {
switch (Arg->getOption().getID()) {
case OPT_l:
- addFile(searchLibrary(Arg->getValue()));
+ addLibrary(Arg->getValue());
break;
+ case OPT_alias_script_T:
case OPT_INPUT:
case OPT_script:
addFile(Arg->getValue());
@@ -261,75 +477,112 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
case OPT_no_whole_archive:
WholeArchive = false;
break;
+ case OPT_start_lib:
+ InLib = true;
+ break;
+ case OPT_end_lib:
+ InLib = false;
+ break;
}
}
- if (Files.empty())
+ if (Files.empty() && !HasError)
error("no input files.");
+
+ // If -m <machine_type> was not given, infer it from object files.
+ if (Config->EKind == ELFNoneKind) {
+ for (std::unique_ptr<InputFile> &F : Files) {
+ if (F->EKind == ELFNoneKind)
+ continue;
+ Config->EKind = F->EKind;
+ Config->EMachine = F->EMachine;
+ break;
+ }
+ }
}
+// Do actual linking. Note that when this function is called,
+// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
SymbolTable<ELFT> Symtab;
- Target.reset(createTarget());
-
- if (!Config->Shared) {
- // Add entry symbol.
- //
- // There is no entry symbol for AMDGPU binaries, so skip adding one to avoid
- // having and undefined symbol.
- if (Config->Entry.empty() && Config->EMachine != EM_AMDGPU)
- Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start";
-
- // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
- // is magical and is used to produce a R_386_GOTPC relocation.
- // The R_386_GOTPC relocation value doesn't actually depend on the
- // symbol value, so it could use an index of STN_UNDEF which, according
- // to the spec, means the symbol value is 0.
- // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
- // the object file.
- // The situation is even stranger on x86_64 where the assembly doesn't
- // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
- // an undefined symbol in the .o files.
- // Given that the symbol is effectively unused, we just create a dummy
- // hidden one to avoid the undefined symbol error.
- Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
- }
+ elf::Symtab<ELFT>::X = &Symtab;
+
+ std::unique_ptr<TargetInfo> TI(createTarget());
+ Target = TI.get();
+ LinkerScript<ELFT> LS;
+ Script<ELFT>::X = &LS;
+
+ Config->Rela = ELFT::Is64Bits || Config->EMachine == EM_X86_64;
+ Config->Mips64EL =
+ (Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind);
+
+ // Add entry symbol. Note that AMDGPU binaries have no entry points.
+ if (Config->Entry.empty() && !Config->Shared && !Config->Relocatable &&
+ Config->EMachine != EM_AMDGPU)
+ Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start";
+
+ // Default output filename is "a.out" by the Unix tradition.
+ if (Config->OutputFile.empty())
+ Config->OutputFile = "a.out";
+
+ // Handle --trace-symbol.
+ for (auto *Arg : Args.filtered(OPT_trace_symbol))
+ Symtab.trace(Arg->getValue());
+ // Set either EntryAddr (if S is a number) or EntrySym (otherwise).
if (!Config->Entry.empty()) {
- // Set either EntryAddr (if S is a number) or EntrySym (otherwise).
StringRef S = Config->Entry;
if (S.getAsInteger(0, Config->EntryAddr))
Config->EntrySym = Symtab.addUndefined(S);
}
- if (Config->EMachine == EM_MIPS) {
- // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
- // start of function and gp pointer into GOT. Use 'strong' variant of
- // the addIgnored to prevent '_gp_disp' substitution.
- Config->MipsGpDisp = Symtab.addIgnoredStrong("_gp_disp");
-
- // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
- // so that it points to an absolute address which is relative to GOT.
- // See "Global Data Symbols" in Chapter 6 in the following document:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- Symtab.addAbsolute("_gp", ElfSym<ELFT>::MipsGp);
+ // Initialize Config->ImageBase.
+ if (auto *Arg = Args.getLastArg(OPT_image_base)) {
+ StringRef S = Arg->getValue();
+ if (S.getAsInteger(0, Config->ImageBase))
+ error(Arg->getSpelling() + ": number expected, but got " + S);
+ else if ((Config->ImageBase % Target->PageSize) != 0)
+ warning(Arg->getSpelling() + ": address isn't multiple of page size");
+ } else {
+ Config->ImageBase = Config->Pic ? 0 : Target->DefaultImageBase;
}
for (std::unique_ptr<InputFile> &F : Files)
Symtab.addFile(std::move(F));
+ if (HasError)
+ return; // There were duplicate symbols or incompatible files
- for (StringRef S : Config->Undefined)
- Symtab.addUndefinedOpt(S);
+ Symtab.scanUndefinedFlags();
+ Symtab.scanShlibUndefined();
+ Symtab.scanDynamicList();
+ Symtab.scanVersionScript();
+ Symtab.scanSymbolVersions();
+
+ Symtab.addCombinedLtoObject();
+ if (HasError)
+ return;
for (auto *Arg : Args.filtered(OPT_wrap))
Symtab.wrap(Arg->getValue());
- if (Config->OutputFile.empty())
- Config->OutputFile = "a.out";
-
// Write the result to the file.
- Symtab.scanShlibUndefined();
if (Config->GcSections)
- markLive<ELFT>(&Symtab);
+ markLive<ELFT>();
+ if (Config->ICF)
+ doIcf<ELFT>();
+
+ // MergeInputSection::splitIntoPieces needs to be called before
+ // any call of MergeInputSection::getOffset. Do that.
+ for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
+ Symtab.getObjectFiles())
+ for (InputSectionBase<ELFT> *S : F->getSections()) {
+ if (!S || S == &InputSection<ELFT>::Discarded || !S->Live)
+ continue;
+ if (S->Compressed)
+ S->uncompress();
+ if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S))
+ MS->splitIntoPieces();
+ }
+
writeResult<ELFT>(&Symtab);
}
diff --git a/ELF/Driver.h b/ELF/Driver.h
index 720ef46dc710..6b9b9bb208e5 100644
--- a/ELF/Driver.h
+++ b/ELF/Driver.h
@@ -12,36 +12,54 @@
#include "SymbolTable.h"
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/raw_ostream.h"
namespace lld {
-namespace elf2 {
+namespace elf {
extern class LinkerDriver *Driver;
-// Entry point of the ELF linker.
-void link(ArrayRef<const char *> Args);
+class CpioFile;
class LinkerDriver {
public:
void main(ArrayRef<const char *> Args);
void addFile(StringRef Path);
+ void addLibrary(StringRef Name);
+ llvm::LLVMContext Context; // to parse bitcode ifles
+ std::unique_ptr<CpioFile> Cpio; // for reproduce
private:
+ std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB);
+ llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
void readConfigs(llvm::opt::InputArgList &Args);
void createFiles(llvm::opt::InputArgList &Args);
template <class ELFT> void link(llvm::opt::InputArgList &Args);
- llvm::BumpPtrAllocator Alloc;
+ // True if we are in --whole-archive and --no-whole-archive.
bool WholeArchive = false;
+
+ // True if we are in --start-lib and --end-lib.
+ bool InLib = false;
+
+ llvm::BumpPtrAllocator Alloc;
std::vector<std::unique_ptr<InputFile>> Files;
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
};
// Parses command line options.
-llvm::opt::InputArgList parseArgs(llvm::BumpPtrAllocator *A,
- ArrayRef<const char *> Args);
+class ELFOptTable : public llvm::opt::OptTable {
+public:
+ ELFOptTable();
+ llvm::opt::InputArgList parse(ArrayRef<const char *> Argv);
+
+private:
+ llvm::BumpPtrAllocator Alloc;
+};
// Create enum with OPT_xxx values for each option in Options.td
enum {
@@ -51,14 +69,43 @@ enum {
#undef OPTION
};
-// Parses a linker script. Calling this function updates the Symtab and Config.
-void readLinkerScript(llvm::BumpPtrAllocator *A, MemoryBufferRef MB);
+// This is the class to create a .cpio file for --reproduce.
+//
+// If "--reproduce foo" is given, we create a file "foo.cpio" and
+// copy all input files to the archive, along with a response file
+// to re-run the same command with the same inputs.
+// It is useful for reporting issues to LLD developers.
+//
+// Cpio as a file format is a deliberate choice. It's standardized in
+// POSIX and very easy to create. cpio command is available virtually
+// on all Unix systems. See
+// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_07
+// for the format details.
+class CpioFile {
+public:
+ static CpioFile *create(StringRef OutputPath);
+ void append(StringRef Path, StringRef Data);
+
+private:
+ CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef Basename);
+
+ std::unique_ptr<llvm::raw_fd_ostream> OS;
+ llvm::StringSet<> Seen;
+ std::string Basename;
+};
+
+void printHelp(const char *Argv0);
+std::string getVersionString();
+std::vector<uint8_t> parseHexstring(StringRef S);
+
+std::string createResponseFile(const llvm::opt::InputArgList &Args);
+std::string relativeToRoot(StringRef Path);
std::string findFromSearchPaths(StringRef Path);
std::string searchLibrary(StringRef Path);
std::string buildSysrootedPath(llvm::StringRef Dir, llvm::StringRef File);
-} // namespace elf2
+} // namespace elf
} // namespace lld
#endif
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
index 965ed4f00a61..3f18259b4ae7 100644
--- a/ELF/DriverUtils.cpp
+++ b/ELF/DriverUtils.cpp
@@ -15,16 +15,20 @@
#include "Driver.h"
#include "Error.h"
+#include "lld/Config/Version.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
using namespace llvm;
+using namespace llvm::sys;
using namespace lld;
-using namespace lld::elf2;
+using namespace lld::elf;
// Create OptTable
@@ -34,55 +38,208 @@ using namespace lld::elf2;
#undef PREFIX
// Create table mapping all options defined in Options.td
-static const opt::OptTable::Info infoTable[] = {
+static const opt::OptTable::Info OptInfo[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \
{ \
X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, X8, X7, OPT_##GROUP, \
OPT_##ALIAS, X6 \
- } \
- ,
+ },
#include "Options.inc"
#undef OPTION
};
-class ELFOptTable : public opt::OptTable {
-public:
- ELFOptTable() : OptTable(infoTable) {}
-};
+ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
+
+static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
+ StringRef S = Arg->getValue();
+ if (S != "windows" && S != "posix")
+ error("invalid response file quoting: " + S);
+ if (S == "windows")
+ return cl::TokenizeWindowsCommandLine;
+ return cl::TokenizeGNUCommandLine;
+ }
+ if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
+ return cl::TokenizeWindowsCommandLine;
+ return cl::TokenizeGNUCommandLine;
+}
// Parses a given list of options.
-opt::InputArgList elf2::parseArgs(llvm::BumpPtrAllocator *A,
- ArrayRef<const char *> Argv) {
+opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// Make InputArgList from string vectors.
- ELFOptTable Table;
unsigned MissingIndex;
unsigned MissingCount;
+ SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
+
+ // We need to get the quoting style for response files before parsing all
+ // options so we parse here before and ignore all the options but
+ // --rsp-quoting.
+ opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
// Expand response files. '@<filename>' is replaced by the file's contents.
- SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
- StringSaver Saver(*A);
- llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, Vec);
+ StringSaver Saver(Alloc);
+ cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
// Parse options and then do error checking.
- opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount);
+ Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
if (MissingCount)
error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) +
"\", expected " + Twine(MissingCount) +
(MissingCount == 1 ? " argument.\n" : " arguments"));
- iterator_range<opt::arg_iterator> Unknowns = Args.filtered(OPT_UNKNOWN);
- for (auto *Arg : Unknowns)
- warning("warning: unknown argument: " + Arg->getSpelling());
- if (Unknowns.begin() != Unknowns.end())
- error("unknown argument(s) found");
-
+ for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+ error("unknown argument: " + Arg->getSpelling());
return Args;
}
-std::string elf2::findFromSearchPaths(StringRef Path) {
+void elf::printHelp(const char *Argv0) {
+ ELFOptTable Table;
+ Table.PrintHelp(outs(), Argv0, "lld", false);
+}
+
+std::string elf::getVersionString() {
+ std::string Version = getLLDVersion();
+ std::string Repo = getLLDRepositoryVersion();
+ if (Repo.empty())
+ return "LLD " + Version + "\n";
+ return "LLD " + Version + " " + Repo + "\n";
+}
+
+// Makes a given pathname an absolute path first, and then remove
+// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
+// assuming that the current directory is "/home/john/bar".
+std::string elf::relativeToRoot(StringRef Path) {
+ SmallString<128> Abs = Path;
+ if (std::error_code EC = fs::make_absolute(Abs))
+ fatal("make_absolute failed: " + EC.message());
+ path::remove_dots(Abs, /*remove_dot_dot=*/true);
+
+ // This is Windows specific. root_name() returns a drive letter
+ // (e.g. "c:") or a UNC name (//net). We want to keep it as part
+ // of the result.
+ SmallString<128> Res;
+ StringRef Root = path::root_name(Abs);
+ if (Root.endswith(":"))
+ Res = Root.drop_back();
+ else if (Root.startswith("//"))
+ Res = Root.substr(2);
+
+ path::append(Res, path::relative_path(Abs));
+ return Res.str();
+}
+
+CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S)
+ : OS(std::move(OS)), Basename(S) {}
+
+CpioFile *CpioFile::create(StringRef OutputPath) {
+ std::string Path = (OutputPath + ".cpio").str();
+ std::error_code EC;
+ auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, fs::F_None);
+ if (EC) {
+ error(EC, "--reproduce: failed to open " + Path);
+ return nullptr;
+ }
+ return new CpioFile(std::move(OS), path::filename(OutputPath));
+}
+
+static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) {
+ // The c_dev/c_ino pair should be unique according to the spec,
+ // but no one seems to care.
+ OS << "070707"; // c_magic
+ OS << "000000"; // c_dev
+ OS << "000000"; // c_ino
+ OS << "100664"; // c_mode: C_ISREG | rw-rw-r--
+ OS << "000000"; // c_uid
+ OS << "000000"; // c_gid
+ OS << "000001"; // c_nlink
+ OS << "000000"; // c_rdev
+ OS << "00000000000"; // c_mtime
+ OS << format("%06o", Path.size() + 1); // c_namesize
+ OS << format("%011o", Data.size()); // c_filesize
+ OS << Path << '\0'; // c_name
+ OS << Data; // c_filedata
+}
+
+void CpioFile::append(StringRef Path, StringRef Data) {
+ if (!Seen.insert(Path).second)
+ return;
+
+ // Construct an in-archive filename so that /home/foo/bar is stored
+ // as baz/home/foo/bar where baz is the basename of the output file.
+ // (i.e. in that case we are creating baz.cpio.)
+ SmallString<128> Fullpath;
+ path::append(Fullpath, Basename, Path);
+
+ // Use unix path separators so the cpio can be extracted on both unix and
+ // windows.
+ std::replace(Fullpath.begin(), Fullpath.end(), '\\', '/');
+
+ writeMember(*OS, Fullpath, Data);
+
+ // Print the trailer and seek back.
+ // This way we have a valid archive if we crash.
+ uint64_t Pos = OS->tell();
+ writeMember(*OS, "TRAILER!!!", "");
+ OS->seek(Pos);
+}
+
+// Quote a given string if it contains a space character.
+static std::string quote(StringRef S) {
+ if (S.find(' ') == StringRef::npos)
+ return S;
+ return ("\"" + S + "\"").str();
+}
+
+static std::string rewritePath(StringRef S) {
+ if (fs::exists(S))
+ return relativeToRoot(S);
+ return S;
+}
+
+static std::string stringize(opt::Arg *Arg) {
+ std::string K = Arg->getSpelling();
+ if (Arg->getNumValues() == 0)
+ return K;
+ std::string V = quote(Arg->getValue());
+ if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
+ return K + V;
+ return K + " " + V;
+}
+
+// Reconstructs command line arguments so that so that you can re-run
+// the same command with the same inputs. This is for --reproduce.
+std::string elf::createResponseFile(const opt::InputArgList &Args) {
+ SmallString<0> Data;
+ raw_svector_ostream OS(Data);
+
+ // Copy the command line to the output while rewriting paths.
+ for (auto *Arg : Args) {
+ switch (Arg->getOption().getID()) {
+ case OPT_reproduce:
+ break;
+ case OPT_INPUT:
+ OS << quote(rewritePath(Arg->getValue())) << "\n";
+ break;
+ case OPT_L:
+ case OPT_dynamic_list:
+ case OPT_rpath:
+ case OPT_alias_script_T:
+ case OPT_script:
+ case OPT_version_script:
+ OS << Arg->getSpelling() << " "
+ << quote(rewritePath(Arg->getValue())) << "\n";
+ break;
+ default:
+ OS << stringize(Arg) << "\n";
+ }
+ }
+ return Data.str();
+}
+
+std::string elf::findFromSearchPaths(StringRef Path) {
for (StringRef Dir : Config->SearchPaths) {
std::string FullPath = buildSysrootedPath(Dir, Path);
- if (sys::fs::exists(FullPath))
+ if (fs::exists(FullPath))
return FullPath;
}
return "";
@@ -90,31 +247,30 @@ std::string elf2::findFromSearchPaths(StringRef Path) {
// Searches a given library from input search paths, which are filled
// from -L command line switches. Returns a path to an existent library file.
-std::string elf2::searchLibrary(StringRef Path) {
- std::vector<std::string> Names;
- if (Path[0] == ':') {
- Names.push_back(Path.drop_front());
- } else {
- if (!Config->Static)
- Names.push_back(("lib" + Path + ".so").str());
- Names.push_back(("lib" + Path + ".a").str());
- }
- for (const std::string &Name : Names) {
- std::string S = findFromSearchPaths(Name);
- if (!S.empty())
+std::string elf::searchLibrary(StringRef Path) {
+ if (Path.startswith(":"))
+ return findFromSearchPaths(Path.substr(1));
+ for (StringRef Dir : Config->SearchPaths) {
+ if (!Config->Static) {
+ std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".so").str());
+ if (fs::exists(S))
+ return S;
+ }
+ std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".a").str());
+ if (fs::exists(S))
return S;
}
- error("Unable to find library -l" + Path);
+ return "";
}
// Makes a path by concatenating Dir and File.
// If Dir starts with '=' the result will be preceded by Sysroot,
// which can be set with --sysroot command line switch.
-std::string elf2::buildSysrootedPath(StringRef Dir, StringRef File) {
+std::string elf::buildSysrootedPath(StringRef Dir, StringRef File) {
SmallString<128> Path;
if (Dir.startswith("="))
- sys::path::append(Path, Config->Sysroot, Dir.substr(1), File);
+ path::append(Path, Config->Sysroot, Dir.substr(1), File);
else
- sys::path::append(Path, Dir, File);
+ path::append(Path, Dir, File);
return Path.str();
}
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
new file mode 100644
index 000000000000..b130ac1ca22d
--- /dev/null
+++ b/ELF/EhFrame.cpp
@@ -0,0 +1,167 @@
+//===- EhFrame.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// .eh_frame section contains information on how to unwind the stack when
+// an exception is thrown. The section consists of sequence of CIE and FDE
+// records. The linker needs to merge CIEs and associate FDEs to CIEs.
+// That means the linker has to understand the format of the section.
+//
+// This file contains a few utility functions to read .eh_frame contents.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EhFrame.h"
+#include "Error.h"
+
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::dwarf;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+namespace lld {
+namespace elf {
+
+// .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 readEhRecordSize(ArrayRef<uint8_t> D) {
+ const endianness E = ELFT::TargetEndianness;
+ if (D.size() < 4)
+ fatal("CIE/FDE too small");
+
+ // First 4 bytes of CIE/FDE is the size of the record.
+ // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
+ // but we do not support that format yet.
+ uint64_t V = read32<E>(D.data());
+ if (V == UINT32_MAX)
+ fatal("CIE/FDE too large");
+ uint64_t Size = V + 4;
+ if (Size > D.size())
+ fatal("CIE/FIE ends past the end of the section");
+ return Size;
+}
+
+// Read a byte and advance D by one byte.
+static uint8_t readByte(ArrayRef<uint8_t> &D) {
+ if (D.empty())
+ fatal("corrupted or unsupported CIE information");
+ uint8_t B = D.front();
+ D = D.slice(1);
+ return B;
+}
+
+// Skip an integer encoded in the LEB128 format.
+// Actual number is not of interest because only the runtime needs it.
+// But we need to be at least able to skip it so that we can read
+// the field that follows a LEB128 number.
+static void skipLeb128(ArrayRef<uint8_t> &D) {
+ while (!D.empty()) {
+ uint8_t Val = D.front();
+ D = D.slice(1);
+ if ((Val & 0x80) == 0)
+ return;
+ }
+ fatal("corrupted or unsupported CIE information");
+}
+
+template <class ELFT> static size_t getAugPSize(unsigned Enc) {
+ switch (Enc & 0x0f) {
+ case DW_EH_PE_absptr:
+ case DW_EH_PE_signed:
+ return ELFT::Is64Bits ? 8 : 4;
+ case DW_EH_PE_udata2:
+ case DW_EH_PE_sdata2:
+ return 2;
+ case DW_EH_PE_udata4:
+ case DW_EH_PE_sdata4:
+ return 4;
+ case DW_EH_PE_udata8:
+ case DW_EH_PE_sdata8:
+ return 8;
+ }
+ fatal("unknown FDE encoding");
+}
+
+template <class ELFT> static void skipAugP(ArrayRef<uint8_t> &D) {
+ uint8_t Enc = readByte(D);
+ if ((Enc & 0xf0) == DW_EH_PE_aligned)
+ fatal("DW_EH_PE_aligned encoding is not supported");
+ size_t Size = getAugPSize<ELFT>(Enc);
+ if (Size >= D.size())
+ fatal("corrupted CIE");
+ D = D.slice(Size);
+}
+
+template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> D) {
+ if (D.size() < 8)
+ fatal("CIE too small");
+ D = D.slice(8);
+
+ uint8_t Version = readByte(D);
+ if (Version != 1 && Version != 3)
+ fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version));
+
+ const unsigned char *AugEnd = std::find(D.begin(), D.end(), '\0');
+ if (AugEnd == D.end())
+ fatal("corrupted CIE");
+ StringRef Aug(reinterpret_cast<const char *>(D.begin()), AugEnd - D.begin());
+ D = D.slice(Aug.size() + 1);
+
+ // Code alignment factor should always be 1 for .eh_frame.
+ if (readByte(D) != 1)
+ fatal("CIE code alignment must be 1");
+
+ // Skip data alignment factor.
+ skipLeb128(D);
+
+ // Skip the return address register. In CIE version 1 this is a single
+ // byte. In CIE version 3 this is an unsigned LEB128.
+ if (Version == 1)
+ readByte(D);
+ else
+ skipLeb128(D);
+
+ // We only care about an 'R' value, but other records may precede an 'R'
+ // record. Unfortunately records are not in TLV (type-length-value) format,
+ // so we need to teach the linker how to skip records for each type.
+ for (char C : Aug) {
+ if (C == 'R')
+ return readByte(D);
+ if (C == 'z') {
+ skipLeb128(D);
+ continue;
+ }
+ if (C == 'P') {
+ skipAugP<ELFT>(D);
+ continue;
+ }
+ if (C == 'L') {
+ readByte(D);
+ continue;
+ }
+ fatal("unknown .eh_frame augmentation string: " + Aug);
+ }
+ return DW_EH_PE_absptr;
+}
+
+template size_t readEhRecordSize<ELF32LE>(ArrayRef<uint8_t>);
+template size_t readEhRecordSize<ELF32BE>(ArrayRef<uint8_t>);
+template size_t readEhRecordSize<ELF64LE>(ArrayRef<uint8_t>);
+template size_t readEhRecordSize<ELF64BE>(ArrayRef<uint8_t>);
+
+template uint8_t getFdeEncoding<ELF32LE>(ArrayRef<uint8_t>);
+template uint8_t getFdeEncoding<ELF32BE>(ArrayRef<uint8_t>);
+template uint8_t getFdeEncoding<ELF64LE>(ArrayRef<uint8_t>);
+template uint8_t getFdeEncoding<ELF64BE>(ArrayRef<uint8_t>);
+}
+}
diff --git a/ELF/EhFrame.h b/ELF/EhFrame.h
new file mode 100644
index 000000000000..0d5a2ff2f417
--- /dev/null
+++ b/ELF/EhFrame.h
@@ -0,0 +1,22 @@
+//===- EhFrame.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_EHFRAME_H
+#define LLD_ELF_EHFRAME_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+template <class ELFT> size_t readEhRecordSize(ArrayRef<uint8_t> Data);
+template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> Data);
+}
+}
+
+#endif
diff --git a/ELF/Error.cpp b/ELF/Error.cpp
index e0701f7f4cc6..59a49c17b97c 100644
--- a/ELF/Error.cpp
+++ b/ELF/Error.cpp
@@ -8,31 +8,58 @@
//===----------------------------------------------------------------------===//
#include "Error.h"
+#include "Config.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
namespace lld {
-namespace elf2 {
+namespace elf {
+
+bool HasError;
+raw_ostream *ErrorOS;
-void warning(const Twine &Msg) { llvm::errs() << Msg << "\n"; }
+void log(const Twine &Msg) {
+ if (Config->Verbose)
+ outs() << Msg << "\n";
+}
+
+void warning(const Twine &Msg) {
+ if (Config->FatalWarnings)
+ error(Msg);
+ else
+ *ErrorOS << Msg << "\n";
+}
void error(const Twine &Msg) {
- llvm::errs() << Msg << "\n";
- exit(1);
+ *ErrorOS << Msg << "\n";
+ HasError = true;
}
void error(std::error_code EC, const Twine &Prefix) {
- if (!EC)
- return;
error(Prefix + ": " + EC.message());
}
-void error(std::error_code EC) {
- if (!EC)
- return;
- error(EC.message());
+void fatal(const Twine &Msg) {
+ *ErrorOS << Msg << "\n";
+ exit(1);
+}
+
+void fatal(const Twine &Msg, const Twine &Prefix) {
+ fatal(Prefix + ": " + Msg);
+}
+
+void check(std::error_code EC) {
+ if (EC)
+ fatal(EC.message());
+}
+
+void check(Error Err) {
+ check(errorToErrorCode(std::move(Err)));
}
-} // namespace elf2
+} // namespace elf
} // namespace lld
diff --git a/ELF/Error.h b/ELF/Error.h
index b1d2e7a8fc5b..552f50498464 100644
--- a/ELF/Error.h
+++ b/ELF/Error.h
@@ -13,20 +13,49 @@
#include "lld/Core/LLVM.h"
namespace lld {
-namespace elf2 {
+namespace elf {
+extern bool HasError;
+extern llvm::raw_ostream *ErrorOS;
+
+void log(const Twine &Msg);
void warning(const Twine &Msg);
-LLVM_ATTRIBUTE_NORETURN void error(const Twine &Msg);
+void error(const Twine &Msg);
void error(std::error_code EC, const Twine &Prefix);
-void error(std::error_code EC);
template <typename T> void error(const ErrorOr<T> &V, const Twine &Prefix) {
error(V.getError(), Prefix);
}
-template <typename T> void error(const ErrorOr<T> &V) { error(V.getError()); }
-} // namespace elf2
+LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
+LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg, const Twine &Prefix);
+
+template <class T> T check(ErrorOr<T> E) {
+ if (auto EC = E.getError())
+ fatal(EC.message());
+ return std::move(*E);
+}
+
+template <class T> T check(Expected<T> E) {
+ if (!E)
+ fatal(errorToErrorCode(E.takeError()).message());
+ return std::move(*E);
+}
+
+template <class T> T check(ErrorOr<T> E, const Twine &Prefix) {
+ if (auto EC = E.getError())
+ fatal(EC.message(), Prefix);
+ return std::move(*E);
+}
+
+template <class T> T check(Expected<T> E, const Twine &Prefix) {
+ if (!E)
+ fatal(errorToErrorCode(E.takeError()).message(), Prefix);
+ return std::move(*E);
+}
+
+} // namespace elf
} // namespace lld
#endif
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
new file mode 100644
index 000000000000..10a2603b3b3e
--- /dev/null
+++ b/ELF/ICF.cpp
@@ -0,0 +1,345 @@
+//===- ICF.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Identical Code Folding is a feature to merge sections not by name (which
+// is regular comdat handling) but by contents. If two non-writable sections
+// have the same data, relocations, attributes, etc., then the two
+// are considered identical and merged by the linker. This optimization
+// makes outputs smaller.
+//
+// ICF is theoretically a problem of reducing graphs by merging as many
+// identical subgraphs as possible if we consider sections as vertices and
+// relocations as edges. It may sound simple, but it is a bit more
+// complicated than you might think. The order of processing sections
+// matters because merging two sections can make other sections, whose
+// relocations now point to the same section, mergeable. Graphs may contain
+// cycles. We need a sophisticated algorithm to do this properly and
+// efficiently.
+//
+// What we do in this file is this. We split sections into groups. Sections
+// in the same group are considered identical.
+//
+// We begin by optimistically putting all sections into a single equivalence
+// class. Then we apply a series of checks that split this initial
+// equivalence class into more and more refined equivalence classes based on
+// the properties by which a section can be distinguished.
+//
+// We begin by checking that the section contents and flags are the
+// same. This only needs to be done once since these properties don't depend
+// on the current equivalence class assignment.
+//
+// Then we split the equivalence classes based on checking that their
+// relocations are the same, where relocation targets are compared by their
+// equivalence class, not the concrete section. This may need to be done
+// multiple times because as the equivalence classes are refined, two
+// sections that had a relocation target in the same equivalence class may
+// now target different equivalence classes, and hence these two sections
+// must be put in different equivalence classes (whereas in the previous
+// iteration they were not since the relocation target was the same.)
+//
+// Our algorithm is smart enough to merge the following mutually-recursive
+// functions.
+//
+// void foo() { bar(); }
+// void bar() { foo(); }
+//
+// This algorithm is so-called "optimistic" algorithm described in
+// http://research.google.com/pubs/pub36912.html. (Note that what GNU
+// gold implemented is different from the optimistic algorithm.)
+//
+//===----------------------------------------------------------------------===//
+
+#include "ICF.h"
+#include "Config.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+
+namespace lld {
+namespace elf {
+template <class ELFT> class ICF {
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::uint uintX_t;
+ typedef Elf_Rel_Impl<ELFT, false> Elf_Rel;
+
+ using Comparator = std::function<bool(const InputSection<ELFT> *,
+ const InputSection<ELFT> *)>;
+
+public:
+ void run();
+
+private:
+ uint64_t NextId = 1;
+
+ static void setLive(SymbolTable<ELFT> *S);
+ static uint64_t relSize(InputSection<ELFT> *S);
+ static uint64_t getHash(InputSection<ELFT> *S);
+ static bool isEligible(InputSectionBase<ELFT> *Sec);
+ static std::vector<InputSection<ELFT> *> getSections();
+
+ void segregate(InputSection<ELFT> **Begin, InputSection<ELFT> **End,
+ Comparator Eq);
+
+ void forEachGroup(std::vector<InputSection<ELFT> *> &V, Comparator Eq);
+
+ template <class RelTy>
+ static bool relocationEq(ArrayRef<RelTy> RA, ArrayRef<RelTy> RB);
+
+ template <class RelTy>
+ static bool variableEq(const InputSection<ELFT> *A,
+ const InputSection<ELFT> *B, ArrayRef<RelTy> RA,
+ ArrayRef<RelTy> RB);
+
+ static bool equalsConstant(const InputSection<ELFT> *A,
+ const InputSection<ELFT> *B);
+
+ static bool equalsVariable(const InputSection<ELFT> *A,
+ const InputSection<ELFT> *B);
+};
+}
+}
+
+// Returns a hash value for S. Note that the information about
+// relocation targets is not included in the hash value.
+template <class ELFT> uint64_t ICF<ELFT>::getHash(InputSection<ELFT> *S) {
+ uint64_t Flags = S->getSectionHdr()->sh_flags;
+ uint64_t H = hash_combine(Flags, S->getSize());
+ for (const Elf_Shdr *Rel : S->RelocSections)
+ H = hash_combine(H, (uint64_t)Rel->sh_size);
+ return H;
+}
+
+// Returns true if Sec is subject of ICF.
+template <class ELFT> bool ICF<ELFT>::isEligible(InputSectionBase<ELFT> *Sec) {
+ if (!Sec || Sec == &InputSection<ELFT>::Discarded || !Sec->Live)
+ return false;
+ auto *S = dyn_cast<InputSection<ELFT>>(Sec);
+ if (!S)
+ return false;
+
+ // .init and .fini contains instructions that must be executed to
+ // initialize and finalize the process. They cannot and should not
+ // be merged.
+ StringRef Name = S->getSectionName();
+ if (Name == ".init" || Name == ".fini")
+ return false;
+
+ const Elf_Shdr &H = *S->getSectionHdr();
+ return (H.sh_flags & SHF_ALLOC) && (~H.sh_flags & SHF_WRITE);
+}
+
+template <class ELFT>
+std::vector<InputSection<ELFT> *> ICF<ELFT>::getSections() {
+ std::vector<InputSection<ELFT> *> V;
+ for (const std::unique_ptr<ObjectFile<ELFT>> &F :
+ Symtab<ELFT>::X->getObjectFiles())
+ for (InputSectionBase<ELFT> *S : F->getSections())
+ if (isEligible(S))
+ V.push_back(cast<InputSection<ELFT>>(S));
+ return V;
+}
+
+// All sections between Begin and End must have the same group ID before
+// you call this function. This function compare sections between Begin
+// and End using Eq and assign new group IDs for new groups.
+template <class ELFT>
+void ICF<ELFT>::segregate(InputSection<ELFT> **Begin, InputSection<ELFT> **End,
+ Comparator Eq) {
+ // This loop rearranges [Begin, End) so that all sections that are
+ // equal in terms of Eq are contiguous. The algorithm is quadratic in
+ // the worst case, but that is not an issue in practice because the
+ // number of distinct sections in [Begin, End) is usually very small.
+ InputSection<ELFT> **I = Begin;
+ for (;;) {
+ InputSection<ELFT> *Head = *I;
+ auto Bound = std::stable_partition(
+ I + 1, End, [&](InputSection<ELFT> *S) { return Eq(Head, S); });
+ if (Bound == End)
+ return;
+ uint64_t Id = NextId++;
+ for (; I != Bound; ++I)
+ (*I)->GroupId = Id;
+ }
+}
+
+template <class ELFT>
+void ICF<ELFT>::forEachGroup(std::vector<InputSection<ELFT> *> &V,
+ Comparator Eq) {
+ for (InputSection<ELFT> **I = V.data(), **E = I + V.size(); I != E;) {
+ InputSection<ELFT> *Head = *I;
+ auto Bound = std::find_if(I + 1, E, [&](InputSection<ELFT> *S) {
+ return S->GroupId != Head->GroupId;
+ });
+ segregate(I, Bound, Eq);
+ I = Bound;
+ }
+}
+
+// Compare two lists of relocations.
+template <class ELFT>
+template <class RelTy>
+bool ICF<ELFT>::relocationEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
+ const RelTy *IA = RelsA.begin();
+ const RelTy *EA = RelsA.end();
+ const RelTy *IB = RelsB.begin();
+ const RelTy *EB = RelsB.end();
+ if (EA - IA != EB - IB)
+ return false;
+ for (; IA != EA; ++IA, ++IB)
+ if (IA->r_offset != IB->r_offset ||
+ IA->getType(Config->Mips64EL) != IB->getType(Config->Mips64EL) ||
+ getAddend<ELFT>(*IA) != getAddend<ELFT>(*IB))
+ return false;
+ return true;
+}
+
+// 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) {
+ if (A->RelocSections.size() != B->RelocSections.size())
+ return false;
+
+ for (size_t I = 0, E = A->RelocSections.size(); I != E; ++I) {
+ const Elf_Shdr *RA = A->RelocSections[I];
+ const Elf_Shdr *RB = B->RelocSections[I];
+ ELFFile<ELFT> &FileA = A->File->getObj();
+ ELFFile<ELFT> &FileB = B->File->getObj();
+ if (RA->sh_type == SHT_RELA) {
+ if (!relocationEq(FileA.relas(RA), FileB.relas(RB)))
+ return false;
+ } else {
+ if (!relocationEq(FileA.rels(RA), FileB.rels(RB)))
+ return false;
+ }
+ }
+
+ return A->getSectionHdr()->sh_flags == B->getSectionHdr()->sh_flags &&
+ A->getSize() == B->getSize() &&
+ A->getSectionData() == B->getSectionData();
+}
+
+template <class ELFT>
+template <class RelTy>
+bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A,
+ const InputSection<ELFT> *B, ArrayRef<RelTy> RelsA,
+ ArrayRef<RelTy> RelsB) {
+ const RelTy *IA = RelsA.begin();
+ const RelTy *EA = RelsA.end();
+ const RelTy *IB = RelsB.begin();
+ for (; IA != EA; ++IA, ++IB) {
+ SymbolBody &SA = A->File->getRelocTargetSym(*IA);
+ SymbolBody &SB = B->File->getRelocTargetSym(*IB);
+ if (&SA == &SB)
+ continue;
+
+ // Or, the symbols should be pointing to the same section
+ // in terms of the group ID.
+ auto *DA = dyn_cast<DefinedRegular<ELFT>>(&SA);
+ auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB);
+ if (!DA || !DB)
+ return false;
+ if (DA->Value != DB->Value)
+ return false;
+ InputSection<ELFT> *X = dyn_cast<InputSection<ELFT>>(DA->Section);
+ InputSection<ELFT> *Y = dyn_cast<InputSection<ELFT>>(DB->Section);
+ if (X && Y && X->GroupId && X->GroupId == Y->GroupId)
+ continue;
+ return false;
+ }
+ return true;
+}
+
+// Compare "moving" part of two InputSections, namely relocation targets.
+template <class ELFT>
+bool ICF<ELFT>::equalsVariable(const InputSection<ELFT> *A,
+ const InputSection<ELFT> *B) {
+ for (size_t I = 0, E = A->RelocSections.size(); I != E; ++I) {
+ const Elf_Shdr *RA = A->RelocSections[I];
+ const Elf_Shdr *RB = B->RelocSections[I];
+ ELFFile<ELFT> &FileA = A->File->getObj();
+ ELFFile<ELFT> &FileB = B->File->getObj();
+ if (RA->sh_type == SHT_RELA) {
+ if (!variableEq(A, B, FileA.relas(RA), FileB.relas(RB)))
+ return false;
+ } else {
+ if (!variableEq(A, B, FileA.rels(RA), FileB.rels(RB)))
+ return false;
+ }
+ }
+ return true;
+}
+
+// The main function of ICF.
+template <class ELFT> void ICF<ELFT>::run() {
+ // Initially, we use hash values as section group IDs. Therefore,
+ // if two sections have the same ID, they are likely (but not
+ // guaranteed) to have the same static contents in terms of ICF.
+ std::vector<InputSection<ELFT> *> V = getSections();
+ for (InputSection<ELFT> *S : V)
+ // Set MSB on to avoid collisions with serial group IDs
+ S->GroupId = getHash(S) | (uint64_t(1) << 63);
+
+ // From now on, sections in V are ordered so that sections in
+ // the same group are consecutive in the vector.
+ std::stable_sort(V.begin(), V.end(),
+ [](InputSection<ELFT> *A, InputSection<ELFT> *B) {
+ return A->GroupId < B->GroupId;
+ });
+
+ // Compare static contents and assign unique IDs for each static content.
+ forEachGroup(V, equalsConstant);
+
+ // Split groups by comparing relocations until we get a convergence.
+ int Cnt = 1;
+ for (;;) {
+ ++Cnt;
+ uint64_t Id = NextId;
+ forEachGroup(V, equalsVariable);
+ if (Id == NextId)
+ break;
+ }
+ log("ICF needed " + Twine(Cnt) + " iterations.");
+
+ // Merge sections in the same group.
+ for (auto I = V.begin(), E = V.end(); I != E;) {
+ InputSection<ELFT> *Head = *I++;
+ auto Bound = std::find_if(I, E, [&](InputSection<ELFT> *S) {
+ return Head->GroupId != S->GroupId;
+ });
+ if (I == Bound)
+ continue;
+ log("selected " + Head->getSectionName());
+ while (I != Bound) {
+ InputSection<ELFT> *S = *I++;
+ log(" removed " + S->getSectionName());
+ Head->replace(S);
+ }
+ }
+}
+
+// ICF entry point function.
+template <class ELFT> void elf::doIcf() { ICF<ELFT>().run(); }
+
+template void elf::doIcf<ELF32LE>();
+template void elf::doIcf<ELF32BE>();
+template void elf::doIcf<ELF64LE>();
+template void elf::doIcf<ELF64BE>();
diff --git a/ELF/ICF.h b/ELF/ICF.h
new file mode 100644
index 000000000000..502e128c8109
--- /dev/null
+++ b/ELF/ICF.h
@@ -0,0 +1,19 @@
+//===- ICF.h --------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_ICF_H
+#define LLD_ELF_ICF_H
+
+namespace lld {
+namespace elf {
+template <class ELFT> void doIcf();
+}
+}
+
+#endif
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 6a908d450f60..57e556395937 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -8,10 +8,17 @@
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
-#include "InputSection.h"
+#include "Driver.h"
#include "Error.h"
+#include "InputSection.h"
+#include "SymbolTable.h"
#include "Symbols.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/CodeGen/Analysis.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::ELF;
@@ -19,43 +26,52 @@ using namespace llvm::object;
using namespace llvm::sys::fs;
using namespace lld;
-using namespace lld::elf2;
-
-namespace {
-class ECRAII {
- std::error_code EC;
-
-public:
- std::error_code &getEC() { return EC; }
- ~ECRAII() { error(EC); }
-};
+using namespace lld::elf;
+
+// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
+std::string elf::getFilename(const InputFile *F) {
+ if (!F)
+ return "(internal)";
+ if (!F->ArchiveName.empty())
+ return (F->ArchiveName + "(" + F->getName() + ")").str();
+ return F->getName();
}
template <class ELFT>
-ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef M)
- : InputFile(K, M), ELFObj(MB.getBuffer(), ECRAII().getEC()) {}
+static ELFFile<ELFT> createELFObj(MemoryBufferRef MB) {
+ std::error_code EC;
+ ELFFile<ELFT> F(MB.getBuffer(), EC);
+ if (EC)
+ error(EC, "failed to read " + MB.getBufferIdentifier());
+ return F;
+}
-template <class ELFT>
-ELFKind ELFFileBase<ELFT>::getELFKind() {
+template <class ELFT> static ELFKind getELFKind() {
if (ELFT::TargetEndianness == support::little)
return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
return ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
}
template <class ELFT>
-typename ELFFileBase<ELFT>::Elf_Sym_Range
-ELFFileBase<ELFT>::getSymbolsHelper(bool Local) {
+ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB)
+ : InputFile(K, MB), ELFObj(createELFObj<ELFT>(MB)) {
+ EKind = getELFKind<ELFT>();
+ EMachine = ELFObj.getHeader()->e_machine;
+}
+
+template <class ELFT>
+typename ELFT::SymRange ELFFileBase<ELFT>::getElfSymbols(bool OnlyGlobals) {
if (!Symtab)
return Elf_Sym_Range(nullptr, nullptr);
Elf_Sym_Range Syms = ELFObj.symbols(Symtab);
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
uint32_t FirstNonLocal = Symtab->sh_info;
if (FirstNonLocal > NumSymbols)
- error("Invalid sh_info in symbol table");
- if (!Local)
- return make_range(Syms.begin() + FirstNonLocal, Syms.end());
- // +1 to skip over dummy symbol.
- return make_range(Syms.begin() + 1, Syms.begin() + FirstNonLocal);
+ fatal(getFilename(this) + ": invalid sh_info in symbol table");
+
+ if (OnlyGlobals)
+ return makeArrayRef(Syms.begin() + FirstNonLocal, Syms.end());
+ return makeArrayRef(Syms.begin(), Syms.end());
}
template <class ELFT>
@@ -63,7 +79,7 @@ uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
uint32_t I = Sym.st_shndx;
if (I == ELF::SHN_XINDEX)
return ELFObj.getExtendedSymbolTableIndex(&Sym, Symtab, SymtabSHNDX);
- if (I >= ELF::SHN_LORESERVE || I == ELF::SHN_ABS)
+ if (I >= ELF::SHN_LORESERVE)
return 0;
return I;
}
@@ -71,44 +87,46 @@ uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
template <class ELFT> void ELFFileBase<ELFT>::initStringTable() {
if (!Symtab)
return;
- ErrorOr<StringRef> StringTableOrErr = ELFObj.getStringTableForSymtab(*Symtab);
- error(StringTableOrErr);
- StringTable = *StringTableOrErr;
+ StringTable = check(ELFObj.getStringTableForSymtab(*Symtab));
}
template <class ELFT>
-typename ELFFileBase<ELFT>::Elf_Sym_Range
-ELFFileBase<ELFT>::getNonLocalSymbols() {
- return getSymbolsHelper(false);
+elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
+ : ELFFileBase<ELFT>(Base::ObjectKind, M) {}
+
+template <class ELFT>
+ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getNonLocalSymbols() {
+ if (!this->Symtab)
+ return this->SymbolBodies;
+ uint32_t FirstNonLocal = this->Symtab->sh_info;
+ return makeArrayRef(this->SymbolBodies).slice(FirstNonLocal);
}
template <class ELFT>
-ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
- : ELFFileBase<ELFT>(Base::ObjectKind, M) {}
+ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() {
+ if (!this->Symtab)
+ return this->SymbolBodies;
+ uint32_t FirstNonLocal = this->Symtab->sh_info;
+ return makeArrayRef(this->SymbolBodies).slice(1, FirstNonLocal - 1);
+}
template <class ELFT>
-typename ObjectFile<ELFT>::Elf_Sym_Range ObjectFile<ELFT>::getLocalSymbols() {
- return this->getSymbolsHelper(true);
+ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() {
+ if (!this->Symtab)
+ return this->SymbolBodies;
+ return makeArrayRef(this->SymbolBodies).slice(1);
}
-template <class ELFT> uint32_t ObjectFile<ELFT>::getMipsGp0() const {
- if (MipsReginfo)
+template <class ELFT> uint32_t elf::ObjectFile<ELFT>::getMipsGp0() const {
+ if (ELFT::Is64Bits && MipsOptions && MipsOptions->Reginfo)
+ return MipsOptions->Reginfo->ri_gp_value;
+ if (!ELFT::Is64Bits && MipsReginfo && MipsReginfo->Reginfo)
return MipsReginfo->Reginfo->ri_gp_value;
return 0;
}
template <class ELFT>
-const typename ObjectFile<ELFT>::Elf_Sym *
-ObjectFile<ELFT>::getLocalSymbol(uintX_t SymIndex) {
- uint32_t FirstNonLocal = this->Symtab->sh_info;
- if (SymIndex >= FirstNonLocal)
- return nullptr;
- Elf_Sym_Range Syms = this->ELFObj.symbols(this->Symtab);
- return Syms.begin() + SymIndex;
-}
-
-template <class ELFT>
-void ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) {
+void elf::ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) {
// Read section and symbol tables.
initializeSections(ComdatGroups);
initializeSymbols();
@@ -118,63 +136,57 @@ void ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) {
// They are identified and deduplicated by group name. This function
// returns a group name.
template <class ELFT>
-StringRef ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) {
+StringRef elf::ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) {
const ELFFile<ELFT> &Obj = this->ELFObj;
- uint32_t SymtabdSectionIndex = Sec.sh_link;
- ErrorOr<const Elf_Shdr *> SecOrErr = Obj.getSection(SymtabdSectionIndex);
- error(SecOrErr);
- const Elf_Shdr *SymtabSec = *SecOrErr;
- uint32_t SymIndex = Sec.sh_info;
- const Elf_Sym *Sym = Obj.getSymbol(SymtabSec, SymIndex);
- ErrorOr<StringRef> StringTableOrErr = Obj.getStringTableForSymtab(*SymtabSec);
- error(StringTableOrErr);
- ErrorOr<StringRef> SignatureOrErr = Sym->getName(*StringTableOrErr);
- error(SignatureOrErr);
- return *SignatureOrErr;
+ const Elf_Shdr *Symtab = check(Obj.getSection(Sec.sh_link));
+ const Elf_Sym *Sym = Obj.getSymbol(Symtab, Sec.sh_info);
+ StringRef Strtab = check(Obj.getStringTableForSymtab(*Symtab));
+ return check(Sym->getName(Strtab));
}
template <class ELFT>
-ArrayRef<typename ObjectFile<ELFT>::uint32_X>
-ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
+ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word>
+elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
const ELFFile<ELFT> &Obj = this->ELFObj;
- ErrorOr<ArrayRef<uint32_X>> EntriesOrErr =
- Obj.template getSectionContentsAsArray<uint32_X>(&Sec);
- error(EntriesOrErr);
- ArrayRef<uint32_X> Entries = *EntriesOrErr;
+ ArrayRef<Elf_Word> Entries =
+ check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec));
if (Entries.empty() || Entries[0] != GRP_COMDAT)
- error("Unsupported SHT_GROUP format");
+ fatal(getFilename(this) + ": unsupported SHT_GROUP format");
return Entries.slice(1);
}
template <class ELFT>
-static bool shouldMerge(const typename ELFFile<ELFT>::Elf_Shdr &Sec) {
- typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
+ // We don't merge sections if -O0 (default is -O1). This makes sometimes
+ // the linker significantly faster, although the output will be bigger.
+ if (Config->Optimize == 0)
+ return false;
+
uintX_t Flags = Sec.sh_flags;
if (!(Flags & SHF_MERGE))
return false;
if (Flags & SHF_WRITE)
- error("Writable SHF_MERGE sections are not supported");
+ fatal(getFilename(this) + ": writable SHF_MERGE section is not supported");
uintX_t EntSize = Sec.sh_entsize;
if (!EntSize || Sec.sh_size % EntSize)
- error("SHF_MERGE section size must be a multiple of sh_entsize");
+ fatal(getFilename(this) +
+ ": SHF_MERGE section size must be a multiple of sh_entsize");
- // Don't try to merge if the aligment is larger than the sh_entsize.
+ // Don't try to merge if the alignment is larger than the sh_entsize and this
+ // is not SHF_STRINGS.
//
- // If this is not a SHF_STRINGS, we would need to pad after every entity. It
- // would be equivalent for the producer of the .o to just set a larger
+ // Since this is not a SHF_STRINGS, we would need to pad after every entity.
+ // It would be equivalent for the producer of the .o to just set a larger
// sh_entsize.
- //
- // If this is a SHF_STRINGS, the larger alignment makes sense. Unfortunately
- // it would complicate tail merging. This doesn't seem that common to
- // justify the effort.
- if (Sec.sh_addralign > EntSize)
- return false;
+ if (Flags & SHF_STRINGS)
+ return true;
- return true;
+ return Sec.sh_addralign <= EntSize;
}
template <class ELFT>
-void ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &ComdatGroups) {
+void elf::ObjectFile<ELFT>::initializeSections(
+ DenseSet<StringRef> &ComdatGroups) {
uint64_t Size = this->ELFObj.getNumSections();
Sections.resize(Size);
unsigned I = -1;
@@ -191,53 +203,85 @@ void ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &ComdatGroups) {
continue;
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
if (SecIndex >= Size)
- error("Invalid section index in group");
+ fatal(getFilename(this) + ": invalid section index in group: " +
+ Twine(SecIndex));
Sections[SecIndex] = &InputSection<ELFT>::Discarded;
}
break;
case SHT_SYMTAB:
this->Symtab = &Sec;
break;
- case SHT_SYMTAB_SHNDX: {
- ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable = Obj.getSHNDXTable(Sec);
- error(ErrorOrTable);
- this->SymtabSHNDX = *ErrorOrTable;
+ case SHT_SYMTAB_SHNDX:
+ this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec));
break;
- }
case SHT_STRTAB:
case SHT_NULL:
break;
case SHT_RELA:
case SHT_REL: {
- uint32_t RelocatedSectionIndex = Sec.sh_info;
- if (RelocatedSectionIndex >= Size)
- error("Invalid relocated section index");
- InputSectionBase<ELFT> *RelocatedSection =
- Sections[RelocatedSectionIndex];
- if (!RelocatedSection)
- error("Unsupported relocation reference");
- if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection)) {
+ // 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) {
+ Sections[I] = new (IAlloc.Allocate()) InputSection<ELFT>(this, &Sec);
+ break;
+ }
+
+ // Find the relocation target section and associate this
+ // section with it.
+ InputSectionBase<ELFT> *Target = getRelocTarget(Sec);
+ if (!Target)
+ break;
+ if (auto *S = dyn_cast<InputSection<ELFT>>(Target)) {
S->RelocSections.push_back(&Sec);
- } else if (auto *S = dyn_cast<EHInputSection<ELFT>>(RelocatedSection)) {
+ break;
+ }
+ if (auto *S = dyn_cast<EhInputSection<ELFT>>(Target)) {
if (S->RelocSection)
- error("Multiple relocation sections to .eh_frame are not supported");
+ fatal(
+ getFilename(this) +
+ ": multiple relocation sections to .eh_frame are not supported");
S->RelocSection = &Sec;
- } else {
- error("Relocations pointing to SHF_MERGE are not supported");
+ break;
}
- break;
+ fatal(getFilename(this) +
+ ": relocations pointing to SHF_MERGE are not supported");
}
+ case SHT_ARM_ATTRIBUTES:
+ // FIXME: ARM meta-data section. At present attributes are ignored,
+ // they can be used to reason about object compatibility.
+ Sections[I] = &InputSection<ELFT>::Discarded;
+ break;
default:
Sections[I] = createInputSection(Sec);
}
}
}
-template <class ELFT> InputSectionBase<ELFT> *
-ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
- ErrorOr<StringRef> NameOrErr = this->ELFObj.getSectionName(&Sec);
- error(NameOrErr);
- StringRef Name = *NameOrErr;
+template <class ELFT>
+InputSectionBase<ELFT> *
+elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
+ uint32_t Idx = Sec.sh_info;
+ if (Idx >= Sections.size())
+ fatal(getFilename(this) + ": invalid relocated section index: " +
+ Twine(Idx));
+ InputSectionBase<ELFT> *Target = 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)
+ return nullptr;
+
+ if (!Target)
+ fatal(getFilename(this) + ": unsupported relocation reference");
+ return Target;
+}
+
+template <class ELFT>
+InputSectionBase<ELFT> *
+elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
+ StringRef Name = check(this->ELFObj.getSectionName(&Sec));
// .note.GNU-stack is a marker section to control the presence of
// PT_GNU_STACK segment in outputs. Since the presence of the segment
@@ -246,98 +290,129 @@ ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
if (Name == ".note.GNU-stack")
return &InputSection<ELFT>::Discarded;
- // A MIPS object file has a special section that contains register
- // usage info, which needs to be handled by the linker specially.
- if (Config->EMachine == EM_MIPS && Name == ".reginfo") {
- MipsReginfo = new (Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
- return MipsReginfo;
+ if (Name == ".note.GNU-split-stack") {
+ error("objects using splitstacks are not supported");
+ return &InputSection<ELFT>::Discarded;
}
- if (Name == ".eh_frame")
- return new (EHAlloc.Allocate()) EHInputSection<ELFT>(this, &Sec);
- if (shouldMerge<ELFT>(Sec))
+ if (Config->StripDebug && Name.startswith(".debug"))
+ return &InputSection<ELFT>::Discarded;
+
+ // A MIPS object file has a special sections that contain register
+ // usage info, which need to be handled by the linker specially.
+ if (Config->EMachine == EM_MIPS) {
+ if (Name == ".reginfo") {
+ MipsReginfo.reset(new MipsReginfoInputSection<ELFT>(this, &Sec));
+ return MipsReginfo.get();
+ }
+ if (Name == ".MIPS.options") {
+ MipsOptions.reset(new MipsOptionsInputSection<ELFT>(this, &Sec));
+ return MipsOptions.get();
+ }
+ }
+
+ // 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 new (EHAlloc.Allocate()) EhInputSection<ELFT>(this, &Sec);
+
+ if (shouldMerge(Sec))
return new (MAlloc.Allocate()) MergeInputSection<ELFT>(this, &Sec);
- return new (Alloc) InputSection<ELFT>(this, &Sec);
+ return new (IAlloc.Allocate()) InputSection<ELFT>(this, &Sec);
}
-template <class ELFT> void ObjectFile<ELFT>::initializeSymbols() {
+template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
this->initStringTable();
- Elf_Sym_Range Syms = this->getNonLocalSymbols();
+ Elf_Sym_Range Syms = this->getElfSymbols(false);
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
SymbolBodies.reserve(NumSymbols);
for (const Elf_Sym &Sym : Syms)
- SymbolBodies.push_back(createSymbolBody(this->StringTable, &Sym));
+ SymbolBodies.push_back(createSymbolBody(&Sym));
}
template <class ELFT>
InputSectionBase<ELFT> *
-ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
+elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
uint32_t Index = this->getSectionIndex(Sym);
if (Index == 0)
return nullptr;
if (Index >= Sections.size() || !Sections[Index])
- error("Invalid section index");
- return Sections[Index];
+ fatal(getFilename(this) + ": invalid section index: " + Twine(Index));
+ InputSectionBase<ELFT> *S = Sections[Index];
+ if (S == &InputSectionBase<ELFT>::Discarded)
+ return S;
+ return S->Repl;
}
template <class ELFT>
-SymbolBody *ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
- const Elf_Sym *Sym) {
- ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable);
- error(NameOrErr);
- StringRef Name = *NameOrErr;
+SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
+ int Binding = Sym->getBinding();
+ InputSectionBase<ELFT> *Sec = getSection(*Sym);
+ if (Binding == STB_LOCAL) {
+ if (Sym->st_shndx == SHN_UNDEF)
+ return new (this->Alloc)
+ Undefined(Sym->st_name, Sym->st_other, Sym->getType(), this);
+ return new (this->Alloc) DefinedRegular<ELFT>(*Sym, Sec);
+ }
+
+ StringRef Name = check(Sym->getName(this->StringTable));
switch (Sym->st_shndx) {
case SHN_UNDEF:
- return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
+ return elf::Symtab<ELFT>::X
+ ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(),
+ /*CanOmitFromDynSym*/ false, this)
+ ->body();
case SHN_COMMON:
- return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value,
- Sym->getBinding() == llvm::ELF::STB_WEAK,
- Sym->getVisibility());
+ return elf::Symtab<ELFT>::X
+ ->addCommon(Name, Sym->st_size, Sym->st_value, Binding, Sym->st_other,
+ Sym->getType(), this)
+ ->body();
}
- switch (Sym->getBinding()) {
+ switch (Binding) {
default:
- error("unexpected binding");
+ fatal(getFilename(this) + ": unexpected binding: " + Twine(Binding));
case STB_GLOBAL:
case STB_WEAK:
- case STB_GNU_UNIQUE: {
- InputSectionBase<ELFT> *Sec = getSection(*Sym);
+ case STB_GNU_UNIQUE:
if (Sec == &InputSection<ELFT>::Discarded)
- return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
- return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, Sec);
- }
+ return elf::Symtab<ELFT>::X
+ ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(),
+ /*CanOmitFromDynSym*/ false, this)
+ ->body();
+ return elf::Symtab<ELFT>::X->addRegular(Name, *Sym, Sec)->body();
}
}
-void ArchiveFile::parse() {
- ErrorOr<std::unique_ptr<Archive>> FileOrErr = Archive::create(MB);
- error(FileOrErr, "Failed to parse archive");
- File = std::move(*FileOrErr);
-
- // Allocate a buffer for Lazy objects.
- size_t NumSyms = File->getNumberOfSymbols();
- LazySymbols.reserve(NumSyms);
+template <class ELFT> void ArchiveFile::parse() {
+ File = check(Archive::create(MB), "failed to parse archive");
// Read the symbol table to construct Lazy objects.
for (const Archive::Symbol &Sym : File->symbols())
- LazySymbols.emplace_back(this, Sym);
+ Symtab<ELFT>::X->addLazyArchive(this, Sym);
}
// Returns a buffer pointing to a member file containing a given symbol.
MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
- ErrorOr<Archive::Child> COrErr = Sym->getMember();
- error(COrErr, "Could not get the member for symbol " + Sym->getName());
- const Archive::Child &C = *COrErr;
+ Archive::Child C =
+ check(Sym->getMember(),
+ "could not get the member for symbol " + Sym->getName());
if (!Seen.insert(C.getChildOffset()).second)
return MemoryBufferRef();
- ErrorOr<MemoryBufferRef> RefOrErr = C.getMemoryBufferRef();
- if (!RefOrErr)
- error(RefOrErr, "Could not get the buffer for the member defining symbol " +
- Sym->getName());
- return *RefOrErr;
+ MemoryBufferRef Ret =
+ check(C.getMemoryBufferRef(),
+ "could not get the buffer for the member defining symbol " +
+ Sym->getName());
+
+ if (C.getParent()->isThin() && Driver->Cpio)
+ Driver->Cpio->append(relativeToRoot(check(C.getFullName())),
+ Ret.getBuffer());
+
+ return Ret;
}
template <class ELFT>
@@ -345,21 +420,19 @@ SharedFile<ELFT>::SharedFile(MemoryBufferRef M)
: ELFFileBase<ELFT>(Base::SharedKind, M), AsNeeded(Config->AsNeeded) {}
template <class ELFT>
-const typename ELFFile<ELFT>::Elf_Shdr *
+const typename ELFT::Shdr *
SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
uint32_t Index = this->getSectionIndex(Sym);
if (Index == 0)
return nullptr;
- ErrorOr<const Elf_Shdr *> Ret = this->ELFObj.getSection(Index);
- error(Ret);
- return *Ret;
+ return check(this->ELFObj.getSection(Index));
}
// Partially parse the shared object file so that we can call
// getSoName on this object.
template <class ELFT> void SharedFile<ELFT>::parseSoName() {
- typedef typename ELFFile<ELFT>::Elf_Dyn Elf_Dyn;
- typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+ typedef typename ELFT::Dyn Elf_Dyn;
+ typedef typename ELFT::uint uintX_t;
const Elf_Shdr *DynamicSec = nullptr;
const ELFFile<ELFT> Obj = this->ELFObj;
@@ -373,12 +446,15 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
case SHT_DYNAMIC:
DynamicSec = &Sec;
break;
- case SHT_SYMTAB_SHNDX: {
- ErrorOr<ArrayRef<Elf_Word>> ErrorOrTable = Obj.getSHNDXTable(Sec);
- error(ErrorOrTable);
- this->SymtabSHNDX = *ErrorOrTable;
+ case SHT_SYMTAB_SHNDX:
+ this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec));
+ break;
+ case SHT_GNU_versym:
+ this->VersymSec = &Sec;
+ break;
+ case SHT_GNU_verdef:
+ this->VerdefSec = &Sec;
break;
- }
}
}
@@ -395,83 +471,358 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
if (Dyn.d_tag == DT_SONAME) {
uintX_t Val = Dyn.getVal();
if (Val >= this->StringTable.size())
- error("Invalid DT_SONAME entry");
+ fatal(getFilename(this) + ": invalid DT_SONAME entry");
SoName = StringRef(this->StringTable.data() + Val);
return;
}
}
}
+// Parse the version definitions in the object file if present. Returns a vector
+// whose nth element contains a pointer to the Elf_Verdef for version identifier
+// n. Version identifiers that are not definitions map to nullptr. The array
+// always has at least length 1.
+template <class ELFT>
+std::vector<const typename ELFT::Verdef *>
+SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
+ std::vector<const Elf_Verdef *> Verdefs(1);
+ // We only need to process symbol versions for this DSO if it has both a
+ // versym and a verdef section, which indicates that the DSO contains symbol
+ // version definitions.
+ if (!VersymSec || !VerdefSec)
+ return Verdefs;
+
+ // The location of the first global versym entry.
+ Versym = reinterpret_cast<const Elf_Versym *>(this->ELFObj.base() +
+ VersymSec->sh_offset) +
+ this->Symtab->sh_info;
+
+ // We cannot determine the largest verdef identifier without inspecting
+ // every Elf_Verdef, but both bfd and gold assign verdef identifiers
+ // sequentially starting from 1, so we predict that the largest identifier
+ // will be VerdefCount.
+ unsigned VerdefCount = VerdefSec->sh_info;
+ Verdefs.resize(VerdefCount + 1);
+
+ // Build the Verdefs array by following the chain of Elf_Verdef objects
+ // from the start of the .gnu.version_d section.
+ const uint8_t *Verdef = this->ELFObj.base() + VerdefSec->sh_offset;
+ for (unsigned I = 0; I != VerdefCount; ++I) {
+ auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
+ Verdef += CurVerdef->vd_next;
+ unsigned VerdefIndex = CurVerdef->vd_ndx;
+ if (Verdefs.size() <= VerdefIndex)
+ Verdefs.resize(VerdefIndex + 1);
+ Verdefs[VerdefIndex] = CurVerdef;
+ }
+
+ return Verdefs;
+}
+
// Fully parse the shared object file. This must be called after parseSoName().
template <class ELFT> void SharedFile<ELFT>::parseRest() {
- Elf_Sym_Range Syms = this->getNonLocalSymbols();
- uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
- SymbolBodies.reserve(NumSymbols);
+ // Create mapping from version identifiers to Elf_Verdef entries.
+ const Elf_Versym *Versym = nullptr;
+ std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym);
+
+ Elf_Sym_Range Syms = this->getElfSymbols(true);
for (const Elf_Sym &Sym : Syms) {
- ErrorOr<StringRef> NameOrErr = Sym.getName(this->StringTable);
- error(NameOrErr.getError());
- StringRef Name = *NameOrErr;
+ unsigned VersymIndex = 0;
+ if (Versym) {
+ VersymIndex = Versym->vs_index;
+ ++Versym;
+ }
- if (Sym.isUndefined())
+ StringRef Name = check(Sym.getName(this->StringTable));
+ if (Sym.isUndefined()) {
Undefs.push_back(Name);
- else
- SymbolBodies.emplace_back(this, Name, Sym);
+ continue;
+ }
+
+ if (Versym) {
+ // Ignore local symbols and non-default versions.
+ if (VersymIndex == VER_NDX_LOCAL || (VersymIndex & VERSYM_HIDDEN))
+ continue;
+ }
+
+ const Elf_Verdef *V =
+ VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex];
+ elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
}
}
-template <typename T>
-static std::unique_ptr<InputFile> createELFFileAux(MemoryBufferRef MB) {
- std::unique_ptr<T> Ret = llvm::make_unique<T>(MB);
+static ELFKind getELFKind(MemoryBufferRef MB) {
+ std::string TripleStr = getBitcodeTargetTriple(MB, Driver->Context);
+ Triple TheTriple(TripleStr);
+ bool Is64Bits = TheTriple.isArch64Bit();
+ if (TheTriple.isLittleEndian())
+ return Is64Bits ? ELF64LEKind : ELF32LEKind;
+ return Is64Bits ? ELF64BEKind : ELF32BEKind;
+}
- if (!Config->FirstElf)
- Config->FirstElf = Ret.get();
+static uint8_t getMachineKind(MemoryBufferRef MB) {
+ std::string TripleStr = getBitcodeTargetTriple(MB, Driver->Context);
+ switch (Triple(TripleStr).getArch()) {
+ case Triple::aarch64:
+ return EM_AARCH64;
+ case Triple::arm:
+ return EM_ARM;
+ case Triple::mips:
+ case Triple::mipsel:
+ case Triple::mips64:
+ case Triple::mips64el:
+ return EM_MIPS;
+ case Triple::ppc:
+ return EM_PPC;
+ case Triple::ppc64:
+ return EM_PPC64;
+ case Triple::x86:
+ return EM_386;
+ case Triple::x86_64:
+ return EM_X86_64;
+ default:
+ fatal(MB.getBufferIdentifier() +
+ ": could not infer e_machine from bitcode target triple " +
+ TripleStr);
+ }
+}
+
+BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) {
+ EKind = getELFKind(MB);
+ EMachine = getMachineKind(MB);
+}
- if (Config->EKind == ELFNoneKind) {
- Config->EKind = Ret->getELFKind();
- Config->EMachine = Ret->getEMachine();
+static uint8_t getGvVisibility(const GlobalValue *GV) {
+ switch (GV->getVisibility()) {
+ case GlobalValue::DefaultVisibility:
+ return STV_DEFAULT;
+ case GlobalValue::HiddenVisibility:
+ return STV_HIDDEN;
+ case GlobalValue::ProtectedVisibility:
+ return STV_PROTECTED;
}
+ llvm_unreachable("unknown visibility");
+}
+
+template <class ELFT>
+Symbol *BitcodeFile::createSymbol(const DenseSet<const Comdat *> &KeptComdats,
+ const IRObjectFile &Obj,
+ const BasicSymbolRef &Sym) {
+ const GlobalValue *GV = Obj.getSymbolGV(Sym.getRawDataRefImpl());
+
+ SmallString<64> Name;
+ raw_svector_ostream OS(Name);
+ Sym.printName(OS);
+ StringRef NameRef = Saver.save(StringRef(Name));
+
+ uint32_t Flags = Sym.getFlags();
+ bool IsWeak = Flags & BasicSymbolRef::SF_Weak;
+ uint32_t Binding = IsWeak ? STB_WEAK : STB_GLOBAL;
+
+ uint8_t Type = STT_NOTYPE;
+ bool CanOmitFromDynSym = false;
+ // FIXME: Expose a thread-local flag for module asm symbols.
+ if (GV) {
+ if (GV->isThreadLocal())
+ Type = STT_TLS;
+ CanOmitFromDynSym = canBeOmittedFromSymbolTable(GV);
+ }
+
+ uint8_t Visibility;
+ if (GV)
+ Visibility = getGvVisibility(GV);
+ else
+ // FIXME: Set SF_Hidden flag correctly for module asm symbols, and expose
+ // protected visibility.
+ Visibility = STV_DEFAULT;
+
+ if (GV)
+ if (const Comdat *C = GV->getComdat())
+ if (!KeptComdats.count(C))
+ return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
+ CanOmitFromDynSym, this);
+
+ const Module &M = Obj.getModule();
+ if (Flags & BasicSymbolRef::SF_Undefined)
+ return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
+ CanOmitFromDynSym, this);
+ if (Flags & BasicSymbolRef::SF_Common) {
+ // FIXME: Set SF_Common flag correctly for module asm symbols, and expose
+ // size and alignment.
+ assert(GV);
+ const DataLayout &DL = M.getDataLayout();
+ uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
+ return Symtab<ELFT>::X->addCommon(NameRef, Size, GV->getAlignment(),
+ Binding, Visibility, STT_OBJECT, this);
+ }
+ return Symtab<ELFT>::X->addBitcode(NameRef, IsWeak, Visibility, Type,
+ CanOmitFromDynSym, this);
+}
- return std::move(Ret);
+bool BitcodeFile::shouldSkip(uint32_t Flags) {
+ return !(Flags & BasicSymbolRef::SF_Global) ||
+ (Flags & BasicSymbolRef::SF_FormatSpecific);
+}
+
+template <class ELFT>
+void BitcodeFile::parse(DenseSet<StringRef> &ComdatGroups) {
+ Obj = check(IRObjectFile::create(MB, Driver->Context));
+ const Module &M = Obj->getModule();
+
+ DenseSet<const Comdat *> KeptComdats;
+ for (const auto &P : M.getComdatSymbolTable()) {
+ StringRef N = Saver.save(P.first());
+ if (ComdatGroups.insert(N).second)
+ KeptComdats.insert(&P.second);
+ }
+
+ for (const BasicSymbolRef &Sym : Obj->symbols())
+ if (!shouldSkip(Sym.getFlags()))
+ Symbols.push_back(createSymbol<ELFT>(KeptComdats, *Obj, Sym));
}
template <template <class> class T>
static std::unique_ptr<InputFile> createELFFile(MemoryBufferRef MB) {
- std::pair<unsigned char, unsigned char> Type = getElfArchType(MB.getBuffer());
- if (Type.second != ELF::ELFDATA2LSB && Type.second != ELF::ELFDATA2MSB)
- error("Invalid data encoding: " + MB.getBufferIdentifier());
-
- if (Type.first == ELF::ELFCLASS32) {
- if (Type.second == ELF::ELFDATA2LSB)
- return createELFFileAux<T<ELF32LE>>(MB);
- return createELFFileAux<T<ELF32BE>>(MB);
- }
- if (Type.first == ELF::ELFCLASS64) {
- if (Type.second == ELF::ELFDATA2LSB)
- return createELFFileAux<T<ELF64LE>>(MB);
- return createELFFileAux<T<ELF64BE>>(MB);
- }
- error("Invalid file class: " + MB.getBufferIdentifier());
+ unsigned char Size;
+ unsigned char Endian;
+ std::tie(Size, Endian) = getElfArchType(MB.getBuffer());
+ if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB)
+ fatal("invalid data encoding: " + MB.getBufferIdentifier());
+
+ std::unique_ptr<InputFile> Obj;
+ if (Size == ELFCLASS32 && Endian == ELFDATA2LSB)
+ Obj.reset(new T<ELF32LE>(MB));
+ else if (Size == ELFCLASS32 && Endian == ELFDATA2MSB)
+ Obj.reset(new T<ELF32BE>(MB));
+ else if (Size == ELFCLASS64 && Endian == ELFDATA2LSB)
+ Obj.reset(new T<ELF64LE>(MB));
+ else if (Size == ELFCLASS64 && Endian == ELFDATA2MSB)
+ Obj.reset(new T<ELF64BE>(MB));
+ else
+ fatal("invalid file class: " + MB.getBufferIdentifier());
+
+ if (!Config->FirstElf)
+ Config->FirstElf = Obj.get();
+ return Obj;
+}
+
+static bool isBitcode(MemoryBufferRef MB) {
+ using namespace sys::fs;
+ return identify_magic(MB.getBuffer()) == file_magic::bitcode;
}
-std::unique_ptr<InputFile> elf2::createObjectFile(MemoryBufferRef MB) {
- return createELFFile<ObjectFile>(MB);
+std::unique_ptr<InputFile> elf::createObjectFile(MemoryBufferRef MB,
+ StringRef ArchiveName) {
+ std::unique_ptr<InputFile> F;
+ if (isBitcode(MB))
+ F.reset(new BitcodeFile(MB));
+ else
+ F = createELFFile<ObjectFile>(MB);
+ F->ArchiveName = ArchiveName;
+ return F;
}
-std::unique_ptr<InputFile> elf2::createSharedFile(MemoryBufferRef MB) {
+std::unique_ptr<InputFile> elf::createSharedFile(MemoryBufferRef MB) {
return createELFFile<SharedFile>(MB);
}
-template class elf2::ELFFileBase<ELF32LE>;
-template class elf2::ELFFileBase<ELF32BE>;
-template class elf2::ELFFileBase<ELF64LE>;
-template class elf2::ELFFileBase<ELF64BE>;
+MemoryBufferRef LazyObjectFile::getBuffer() {
+ if (Seen)
+ return MemoryBufferRef();
+ Seen = true;
+ return MB;
+}
-template class elf2::ObjectFile<ELF32LE>;
-template class elf2::ObjectFile<ELF32BE>;
-template class elf2::ObjectFile<ELF64LE>;
-template class elf2::ObjectFile<ELF64BE>;
+template <class ELFT>
+void LazyObjectFile::parse() {
+ for (StringRef Sym : getSymbols())
+ Symtab<ELFT>::X->addLazyObject(Sym, *this);
+}
+
+template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::SymRange Elf_Sym_Range;
+
+ const ELFFile<ELFT> Obj = createELFObj<ELFT>(this->MB);
+ for (const Elf_Shdr &Sec : Obj.sections()) {
+ if (Sec.sh_type != SHT_SYMTAB)
+ continue;
+ Elf_Sym_Range Syms = Obj.symbols(&Sec);
+ uint32_t FirstNonLocal = Sec.sh_info;
+ StringRef StringTable = check(Obj.getStringTableForSymtab(Sec));
+ 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)));
+ return V;
+ }
+ return {};
+}
+
+std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
+ LLVMContext Context;
+ std::unique_ptr<IRObjectFile> Obj =
+ check(IRObjectFile::create(this->MB, Context));
+ std::vector<StringRef> V;
+ for (const BasicSymbolRef &Sym : Obj->symbols()) {
+ uint32_t Flags = Sym.getFlags();
+ if (BitcodeFile::shouldSkip(Flags))
+ continue;
+ if (Flags & BasicSymbolRef::SF_Undefined)
+ continue;
+ SmallString<64> Name;
+ raw_svector_ostream OS(Name);
+ Sym.printName(OS);
+ V.push_back(Saver.save(StringRef(Name)));
+ }
+ return V;
+}
+
+// Returns a vector of globally-visible defined symbol names.
+std::vector<StringRef> LazyObjectFile::getSymbols() {
+ if (isBitcode(this->MB))
+ return getBitcodeSymbols();
+
+ unsigned char Size;
+ unsigned char Endian;
+ std::tie(Size, Endian) = getElfArchType(this->MB.getBuffer());
+ if (Size == ELFCLASS32) {
+ if (Endian == ELFDATA2LSB)
+ return getElfSymbols<ELF32LE>();
+ return getElfSymbols<ELF32BE>();
+ }
+ if (Endian == ELFDATA2LSB)
+ return getElfSymbols<ELF64LE>();
+ return getElfSymbols<ELF64BE>();
+}
-template class elf2::SharedFile<ELF32LE>;
-template class elf2::SharedFile<ELF32BE>;
-template class elf2::SharedFile<ELF64LE>;
-template class elf2::SharedFile<ELF64BE>;
+template void ArchiveFile::parse<ELF32LE>();
+template void ArchiveFile::parse<ELF32BE>();
+template void ArchiveFile::parse<ELF64LE>();
+template void ArchiveFile::parse<ELF64BE>();
+
+template void BitcodeFile::parse<ELF32LE>(DenseSet<StringRef> &);
+template void BitcodeFile::parse<ELF32BE>(DenseSet<StringRef> &);
+template void BitcodeFile::parse<ELF64LE>(DenseSet<StringRef> &);
+template void BitcodeFile::parse<ELF64BE>(DenseSet<StringRef> &);
+
+template void LazyObjectFile::parse<ELF32LE>();
+template void LazyObjectFile::parse<ELF32BE>();
+template void LazyObjectFile::parse<ELF64LE>();
+template void LazyObjectFile::parse<ELF64BE>();
+
+template class elf::ELFFileBase<ELF32LE>;
+template class elf::ELFFileBase<ELF32BE>;
+template class elf::ELFFileBase<ELF64LE>;
+template class elf::ELFFileBase<ELF64BE>;
+
+template class elf::ObjectFile<ELF32LE>;
+template class elf::ObjectFile<ELF32BE>;
+template class elf::ObjectFile<ELF64LE>;
+template class elf::ObjectFile<ELF64BE>;
+
+template class elf::SharedFile<ELF32LE>;
+template class elf::SharedFile<ELF32BE>;
+template class elf::SharedFile<ELF64LE>;
+template class elf::SharedFile<ELF64BE>;
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 45d403c0125c..79cb751494b3 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -18,11 +18,16 @@
#include "lld/Core/LLVM.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/Comdat.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/StringSaver.h"
+
+#include <map>
namespace lld {
-namespace elf2 {
+namespace elf {
using llvm::object::Archive;
@@ -33,25 +38,45 @@ class SymbolBody;
// The root class of input files.
class InputFile {
public:
- enum Kind { ObjectKind, SharedKind, ArchiveKind };
+ enum Kind {
+ ObjectKind,
+ SharedKind,
+ LazyObjectKind,
+ ArchiveKind,
+ BitcodeKind,
+ };
+
Kind kind() const { return FileKind; }
StringRef getName() const { return MB.getBufferIdentifier(); }
+ MemoryBufferRef MB;
+
+ // 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 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;
protected:
InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
- MemoryBufferRef MB;
private:
const Kind FileKind;
};
+// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
+std::string getFilename(const InputFile *F);
+
template <typename ELFT> class ELFFileBase : public InputFile {
public:
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::SymRange Elf_Sym_Range;
ELFFileBase(Kind K, MemoryBufferRef M);
static bool classof(const InputFile *F) {
@@ -59,11 +84,9 @@ public:
return K == ObjectKind || K == SharedKind;
}
- static ELFKind getELFKind();
const llvm::object::ELFFile<ELFT> &getObj() const { return ELFObj; }
llvm::object::ELFFile<ELFT> &getObj() { return ELFObj; }
- uint16_t getEMachine() const { return getObj().getHeader()->e_machine; }
uint8_t getOSABI() const {
return getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI];
}
@@ -72,39 +95,36 @@ public:
uint32_t getSectionIndex(const Elf_Sym &Sym) const;
+ Elf_Sym_Range getElfSymbols(bool OnlyGlobals);
+
protected:
llvm::object::ELFFile<ELFT> ELFObj;
const Elf_Shdr *Symtab = nullptr;
ArrayRef<Elf_Word> SymtabSHNDX;
StringRef StringTable;
void initStringTable();
- Elf_Sym_Range getNonLocalSymbols();
- Elf_Sym_Range getSymbolsHelper(bool);
};
// .o file.
template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
typedef ELFFileBase<ELFT> Base;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
-
- // uint32 in ELFT's byte order
- typedef llvm::support::detail::packed_endian_specific_integral<
- uint32_t, ELFT::TargetEndianness, 2>
- uint32_X;
+ 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(const Elf_Shdr &Sec);
- ArrayRef<uint32_X> getShtGroupEntries(const Elf_Shdr &Sec);
+ ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec);
public:
static bool classof(const InputFile *F) {
return F->kind() == Base::ObjectKind;
}
- ArrayRef<SymbolBody *> getSymbols() { return SymbolBodies; }
+ ArrayRef<SymbolBody *> getSymbols();
+ ArrayRef<SymbolBody *> getLocalSymbols();
+ ArrayRef<SymbolBody *> getNonLocalSymbols();
explicit ObjectFile(MemoryBufferRef M);
void parse(llvm::DenseSet<StringRef> &ComdatGroups);
@@ -112,15 +132,14 @@ public:
ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
- SymbolBody *getSymbolBody(uint32_t SymbolIndex) const {
- uint32_t FirstNonLocal = this->Symtab->sh_info;
- if (SymbolIndex < FirstNonLocal)
- return nullptr;
- return SymbolBodies[SymbolIndex - FirstNonLocal];
+ SymbolBody &getSymbolBody(uint32_t SymbolIndex) const {
+ return *SymbolBodies[SymbolIndex];
}
- Elf_Sym_Range getLocalSymbols();
- const Elf_Sym *getLocalSymbol(uintX_t SymIndex);
+ template <typename RelT> SymbolBody &getRelocTargetSym(const RelT &Rel) const {
+ uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL);
+ return getSymbolBody(SymIndex);
+ }
const Elf_Shdr *getSymbolTable() const { return this->Symtab; };
@@ -129,12 +148,22 @@ public:
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
uint32_t getMipsGp0() const;
+ // The number is the offset in the string table. It will be used as the
+ // st_name of the symbol.
+ std::vector<std::pair<const DefinedRegular<ELFT> *, unsigned>> KeptLocalSyms;
+
+ // SymbolBodies and Thunks for sections in this file are allocated
+ // using this buffer.
+ llvm::BumpPtrAllocator Alloc;
+
private:
void initializeSections(llvm::DenseSet<StringRef> &ComdatGroups);
void initializeSymbols();
+ InputSectionBase<ELFT> *getRelocTarget(const Elf_Shdr &Sec);
InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec);
- SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym);
+ 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;
@@ -143,49 +172,97 @@ private:
std::vector<SymbolBody *> SymbolBodies;
// MIPS .reginfo section defined by this file.
- MipsReginfoInputSection<ELFT> *MipsReginfo = nullptr;
+ std::unique_ptr<MipsReginfoInputSection<ELFT>> MipsReginfo;
+ // MIPS .MIPS.options section defined by this file.
+ std::unique_ptr<MipsOptionsInputSection<ELFT>> MipsOptions;
- llvm::BumpPtrAllocator Alloc;
+ llvm::SpecificBumpPtrAllocator<InputSection<ELFT>> IAlloc;
llvm::SpecificBumpPtrAllocator<MergeInputSection<ELFT>> MAlloc;
- llvm::SpecificBumpPtrAllocator<EHInputSection<ELFT>> EHAlloc;
+ llvm::SpecificBumpPtrAllocator<EhInputSection<ELFT>> EHAlloc;
+};
+
+// LazyObjectFile is analogous to ArchiveFile in the sense that
+// the file contains lazy symbols. The difference is that
+// LazyObjectFile wraps a single file instead of multiple files.
+//
+// This class is used for --start-lib and --end-lib options which
+// instruct the linker to link object files between them with the
+// archive file semantics.
+class LazyObjectFile : public InputFile {
+public:
+ explicit LazyObjectFile(MemoryBufferRef M) : InputFile(LazyObjectKind, M) {}
+
+ static bool classof(const InputFile *F) {
+ return F->kind() == LazyObjectKind;
+ }
+
+ template <class ELFT> void parse();
+ MemoryBufferRef getBuffer();
+
+private:
+ std::vector<StringRef> getSymbols();
+ template <class ELFT> std::vector<StringRef> getElfSymbols();
+ std::vector<StringRef> getBitcodeSymbols();
+
+ llvm::BumpPtrAllocator Alloc;
+ llvm::StringSaver Saver{Alloc};
+ bool Seen = false;
};
+// An ArchiveFile object represents a .a file.
class ArchiveFile : public InputFile {
public:
explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
- void parse();
+ template <class ELFT> void parse();
// Returns a memory buffer for a given symbol. An empty memory buffer
// is returned if we have already returned the same memory buffer.
// (So that we don't instantiate same members more than once.)
MemoryBufferRef getMember(const Archive::Symbol *Sym);
- llvm::MutableArrayRef<Lazy> getLazySymbols() { return LazySymbols; }
-
private:
std::unique_ptr<Archive> File;
- std::vector<Lazy> LazySymbols;
llvm::DenseSet<uint64_t> Seen;
};
+class BitcodeFile : public InputFile {
+public:
+ explicit BitcodeFile(MemoryBufferRef M);
+ static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
+ template <class ELFT>
+ void parse(llvm::DenseSet<StringRef> &ComdatGroups);
+ ArrayRef<Symbol *> getSymbols() { return Symbols; }
+ static bool shouldSkip(uint32_t Flags);
+ std::unique_ptr<llvm::object::IRObjectFile> Obj;
+
+private:
+ std::vector<Symbol *> Symbols;
+ llvm::BumpPtrAllocator Alloc;
+ llvm::StringSaver Saver{Alloc};
+ template <class ELFT>
+ Symbol *createSymbol(const llvm::DenseSet<const llvm::Comdat *> &KeptComdats,
+ const llvm::object::IRObjectFile &Obj,
+ const llvm::object::BasicSymbolRef &Sym);
+};
+
// .so file.
template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
typedef ELFFileBase<ELFT> Base;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::SymRange Elf_Sym_Range;
+ typedef typename ELFT::Versym Elf_Versym;
+ typedef typename ELFT::Verdef Elf_Verdef;
- std::vector<SharedSymbol<ELFT>> SymbolBodies;
std::vector<StringRef> Undefs;
StringRef SoName;
+ const Elf_Shdr *VersymSec = nullptr;
+ const Elf_Shdr *VerdefSec = nullptr;
public:
StringRef getSoName() const { return SoName; }
- llvm::MutableArrayRef<SharedSymbol<ELFT>> getSharedSymbols() {
- return SymbolBodies;
- }
const Elf_Shdr *getSection(const Elf_Sym &Sym) const;
llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; }
@@ -197,6 +274,19 @@ public:
void parseSoName();
void parseRest();
+ std::vector<const Elf_Verdef *> parseVerdefs(const Elf_Versym *&Versym);
+
+ struct NeededVer {
+ // The string table offset of the version name in the output file.
+ size_t StrTab;
+
+ // The version identifier for this version name.
+ uint16_t Index;
+ };
+
+ // Mapping from Elf_Verdef data structures to information about Elf_Vernaux
+ // data structures in the output file.
+ std::map<const Elf_Verdef *, NeededVer> VerdefMap;
// Used for --as-needed
bool AsNeeded = false;
@@ -204,10 +294,11 @@ public:
bool isNeeded() const { return !AsNeeded || IsUsed; }
};
-std::unique_ptr<InputFile> createObjectFile(MemoryBufferRef MB);
+std::unique_ptr<InputFile> createObjectFile(MemoryBufferRef MB,
+ StringRef ArchiveName = "");
std::unique_ptr<InputFile> createSharedFile(MemoryBufferRef MB);
-} // namespace elf2
+} // namespace elf
} // namespace lld
#endif
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index f6aa51b47b98..6564e7995a89 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -9,86 +9,118 @@
#include "InputSection.h"
#include "Config.h"
+#include "EhFrame.h"
#include "Error.h"
#include "InputFiles.h"
+#include "LinkerScript.h"
#include "OutputSections.h"
#include "Target.h"
+#include "Thunks.h"
+
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
+using namespace llvm::support::endian;
using namespace lld;
-using namespace lld::elf2;
+using namespace lld::elf;
+
+template <class ELFT> bool elf::isDiscarded(InputSectionBase<ELFT> *S) {
+ return !S || S == &InputSection<ELFT>::Discarded || !S->Live ||
+ Script<ELFT>::X->isDiscarded(S);
+}
template <class ELFT>
-InputSectionBase<ELFT>::InputSectionBase(ObjectFile<ELFT> *File,
+InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
const Elf_Shdr *Header,
Kind SectionKind)
- : Header(Header), File(File), SectionKind(SectionKind) {}
+ : Header(Header), File(File), SectionKind(SectionKind), Repl(this),
+ Compressed(Header->sh_flags & SHF_COMPRESSED) {
+ // The garbage collector sets sections' Live bits.
+ // If GC is disabled, all sections are considered live by default.
+ Live = !Config->GcSections;
+
+ // The ELF spec states that a value of 0 means the section has
+ // no alignment constraits.
+ Alignment = std::max<uintX_t>(Header->sh_addralign, 1);
+}
+
+template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const {
+ if (auto *D = dyn_cast<InputSection<ELFT>>(this))
+ if (D->getThunksSize() > 0)
+ return D->getThunkOff() + D->getThunksSize();
+ return Header->sh_size;
+}
template <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const {
- ErrorOr<StringRef> Name = File->getObj().getSectionName(this->Header);
- error(Name);
- return *Name;
+ return check(File->getObj().getSectionName(this->Header));
}
template <class ELFT>
ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const {
- ErrorOr<ArrayRef<uint8_t>> Ret =
- this->File->getObj().getSectionContents(this->Header);
- error(Ret);
- return *Ret;
+ if (Compressed)
+ return ArrayRef<uint8_t>((const uint8_t *)Uncompressed.data(),
+ Uncompressed.size());
+ return check(this->File->getObj().getSectionContents(this->Header));
}
template <class ELFT>
-typename ELFFile<ELFT>::uintX_t
-InputSectionBase<ELFT>::getOffset(uintX_t Offset) {
+typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const {
switch (SectionKind) {
case Regular:
return cast<InputSection<ELFT>>(this)->OutSecOff + Offset;
case EHFrame:
- return cast<EHInputSection<ELFT>>(this)->getOffset(Offset);
+ return cast<EhInputSection<ELFT>>(this)->getOffset(Offset);
case Merge:
return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
case MipsReginfo:
- // MIPS .reginfo sections are consumed by the linker,
- // so it should never be copied to output.
- llvm_unreachable("MIPS .reginfo reached writeTo().");
+ case MipsOptions:
+ // MIPS .reginfo and .MIPS.options sections are consumed by the linker,
+ // and the linker produces a single output section. It is possible that
+ // input files contain section symbol points to the corresponding input
+ // section. Redirect it to the produced output section.
+ if (Offset != 0)
+ fatal("Unsupported reference to the middle of '" + getSectionName() +
+ "' section");
+ return this->OutSec->getVA();
}
- llvm_unreachable("Invalid section kind");
+ llvm_unreachable("invalid section kind");
}
-template <class ELFT>
-typename ELFFile<ELFT>::uintX_t
-InputSectionBase<ELFT>::getOffset(const Elf_Sym &Sym) {
- return getOffset(Sym.st_value);
-}
+template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
+ if (!zlib::isAvailable())
+ fatal("build lld with zlib to enable compressed sections support");
-// Returns a section that Rel relocation is pointing to.
-template <class ELFT>
-InputSectionBase<ELFT> *
-InputSectionBase<ELFT>::getRelocTarget(const Elf_Rel &Rel) {
- // Global symbol
- uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL);
- if (SymbolBody *B = File->getSymbolBody(SymIndex))
- if (auto *D = dyn_cast<DefinedRegular<ELFT>>(B->repl()))
- return D->Section;
- // Local symbol
- if (const Elf_Sym *Sym = File->getLocalSymbol(SymIndex))
- if (InputSectionBase<ELFT> *Sec = File->getSection(*Sym))
- return Sec;
- return nullptr;
+ // A compressed section consists of a header of Elf_Chdr type
+ // followed by compressed data.
+ ArrayRef<uint8_t> Data =
+ check(this->File->getObj().getSectionContents(this->Header));
+ if (Data.size() < sizeof(Elf_Chdr))
+ fatal("corrupt compressed section");
+
+ auto *Hdr = reinterpret_cast<const Elf_Chdr *>(Data.data());
+ Data = Data.slice(sizeof(Elf_Chdr));
+
+ if (Hdr->ch_type != ELFCOMPRESS_ZLIB)
+ fatal("unsupported compression type");
+
+ StringRef Buf((const char *)Data.data(), Data.size());
+ if (zlib::uncompress(Buf, Uncompressed, Hdr->ch_size) != zlib::StatusOK)
+ fatal("error uncompressing section");
}
template <class ELFT>
-InputSectionBase<ELFT> *
-InputSectionBase<ELFT>::getRelocTarget(const Elf_Rela &Rel) {
- return getRelocTarget(reinterpret_cast<const Elf_Rel &>(Rel));
+typename ELFT::uint
+InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const {
+ return getOffset(Sym.Value);
}
template <class ELFT>
-InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header)
+InputSection<ELFT>::InputSection(elf::ObjectFile<ELFT> *F,
+ const Elf_Shdr *Header)
: InputSectionBase<ELFT>(F, Header, Base::Regular) {}
template <class ELFT>
@@ -97,267 +129,494 @@ bool InputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
}
template <class ELFT>
-template <bool isRela>
-uint8_t *
-InputSectionBase<ELFT>::findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex,
- uint32_t Type,
- RelIteratorRange<isRela> Rels) {
- // Some MIPS relocations use addend calculated from addend of the relocation
- // itself and addend of paired relocation. ABI requires to compute such
- // combined addend in case of REL relocation record format only.
- // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (isRela || Config->EMachine != EM_MIPS)
- return nullptr;
- if (Type == R_MIPS_HI16)
- Type = R_MIPS_LO16;
- else if (Type == R_MIPS_PCHI16)
- Type = R_MIPS_PCLO16;
- else if (Type == R_MICROMIPS_HI16)
- Type = R_MICROMIPS_LO16;
- else
- return nullptr;
- for (const auto &RI : Rels) {
- if (RI.getType(Config->Mips64EL) != Type)
- continue;
- if (RI.getSymbol(Config->Mips64EL) != SymIndex)
- continue;
- uintX_t Offset = getOffset(RI.r_offset);
- if (Offset == (uintX_t)-1)
- return nullptr;
- return Buf + Offset;
- }
- return nullptr;
+InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
+ assert(this->Header->sh_type == SHT_RELA || this->Header->sh_type == SHT_REL);
+ ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections();
+ return Sections[this->Header->sh_info];
}
template <class ELFT>
-static typename llvm::object::ELFFile<ELFT>::uintX_t
-getSymSize(SymbolBody &Body) {
- if (auto *SS = dyn_cast<DefinedElf<ELFT>>(&Body))
- return SS->Sym.st_size;
- return 0;
+void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) {
+ Thunks.push_back(T);
+}
+
+template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const {
+ return this->Header->sh_size;
}
+template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const {
+ uint64_t Total = 0;
+ for (const Thunk<ELFT> *T : Thunks)
+ Total += T->size();
+ return Total;
+}
+
+// This is used for -r. We can't use memcpy to copy relocations because we need
+// to update symbol table offset and section index for each relocation. So we
+// copy relocations one by one.
template <class ELFT>
-template <bool isRela>
-void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
- RelIteratorRange<isRela> Rels) {
- typedef Elf_Rel_Impl<ELFT, isRela> RelType;
- size_t Num = Rels.end() - Rels.begin();
- for (size_t I = 0; I < Num; ++I) {
- const RelType &RI = *(Rels.begin() + I);
- uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
- uint32_t Type = RI.getType(Config->Mips64EL);
- uintX_t Offset = getOffset(RI.r_offset);
- if (Offset == (uintX_t)-1)
- continue;
+template <class RelTy>
+void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+ InputSectionBase<ELFT> *RelocatedSection = getRelocatedSection();
- uint8_t *BufLoc = Buf + Offset;
- uintX_t AddrLoc = OutSec->getVA() + Offset;
- auto NextRelocs = llvm::make_range(&RI, Rels.end());
+ for (const RelTy &Rel : Rels) {
+ uint32_t Type = Rel.getType(Config->Mips64EL);
+ SymbolBody &Body = this->File->getRelocTargetSym(Rel);
- if (Target->isTlsLocalDynamicReloc(Type) &&
- !Target->isTlsOptimized(Type, nullptr)) {
- Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
- Out<ELFT>::Got->getLocalTlsIndexVA() +
- getAddend<ELFT>(RI));
- continue;
- }
+ RelTy *P = reinterpret_cast<RelTy *>(Buf);
+ Buf += sizeof(RelTy);
- const Elf_Shdr *SymTab = File->getSymbolTable();
- SymbolBody *Body = nullptr;
- if (SymIndex >= SymTab->sh_info)
- Body = File->getSymbolBody(SymIndex)->repl();
-
- if (Target->isTlsOptimized(Type, Body)) {
- uintX_t SymVA;
- if (!Body)
- SymVA = getLocalRelTarget(*File, RI, 0);
- else if (Target->relocNeedsGot(Type, *Body))
- SymVA = Out<ELFT>::Got->getEntryAddr(*Body);
- else
- SymVA = getSymVA<ELFT>(*Body);
- // By optimizing TLS relocations, it is sometimes needed to skip
- // relocations that immediately follow TLS relocations. This function
- // knows how many slots we need to skip.
- I += Target->relocateTlsOptimize(BufLoc, BufEnd, Type, AddrLoc, SymVA,
- *Body);
- continue;
+ P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
+ P->setSymbolAndType(Body.DynsymIndex, Type, Config->Mips64EL);
+ }
+}
+
+// Page(Expr) is the page address of the expression Expr, defined
+// as (Expr & ~0xFFF). (This applies even if the machine page size
+// supported by the platform has a different value.)
+static uint64_t getAArch64Page(uint64_t Expr) {
+ return Expr & (~static_cast<uint64_t>(0xFFF));
+}
+
+template <class ELFT>
+static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
+ typename ELFT::uint P,
+ const SymbolBody &Body, RelExpr Expr) {
+ typedef typename ELFT::uint uintX_t;
+
+ switch (Expr) {
+ case R_HINT:
+ llvm_unreachable("cannot relocate hint relocs");
+ case R_TLSLD:
+ return Out<ELFT>::Got->getTlsIndexOff() + A -
+ Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+ case R_TLSLD_PC:
+ return Out<ELFT>::Got->getTlsIndexVA() + A - P;
+ case R_THUNK_ABS:
+ return Body.getThunkVA<ELFT>() + A;
+ case R_THUNK_PC:
+ case R_THUNK_PLT_PC:
+ return Body.getThunkVA<ELFT>() + A - P;
+ case R_PPC_TOC:
+ return getPPC64TocBase() + A;
+ case R_TLSGD:
+ return Out<ELFT>::Got->getGlobalDynOffset(Body) + A -
+ Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+ case R_TLSGD_PC:
+ return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+ case R_TLSDESC:
+ return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
+ case R_TLSDESC_PAGE:
+ return getAArch64Page(Out<ELFT>::Got->getGlobalDynAddr(Body) + A) -
+ getAArch64Page(P);
+ case R_PLT:
+ return Body.getPltVA<ELFT>() + A;
+ case R_PLT_PC:
+ case R_PPC_PLT_OPD:
+ return Body.getPltVA<ELFT>() + A - P;
+ case R_SIZE:
+ return Body.getSize<ELFT>() + A;
+ case R_GOTREL:
+ return Body.getVA<ELFT>(A) - Out<ELFT>::Got->getVA();
+ case R_RELAX_TLS_GD_TO_IE_END:
+ case R_GOT_FROM_END:
+ return Body.getGotOffset<ELFT>() + A -
+ Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+ case R_RELAX_TLS_GD_TO_IE_ABS:
+ case R_GOT:
+ return Body.getGotVA<ELFT>() + A;
+ case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
+ case R_GOT_PAGE_PC:
+ return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
+ case R_RELAX_TLS_GD_TO_IE:
+ case R_GOT_PC:
+ return Body.getGotVA<ELFT>() + A - P;
+ case R_GOTONLY_PC:
+ return Out<ELFT>::Got->getVA() + A - P;
+ case R_RELAX_TLS_LD_TO_LE:
+ case R_RELAX_TLS_IE_TO_LE:
+ case R_RELAX_TLS_GD_TO_LE:
+ case R_TLS:
+ if (Target->TcbSize)
+ return Body.getVA<ELFT>(A) +
+ alignTo(Target->TcbSize, Out<ELFT>::TlsPhdr->p_align);
+ return Body.getVA<ELFT>(A) - Out<ELFT>::TlsPhdr->p_memsz;
+ case R_RELAX_TLS_GD_TO_LE_NEG:
+ case R_NEG_TLS:
+ return Out<ELF32LE>::TlsPhdr->p_memsz - Body.getVA<ELFT>(A);
+ case R_ABS:
+ case R_RELAX_GOT_PC_NOPIC:
+ return Body.getVA<ELFT>(A);
+ case R_GOT_OFF:
+ return Body.getGotOffset<ELFT>() + A;
+ case R_MIPS_GOT_LOCAL_PAGE:
+ // If relocation against MIPS local symbol requires GOT entry, this entry
+ // should be initialized by 'page address'. This address is high 16-bits
+ // of sum the symbol's value and the addend.
+ return Out<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
+ case R_MIPS_GOT_OFF:
+ // In case of MIPS if a GOT relocation has non-zero addend this addend
+ // should be applied to the GOT entry content not to the GOT entry offset.
+ // That is why we use separate expression type.
+ return Out<ELFT>::Got->getMipsGotOffset(Body, A);
+ case R_MIPS_TLSGD:
+ return Out<ELFT>::Got->getGlobalDynOffset(Body) +
+ Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+ case R_MIPS_TLSLD:
+ return Out<ELFT>::Got->getTlsIndexOff() +
+ Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+ case R_PPC_OPD: {
+ uint64_t SymVA = Body.getVA<ELFT>(A);
+ // If we have an undefined weak symbol, we might get here with a symbol
+ // address of zero. That could overflow, but the code must be unreachable,
+ // so don't bother doing anything at all.
+ if (!SymVA)
+ return 0;
+ if (Out<ELF64BE>::Opd) {
+ // If this is a local call, and we currently have the address of a
+ // function-descriptor, get the underlying code address instead.
+ uint64_t OpdStart = Out<ELF64BE>::Opd->getVA();
+ uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
+ bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
+ if (InOpd)
+ SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]);
}
+ return SymVA - P;
+ }
+ case R_PC:
+ case R_RELAX_GOT_PC:
+ return Body.getVA<ELFT>(A) - P;
+ case R_PLT_PAGE_PC:
+ case R_PAGE_PC:
+ return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
+ }
+ llvm_unreachable("Invalid expression");
+}
- // Handle relocations for local symbols -- they never get
- // resolved so we don't allocate a SymbolBody.
- uintX_t A = getAddend<ELFT>(RI);
- if (!Body) {
- uintX_t SymVA = getLocalRelTarget(*File, RI, A);
- // We need to adjust SymVA value in case of R_MIPS_GPREL16/32 relocations
- // because they use the following expression to calculate the relocation's
- // result for local symbol: S + A + GP0 - G.
- if (Config->EMachine == EM_MIPS &&
- (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32))
- SymVA += File->getMipsGp0();
- Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0,
- findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
- continue;
+// This function applies relocations to sections without SHF_ALLOC bit.
+// Such sections are never mapped to memory at runtime. Debug sections are
+// an example. Relocations in non-alloc sections are much easier to
+// handle than in allocated sections because it will never need complex
+// treatement such as GOT or PLT (because at runtime no one refers them).
+// So, we handle relocations for non-alloc sections directly in this
+// function as a performance optimization.
+template <class ELFT>
+template <class RelTy>
+void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+ const unsigned Bits = sizeof(uintX_t) * 8;
+ for (const RelTy &Rel : Rels) {
+ uint32_t Type = Rel.getType(Config->Mips64EL);
+ uintX_t Offset = this->getOffset(Rel.r_offset);
+ uint8_t *BufLoc = Buf + Offset;
+ uintX_t Addend = getAddend<ELFT>(Rel);
+ if (!RelTy::IsRela)
+ Addend += Target->getImplicitAddend(BufLoc, Type);
+
+ SymbolBody &Sym = this->File->getRelocTargetSym(Rel);
+ if (Target->getRelExpr(Type, Sym) != R_ABS) {
+ error(this->getSectionName() + " has non-ABS reloc");
+ return;
}
- if (Target->isTlsGlobalDynamicReloc(Type) &&
- !Target->isTlsOptimized(Type, Body)) {
- Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
- Out<ELFT>::Got->getGlobalDynAddr(*Body) +
- getAddend<ELFT>(RI));
- continue;
+ uintX_t AddrLoc = this->OutSec->getVA() + Offset;
+ uint64_t SymVA =
+ SignExtend64<Bits>(getSymVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS));
+ Target->relocateOne(BufLoc, Type, SymVA);
+ }
+}
+
+template <class ELFT>
+void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+ // scanReloc function in Writer.cpp constructs Relocations
+ // vector only for SHF_ALLOC'ed sections. For other sections,
+ // we handle relocations directly here.
+ auto *IS = dyn_cast<InputSection<ELFT>>(this);
+ if (IS && !(IS->Header->sh_flags & SHF_ALLOC)) {
+ for (const Elf_Shdr *RelSec : IS->RelocSections) {
+ if (RelSec->sh_type == SHT_RELA)
+ IS->relocateNonAlloc(Buf, IS->File->getObj().relas(RelSec));
+ else
+ IS->relocateNonAlloc(Buf, IS->File->getObj().rels(RelSec));
}
+ return;
+ }
- uintX_t SymVA = getSymVA<ELFT>(*Body);
- if (Target->relocNeedsPlt(Type, *Body)) {
- SymVA = Out<ELFT>::Plt->getEntryAddr(*Body);
- } else if (Target->relocNeedsGot(Type, *Body)) {
- SymVA = Out<ELFT>::Got->getEntryAddr(*Body);
- if (Body->isTls())
- Type = Target->getTlsGotReloc(Type);
- } else if (!Target->needsCopyRel(Type, *Body) &&
- isa<SharedSymbol<ELFT>>(*Body)) {
- continue;
- } else if (Target->isTlsDynReloc(Type, *Body)) {
- continue;
- } else if (Target->isSizeReloc(Type) && canBePreempted(Body, false)) {
- // A SIZE relocation is supposed to set a symbol size, but if a symbol
- // can be preempted, the size at runtime may be different than link time.
- // If that's the case, we leave the field alone rather than filling it
- // with a possibly incorrect value.
- continue;
- } else if (Config->EMachine == EM_MIPS) {
- if (Type == R_MIPS_HI16 && Body == Config->MipsGpDisp)
- SymVA = getMipsGpAddr<ELFT>() - AddrLoc;
- else if (Type == R_MIPS_LO16 && Body == Config->MipsGpDisp)
- SymVA = getMipsGpAddr<ELFT>() - AddrLoc + 4;
+ const unsigned Bits = sizeof(uintX_t) * 8;
+ for (const Relocation<ELFT> &Rel : Relocations) {
+ uintX_t Offset = Rel.InputSec->getOffset(Rel.Offset);
+ uint8_t *BufLoc = Buf + Offset;
+ uint32_t Type = Rel.Type;
+ uintX_t A = Rel.Addend;
+
+ uintX_t AddrLoc = OutSec->getVA() + Offset;
+ RelExpr Expr = Rel.Expr;
+ uint64_t SymVA =
+ SignExtend64<Bits>(getSymVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr));
+
+ switch (Expr) {
+ case R_RELAX_GOT_PC:
+ case R_RELAX_GOT_PC_NOPIC:
+ Target->relaxGot(BufLoc, SymVA);
+ break;
+ case R_RELAX_TLS_IE_TO_LE:
+ Target->relaxTlsIeToLe(BufLoc, Type, SymVA);
+ break;
+ case R_RELAX_TLS_LD_TO_LE:
+ Target->relaxTlsLdToLe(BufLoc, Type, SymVA);
+ break;
+ case R_RELAX_TLS_GD_TO_LE:
+ case R_RELAX_TLS_GD_TO_LE_NEG:
+ Target->relaxTlsGdToLe(BufLoc, Type, SymVA);
+ break;
+ case R_RELAX_TLS_GD_TO_IE:
+ case R_RELAX_TLS_GD_TO_IE_ABS:
+ case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
+ case R_RELAX_TLS_GD_TO_IE_END:
+ Target->relaxTlsGdToIe(BufLoc, Type, SymVA);
+ break;
+ case R_PPC_PLT_OPD:
+ // Patch a nop (0x60000000) to a ld.
+ if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000)
+ write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
+ // fallthrough
+ default:
+ Target->relocateOne(BufLoc, Type, SymVA);
+ break;
}
- uintX_t Size = getSymSize<ELFT>(*Body);
- Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + A, Size + A,
- findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
}
}
template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
if (this->Header->sh_type == SHT_NOBITS)
return;
+ ELFFile<ELFT> &EObj = this->File->getObj();
+
+ // If -r is given, then an InputSection may be a relocation section.
+ if (this->Header->sh_type == SHT_RELA) {
+ copyRelocations(Buf + OutSecOff, EObj.relas(this->Header));
+ return;
+ }
+ if (this->Header->sh_type == SHT_REL) {
+ copyRelocations(Buf + OutSecOff, EObj.rels(this->Header));
+ return;
+ }
+
// Copy section contents from source object file to output file.
ArrayRef<uint8_t> Data = this->getSectionData();
memcpy(Buf + OutSecOff, Data.data(), Data.size());
- ELFFile<ELFT> &EObj = this->File->getObj();
- uint8_t *BufEnd = Buf + OutSecOff + Data.size();
// Iterate over all relocation sections that apply to this section.
- for (const Elf_Shdr *RelSec : this->RelocSections) {
- if (RelSec->sh_type == SHT_RELA)
- this->relocate(Buf, BufEnd, EObj.relas(RelSec));
- else
- this->relocate(Buf, BufEnd, EObj.rels(RelSec));
+ uint8_t *BufEnd = Buf + OutSecOff + Data.size();
+ this->relocate(Buf, BufEnd);
+
+ // The section might have a data/code generated by the linker and need
+ // to be written after the section. Usually these are thunks - small piece
+ // of code used to jump between "incompatible" functions like PIC and non-PIC
+ // or if the jump target too far and its address does not fit to the short
+ // jump istruction.
+ if (!Thunks.empty()) {
+ Buf += OutSecOff + getThunkOff();
+ for (const Thunk<ELFT> *T : Thunks) {
+ T->writeTo(Buf);
+ Buf += T->size();
+ }
}
}
template <class ELFT>
+void InputSection<ELFT>::replace(InputSection<ELFT> *Other) {
+ this->Alignment = std::max(this->Alignment, Other->Alignment);
+ Other->Repl = this->Repl;
+ Other->Live = false;
+}
+
+template <class ELFT>
SplitInputSection<ELFT>::SplitInputSection(
- ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+ elf::ObjectFile<ELFT> *File, const Elf_Shdr *Header,
typename InputSectionBase<ELFT>::Kind SectionKind)
: InputSectionBase<ELFT>(File, Header, SectionKind) {}
template <class ELFT>
-EHInputSection<ELFT>::EHInputSection(ObjectFile<ELFT> *F,
+EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F,
const Elf_Shdr *Header)
: SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::EHFrame) {
// Mark .eh_frame sections as live by default because there are
// usually no relocations that point to .eh_frames. Otherwise,
- // the garbage collector would drop all .eh_frame sections.
+ // the garbage collector would drop all .eh_frame sections.
this->Live = true;
}
template <class ELFT>
-bool EHInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+bool EhInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
}
+// .eh_frame is a sequence of CIE or FDE records.
+// This function splits an input section into records and returns them.
+template <class ELFT>
+void EhInputSection<ELFT>::split() {
+ ArrayRef<uint8_t> Data = this->getSectionData();
+ for (size_t Off = 0, End = Data.size(); Off != End;) {
+ size_t Size = readEhRecordSize<ELFT>(Data.slice(Off));
+ this->Pieces.emplace_back(Off, Data.slice(Off, Size));
+ // The empty record is the end marker.
+ if (Size == 4)
+ break;
+ Off += Size;
+ }
+}
+
template <class ELFT>
-typename EHInputSection<ELFT>::uintX_t
-EHInputSection<ELFT>::getOffset(uintX_t Offset) {
+typename ELFT::uint EhInputSection<ELFT>::getOffset(uintX_t Offset) const {
// The file crtbeginT.o has relocations pointing to the start of an empty
// .eh_frame that is known to be the first in the link. It does that to
// identify the start of the output .eh_frame. Handle this special case.
if (this->getSectionHdr()->sh_size == 0)
return Offset;
- std::pair<uintX_t, uintX_t> *I = this->getRangeAndSize(Offset).first;
- uintX_t Base = I->second;
- if (Base == uintX_t(-1))
+ const SectionPiece *Piece = this->getSectionPiece(Offset);
+ if (Piece->OutputOff == size_t(-1))
return -1; // Not in the output
- uintX_t Addend = Offset - I->first;
- return Base + Addend;
+ uintX_t Addend = Offset - Piece->InputOff;
+ return Piece->OutputOff + Addend;
+}
+
+static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) {
+ // Optimize the common case.
+ StringRef S((const char *)A.data(), A.size());
+ if (EntSize == 1)
+ return S.find(0);
+
+ for (unsigned I = 0, N = S.size(); I != N; I += EntSize) {
+ const char *B = S.begin() + I;
+ if (std::all_of(B, B + EntSize, [](char C) { return C == 0; }))
+ return I;
+ }
+ return StringRef::npos;
+}
+
+// Split SHF_STRINGS section. Such section is a sequence of
+// null-terminated strings.
+static std::vector<SectionPiece> splitStrings(ArrayRef<uint8_t> Data,
+ size_t EntSize) {
+ std::vector<SectionPiece> V;
+ size_t Off = 0;
+ while (!Data.empty()) {
+ size_t End = findNull(Data, EntSize);
+ if (End == StringRef::npos)
+ fatal("string is not null terminated");
+ size_t Size = End + EntSize;
+ V.emplace_back(Off, Data.slice(0, Size));
+ Data = Data.slice(Size);
+ Off += Size;
+ }
+ return V;
+}
+
+// Split non-SHF_STRINGS section. Such section is a sequence of
+// fixed size records.
+static std::vector<SectionPiece> splitNonStrings(ArrayRef<uint8_t> Data,
+ size_t EntSize) {
+ std::vector<SectionPiece> V;
+ size_t Size = Data.size();
+ assert((Size % EntSize) == 0);
+ for (unsigned I = 0, N = Size; I != N; I += EntSize)
+ V.emplace_back(I, Data.slice(I, EntSize));
+ return V;
}
template <class ELFT>
-MergeInputSection<ELFT>::MergeInputSection(ObjectFile<ELFT> *F,
+MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F,
const Elf_Shdr *Header)
: SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::Merge) {}
+template <class ELFT> void MergeInputSection<ELFT>::splitIntoPieces() {
+ ArrayRef<uint8_t> Data = this->getSectionData();
+ uintX_t EntSize = this->Header->sh_entsize;
+ if (this->Header->sh_flags & SHF_STRINGS)
+ this->Pieces = splitStrings(Data, EntSize);
+ else
+ this->Pieces = splitNonStrings(Data, EntSize);
+
+ if (Config->GcSections)
+ for (uintX_t Off : LiveOffsets)
+ this->getSectionPiece(Off)->Live = true;
+}
+
template <class ELFT>
bool MergeInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
return S->SectionKind == InputSectionBase<ELFT>::Merge;
}
+// Do binary search to get a section piece at a given input offset.
template <class ELFT>
-std::pair<std::pair<typename ELFFile<ELFT>::uintX_t,
- typename ELFFile<ELFT>::uintX_t> *,
- typename ELFFile<ELFT>::uintX_t>
-SplitInputSection<ELFT>::getRangeAndSize(uintX_t Offset) {
+SectionPiece *SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) {
+ auto *This = static_cast<const SplitInputSection<ELFT> *>(this);
+ return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
+}
+
+template <class ELFT>
+const SectionPiece *
+SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
ArrayRef<uint8_t> D = this->getSectionData();
StringRef Data((const char *)D.data(), D.size());
uintX_t Size = Data.size();
if (Offset >= Size)
- error("Entry is past the end of the section");
+ fatal("entry is past the end of the section");
// Find the element this offset points to.
auto I = std::upper_bound(
- Offsets.begin(), Offsets.end(), Offset,
- [](const uintX_t &A, const std::pair<uintX_t, uintX_t> &B) {
- return A < B.first;
- });
- uintX_t End = I == Offsets.end() ? Data.size() : I->first;
+ Pieces.begin(), Pieces.end(), Offset,
+ [](const uintX_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
- return std::make_pair(&*I, End);
+ return &*I;
}
+// Returns the offset in an output section for a given input offset.
+// Because contents of a mergeable section is not contiguous in output,
+// it is not just an addition to a base output offset.
template <class ELFT>
-typename MergeInputSection<ELFT>::uintX_t
-MergeInputSection<ELFT>::getOffset(uintX_t Offset) {
- std::pair<std::pair<uintX_t, uintX_t> *, uintX_t> T =
- this->getRangeAndSize(Offset);
- std::pair<uintX_t, uintX_t> *I = T.first;
- uintX_t End = T.second;
- uintX_t Start = I->first;
-
- // Compute the Addend and if the Base is cached, return.
- uintX_t Addend = Offset - Start;
- uintX_t &Base = I->second;
- if (Base != uintX_t(-1))
- return Base + Addend;
-
- // Map the base to the offset in the output section and cache it.
- ArrayRef<uint8_t> D = this->getSectionData();
- StringRef Data((const char *)D.data(), D.size());
- StringRef Entry = Data.substr(Start, End - Start);
- Base =
- static_cast<MergeOutputSection<ELFT> *>(this->OutSec)->getOffset(Entry);
- return Base + Addend;
+typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+ auto It = OffsetMap.find(Offset);
+ if (It != OffsetMap.end())
+ return It->second;
+
+ // If Offset is not at beginning of a section piece, it is not in the map.
+ // In that case we need to search from the original section piece vector.
+ const SectionPiece &Piece = *this->getSectionPiece(Offset);
+ assert(Piece.Live);
+ uintX_t Addend = Offset - Piece.InputOff;
+ return Piece.OutputOff + Addend;
+}
+
+// Create a map from input offsets to output offsets for all section pieces.
+// It is called after finalize().
+template <class ELFT> void MergeInputSection<ELFT>::finalizePieces() {
+ OffsetMap.grow(this->Pieces.size());
+ for (SectionPiece &Piece : this->Pieces) {
+ if (!Piece.Live)
+ continue;
+ if (Piece.OutputOff == size_t(-1)) {
+ // Offsets of tail-merged strings are computed lazily.
+ auto *OutSec = static_cast<MergeOutputSection<ELFT> *>(this->OutSec);
+ ArrayRef<uint8_t> D = Piece.data();
+ StringRef S((const char *)D.data(), D.size());
+ Piece.OutputOff = OutSec->getOffset(S);
+ }
+ OffsetMap[Piece.InputOff] = Piece.OutputOff;
+ }
}
template <class ELFT>
-MipsReginfoInputSection<ELFT>::MipsReginfoInputSection(ObjectFile<ELFT> *F,
+MipsReginfoInputSection<ELFT>::MipsReginfoInputSection(elf::ObjectFile<ELFT> *F,
const Elf_Shdr *Hdr)
: InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsReginfo) {
// Initialize this->Reginfo.
ArrayRef<uint8_t> D = this->getSectionData();
- if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>))
- error("Invalid size of .reginfo section");
+ if (D.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) {
+ error("invalid size of .reginfo section");
+ return;
+ }
Reginfo = reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>(D.data());
}
@@ -366,31 +625,67 @@ bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;
}
-namespace lld {
-namespace elf2 {
-template class InputSectionBase<object::ELF32LE>;
-template class InputSectionBase<object::ELF32BE>;
-template class InputSectionBase<object::ELF64LE>;
-template class InputSectionBase<object::ELF64BE>;
-
-template class InputSection<object::ELF32LE>;
-template class InputSection<object::ELF32BE>;
-template class InputSection<object::ELF64LE>;
-template class InputSection<object::ELF64BE>;
-
-template class EHInputSection<object::ELF32LE>;
-template class EHInputSection<object::ELF32BE>;
-template class EHInputSection<object::ELF64LE>;
-template class EHInputSection<object::ELF64BE>;
-
-template class MergeInputSection<object::ELF32LE>;
-template class MergeInputSection<object::ELF32BE>;
-template class MergeInputSection<object::ELF64LE>;
-template class MergeInputSection<object::ELF64BE>;
-
-template class MipsReginfoInputSection<object::ELF32LE>;
-template class MipsReginfoInputSection<object::ELF32BE>;
-template class MipsReginfoInputSection<object::ELF64LE>;
-template class MipsReginfoInputSection<object::ELF64BE>;
+template <class ELFT>
+MipsOptionsInputSection<ELFT>::MipsOptionsInputSection(elf::ObjectFile<ELFT> *F,
+ const Elf_Shdr *Hdr)
+ : InputSectionBase<ELFT>(F, Hdr, InputSectionBase<ELFT>::MipsOptions) {
+ // Find ODK_REGINFO option in the section's content.
+ ArrayRef<uint8_t> D = this->getSectionData();
+ while (!D.empty()) {
+ if (D.size() < sizeof(Elf_Mips_Options<ELFT>)) {
+ error("invalid size of .MIPS.options section");
+ break;
+ }
+ auto *O = reinterpret_cast<const Elf_Mips_Options<ELFT> *>(D.data());
+ if (O->kind == ODK_REGINFO) {
+ Reginfo = &O->getRegInfo();
+ break;
+ }
+ D = D.slice(O->size);
+ }
}
+
+template <class ELFT>
+bool MipsOptionsInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+ return S->SectionKind == InputSectionBase<ELFT>::MipsOptions;
}
+
+template bool elf::isDiscarded<ELF32LE>(InputSectionBase<ELF32LE> *);
+template bool elf::isDiscarded<ELF32BE>(InputSectionBase<ELF32BE> *);
+template bool elf::isDiscarded<ELF64LE>(InputSectionBase<ELF64LE> *);
+template bool elf::isDiscarded<ELF64BE>(InputSectionBase<ELF64BE> *);
+
+template class elf::InputSectionBase<ELF32LE>;
+template class elf::InputSectionBase<ELF32BE>;
+template class elf::InputSectionBase<ELF64LE>;
+template class elf::InputSectionBase<ELF64BE>;
+
+template class elf::InputSection<ELF32LE>;
+template class elf::InputSection<ELF32BE>;
+template class elf::InputSection<ELF64LE>;
+template class elf::InputSection<ELF64BE>;
+
+template class elf::SplitInputSection<ELF32LE>;
+template class elf::SplitInputSection<ELF32BE>;
+template class elf::SplitInputSection<ELF64LE>;
+template class elf::SplitInputSection<ELF64BE>;
+
+template class elf::EhInputSection<ELF32LE>;
+template class elf::EhInputSection<ELF32BE>;
+template class elf::EhInputSection<ELF64LE>;
+template class elf::EhInputSection<ELF64BE>;
+
+template class elf::MergeInputSection<ELF32LE>;
+template class elf::MergeInputSection<ELF32BE>;
+template class elf::MergeInputSection<ELF64LE>;
+template class elf::MergeInputSection<ELF64BE>;
+
+template class elf::MipsReginfoInputSection<ELF32LE>;
+template class elf::MipsReginfoInputSection<ELF32BE>;
+template class elf::MipsReginfoInputSection<ELF64LE>;
+template class elf::MipsReginfoInputSection<ELF64BE>;
+
+template class elf::MipsOptionsInputSection<ELF32LE>;
+template class elf::MipsOptionsInputSection<ELF32BE>;
+template class elf::MipsOptionsInputSection<ELF64LE>;
+template class elf::MipsOptionsInputSection<ELF64BE>;
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 26956c72a960..61a89c540c5d 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -11,12 +11,22 @@
#define LLD_ELF_INPUT_SECTION_H
#include "Config.h"
+#include "Relocations.h"
+#include "Thunks.h"
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Object/ELF.h"
namespace lld {
-namespace elf2 {
+namespace elf {
+template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S);
+
+class SymbolBody;
+
+template <class ELFT> class ICF;
+template <class ELFT> class DefinedRegular;
template <class ELFT> class ObjectFile;
template <class ELFT> class OutputSection;
template <class ELFT> class OutputSectionBase;
@@ -24,120 +34,148 @@ template <class ELFT> class OutputSectionBase;
// This corresponds to a section of an input file.
template <class ELFT> class InputSectionBase {
protected:
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ 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;
const Elf_Shdr *Header;
// The file this section is from.
ObjectFile<ELFT> *File;
+ // If a section is compressed, this vector has uncompressed section data.
+ SmallVector<char, 0> Uncompressed;
+
public:
- enum Kind { Regular, EHFrame, Merge, MipsReginfo };
+ enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions };
Kind SectionKind;
+ InputSectionBase() : Repl(this) {}
+
InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
Kind SectionKind);
OutputSectionBase<ELFT> *OutSec = nullptr;
+ uint32_t Alignment;
// Used for garbage collection.
- // Live bit makes sense only when Config->GcSections is true.
- bool isLive() const { return !Config->GcSections || Live; }
- bool Live = false;
+ bool Live;
+
+ // This pointer points to the "real" instance of this instance.
+ // Usually Repl == this. However, if ICF merges two sections,
+ // 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;
// Returns the size of this section (even if this is a common or BSS.)
- size_t getSize() const { return Header->sh_size; }
+ size_t getSize() const;
static InputSectionBase<ELFT> Discarded;
StringRef getSectionName() const;
const Elf_Shdr *getSectionHdr() const { return Header; }
ObjectFile<ELFT> *getFile() const { return File; }
-
- // The writer sets and uses the addresses.
- uintX_t getAlign() {
- // The ELF spec states that a value of 0 means the section has no alignment
- // constraits.
- return std::max<uintX_t>(Header->sh_addralign, 1);
- }
-
- uintX_t getOffset(const Elf_Sym &Sym);
+ uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
// Translate an offset in the input section to an offset in the output
// section.
- uintX_t getOffset(uintX_t Offset);
+ uintX_t getOffset(uintX_t Offset) const;
ArrayRef<uint8_t> getSectionData() const;
- // Returns a section that Rel is pointing to. Used by the garbage collector.
- InputSectionBase<ELFT> *getRelocTarget(const Elf_Rel &Rel);
- InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel);
+ void uncompress();
+
+ void relocate(uint8_t *Buf, uint8_t *BufEnd);
+ std::vector<Relocation<ELFT>> Relocations;
+
+ bool Compressed;
+};
+
+template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;
+
+// SectionPiece represents a piece of splittable section contents.
+struct SectionPiece {
+ SectionPiece(size_t Off, ArrayRef<uint8_t> Data)
+ : InputOff(Off), Data((const uint8_t *)Data.data()), Size(Data.size()),
+ Live(!Config->GcSections) {}
- template <bool isRela>
- using RelIteratorRange =
- llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, isRela> *>;
+ ArrayRef<uint8_t> data() { return {Data, Size}; }
+ size_t size() const { return Size; }
- template <bool isRela>
- void relocate(uint8_t *Buf, uint8_t *BufEnd, RelIteratorRange<isRela> Rels);
+ size_t InputOff;
+ size_t OutputOff = -1;
private:
- template <bool isRela>
- uint8_t *findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex, uint32_t Type,
- RelIteratorRange<isRela> Rels);
-};
+ // We use bitfields because SplitInputSection is accessed by
+ // std::upper_bound very often.
+ // We want to save bits to make it cache friendly.
+ const uint8_t *Data;
+ uint32_t Size : 31;
-template <class ELFT>
-InputSectionBase<ELFT>
- InputSectionBase<ELFT>::Discarded(nullptr, nullptr,
- InputSectionBase<ELFT>::Regular);
+public:
+ uint32_t Live : 1;
+};
// Usually sections are copied to the output as atomic chunks of data,
// but some special types of sections are split into small pieces of data
// and each piece is copied to a different place in the output.
// This class represents such special sections.
template <class ELFT> class SplitInputSection : public InputSectionBase<ELFT> {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::uint uintX_t;
public:
SplitInputSection(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
typename InputSectionBase<ELFT>::Kind SectionKind);
- // For each piece of data, we maintain the offsets in the input section and
- // in the output section. The latter may be -1 if it is not assigned yet.
- std::vector<std::pair<uintX_t, uintX_t>> Offsets;
+ // Splittable sections are handled as a sequence of data
+ // rather than a single large blob of data.
+ std::vector<SectionPiece> Pieces;
- std::pair<std::pair<uintX_t, uintX_t> *, uintX_t>
- getRangeAndSize(uintX_t Offset);
+ // Returns the SectionPiece at a given input section offset.
+ SectionPiece *getSectionPiece(uintX_t Offset);
+ const SectionPiece *getSectionPiece(uintX_t Offset) const;
};
// This corresponds to a SHF_MERGE section of an input file.
template <class ELFT> class MergeInputSection : public SplitInputSection<ELFT> {
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename ELFT::uint uintX_t;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::Shdr Elf_Shdr;
public:
MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
static bool classof(const InputSectionBase<ELFT> *S);
- // Translate an offset in the input section to an offset in the output
- // section.
- uintX_t getOffset(uintX_t Offset);
+ void splitIntoPieces();
+
+ // Mark the piece at a given offset live. Used by GC.
+ void markLiveAt(uintX_t Offset) { LiveOffsets.insert(Offset); }
+
+ // Translate an offset in the input section to an offset
+ // in the output section.
+ uintX_t getOffset(uintX_t Offset) const;
+
+ void finalizePieces();
+
+private:
+ llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
+ llvm::DenseSet<uintX_t> LiveOffsets;
};
// This corresponds to a .eh_frame section of an input file.
-template <class ELFT> class EHInputSection : public SplitInputSection<ELFT> {
+template <class ELFT> class EhInputSection : public SplitInputSection<ELFT> {
public:
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
- EHInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::uint uintX_t;
+ EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
static bool classof(const InputSectionBase<ELFT> *S);
+ void split();
// Translate an offset in the input section to an offset in the output
// section.
- uintX_t getOffset(uintX_t Offset);
+ uintX_t getOffset(uintX_t Offset) const;
// Relocation section that refer to this one.
const Elf_Shdr *RelocSection = nullptr;
@@ -145,12 +183,13 @@ public:
// This corresponds to a non SHF_MERGE section of an input file.
template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
+ friend ICF<ELFT>;
typedef InputSectionBase<ELFT> Base;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ 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;
public:
InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
@@ -160,13 +199,41 @@ public:
void writeTo(uint8_t *Buf);
// Relocation sections that refer to this one.
- SmallVector<const Elf_Shdr *, 1> RelocSections;
+ llvm::TinyPtrVector<const Elf_Shdr *> RelocSections;
// The offset from beginning of the output sections this section was assigned
// to. The writer sets a value.
uint64_t OutSecOff = 0;
static bool classof(const InputSectionBase<ELFT> *S);
+
+ 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>
+ void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
+
+private:
+ template <class RelTy>
+ void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
+
+ // Called by ICF to merge two input sections.
+ void replace(InputSection<ELFT> *Other);
+
+ // Used by ICF.
+ uint64_t GroupId = 0;
+
+ llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks;
};
// MIPS .reginfo section provides information on the registers used by the code
@@ -177,16 +244,27 @@ public:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
template <class ELFT>
class MipsReginfoInputSection : public InputSectionBase<ELFT> {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename ELFT::Shdr Elf_Shdr;
public:
MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr);
static bool classof(const InputSectionBase<ELFT> *S);
- const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo;
+ const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr;
+};
+
+template <class ELFT>
+class MipsOptionsInputSection : public InputSectionBase<ELFT> {
+ typedef typename ELFT::Shdr Elf_Shdr;
+
+public:
+ MipsOptionsInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr);
+ static bool classof(const InputSectionBase<ELFT> *S);
+
+ const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr;
};
-} // namespace elf2
+} // namespace elf
} // namespace lld
#endif
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
new file mode 100644
index 000000000000..0e8006a3b32a
--- /dev/null
+++ b/ELF/LTO.cpp
@@ -0,0 +1,325 @@
+//===- 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 "Driver.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/Analysis/LoopPassManager.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/CodeGen/ParallelCG.h"
+#include "llvm/IR/AutoUpgrade.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/LTO/legacy/UpdateCompilerUsed.h"
+#include "llvm/Linker/IRMover.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+// This is for use when debugging LTO.
+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);
+ OS << Buffer;
+}
+
+// This is for use when debugging LTO.
+static void saveBCFile(Module &M, 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);
+ WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true);
+}
+
+static void runNewCustomLtoPasses(Module &M, TargetMachine &TM) {
+ PassBuilder PB(&TM);
+
+ AAManager AA;
+
+ // Parse a custom AA pipeline if asked to.
+ if (!PB.parseAAPipeline(AA, Config->LtoAAPipeline)) {
+ error("Unable to parse AA pipeline description: " + Config->LtoAAPipeline);
+ return;
+ }
+
+ LoopAnalysisManager LAM;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+
+ // Register the AA manager first so that our version is the one used.
+ FAM.registerPass([&] { return std::move(AA); });
+
+ // Register all the basic analyses with the managers.
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
+ PB.registerLoopAnalyses(LAM);
+ PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+ ModulePassManager MPM;
+ if (!Config->DisableVerify)
+ MPM.addPass(VerifierPass());
+
+ // Now, add all the passes we've been requested to.
+ if (!PB.parsePassPipeline(MPM, Config->LtoNewPmPasses)) {
+ error("unable to parse pass pipeline description: " +
+ Config->LtoNewPmPasses);
+ return;
+ }
+
+ if (!Config->DisableVerify)
+ MPM.addPass(VerifierPass());
+ MPM.run(M, MAM);
+}
+
+static void runOldLtoPasses(Module &M, TargetMachine &TM) {
+ // Note that the gold plugin has a similar piece of code, so
+ // it is probably better to move this code to a common place.
+ legacy::PassManager LtoPasses;
+ LtoPasses.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
+ PassManagerBuilder PMB;
+ PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple()));
+ PMB.Inliner = createFunctionInliningPass();
+ PMB.VerifyInput = PMB.VerifyOutput = !Config->DisableVerify;
+ PMB.LoopVectorize = true;
+ PMB.SLPVectorize = true;
+ PMB.OptLevel = Config->LtoO;
+ PMB.populateLTOPassManager(LtoPasses);
+ LtoPasses.run(M);
+}
+
+static void runLTOPasses(Module &M, TargetMachine &TM) {
+ if (!Config->LtoNewPmPasses.empty()) {
+ // The user explicitly asked for a set of passes to be run.
+ // This needs the new PM to work as there's no clean way to
+ // pass a set of passes to run in the legacy PM.
+ runNewCustomLtoPasses(M, TM);
+ if (HasError)
+ return;
+ } else {
+ // Run the 'default' set of LTO passes. This code still uses
+ // the legacy PM as the new one is not the default.
+ runOldLtoPasses(M, TM);
+ }
+
+ if (Config->SaveTemps)
+ saveBCFile(M, Config->OutputFile + ".lto.opt.bc");
+}
+
+static bool shouldInternalize(const SmallPtrSet<GlobalValue *, 8> &Used,
+ Symbol *S, GlobalValue *GV) {
+ if (S->IsUsedInRegularObj || Used.count(GV))
+ return false;
+ return !S->includeInDynsym();
+}
+
+BitcodeCompiler::BitcodeCompiler()
+ : Combined(new Module("ld-temp.o", Driver->Context)) {}
+
+static void undefine(Symbol *S) {
+ replaceBody<Undefined>(S, S->body()->getName(), STV_DEFAULT, S->body()->Type,
+ nullptr);
+}
+
+static void handleUndefinedAsmRefs(const BasicSymbolRef &Sym, GlobalValue *GV,
+ StringSet<> &AsmUndefinedRefs) {
+ // GV associated => not an assembly symbol, bail out.
+ if (GV)
+ return;
+
+ // This is an undefined reference to a symbol in asm. We put that in
+ // compiler.used, so that we can preserve it from being dropped from
+ // the output, without necessarily preventing its internalization.
+ SmallString<64> Name;
+ raw_svector_ostream OS(Name);
+ Sym.printName(OS);
+ AsmUndefinedRefs.insert(Name.str());
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+ std::unique_ptr<IRObjectFile> Obj = std::move(F.Obj);
+ std::vector<GlobalValue *> Keep;
+ unsigned BodyIndex = 0;
+ ArrayRef<Symbol *> Syms = F.getSymbols();
+
+ Module &M = Obj->getModule();
+ if (M.getDataLayoutStr().empty())
+ fatal("invalid bitcode file: " + F.getName() + " has no datalayout");
+
+ // Discard non-compatible debug infos if necessary.
+ M.materializeMetadata();
+ UpgradeDebugInfo(M);
+
+ // If a symbol appears in @llvm.used, the linker is required
+ // to treat the symbol as there is a reference to the symbol
+ // that it cannot see. Therefore, we can't internalize.
+ SmallPtrSet<GlobalValue *, 8> Used;
+ collectUsedGlobalVariables(M, Used, /* CompilerUsed */ false);
+
+ for (const BasicSymbolRef &Sym : Obj->symbols()) {
+ uint32_t Flags = Sym.getFlags();
+ GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl());
+ if (GV && GV->hasAppendingLinkage())
+ Keep.push_back(GV);
+ if (BitcodeFile::shouldSkip(Flags))
+ continue;
+ Symbol *S = Syms[BodyIndex++];
+ if (Flags & BasicSymbolRef::SF_Undefined) {
+ handleUndefinedAsmRefs(Sym, GV, AsmUndefinedRefs);
+ continue;
+ }
+ auto *B = dyn_cast<DefinedBitcode>(S->body());
+ if (!B || B->file() != &F)
+ continue;
+
+ // We collect the set of symbols we want to internalize here
+ // and change the linkage after the IRMover executed, i.e. after
+ // we imported the symbols and satisfied undefined references
+ // to it. We can't just change linkage here because otherwise
+ // the IRMover will just rename the symbol.
+ if (GV && shouldInternalize(Used, S, GV))
+ InternalizedSyms.insert(GV->getName());
+
+ // At this point we know that either the combined LTO object will provide a
+ // definition of a symbol, or we will internalize it. In either case, we
+ // need to undefine the symbol. In the former case, the real definition
+ // needs to be able to replace the original definition without conflicting.
+ // In the latter case, we need to allow the combined LTO object to provide a
+ // definition with the same name, for example when doing parallel codegen.
+ undefine(S);
+
+ if (!GV)
+ // Module asm symbol.
+ continue;
+
+ switch (GV->getLinkage()) {
+ default:
+ break;
+ case GlobalValue::LinkOnceAnyLinkage:
+ GV->setLinkage(GlobalValue::WeakAnyLinkage);
+ break;
+ case GlobalValue::LinkOnceODRLinkage:
+ GV->setLinkage(GlobalValue::WeakODRLinkage);
+ break;
+ }
+
+ Keep.push_back(GV);
+ }
+
+ IRMover Mover(*Combined);
+ if (Error E = Mover.move(Obj->takeModule(), Keep,
+ [](GlobalValue &, IRMover::ValueAdder) {})) {
+ handleAllErrors(std::move(E), [&](const ErrorInfoBase &EIB) {
+ fatal("failed to link module " + F.getName() + ": " + EIB.message());
+ });
+ }
+}
+
+static void internalize(GlobalValue &GV) {
+ assert(!GV.hasLocalLinkage() &&
+ "Trying to internalize a symbol with local linkage!");
+ GV.setLinkage(GlobalValue::InternalLinkage);
+}
+
+std::vector<std::unique_ptr<InputFile>> BitcodeCompiler::runSplitCodegen(
+ const std::function<std::unique_ptr<TargetMachine>()> &TMFactory) {
+ unsigned NumThreads = Config->LtoJobs;
+ OwningData.resize(NumThreads);
+
+ std::list<raw_svector_ostream> OSs;
+ std::vector<raw_pwrite_stream *> OSPtrs;
+ for (SmallString<0> &Obj : OwningData) {
+ OSs.emplace_back(Obj);
+ OSPtrs.push_back(&OSs.back());
+ }
+
+ splitCodeGen(std::move(Combined), OSPtrs, {}, TMFactory);
+
+ std::vector<std::unique_ptr<InputFile>> ObjFiles;
+ for (SmallString<0> &Obj : OwningData)
+ ObjFiles.push_back(createObjectFile(
+ MemoryBufferRef(Obj, "LLD-INTERNAL-combined-lto-object")));
+
+ // If -save-temps is given, we need to save temporary objects to files.
+ // This is for debugging.
+ if (Config->SaveTemps) {
+ if (NumThreads == 1) {
+ saveBuffer(OwningData[0], Config->OutputFile + ".lto.o");
+ } else {
+ for (unsigned I = 0; I < NumThreads; ++I)
+ saveBuffer(OwningData[I], Config->OutputFile + Twine(I) + ".lto.o");
+ }
+ }
+
+ return ObjFiles;
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting ObjectFile.
+std::vector<std::unique_ptr<InputFile>> BitcodeCompiler::compile() {
+ for (const auto &Name : InternalizedSyms) {
+ GlobalValue *GV = Combined->getNamedValue(Name.first());
+ assert(GV);
+ internalize(*GV);
+ }
+
+ std::string TheTriple = Combined->getTargetTriple();
+ std::string Msg;
+ const Target *T = TargetRegistry::lookupTarget(TheTriple, Msg);
+ if (!T)
+ fatal("target not found: " + Msg);
+
+ // LLD supports the new relocations.
+ TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+ Options.RelaxELFRelocations = true;
+
+ auto CreateTargetMachine = [&]() {
+ return std::unique_ptr<TargetMachine>(T->createTargetMachine(
+ TheTriple, "", "", Options, Config->Pic ? Reloc::PIC_ : Reloc::Static));
+ };
+
+ std::unique_ptr<TargetMachine> TM = CreateTargetMachine();
+
+ // Update llvm.compiler.used so that optimizations won't strip
+ // off AsmUndefinedReferences.
+ updateCompilerUsed(*Combined, *TM, AsmUndefinedRefs);
+
+ if (Config->SaveTemps)
+ saveBCFile(*Combined, Config->OutputFile + ".lto.bc");
+
+ runLTOPasses(*Combined, *TM);
+ if (HasError)
+ return {};
+
+ return runSplitCodegen(CreateTargetMachine);
+}
diff --git a/ELF/LTO.h b/ELF/LTO.h
new file mode 100644
index 000000000000..81dffb6004b2
--- /dev/null
+++ b/ELF/LTO.h
@@ -0,0 +1,54 @@
+//===- 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 ELF
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular ELF 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
+// an ELF file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_LTO_H
+#define LLD_ELF_LTO_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Linker/IRMover.h"
+
+namespace lld {
+namespace elf {
+
+class BitcodeFile;
+class InputFile;
+
+class BitcodeCompiler {
+public:
+ BitcodeCompiler();
+ void add(BitcodeFile &F);
+ std::vector<std::unique_ptr<InputFile>> compile();
+
+private:
+ std::vector<std::unique_ptr<InputFile>> runSplitCodegen(
+ const std::function<std::unique_ptr<llvm::TargetMachine>()> &TMFactory);
+
+ std::unique_ptr<llvm::Module> Combined;
+ std::vector<SmallString<0>> OwningData;
+ llvm::StringSet<> InternalizedSyms;
+ llvm::StringSet<> AsmUndefinedRefs;
+};
+}
+}
+
+#endif
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index a6df9ed48cdc..61abdc185e11 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -13,154 +13,366 @@
//
//===----------------------------------------------------------------------===//
+#include "LinkerScript.h"
#include "Config.h"
#include "Driver.h"
+#include "InputSection.h"
+#include "OutputSections.h"
+#include "ScriptParser.h"
+#include "Strings.h"
+#include "Symbols.h"
#include "SymbolTable.h"
+#include "Target.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ELF.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
using namespace lld;
-using namespace lld::elf2;
+using namespace lld::elf;
+ScriptConfiguration *elf::ScriptConfig;
+
+// This is an operator-precedence parser to parse and evaluate
+// a linker script expression. For each linker script arithmetic
+// expression (e.g. ". = . + 0x1000"), a new instance of ExprParser
+// is created and ran.
namespace {
-class LinkerScript {
+class ExprParser : public ScriptParserBase {
public:
- LinkerScript(BumpPtrAllocator *A, StringRef S, bool B)
- : Saver(*A), Tokens(tokenize(S)), IsUnderSysroot(B) {}
- void run();
+ ExprParser(std::vector<StringRef> &Tokens, uint64_t Dot)
+ : ScriptParserBase(Tokens), Dot(Dot) {}
+
+ uint64_t run();
private:
- static std::vector<StringRef> tokenize(StringRef S);
- static StringRef skipSpace(StringRef S);
- StringRef next();
- bool skip(StringRef Tok);
- bool atEOF() { return Tokens.size() == Pos; }
- void expect(StringRef Expect);
+ uint64_t parsePrimary();
+ uint64_t parseTernary(uint64_t Cond);
+ uint64_t apply(StringRef Op, uint64_t L, uint64_t R);
+ uint64_t parseExpr1(uint64_t Lhs, int MinPrec);
+ uint64_t parseExpr();
- void addFile(StringRef Path);
+ uint64_t Dot;
+};
+}
- void readAsNeeded();
- void readEntry();
- void readExtern();
- void readGroup();
- void readInclude();
- void readOutput();
- void readOutputArch();
- void readOutputFormat();
- void readSearchDir();
- void readSections();
+static int precedence(StringRef Op) {
+ return StringSwitch<int>(Op)
+ .Case("*", 4)
+ .Case("/", 4)
+ .Case("+", 3)
+ .Case("-", 3)
+ .Case("<", 2)
+ .Case(">", 2)
+ .Case(">=", 2)
+ .Case("<=", 2)
+ .Case("==", 2)
+ .Case("!=", 2)
+ .Case("&", 1)
+ .Default(-1);
+}
- void readOutputSectionDescription();
+static uint64_t evalExpr(std::vector<StringRef> &Tokens, uint64_t Dot) {
+ return ExprParser(Tokens, Dot).run();
+}
- StringSaver Saver;
- std::vector<StringRef> Tokens;
- size_t Pos = 0;
- bool IsUnderSysroot;
-};
+uint64_t ExprParser::run() {
+ uint64_t V = parseExpr();
+ if (!atEOF() && !Error)
+ setError("stray token: " + peek());
+ return V;
}
-void LinkerScript::run() {
- while (!atEOF()) {
- StringRef Tok = next();
- if (Tok == ";")
- continue;
- if (Tok == "ENTRY") {
- readEntry();
- } else if (Tok == "EXTERN") {
- readExtern();
- } else if (Tok == "GROUP" || Tok == "INPUT") {
- readGroup();
- } else if (Tok == "INCLUDE") {
- readInclude();
- } else if (Tok == "OUTPUT") {
- readOutput();
- } else if (Tok == "OUTPUT_ARCH") {
- readOutputArch();
- } else if (Tok == "OUTPUT_FORMAT") {
- readOutputFormat();
- } else if (Tok == "SEARCH_DIR") {
- readSearchDir();
- } else if (Tok == "SECTIONS") {
- readSections();
- } else {
- error("unknown directive: " + Tok);
+// This is a part of the operator-precedence parser to evaluate
+// arithmetic expressions in SECTIONS command. This function evaluates an
+// integer literal, a parenthesized expression, the ALIGN function,
+// or the special variable ".".
+uint64_t ExprParser::parsePrimary() {
+ StringRef Tok = next();
+ if (Tok == ".")
+ return Dot;
+ if (Tok == "(") {
+ uint64_t V = parseExpr();
+ expect(")");
+ return V;
+ }
+ if (Tok == "ALIGN") {
+ expect("(");
+ uint64_t V = parseExpr();
+ expect(")");
+ return alignTo(Dot, V);
+ }
+ uint64_t V = 0;
+ if (Tok.getAsInteger(0, V))
+ setError("malformed number: " + Tok);
+ return V;
+}
+
+uint64_t ExprParser::parseTernary(uint64_t Cond) {
+ next();
+ uint64_t V = parseExpr();
+ expect(":");
+ uint64_t W = parseExpr();
+ return Cond ? V : W;
+}
+
+uint64_t ExprParser::apply(StringRef Op, uint64_t L, uint64_t R) {
+ if (Op == "*")
+ return L * R;
+ if (Op == "/") {
+ if (R == 0) {
+ error("division by zero");
+ return 0;
}
+ return L / R;
}
+ if (Op == "+")
+ return L + R;
+ if (Op == "-")
+ return L - R;
+ if (Op == "<")
+ return L < R;
+ if (Op == ">")
+ return L > R;
+ if (Op == ">=")
+ return L >= R;
+ if (Op == "<=")
+ return L <= R;
+ if (Op == "==")
+ return L == R;
+ if (Op == "!=")
+ return L != R;
+ if (Op == "&")
+ return L & R;
+ llvm_unreachable("invalid operator");
}
-// Split S into linker script tokens.
-std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
- std::vector<StringRef> Ret;
- for (;;) {
- S = skipSpace(S);
- if (S.empty())
- return Ret;
-
- // Quoted token
- if (S.startswith("\"")) {
- size_t E = S.find("\"", 1);
- if (E == StringRef::npos)
- error("unclosed quote");
- Ret.push_back(S.substr(1, E));
- S = S.substr(E + 1);
- continue;
+// This is a part of the operator-precedence parser.
+// This function assumes that the remaining token stream starts
+// with an operator.
+uint64_t ExprParser::parseExpr1(uint64_t Lhs, int MinPrec) {
+ while (!atEOF()) {
+ // Read an operator and an expression.
+ StringRef Op1 = peek();
+ if (Op1 == "?")
+ return parseTernary(Lhs);
+ if (precedence(Op1) < MinPrec)
+ return Lhs;
+ next();
+ uint64_t Rhs = parsePrimary();
+
+ // Evaluate the remaining part of the expression first if the
+ // next operator has greater precedence than the previous one.
+ // For example, if we have read "+" and "3", and if the next
+ // operator is "*", then we'll evaluate 3 * ... part first.
+ while (!atEOF()) {
+ StringRef Op2 = peek();
+ if (precedence(Op2) <= precedence(Op1))
+ break;
+ Rhs = parseExpr1(Rhs, precedence(Op2));
}
- // Unquoted token
- 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;
- Ret.push_back(S.substr(0, Pos));
- S = S.substr(Pos);
+ Lhs = apply(Op1, Lhs, Rhs);
}
+ return Lhs;
+}
+
+// Reads and evaluates an arithmetic expression.
+uint64_t ExprParser::parseExpr() { return parseExpr1(parsePrimary(), 0); }
+
+template <class ELFT>
+StringRef LinkerScript<ELFT>::getOutputSection(InputSectionBase<ELFT> *S) {
+ for (SectionRule &R : Opt.Sections)
+ if (globMatch(R.SectionPattern, S->getSectionName()))
+ return R.Dest;
+ return "";
+}
+
+template <class ELFT>
+bool LinkerScript<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) {
+ return getOutputSection(S) == "/DISCARD/";
}
-// Skip leading whitespace characters or /**/-style comments.
-StringRef LinkerScript::skipSpace(StringRef S) {
- for (;;) {
- if (S.startswith("/*")) {
- size_t E = S.find("*/", 2);
- if (E == StringRef::npos)
- error("unclosed comment in a linker script");
- S = S.substr(E + 2);
+template <class ELFT>
+bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
+ for (StringRef Pat : Opt.KeptSections)
+ if (globMatch(Pat, S->getSectionName()))
+ return true;
+ return false;
+}
+
+template <class ELFT>
+void LinkerScript<ELFT>::assignAddresses(
+ ArrayRef<OutputSectionBase<ELFT> *> Sections) {
+ // Orphan sections are sections present in the input files which
+ // are not explicitly placed into the output file by the linker script.
+ // We place orphan sections at end of file.
+ // Other linkers places them using some heuristics as described in
+ // https://sourceware.org/binutils/docs/ld/Orphan-Sections.html#Orphan-Sections.
+ for (OutputSectionBase<ELFT> *Sec : Sections) {
+ StringRef Name = Sec->getName();
+ if (getSectionIndex(Name) == INT_MAX)
+ Opt.Commands.push_back({SectionKind, {}, Name});
+ }
+
+ // Assign addresses as instructed by linker script SECTIONS sub-commands.
+ Dot = Out<ELFT>::ElfHeader->getSize() + Out<ELFT>::ProgramHeaders->getSize();
+ uintX_t MinVA = std::numeric_limits<uintX_t>::max();
+ uintX_t ThreadBssOffset = 0;
+
+ for (SectionsCommand &Cmd : Opt.Commands) {
+ if (Cmd.Kind == AssignmentKind) {
+ uint64_t Val = evalExpr(Cmd.Expr, Dot);
+
+ if (Cmd.Name == ".") {
+ Dot = Val;
+ } else {
+ auto *D = cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd.Name));
+ D->Value = Val;
+ }
continue;
}
- size_t Size = S.size();
- S = S.ltrim();
- if (S.size() == Size)
- return S;
+
+ // Find all the sections with required name. There can be more than
+ // ont section with such name, if the alignment, flags or type
+ // attribute differs.
+ assert(Cmd.Kind == SectionKind);
+ for (OutputSectionBase<ELFT> *Sec : Sections) {
+ if (Sec->getName() != Cmd.Name)
+ continue;
+
+ if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) {
+ uintX_t TVA = Dot + ThreadBssOffset;
+ TVA = alignTo(TVA, Sec->getAlignment());
+ Sec->setVA(TVA);
+ ThreadBssOffset = TVA - Dot + Sec->getSize();
+ continue;
+ }
+
+ if (Sec->getFlags() & SHF_ALLOC) {
+ Dot = alignTo(Dot, Sec->getAlignment());
+ Sec->setVA(Dot);
+ MinVA = std::min(MinVA, Dot);
+ Dot += Sec->getSize();
+ continue;
+ }
+ }
}
+
+ // ELF and Program headers need to be right before the first section in
+ // memory.
+ // Set their addresses accordingly.
+ MinVA = alignDown(MinVA - Out<ELFT>::ElfHeader->getSize() -
+ Out<ELFT>::ProgramHeaders->getSize(),
+ Target->PageSize);
+ Out<ELFT>::ElfHeader->setVA(MinVA);
+ Out<ELFT>::ProgramHeaders->setVA(Out<ELFT>::ElfHeader->getSize() + MinVA);
}
-StringRef LinkerScript::next() {
- if (atEOF())
- error("unexpected EOF");
- return Tokens[Pos++];
+template <class ELFT>
+ArrayRef<uint8_t> LinkerScript<ELFT>::getFiller(StringRef Name) {
+ auto I = Opt.Filler.find(Name);
+ if (I == Opt.Filler.end())
+ return {};
+ return I->second;
}
-bool LinkerScript::skip(StringRef Tok) {
- if (atEOF())
- error("unexpected EOF");
- if (Tok != Tokens[Pos])
- return false;
- ++Pos;
- return true;
+// Returns the index of the given section name in linker script
+// SECTIONS commands. Sections are laid out as the same order as they
+// were in the script. If a given name did not appear in the script,
+// it returns INT_MAX, so that it will be laid out at end of file.
+template <class ELFT>
+int LinkerScript<ELFT>::getSectionIndex(StringRef Name) {
+ auto Begin = Opt.Commands.begin();
+ auto End = Opt.Commands.end();
+ auto I = std::find_if(Begin, End, [&](SectionsCommand &N) {
+ return N.Kind == SectionKind && N.Name == Name;
+ });
+ return I == End ? INT_MAX : (I - Begin);
}
-void LinkerScript::expect(StringRef Expect) {
- StringRef Tok = next();
- if (Tok != Expect)
- error(Expect + " expected, but got " + Tok);
+// A compartor to sort output sections. Returns -1 or 1 if
+// A or B are mentioned in linker script. Otherwise, returns 0.
+template <class ELFT>
+int LinkerScript<ELFT>::compareSections(StringRef A, StringRef B) {
+ int I = getSectionIndex(A);
+ int J = getSectionIndex(B);
+ if (I == INT_MAX && J == INT_MAX)
+ return 0;
+ return I < J ? -1 : 1;
+}
+
+template <class ELFT>
+void LinkerScript<ELFT>::addScriptedSymbols() {
+ for (SectionsCommand &Cmd : Opt.Commands)
+ if (Cmd.Kind == AssignmentKind)
+ if (Cmd.Name != "." && Symtab<ELFT>::X->find(Cmd.Name) == nullptr)
+ Symtab<ELFT>::X->addAbsolute(Cmd.Name, STV_DEFAULT);
}
-void LinkerScript::addFile(StringRef S) {
+class elf::ScriptParser : public ScriptParserBase {
+ typedef void (ScriptParser::*Handler)();
+
+public:
+ ScriptParser(StringRef S, bool B) : ScriptParserBase(S), IsUnderSysroot(B) {}
+
+ void run();
+
+private:
+ void addFile(StringRef Path);
+
+ void readAsNeeded();
+ void readEntry();
+ void readExtern();
+ void readGroup();
+ void readInclude();
+ void readNothing() {}
+ void readOutput();
+ void readOutputArch();
+ void readOutputFormat();
+ void readSearchDir();
+ void readSections();
+
+ void readLocationCounterValue();
+ void readOutputSectionDescription(StringRef OutSec);
+ void readSymbolAssignment(StringRef Name);
+ std::vector<StringRef> readSectionsCommandExpr();
+
+ const static StringMap<Handler> Cmd;
+ ScriptConfiguration &Opt = *ScriptConfig;
+ StringSaver Saver = {ScriptConfig->Alloc};
+ bool IsUnderSysroot;
+};
+
+const StringMap<elf::ScriptParser::Handler> elf::ScriptParser::Cmd = {
+ {"ENTRY", &ScriptParser::readEntry},
+ {"EXTERN", &ScriptParser::readExtern},
+ {"GROUP", &ScriptParser::readGroup},
+ {"INCLUDE", &ScriptParser::readInclude},
+ {"INPUT", &ScriptParser::readGroup},
+ {"OUTPUT", &ScriptParser::readOutput},
+ {"OUTPUT_ARCH", &ScriptParser::readOutputArch},
+ {"OUTPUT_FORMAT", &ScriptParser::readOutputFormat},
+ {"SEARCH_DIR", &ScriptParser::readSearchDir},
+ {"SECTIONS", &ScriptParser::readSections},
+ {";", &ScriptParser::readNothing}};
+
+void ScriptParser::run() {
+ while (!atEOF()) {
+ StringRef Tok = next();
+ if (Handler Fn = Cmd.lookup(Tok))
+ (this->*Fn)();
+ else
+ setError("unknown directive: " + Tok);
+ }
+}
+
+void ScriptParser::addFile(StringRef S) {
if (IsUnderSysroot && S.startswith("/")) {
SmallString<128> Path;
(Config->Sysroot + S).toStringRef(Path);
@@ -178,22 +390,23 @@ void LinkerScript::addFile(StringRef S) {
else
Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
} else if (S.startswith("-l")) {
- Driver->addFile(searchLibrary(S.substr(2)));
+ Driver->addLibrary(S.substr(2));
} else if (sys::fs::exists(S)) {
Driver->addFile(S);
} else {
std::string Path = findFromSearchPaths(S);
if (Path.empty())
- error("Unable to find " + S);
- Driver->addFile(Saver.save(Path));
+ setError("unable to find " + S);
+ else
+ Driver->addFile(Saver.save(Path));
}
}
-void LinkerScript::readAsNeeded() {
+void ScriptParser::readAsNeeded() {
expect("(");
bool Orig = Config->AsNeeded;
Config->AsNeeded = true;
- for (;;) {
+ while (!Error) {
StringRef Tok = next();
if (Tok == ")")
break;
@@ -202,7 +415,7 @@ void LinkerScript::readAsNeeded() {
Config->AsNeeded = Orig;
}
-void LinkerScript::readEntry() {
+void ScriptParser::readEntry() {
// -e <symbol> takes predecence over ENTRY(<symbol>).
expect("(");
StringRef Tok = next();
@@ -211,9 +424,9 @@ void LinkerScript::readEntry() {
expect(")");
}
-void LinkerScript::readExtern() {
+void ScriptParser::readExtern() {
expect("(");
- for (;;) {
+ while (!Error) {
StringRef Tok = next();
if (Tok == ")")
return;
@@ -221,9 +434,9 @@ void LinkerScript::readExtern() {
}
}
-void LinkerScript::readGroup() {
+void ScriptParser::readGroup() {
expect("(");
- for (;;) {
+ while (!Error) {
StringRef Tok = next();
if (Tok == ")")
return;
@@ -235,17 +448,20 @@ void LinkerScript::readGroup() {
}
}
-void LinkerScript::readInclude() {
+void ScriptParser::readInclude() {
StringRef Tok = next();
auto MBOrErr = MemoryBuffer::getFile(Tok);
- error(MBOrErr, "cannot open " + Tok);
+ if (!MBOrErr) {
+ setError("cannot open " + Tok);
+ return;
+ }
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
std::vector<StringRef> V = tokenize(S);
Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
}
-void LinkerScript::readOutput() {
+void ScriptParser::readOutput() {
// -o <file> takes predecence over OUTPUT(<file>).
expect("(");
StringRef Tok = next();
@@ -254,54 +470,121 @@ void LinkerScript::readOutput() {
expect(")");
}
-void LinkerScript::readOutputArch() {
+void ScriptParser::readOutputArch() {
// Error checking only for now.
expect("(");
next();
expect(")");
}
-void LinkerScript::readOutputFormat() {
+void ScriptParser::readOutputFormat() {
// Error checking only for now.
expect("(");
next();
StringRef Tok = next();
if (Tok == ")")
return;
- if (Tok != ",")
- error("unexpected token: " + Tok);
+ if (Tok != ",") {
+ setError("unexpected token: " + Tok);
+ return;
+ }
next();
expect(",");
next();
expect(")");
}
-void LinkerScript::readSearchDir() {
+void ScriptParser::readSearchDir() {
expect("(");
Config->SearchPaths.push_back(next());
expect(")");
}
-void LinkerScript::readSections() {
+void ScriptParser::readSections() {
+ Opt.DoLayout = true;
expect("{");
- while (!skip("}"))
- readOutputSectionDescription();
+ while (!Error && !skip("}")) {
+ StringRef Tok = peek();
+ if (Tok == ".") {
+ readLocationCounterValue();
+ continue;
+ }
+ next();
+ if (peek() == "=")
+ readSymbolAssignment(Tok);
+ else
+ readOutputSectionDescription(Tok);
+ }
}
-void LinkerScript::readOutputSectionDescription() {
- StringRef Name = next();
- std::vector<StringRef> &InputSections = Config->OutputSections[Name];
+void ScriptParser::readLocationCounterValue() {
+ expect(".");
+ expect("=");
+ std::vector<StringRef> Expr = readSectionsCommandExpr();
+ if (Expr.empty())
+ error("error in location counter expression");
+ else
+ Opt.Commands.push_back({AssignmentKind, std::move(Expr), "."});
+}
+void ScriptParser::readOutputSectionDescription(StringRef OutSec) {
+ Opt.Commands.push_back({SectionKind, {}, OutSec});
expect(":");
expect("{");
- while (!skip("}")) {
- next(); // Skip input file name.
- expect("(");
- while (!skip(")"))
- InputSections.push_back(next());
+
+ while (!Error && !skip("}")) {
+ StringRef Tok = next();
+ if (Tok == "*") {
+ expect("(");
+ while (!Error && !skip(")"))
+ Opt.Sections.emplace_back(OutSec, next());
+ } else if (Tok == "KEEP") {
+ expect("(");
+ expect("*");
+ expect("(");
+ while (!Error && !skip(")")) {
+ StringRef Sec = next();
+ Opt.Sections.emplace_back(OutSec, Sec);
+ Opt.KeptSections.push_back(Sec);
+ }
+ expect(")");
+ } else {
+ setError("unknown command " + Tok);
+ }
+ }
+
+ StringRef Tok = peek();
+ if (Tok.startswith("=")) {
+ if (!Tok.startswith("=0x")) {
+ setError("filler should be a hexadecimal value");
+ return;
+ }
+ Tok = Tok.substr(3);
+ Opt.Filler[OutSec] = parseHex(Tok);
+ next();
}
}
+void ScriptParser::readSymbolAssignment(StringRef Name) {
+ expect("=");
+ std::vector<StringRef> Expr = readSectionsCommandExpr();
+ if (Expr.empty())
+ error("error in symbol assignment expression");
+ else
+ Opt.Commands.push_back({AssignmentKind, std::move(Expr), Name});
+}
+
+std::vector<StringRef> ScriptParser::readSectionsCommandExpr() {
+ std::vector<StringRef> Expr;
+ while (!Error) {
+ StringRef Tok = next();
+ if (Tok == ";")
+ break;
+ Expr.push_back(Tok);
+ }
+ return Expr;
+}
+
static bool isUnderSysroot(StringRef Path) {
if (Config->Sysroot == "")
return false;
@@ -311,8 +594,13 @@ static bool isUnderSysroot(StringRef Path) {
return false;
}
-// Entry point. The other functions or classes are private to this file.
-void elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) {
+// Entry point.
+void elf::readLinkerScript(MemoryBufferRef MB) {
StringRef Path = MB.getBufferIdentifier();
- LinkerScript(A, MB.getBuffer(), isUnderSysroot(Path)).run();
+ ScriptParser(MB.getBuffer(), isUnderSysroot(Path)).run();
}
+
+template class elf::LinkerScript<ELF32LE>;
+template class elf::LinkerScript<ELF32BE>;
+template class elf::LinkerScript<ELF64LE>;
+template class elf::LinkerScript<ELF64BE>;
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
new file mode 100644
index 000000000000..768f78a66468
--- /dev/null
+++ b/ELF/LinkerScript.h
@@ -0,0 +1,103 @@
+//===- LinkerScript.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_LINKER_SCRIPT_H
+#define LLD_ELF_LINKER_SCRIPT_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace lld {
+namespace elf {
+
+// Parses a linker script. Calling this function updates
+// Config and ScriptConfig.
+void readLinkerScript(MemoryBufferRef MB);
+
+class ScriptParser;
+template <class ELFT> class InputSectionBase;
+template <class ELFT> class OutputSectionBase;
+
+// This class represents each rule in SECTIONS command.
+struct SectionRule {
+ SectionRule(StringRef D, StringRef S)
+ : Dest(D), SectionPattern(S) {}
+
+ StringRef Dest;
+
+ StringRef SectionPattern;
+};
+
+// This enum represents what we can observe in SECTIONS tag of script:
+// ExprKind is a location counter change, like ". = . + 0x1000"
+// SectionKind is a description of output section, like ".data :..."
+enum SectionsCommandKind { SectionKind, AssignmentKind };
+
+struct SectionsCommand {
+ SectionsCommandKind Kind;
+ std::vector<StringRef> Expr;
+ StringRef Name;
+};
+
+// ScriptConfiguration holds linker script parse results.
+struct ScriptConfiguration {
+ // SECTIONS commands.
+ std::vector<SectionRule> Sections;
+
+ // Section fill attribute for each section.
+ llvm::StringMap<std::vector<uint8_t>> Filler;
+
+ // Used to assign addresses to sections.
+ std::vector<SectionsCommand> Commands;
+
+ bool DoLayout = false;
+
+ llvm::BumpPtrAllocator Alloc;
+
+ // List of section patterns specified with KEEP commands. They will
+ // be kept even if they are unused and --gc-sections is specified.
+ std::vector<StringRef> KeptSections;
+};
+
+extern ScriptConfiguration *ScriptConfig;
+
+// This is a runner of the linker script.
+template <class ELFT> class LinkerScript {
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ StringRef getOutputSection(InputSectionBase<ELFT> *S);
+ ArrayRef<uint8_t> getFiller(StringRef Name);
+ bool isDiscarded(InputSectionBase<ELFT> *S);
+ bool shouldKeep(InputSectionBase<ELFT> *S);
+ void assignAddresses(ArrayRef<OutputSectionBase<ELFT> *> S);
+ int compareSections(StringRef A, StringRef B);
+ void addScriptedSymbols();
+
+private:
+ // "ScriptConfig" is a bit too long, so define a short name for it.
+ ScriptConfiguration &Opt = *ScriptConfig;
+
+ int getSectionIndex(StringRef Name);
+
+ uintX_t Dot;
+};
+
+// 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;
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index f682f3b8b473..41e30ce599d2 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -21,9 +21,12 @@
//===----------------------------------------------------------------------===//
#include "InputSection.h"
+#include "LinkerScript.h"
#include "OutputSections.h"
+#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
+#include "Target.h"
#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ELF.h"
@@ -35,30 +38,78 @@ using namespace llvm::ELF;
using namespace llvm::object;
using namespace lld;
-using namespace lld::elf2;
+using namespace lld::elf;
+
+// 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;
+};
-// Calls Fn for each section that Sec refers to via relocations.
template <class ELFT>
-static void forEachSuccessor(InputSection<ELFT> *Sec,
- std::function<void(InputSectionBase<ELFT> *)> Fn) {
- typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
- typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
-
- ELFFile<ELFT> &Obj = Sec->getFile()->getObj();
- for (const Elf_Shdr *RelSec : Sec->RelocSections) {
- if (RelSec->sh_type == SHT_RELA) {
- for (const Elf_Rela &RI : Obj.relas(RelSec))
- if (InputSectionBase<ELFT> *Succ = Sec->getRelocTarget(RI))
- Fn(Succ);
- } else {
- for (const Elf_Rel &RI : Obj.rels(RelSec))
- if (InputSectionBase<ELFT> *Succ = Sec->getRelocTarget(RI))
- Fn(Succ);
- }
+static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
+ const typename ELFT::Rel &Rel) {
+ return Target->getImplicitAddend(Sec.getSectionData().begin(),
+ Rel.getType(Config->Mips64EL));
+}
+
+template <class ELFT>
+static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
+ const typename ELFT::Rela &Rel) {
+ return Rel.r_addend;
+}
+
+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};
+}
+
+template <class ELFT, class Elf_Shdr>
+static void run(ELFFile<ELFT> &Obj, InputSectionBase<ELFT> &Sec,
+ Elf_Shdr *RelSec, std::function<void(ResolvedReloc<ELFT>)> Fn) {
+ if (RelSec->sh_type == SHT_RELA) {
+ for (const typename ELFT::Rela &RI : Obj.relas(RelSec))
+ Fn(resolveReloc(Sec, RI));
+ } else {
+ for (const typename ELFT::Rel &RI : Obj.rels(RelSec))
+ Fn(resolveReloc(Sec, RI));
}
}
+// 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) {
+ ELFFile<ELFT> &Obj = Sec.getFile()->getObj();
+ for (const typename ELFT::Shdr *RelSec : Sec.RelocSections)
+ run(Obj, Sec, RelSec, Fn);
+}
+
+template <class ELFT>
+static void scanEhFrameSection(EhInputSection<ELFT> &EH,
+ std::function<void(ResolvedReloc<ELFT>)> Fn) {
+ if (!EH.RelocSection)
+ return;
+ ELFFile<ELFT> &EObj = EH.getFile()->getObj();
+ run<ELFT>(EObj, EH, EH.RelocSection, [&](ResolvedReloc<ELFT> R) {
+ if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+ return;
+ if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR)
+ return;
+ Fn({R.Sec, 0});
+ });
+}
+
// Sections listed below are special because they are used by the loader
// just by being in an ELF file. They should not be garbage-collected.
template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
@@ -70,6 +121,12 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
return true;
default:
StringRef S = Sec->getSectionName();
+
+ // We do not want to reclaim sections if they can be referred
+ // by __start_* and __stop_* symbols.
+ if (isValidCIdentifier(S))
+ return true;
+
return S.startswith(".ctors") || S.startswith(".dtors") ||
S.startswith(".init") || S.startswith(".fini") ||
S.startswith(".jcr");
@@ -79,52 +136,66 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
// This is the main function of the garbage collector.
// Starting from GC-root sections, this function visits all reachable
// sections to set their "Live" bits.
-template <class ELFT> void elf2::markLive(SymbolTable<ELFT> *Symtab) {
+template <class ELFT> void elf::markLive() {
SmallVector<InputSection<ELFT> *, 256> Q;
- auto Enqueue = [&](InputSectionBase<ELFT> *Sec) {
- if (!Sec || Sec->Live)
+ auto Enqueue = [&](ResolvedReloc<ELFT> R) {
+ if (!R.Sec)
+ return;
+
+ // 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))
+ MS->markLiveAt(R.Offset);
+
+ if (R.Sec->Live)
return;
- Sec->Live = true;
- if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(Sec))
+ R.Sec->Live = true;
+ if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(R.Sec))
Q.push_back(S);
};
- auto MarkSymbol = [&](SymbolBody *Sym) {
- if (Sym)
- if (auto *D = dyn_cast<DefinedRegular<ELFT>>(Sym->repl()))
- Enqueue(D->Section);
+ auto MarkSymbol = [&](const SymbolBody *Sym) {
+ if (auto *D = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym))
+ Enqueue({D->Section, D->Value});
};
// Add GC root symbols.
- MarkSymbol(Config->EntrySym);
- MarkSymbol(Symtab->find(Config->Init));
- MarkSymbol(Symtab->find(Config->Fini));
+ if (Config->EntrySym)
+ MarkSymbol(Config->EntrySym->body());
+ MarkSymbol(Symtab<ELFT>::X->find(Config->Init));
+ MarkSymbol(Symtab<ELFT>::X->find(Config->Fini));
for (StringRef S : Config->Undefined)
- MarkSymbol(Symtab->find(S));
+ MarkSymbol(Symtab<ELFT>::X->find(S));
// Preserve externally-visible symbols if the symbols defined by this
// file can interrupt other ELF file's symbols at runtime.
- if (Config->Shared || Config->ExportDynamic) {
- for (const std::pair<StringRef, Symbol *> &P : Symtab->getSymbols()) {
- SymbolBody *B = P.second->Body;
- if (B->getVisibility() == STV_DEFAULT)
- MarkSymbol(B);
- }
- }
+ for (const Symbol *S : Symtab<ELFT>::X->getSymbols())
+ if (S->includeInDynsym())
+ MarkSymbol(S->body());
- // Preserve special sections.
- for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab->getObjectFiles())
+ // Preserve special sections and those which are specified in linker
+ // script KEEP command.
+ for (const std::unique_ptr<ObjectFile<ELFT>> &F :
+ Symtab<ELFT>::X->getObjectFiles())
for (InputSectionBase<ELFT> *Sec : F->getSections())
- if (Sec && Sec != &InputSection<ELFT>::Discarded && isReserved(Sec))
- Enqueue(Sec);
+ if (Sec && Sec != &InputSection<ELFT>::Discarded) {
+ // .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))
+ scanEhFrameSection<ELFT>(*EH, Enqueue);
+ if (isReserved(Sec) || Script<ELFT>::X->shouldKeep(Sec))
+ Enqueue({Sec, 0});
+ }
// Mark all reachable sections.
while (!Q.empty())
- forEachSuccessor<ELFT>(Q.pop_back_val(), Enqueue);
+ forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue);
}
-template void elf2::markLive<ELF32LE>(SymbolTable<ELF32LE> *);
-template void elf2::markLive<ELF32BE>(SymbolTable<ELF32BE> *);
-template void elf2::markLive<ELF64LE>(SymbolTable<ELF64LE> *);
-template void elf2::markLive<ELF64BE>(SymbolTable<ELF64BE> *);
+template void elf::markLive<ELF32LE>();
+template void elf::markLive<ELF32BE>();
+template void elf::markLive<ELF64LE>();
+template void elf::markLive<ELF64BE>();
diff --git a/ELF/Options.td b/ELF/Options.td
index 1b02c5c8b795..010f37687f03 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -1,165 +1,276 @@
include "llvm/Option/OptParser.td"
-def Bsymbolic: Flag<["-"], "Bsymbolic">,
- HelpText<"Bind defined symbols locally">;
+// For options whose names are multiple letters, either one dash or
+// two can precede the option name except those that start with 'o'.
+class F<string name>: Flag<["--", "-"], name>;
+class J<string name>: Joined<["--", "-"], name>;
+class S<string name>: Separate<["--", "-"], name>;
+class JS<string name>: JoinedOrSeparate<["--", "-"], name>;
-def Bdynamic: Flag<["-"], "Bdynamic">,
- HelpText<"Link against shared libraries">;
+def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">;
-def Bstatic: Flag<["-"], "Bstatic">,
- HelpText<"Do not link against shared libraries">;
+def Bsymbolic_functions: F<"Bsymbolic-functions">,
+ HelpText<"Bind defined function symbols locally">;
-def L : JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
- HelpText<"Directory to search for libraries">;
+def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">;
-def O : Joined<["-"], "O">, HelpText<"Optimize">;
+def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
-def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">,
- HelpText<"Allow multiple definitions">;
+def build_id: F<"build-id">, HelpText<"Generate build ID note">;
+
+def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+
+def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
+ HelpText<"Add a directory to the library search path">;
+
+def O: Joined<["-"], "O">, HelpText<"Optimize output file size">;
-def allow_shlib_undefined : Flag<["--", "-"], "allow-shlib-undefined">;
+def allow_multiple_definition: F<"allow-multiple-definition">,
+ HelpText<"Allow multiple definitions">;
-def as_needed : Flag<["--"], "as-needed">;
+def as_needed: F<"as-needed">,
+ HelpText<"Only set DT_NEEDED for shared libraries if used">;
-def disable_new_dtags : Flag<["--"], "disable-new-dtags">,
+def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
-def discard_all : Flag<["-"], "discard-all">,
- HelpText<"Delete all local symbols">;
+def discard_all: F<"discard-all">, HelpText<"Delete all local symbols">;
-def discard_locals : Flag<["-"], "discard-locals">,
+def discard_locals: F<"discard-locals">,
HelpText<"Delete temporary local symbols">;
-def discard_none : Flag<["-"], "discard-none">,
+def discard_none: F<"discard-none">,
HelpText<"Keep all symbols in the symbol table">;
-def dynamic_linker : Separate<["--", "-"], "dynamic-linker">,
+def dynamic_linker: S<"dynamic-linker">,
HelpText<"Which dynamic linker to use">;
-def enable_new_dtags : Flag<["--"], "enable-new-dtags">,
+def dynamic_list: S<"dynamic-list">,
+ HelpText<"Read a list of dynamic symbols">;
+
+def eh_frame_hdr: F<"eh-frame-hdr">,
+ HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
+
+def enable_new_dtags: F<"enable-new-dtags">,
HelpText<"Enable new dynamic tags">;
-def entry : Separate<["--", "-"], "entry">, MetaVarName<"<entry>">,
+def end_lib: F<"end-lib">,
+ HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
+
+def entry: S<"entry">, MetaVarName<"<entry>">,
HelpText<"Name of entry point symbol">;
-def export_dynamic : Flag<["--", "-"], "export-dynamic">,
+def export_dynamic: F<"export-dynamic">,
HelpText<"Put symbols in the dynamic symbol table">;
-def fini : Separate<["-"], "fini">, MetaVarName<"<symbol>">,
+def export_dynamic_symbol: S<"export-dynamic-symbol">,
+ HelpText<"Put a symbol in the dynamic symbol table">;
+
+def fatal_warnings: F<"fatal-warnings">,
+ HelpText<"Treat warnings as errors">;
+
+def fini: S<"fini">, MetaVarName<"<symbol>">,
HelpText<"Specify a finalizer function">;
-def hash_style : Separate<["--", "-"], "hash-style">,
+def hash_style: S<"hash-style">,
HelpText<"Specify hash style (sysv, gnu or both)">;
-def gc_sections : Flag<["--"], "gc-sections">,
+def help: F<"help">, HelpText<"Print option help">;
+
+def icf: F<"icf=all">, HelpText<"Enable identical code folding">;
+
+def image_base : J<"image-base=">, HelpText<"Set the base address">;
+
+def gc_sections: F<"gc-sections">,
HelpText<"Enable garbage collection of unused sections">;
-def init : Separate<["-"], "init">, MetaVarName<"<symbol>">,
+def init: S<"init">, MetaVarName<"<symbol>">,
HelpText<"Specify an initializer function">;
-def l : JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
+def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
HelpText<"Root name of library to use">;
-def m : JoinedOrSeparate<["-"], "m">,
- HelpText<"Set target emulation">;
+def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
+ HelpText<"Optimization level for LTO">;
+
+def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+
+def no_as_needed: F<"no-as-needed">,
+ HelpText<"Always DT_NEEDED for shared libraries">;
-def no_allow_shlib_undefined : Flag<["--"], "no-allow-shlib-undefined">;
+def no_demangle: F<"no-demangle">,
+ HelpText<"Do not demangle symbol names">;
-def no_as_needed : Flag<["--"], "no-as-needed">;
+def no_gnu_unique: F<"no-gnu-unique">,
+ HelpText<"Disable STB_GNU_UNIQUE symbol binding">;
-def no_whole_archive : Flag<["--", "-"], "no-whole-archive">,
+def no_whole_archive: F<"no-whole-archive">,
HelpText<"Restores the default behavior of loading archive members">;
-def noinhibit_exec : Flag<["--"], "noinhibit-exec">,
+def noinhibit_exec: F<"noinhibit-exec">,
HelpText<"Retain the executable output file whenever it is still usable">;
-def no_undefined : Flag<["--"], "no-undefined">,
+def no_undefined: F<"no-undefined">,
HelpText<"Report unresolved symbols even if the linker is creating a shared library">;
-def o : Separate<["-"], "o">, MetaVarName<"<path>">,
+def no_undefined_version: F<"no-undefined-version">,
+ HelpText<"Report version scripts that refer undefined symbols">;
+
+def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">;
-def print_gc_sections: Flag<["--"], "print-gc-sections">,
+def pie: F<"pie">, HelpText<"Create a position independent executable">;
+
+def print_gc_sections: F<"print-gc-sections">,
HelpText<"List removed unused sections">;
-def rpath : Separate<["-"], "rpath">,
- HelpText<"Add a DT_RUNPATH to the output">;
+def reproduce: S<"reproduce">,
+ HelpText<"Dump linker invocation and input files for debugging">;
+
+def rpath: S<"rpath">, HelpText<"Add a DT_RUNPATH to the output">;
+
+def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
+
+def script: S<"script">, HelpText<"Read linker script">;
+
+def shared: F<"shared">, HelpText<"Build a shared object">;
+
+def soname: J<"soname=">, HelpText<"Set DT_SONAME">;
-def relocatable : Flag<["--"], "relocatable">;
+def start_lib: F<"start-lib">,
+ HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
-def script : Separate<["--"], "script">, HelpText<"Read linker script">;
+def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
-def shared : Flag<["-"], "shared">,
- HelpText<"Build a shared object">;
+def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
-def soname : Joined<["-"], "soname=">,
- HelpText<"Set DT_SONAME">;
+def sysroot: J<"sysroot=">, HelpText<"Set the system root">;
-def strip_all : Flag<["--"], "strip-all">,
- HelpText<"Strip all symbols">;
+def threads: F<"threads">, HelpText<"Enable use of threads">;
-def sysroot : Joined<["--"], "sysroot=">,
- HelpText<"Set the system root">;
+def trace: F<"trace">, HelpText<"Print the names of the input files">;
-def undefined : Joined<["--"], "undefined=">,
+def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">;
+
+def undefined: J<"undefined=">,
HelpText<"Force undefined symbol during linking">;
-def verbose : Flag<["--"], "verbose">;
+def unresolved_symbols: J<"unresolved-symbols=">,
+ HelpText<"Determine how to handle unresolved symbols">;
+
+def rsp_quoting: J<"rsp-quoting=">,
+ HelpText<"Quoting style for response files. Values supported: windows|posix">;
+
+def verbose: F<"verbose">, HelpText<"Verbose mode">;
+
+def version: F<"version">, HelpText<"Display the version number">;
-def whole_archive : Flag<["--", "-"], "whole-archive">,
+def version_script: S<"version-script">,
+ HelpText<"Read a version script">;
+
+def warn_common: F<"warn-common">,
+ HelpText<"Warn about duplicate common symbols">;
+
+def whole_archive: F<"whole-archive">,
HelpText<"Force load of all members in a static library">;
-def wrap : Separate<["--", "-"], "wrap">, MetaVarName<"<symbol>">,
+def wrap: S<"wrap">, MetaVarName<"<symbol>">,
HelpText<"Use wrapper functions for symbol">;
-def z : JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
+def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
// Aliases
-def alias_Bdynamic_call_shared: Flag<["-"], "call_shared">, Alias<Bdynamic>;
-def alias_Bdynamic_dy: Flag<["-"], "dy">, Alias<Bdynamic>;
-def alias_Bstatic_dn: Flag<["-"], "dn">, Alias<Bstatic>;
-def alias_Bstatic_non_shared: Flag<["-"], "non_shared">, Alias<Bstatic>;
-def alias_Bstatic_static: Flag<["-"], "static">, Alias<Bstatic>;
-def alias_L__library_path : Joined<["--"], "library-path=">, Alias<L>;
+def alias_Bdynamic_call_shared: F<"call_shared">, Alias<Bdynamic>;
+def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>;
+def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>;
+def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>;
+def alias_Bstatic_static: F<"static">, Alias<Bstatic>;
+def alias_L__library_path: J<"library-path=">, Alias<L>;
def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
-def alias_entry_e : Separate<["-"], "e">, Alias<entry>;
+def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
+def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
+def alias_entry_entry: J<"entry=">, Alias<entry>;
def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
-def alias_fini_fini : Joined<["-"], "fini=">, Alias<fini>;
-def alias_hash_style_hash_style : Joined<["--", "-"], "hash-style=">, Alias<hash_style>;
-def alias_init_init : Joined<["-"], "init=">, Alias<init>;
-def alias_l__library : Joined<["--"], "library=">, Alias<l>;
-def alias_o_output : Joined<["--"], "output=">, Alias<o>;
-def alias_rpath_rpath : Joined<["-"], "rpath=">, Alias<rpath>;
-def alias_relocatable_r : Flag<["-"], "r">, Alias<relocatable>;
-def alias_shared_Bshareable : Flag<["-"], "Bshareable">, Alias<shared>;
-def alias_soname_h : Separate<["-"], "h">, Alias<soname>;
-def alias_soname_soname : Separate<["-"], "soname">, Alias<soname>;
-def alias_script_T : Separate<["-"], "T">, Alias<script>;
+def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">,
+ Alias<export_dynamic_symbol>;
+def alias_fini_fini: J<"fini=">, Alias<fini>;
+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_o_output: Joined<["--"], "output=">, Alias<o>;
+def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
+def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
+def alias_rpath_R: Joined<["-"], "R">, Alias<rpath>;
+def alias_rpath_rpath: J<"rpath=">, Alias<rpath>;
+def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>;
+def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>;
+def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>;
+def alias_soname_soname: S<"soname">, Alias<soname>;
def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>;
-def alias_undefined_u : Separate<["-"], "u">, Alias<undefined>;
-def alias_wrap_wrap : Joined<["--", "-"], "wrap=">, Alias<wrap>;
+def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
+def alias_trace: Flag<["-"], "t">, Alias<trace>;
+def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
+def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
+def alias_version_V: Flag<["-"], "V">, Alias<version>;
+def alias_version_v: Flag<["-"], "v">, Alias<version>;
+def alias_wrap_wrap: J<"wrap=">, Alias<wrap>;
// Our symbol resolution algorithm handles symbols in archive files differently
// than traditional linkers, so we don't need --start-group and --end-group.
// These options are recongized for compatibility but ignored.
-def end_group : Flag<["--"], "end-group">;
+def end_group: F<"end-group">;
def end_group_paren: Flag<["-"], ")">;
-def start_group : Flag<["--"], "start-group">;
+def start_group: F<"start-group">;
def start_group_paren: Flag<["-"], "(">;
+// Ignore LTO plugin-related options.
+// clang -flto passes -plugin and -plugin-opt to the linker. This is required
+// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't
+// rely on a plugin. Instead of detecting which linker is used on clang side we
+// just ignore the option on lld side as it's easier. In fact, the linker could
+// be called 'ld' and understanding which linker is used would require parsing of
+// --version output.
+def plugin: S<"plugin">;
+def plugin_eq: J<"plugin=">;
+def plugin_opt: S<"plugin-opt">;
+def plugin_opt_eq: J<"plugin-opt=">;
+
// Options listed below are silently ignored for now for compatibility.
-def build_id : Flag<["--"], "build-id">;
-def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">;
-def fatal_warnings : Flag<["--"], "fatal-warnings">;
-def no_add_needed : Flag<["--"], "no-add-needed">;
-def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">;
-def no_warn_mismatch : Flag<["--"], "no-warn-mismatch">;
-def version_script : Separate<["--"], "version-script">;
-def warn_common : Flag<["--"], "warn-common">;
-def warn_shared_textrel : Flag<["--"], "warn-shared-textrel">;
-def G : Separate<["-"], "G">;
+def allow_shlib_undefined: F<"allow-shlib-undefined">;
+def define_common: F<"define-common">;
+def demangle: F<"demangle">;
+def detect_odr_violations: F<"detect-odr-violations">;
+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">;
+def rpath_link: S<"rpath-link">;
+def rpath_link_eq: J<"rpath-link=">;
+def sort_common: F<"sort-common">;
+def warn_execstack: F<"warn-execstack">;
+def warn_shared_textrel: F<"warn-shared-textrel">;
+def G: Separate<["-"], "G">;
// Aliases for ignored options
-def alias_version_script_version_script : Joined<["--"], "version-script=">, Alias<version_script>;
+def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>;
+def alias_define_common_dc: F<"dc">, Alias<define_common>;
+def alias_define_common_dp: F<"dp">, Alias<define_common>;
+def alias_version_script_version_script: J<"version-script=">,
+ Alias<version_script>;
+
+// LTO-related options.
+def lto_jobs: J<"lto-jobs=">, HelpText<"Number of threads to run codegen">;
+def lto_aa_pipeline: J<"lto-aa-pipeline=">,
+ HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_newpm_passes: J<"lto-newpm-passes=">,
+ HelpText<"Passes to run during LTO">;
+def disable_verify: F<"disable-verify">;
+def mllvm: S<"mllvm">;
+def save_temps: F<"save-temps">;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 2aa814524d6b..50b94015f229 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -9,19 +9,26 @@
#include "OutputSections.h"
#include "Config.h"
+#include "EhFrame.h"
+#include "LinkerScript.h"
+#include "Strings.h"
#include "SymbolTable.h"
#include "Target.h"
+#include "lld/Core/Parallel.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SHA1.h"
+#include <map>
using namespace llvm;
+using namespace llvm::dwarf;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
-using namespace lld::elf2;
-
-bool elf2::HasGotOffRel = false;
+using namespace lld::elf;
template <class ELFT>
OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type,
@@ -30,39 +37,39 @@ OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type,
memset(&Header, 0, sizeof(Elf_Shdr));
Header.sh_type = Type;
Header.sh_flags = Flags;
+ Header.sh_addralign = 1;
+}
+
+template <class ELFT>
+void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *Shdr) {
+ *Shdr = Header;
}
template <class ELFT>
GotPltSection<ELFT>::GotPltSection()
: OutputSectionBase<ELFT>(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
- this->Header.sh_addralign = sizeof(uintX_t);
+ this->Header.sh_addralign = Target->GotPltEntrySize;
}
-template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody *Sym) {
- Sym->GotPltIndex = Target->getGotPltHeaderEntriesNum() + Entries.size();
- Entries.push_back(Sym);
+template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
+ Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
+ Entries.push_back(&Sym);
}
template <class ELFT> bool GotPltSection<ELFT>::empty() const {
return Entries.empty();
}
-template <class ELFT>
-typename GotPltSection<ELFT>::uintX_t
-GotPltSection<ELFT>::getEntryAddr(const SymbolBody &B) const {
- return this->getVA() + B.GotPltIndex * sizeof(uintX_t);
-}
-
template <class ELFT> void GotPltSection<ELFT>::finalize() {
- this->Header.sh_size =
- (Target->getGotPltHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t);
+ this->Header.sh_size = (Target->GotPltHeaderEntriesNum + Entries.size()) *
+ Target->GotPltEntrySize;
}
template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
- Target->writeGotPltHeaderEntries(Buf);
- Buf += Target->getGotPltHeaderEntriesNum() * sizeof(uintX_t);
+ Target->writeGotPltHeader(Buf);
+ Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
for (const SymbolBody *B : Entries) {
- Target->writeGotPltEntry(Buf, Out<ELFT>::Plt->getEntryAddr(*B));
+ Target->writeGotPlt(Buf, *B);
Buf += sizeof(uintX_t);
}
}
@@ -72,37 +79,135 @@ GotSection<ELFT>::GotSection()
: OutputSectionBase<ELFT>(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
if (Config->EMachine == EM_MIPS)
this->Header.sh_flags |= SHF_MIPS_GPREL;
- this->Header.sh_addralign = sizeof(uintX_t);
+ this->Header.sh_addralign = Target->GotEntrySize;
}
-template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody *Sym) {
- Sym->GotIndex = Target->getGotHeaderEntriesNum() + Entries.size();
- Entries.push_back(Sym);
+template <class ELFT>
+void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
+ Sym.GotIndex = Entries.size();
+ Entries.push_back(&Sym);
}
-template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody *Sym) {
- if (Sym->hasGlobalDynIndex())
+template <class ELFT>
+void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_t Addend,
+ RelExpr Expr) {
+ // For "true" local symbols which can be referenced from the same module
+ // only compiler creates two instructions for address loading:
+ //
+ // lw $8, 0($gp) # R_MIPS_GOT16
+ // addi $8, $8, 0 # R_MIPS_LO16
+ //
+ // The first instruction loads high 16 bits of the symbol address while
+ // the second adds an offset. That allows to reduce number of required
+ // GOT entries because only one global offset table entry is necessary
+ // for every 64 KBytes of local data. So for local symbols we need to
+ // allocate number of GOT entries to hold all required "page" addresses.
+ //
+ // All global symbols (hidden and regular) considered by compiler uniformly.
+ // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation
+ // to load address of the symbol. So for each such symbol we need to
+ // allocate dedicated GOT entry to store its address.
+ //
+ // If a symbol is preemptible we need help of dynamic linker to get its
+ // final address. The corresponding GOT entries are allocated in the
+ // "global" part of GOT. Entries for non preemptible global symbol allocated
+ // in the "local" part of GOT.
+ //
+ // See "Global Offset Table" in Chapter 5:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
+ // At this point we do not know final symbol value so to reduce number
+ // of allocated GOT entries do the following trick. Save all output
+ // sections referenced by GOT relocations. Then later in the `finalize`
+ // method calculate number of "pages" required to cover all saved output
+ // section and allocate appropriate number of GOT entries.
+ auto *OutSec = cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec;
+ MipsOutSections.insert(OutSec);
+ return;
+ }
+ if (Sym.isTls()) {
+ // GOT entries created for MIPS TLS relocations behave like
+ // almost GOT entries from other ABIs. They go to the end
+ // of the global offset table.
+ Sym.GotIndex = Entries.size();
+ Entries.push_back(&Sym);
+ return;
+ }
+ auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) {
+ if (S.isInGot() && !A)
+ return;
+ size_t NewIndex = Items.size();
+ if (!MipsGotMap.insert({{&S, A}, NewIndex}).second)
+ return;
+ Items.emplace_back(&S, A);
+ if (!A)
+ S.GotIndex = NewIndex;
+ };
+ if (Sym.isPreemptible()) {
+ // Ignore addends for preemptible symbols. They got single GOT entry anyway.
+ AddEntry(Sym, 0, MipsGlobal);
+ Sym.IsInGlobalMipsGot = true;
+ } else
+ AddEntry(Sym, Addend, MipsLocal);
+}
+
+template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+ if (Sym.GlobalDynIndex != -1U)
return false;
- Sym->GlobalDynIndex = Target->getGotHeaderEntriesNum() + Entries.size();
+ Sym.GlobalDynIndex = Entries.size();
// Global Dynamic TLS entries take two GOT slots.
- Entries.push_back(Sym);
Entries.push_back(nullptr);
+ Entries.push_back(&Sym);
return true;
}
-template <class ELFT> bool GotSection<ELFT>::addCurrentModuleTlsIndex() {
- if (LocalTlsIndexOff != uint32_t(-1))
+// Reserves TLS entries for a TLS module ID and a TLS block offset.
+// In total it takes two GOT slots.
+template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
+ if (TlsIndexOff != uint32_t(-1))
return false;
+ TlsIndexOff = Entries.size() * sizeof(uintX_t);
Entries.push_back(nullptr);
Entries.push_back(nullptr);
- LocalTlsIndexOff = (Entries.size() - 2) * sizeof(uintX_t);
return true;
}
template <class ELFT>
typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getEntryAddr(const SymbolBody &B) const {
- return this->getVA() + B.GotIndex * sizeof(uintX_t);
+GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) {
+ // Initialize the entry by the %hi(EntryValue) expression
+ // but without right-shifting.
+ EntryValue = (EntryValue + 0x8000) & ~0xffff;
+ // Take into account MIPS GOT header.
+ // See comment in the GotSection::writeTo.
+ size_t NewIndex = MipsLocalGotPos.size() + 2;
+ auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex));
+ assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries);
+ return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset;
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const {
+ uintX_t Off = MipsPageEntries;
+ if (B.isTls())
+ Off += MipsLocal.size() + MipsGlobal.size() + B.GotIndex;
+ else if (B.IsInGlobalMipsGot)
+ Off += MipsLocal.size() + B.GotIndex;
+ else if (B.isInGot())
+ Off += B.GotIndex;
+ else {
+ auto It = MipsGotMap.find({&B, Addend});
+ assert(It != MipsGotMap.end());
+ Off += It->second;
+ }
+ return Off * sizeof(uintX_t) - MipsGPOffset;
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() {
+ return (MipsPageEntries + MipsLocal.size() + MipsGlobal.size()) *
+ sizeof(uintX_t);
}
template <class ELFT>
@@ -112,37 +217,85 @@ GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
}
template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
+ return B.GlobalDynIndex * sizeof(uintX_t);
+}
+
+template <class ELFT>
const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
- return Entries.empty() ? nullptr : Entries.front();
+ return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
}
template <class ELFT>
unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
- // TODO: Update when the support of GOT entries for local symbols is added.
- return Target->getGotHeaderEntriesNum();
+ return MipsPageEntries + MipsLocal.size();
}
template <class ELFT> void GotSection<ELFT>::finalize() {
- this->Header.sh_size =
- (Target->getGotHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t);
+ size_t EntriesNum = Entries.size();
+ if (Config->EMachine == EM_MIPS) {
+ // Take into account MIPS GOT header.
+ // See comment in the GotSection::writeTo.
+ MipsPageEntries += 2;
+ for (const OutputSectionBase<ELFT> *OutSec : MipsOutSections) {
+ // Calculate an upper bound of MIPS GOT entries required to store page
+ // addresses of local symbols. We assume the worst case - each 64kb
+ // page of the output section has at least one GOT relocation against it.
+ // Add 0x8000 to the section's size because the page address stored
+ // in the GOT entry is calculated as (value + 0x8000) & ~0xffff.
+ MipsPageEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff;
+ }
+ EntriesNum += MipsPageEntries + MipsLocal.size() + MipsGlobal.size();
+ }
+ this->Header.sh_size = EntriesNum * sizeof(uintX_t);
+}
+
+template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *&Buf) {
+ // Set the MSB of the second GOT slot. This is not required by any
+ // MIPS ABI documentation, though.
+ //
+ // There is a comment in glibc saying that "The MSB of got[1] of a
+ // gnu object is set to identify gnu objects," and in GNU gold it
+ // says "the second entry will be used by some runtime loaders".
+ // But how this field is being used is unclear.
+ //
+ // We are not really willing to mimic other linkers behaviors
+ // without understanding why they do that, but because all files
+ // generated by GNU tools have this special GOT value, and because
+ // we've been doing this for years, it is probably a safe bet to
+ // keep doing this for now. We really need to revisit this to see
+ // if we had to do this.
+ auto *P = reinterpret_cast<typename ELFT::Off *>(Buf);
+ P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
+ // Write 'page address' entries to the local part of the GOT.
+ for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
+ uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first);
+ }
+ Buf += MipsPageEntries * sizeof(uintX_t);
+ auto AddEntry = [&](const MipsGotEntry &SA) {
+ uint8_t *Entry = Buf;
+ Buf += sizeof(uintX_t);
+ const SymbolBody* Body = SA.first;
+ uintX_t VA = Body->template getVA<ELFT>(SA.second);
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
+ };
+ std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
+ std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
}
template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
- Target->writeGotHeaderEntries(Buf);
- Buf += Target->getGotHeaderEntriesNum() * sizeof(uintX_t);
+ if (Config->EMachine == EM_MIPS)
+ writeMipsGot(Buf);
for (const SymbolBody *B : Entries) {
uint8_t *Entry = Buf;
Buf += sizeof(uintX_t);
if (!B)
continue;
- // MIPS has special rules to fill up GOT entries.
- // See "Global Offset Table" in Chapter 5 in the following document
- // for detailed description:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- // As the first approach, we can just store addresses for all symbols.
- if (Config->EMachine != EM_MIPS && canBePreempted(B, false))
+ if (B->isPreemptible())
continue; // The dynamic linker will take care of it.
- uintX_t VA = getSymVA<ELFT>(*B);
+ uintX_t VA = B->getVA<ELFT>();
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
}
}
@@ -154,165 +307,81 @@ PltSection<ELFT>::PltSection()
}
template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
- size_t Off = 0;
- bool LazyReloc = Target->supportsLazyRelocations();
- if (LazyReloc) {
- // First write PLT[0] entry which is special.
- Target->writePltZeroEntry(Buf, Out<ELFT>::GotPlt->getVA(), this->getVA());
- Off += Target->getPltZeroEntrySize();
- }
+ // At beginning of PLT, we have code to call the dynamic linker
+ // to resolve dynsyms at runtime. Write such code.
+ Target->writePltHeader(Buf);
+ size_t Off = Target->PltHeaderSize;
+
for (auto &I : Entries) {
- const SymbolBody *E = I.first;
+ const SymbolBody *B = I.first;
unsigned RelOff = I.second;
- uint64_t GotVA =
- LazyReloc ? Out<ELFT>::GotPlt->getVA() : Out<ELFT>::Got->getVA();
- uint64_t GotE = LazyReloc ? Out<ELFT>::GotPlt->getEntryAddr(*E)
- : Out<ELFT>::Got->getEntryAddr(*E);
+ uint64_t Got = B->getGotPltVA<ELFT>();
uint64_t Plt = this->getVA() + Off;
- Target->writePltEntry(Buf + Off, GotVA, GotE, Plt, E->PltIndex, RelOff);
- Off += Target->getPltEntrySize();
+ Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
+ Off += Target->PltEntrySize;
}
}
-template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody *Sym) {
- Sym->PltIndex = Entries.size();
- unsigned RelOff = Target->supportsLazyRelocations()
- ? Out<ELFT>::RelaPlt->getRelocOffset()
- : Out<ELFT>::RelaDyn->getRelocOffset();
- Entries.push_back(std::make_pair(Sym, RelOff));
-}
-
-template <class ELFT>
-typename PltSection<ELFT>::uintX_t
-PltSection<ELFT>::getEntryAddr(const SymbolBody &B) const {
- return this->getVA() + Target->getPltZeroEntrySize() +
- B.PltIndex * Target->getPltEntrySize();
+template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody &Sym) {
+ Sym.PltIndex = Entries.size();
+ unsigned RelOff = Out<ELFT>::RelaPlt->getRelocOffset();
+ Entries.push_back(std::make_pair(&Sym, RelOff));
}
template <class ELFT> void PltSection<ELFT>::finalize() {
- this->Header.sh_size = Target->getPltZeroEntrySize() +
- Entries.size() * Target->getPltEntrySize();
+ this->Header.sh_size =
+ Target->PltHeaderSize + Entries.size() * Target->PltEntrySize;
}
template <class ELFT>
-RelocationSection<ELFT>::RelocationSection(StringRef Name, bool IsRela)
- : OutputSectionBase<ELFT>(Name, IsRela ? SHT_RELA : SHT_REL, SHF_ALLOC),
- IsRela(IsRela) {
- this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
- this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
+RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
+ : OutputSectionBase<ELFT>(Name, Config->Rela ? SHT_RELA : SHT_REL,
+ SHF_ALLOC),
+ Sort(Sort) {
+ this->Header.sh_entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+ this->Header.sh_addralign = sizeof(uintX_t);
}
-// Applies corresponding symbol and type for dynamic tls relocation.
-// Returns true if relocation was handled.
template <class ELFT>
-bool RelocationSection<ELFT>::applyTlsDynamicReloc(SymbolBody *Body,
- uint32_t Type, Elf_Rel *P,
- Elf_Rel *N) {
- if (Target->isTlsLocalDynamicReloc(Type)) {
- P->setSymbolAndType(0, Target->getTlsModuleIndexReloc(), Config->Mips64EL);
- P->r_offset = Out<ELFT>::Got->getLocalTlsIndexVA();
- return true;
- }
-
- if (!Body || !Target->isTlsGlobalDynamicReloc(Type))
- return false;
-
- if (Target->isTlsOptimized(Type, Body)) {
- P->setSymbolAndType(Body->DynamicSymbolTableIndex,
- Target->getTlsGotReloc(), Config->Mips64EL);
- P->r_offset = Out<ELFT>::Got->getEntryAddr(*Body);
- return true;
- }
+void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
+ Relocs.push_back(Reloc);
+}
- P->setSymbolAndType(Body->DynamicSymbolTableIndex,
- Target->getTlsModuleIndexReloc(), Config->Mips64EL);
- P->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body);
- N->setSymbolAndType(Body->DynamicSymbolTableIndex,
- Target->getTlsOffsetReloc(), Config->Mips64EL);
- N->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t);
- return true;
+template <class ELFT, class RelTy>
+static bool compRelocations(const RelTy &A, const RelTy &B) {
+ return A.getSymbol(Config->Mips64EL) < B.getSymbol(Config->Mips64EL);
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
+ uint8_t *BufBegin = Buf;
for (const DynamicReloc<ELFT> &Rel : Relocs) {
- auto *P = reinterpret_cast<Elf_Rel *>(Buf);
- Buf += IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
-
- // Skip placeholder for global dynamic TLS relocation pair. It was already
- // handled by the previous relocation.
- if (!Rel.C)
- continue;
-
- InputSectionBase<ELFT> &C = *Rel.C;
- const Elf_Rel &RI = *Rel.RI;
- uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
- const ObjectFile<ELFT> &File = *C.getFile();
- SymbolBody *Body = File.getSymbolBody(SymIndex);
- if (Body)
- Body = Body->repl();
+ auto *P = reinterpret_cast<Elf_Rela *>(Buf);
+ Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+
+ if (Config->Rela)
+ P->r_addend = Rel.getAddend();
+ P->r_offset = Rel.getOffset();
+ if (Config->EMachine == EM_MIPS && Rel.getOutputSec() == Out<ELFT>::Got)
+ // Dynamic relocation against MIPS GOT section make deal TLS entries
+ // allocated in the end of the GOT. We need to adjust the offset to take
+ // in account 'local' and 'global' GOT entries.
+ P->r_offset += Out<ELFT>::Got->getMipsTlsOffset();
+ P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
+ }
- uint32_t Type = RI.getType(Config->Mips64EL);
- if (applyTlsDynamicReloc(Body, Type, P, reinterpret_cast<Elf_Rel *>(Buf)))
- continue;
- bool NeedsCopy = Body && Target->needsCopyRel(Type, *Body);
- bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body);
- bool CBP = canBePreempted(Body, NeedsGot);
- bool LazyReloc = Body && Target->supportsLazyRelocations() &&
- Target->relocNeedsPlt(Type, *Body);
- bool IsDynRelative = Type == Target->getRelativeReloc();
-
- unsigned Sym = CBP ? Body->DynamicSymbolTableIndex : 0;
- unsigned Reloc;
- if (!CBP && Body && isGnuIFunc<ELFT>(*Body))
- Reloc = Target->getIRelativeReloc();
- else if (!CBP || IsDynRelative)
- Reloc = Target->getRelativeReloc();
- else if (LazyReloc)
- Reloc = Target->getPltReloc();
- else if (NeedsGot)
- Reloc = Body->isTls() ? Target->getTlsGotReloc() : Target->getGotReloc();
- else if (NeedsCopy)
- Reloc = Target->getCopyReloc();
- else
- Reloc = Target->getDynReloc(Type);
- P->setSymbolAndType(Sym, Reloc, Config->Mips64EL);
-
- if (LazyReloc)
- P->r_offset = Out<ELFT>::GotPlt->getEntryAddr(*Body);
- else if (NeedsGot)
- P->r_offset = Out<ELFT>::Got->getEntryAddr(*Body);
- else if (NeedsCopy)
- P->r_offset = Out<ELFT>::Bss->getVA() +
- cast<SharedSymbol<ELFT>>(Body)->OffsetInBss;
- else
- P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
-
- uintX_t OrigAddend = 0;
- if (IsRela && !NeedsGot)
- OrigAddend = static_cast<const Elf_Rela &>(RI).r_addend;
-
- uintX_t Addend;
- if (NeedsCopy)
- Addend = 0;
- else if (CBP || IsDynRelative)
- Addend = OrigAddend;
- else if (Body)
- Addend = getSymVA<ELFT>(*Body) + OrigAddend;
- else if (IsRela)
- Addend =
- getLocalRelTarget(File, static_cast<const Elf_Rela &>(RI),
- getAddend<ELFT>(static_cast<const Elf_Rela &>(RI)));
+ if (Sort) {
+ if (Config->Rela)
+ std::stable_sort((Elf_Rela *)BufBegin,
+ (Elf_Rela *)BufBegin + Relocs.size(),
+ compRelocations<ELFT, Elf_Rela>);
else
- Addend = getLocalRelTarget(File, RI, 0);
-
- if (IsRela)
- static_cast<Elf_Rela *>(P)->r_addend = Addend;
+ std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(),
+ compRelocations<ELFT, Elf_Rel>);
}
}
template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
- const unsigned EntrySize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
- return EntrySize * Relocs.size();
+ return this->Header.sh_entsize * Relocs.size();
}
template <class ELFT> void RelocationSection<ELFT>::finalize() {
@@ -325,17 +394,11 @@ template <class ELFT>
InterpSection<ELFT>::InterpSection()
: OutputSectionBase<ELFT>(".interp", SHT_PROGBITS, SHF_ALLOC) {
this->Header.sh_size = Config->DynamicLinker.size() + 1;
- this->Header.sh_addralign = 1;
-}
-
-template <class ELFT>
-void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) {
- Header.sh_name = Out<ELFT>::ShStrTab->addString(Name);
- *SHdr = Header;
}
template <class ELFT> void InterpSection<ELFT>::writeTo(uint8_t *Buf) {
- memcpy(Buf, Config->DynamicLinker.data(), Config->DynamicLinker.size());
+ StringRef S = Config->DynamicLinker;
+ memcpy(Buf, S.data(), S.size());
}
template <class ELFT>
@@ -360,7 +423,7 @@ static uint32_t hashSysv(StringRef Name) {
template <class ELFT> void HashTableSection<ELFT>::finalize() {
this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
- unsigned NumEntries = 2; // nbucket and nchain.
+ unsigned NumEntries = 2; // nbucket and nchain.
NumEntries += Out<ELFT>::DynSymTab->getNumSymbols(); // The chain entries.
// Create as many buckets as there are symbols.
@@ -379,9 +442,11 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
Elf_Word *Buckets = P;
Elf_Word *Chains = P + NumSymbols;
- for (SymbolBody *Body : Out<ELFT>::DynSymTab->getSymbols()) {
+ for (const std::pair<SymbolBody *, unsigned> &P :
+ Out<ELFT>::DynSymTab->getSymbols()) {
+ SymbolBody *Body = P.first;
StringRef Name = Body->getName();
- unsigned I = Body->DynamicSymbolTableIndex;
+ unsigned I = Body->DynsymIndex;
uint32_t Hash = hashSysv(Name) % NumSymbols;
Chains[I] = Buckets[Hash];
Buckets[Hash] = I;
@@ -399,7 +464,7 @@ template <class ELFT>
GnuHashTableSection<ELFT>::GnuHashTableSection()
: OutputSectionBase<ELFT>(".gnu.hash", SHT_GNU_HASH, SHF_ALLOC) {
this->Header.sh_entsize = ELFT::Is64Bits ? 0 : 4;
- this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
+ this->Header.sh_addralign = sizeof(uintX_t);
}
template <class ELFT>
@@ -437,7 +502,7 @@ unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) {
}
template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
- unsigned NumHashed = HashedSymbols.size();
+ unsigned NumHashed = Symbols.size();
NBuckets = calcNBuckets(NumHashed);
MaskWords = calcMaskWords(NumHashed);
// Second hash shift estimation: just predefined values.
@@ -452,7 +517,7 @@ template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
writeHeader(Buf);
- if (HashedSymbols.empty())
+ if (Symbols.empty())
return;
writeBloomFilter(Buf);
writeHashTable(Buf);
@@ -462,7 +527,7 @@ template <class ELFT>
void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) {
auto *P = reinterpret_cast<Elf_Word *>(Buf);
*P++ = NBuckets;
- *P++ = Out<ELFT>::DynSymTab->getNumSymbols() - HashedSymbols.size();
+ *P++ = Out<ELFT>::DynSymTab->getNumSymbols() - Symbols.size();
*P++ = MaskWords;
*P++ = Shift2;
Buf = reinterpret_cast<uint8_t *>(P);
@@ -473,10 +538,10 @@ void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) {
unsigned C = sizeof(Elf_Off) * 8;
auto *Masks = reinterpret_cast<Elf_Off *>(Buf);
- for (const HashedSymbolData &Item : HashedSymbols) {
- size_t Pos = (Item.Hash / C) & (MaskWords - 1);
- uintX_t V = (uintX_t(1) << (Item.Hash % C)) |
- (uintX_t(1) << ((Item.Hash >> Shift2) % C));
+ for (const SymbolData &Sym : Symbols) {
+ size_t Pos = (Sym.Hash / C) & (MaskWords - 1);
+ uintX_t V = (uintX_t(1) << (Sym.Hash % C)) |
+ (uintX_t(1) << ((Sym.Hash >> Shift2) % C));
Masks[Pos] |= V;
}
Buf += sizeof(Elf_Off) * MaskWords;
@@ -489,58 +554,64 @@ void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
int PrevBucket = -1;
int I = 0;
- for (const HashedSymbolData &Item : HashedSymbols) {
- int Bucket = Item.Hash % NBuckets;
+ for (const SymbolData &Sym : Symbols) {
+ int Bucket = Sym.Hash % NBuckets;
assert(PrevBucket <= Bucket);
if (Bucket != PrevBucket) {
- Buckets[Bucket] = Item.Body->DynamicSymbolTableIndex;
+ Buckets[Bucket] = Sym.Body->DynsymIndex;
PrevBucket = Bucket;
if (I > 0)
Values[I - 1] |= 1;
}
- Values[I] = Item.Hash & ~1;
+ Values[I] = Sym.Hash & ~1;
++I;
}
if (I > 0)
Values[I - 1] |= 1;
}
-static bool includeInGnuHashTable(SymbolBody *B) {
- // Assume that includeInDynamicSymtab() is already checked.
- return !B->isUndefined();
-}
-
+// Add symbols to this symbol hash table. Note that this function
+// destructively sort a given vector -- which is needed because
+// GNU-style hash table places some sorting requirements.
template <class ELFT>
-void GnuHashTableSection<ELFT>::addSymbols(std::vector<SymbolBody *> &Symbols) {
- std::vector<SymbolBody *> NotHashed;
- NotHashed.reserve(Symbols.size());
- HashedSymbols.reserve(Symbols.size());
- for (SymbolBody *B : Symbols) {
- if (includeInGnuHashTable(B))
- HashedSymbols.push_back(HashedSymbolData{B, hashGnu(B->getName())});
- else
- NotHashed.push_back(B);
- }
- if (HashedSymbols.empty())
+void GnuHashTableSection<ELFT>::addSymbols(
+ std::vector<std::pair<SymbolBody *, size_t>> &V) {
+ // Ideally this will just be 'auto' but GCC 6.1 is not able
+ // to deduce it correctly.
+ std::vector<std::pair<SymbolBody *, size_t>>::iterator Mid =
+ std::stable_partition(V.begin(), V.end(),
+ [](std::pair<SymbolBody *, size_t> &P) {
+ return P.first->isUndefined();
+ });
+ if (Mid == V.end())
return;
+ for (auto I = Mid, E = V.end(); I != E; ++I) {
+ SymbolBody *B = I->first;
+ size_t StrOff = I->second;
+ Symbols.push_back({B, StrOff, hashGnu(B->getName())});
+ }
- unsigned NBuckets = calcNBuckets(HashedSymbols.size());
- std::stable_sort(HashedSymbols.begin(), HashedSymbols.end(),
- [&](const HashedSymbolData &L, const HashedSymbolData &R) {
+ unsigned NBuckets = calcNBuckets(Symbols.size());
+ std::stable_sort(Symbols.begin(), Symbols.end(),
+ [&](const SymbolData &L, const SymbolData &R) {
return L.Hash % NBuckets < R.Hash % NBuckets;
});
- Symbols = std::move(NotHashed);
- for (const HashedSymbolData &Item : HashedSymbols)
- Symbols.push_back(Item.Body);
+ V.erase(Mid, V.end());
+ for (const SymbolData &Sym : Symbols)
+ V.push_back({Sym.Body, Sym.STName});
}
+// Returns the number of version definition entries. Because the first entry
+// is for the version definition itself, it is the number of versioned symbols
+// plus one. Note that we don't support multiple versions yet.
+static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
+
template <class ELFT>
-DynamicSection<ELFT>::DynamicSection(SymbolTable<ELFT> &SymTab)
- : OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE),
- SymTab(SymTab) {
+DynamicSection<ELFT>::DynamicSection()
+ : OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE) {
Elf_Shdr &Header = this->Header;
- Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
+ Header.sh_addralign = sizeof(uintX_t);
Header.sh_entsize = ELFT::Is64Bits ? 16 : 8;
// .dynamic section is not writable on MIPS.
@@ -557,61 +628,66 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
Elf_Shdr &Header = this->Header;
Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
- unsigned NumEntries = 0;
+ auto Add = [=](Entry E) { Entries.push_back(E); };
+
+ // Add strings. We know that these are the last strings to be added to
+ // DynStrTab and doing this here allows this function to set DT_STRSZ.
+ if (!Config->RPath.empty())
+ Add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
+ Out<ELFT>::DynStrTab->addString(Config->RPath)});
+ for (const std::unique_ptr<SharedFile<ELFT>> &F :
+ Symtab<ELFT>::X->getSharedFiles())
+ if (F->isNeeded())
+ Add({DT_NEEDED, Out<ELFT>::DynStrTab->addString(F->getSoName())});
+ if (!Config->SoName.empty())
+ Add({DT_SONAME, Out<ELFT>::DynStrTab->addString(Config->SoName)});
+
+ Out<ELFT>::DynStrTab->finalize();
+
if (Out<ELFT>::RelaDyn->hasRelocs()) {
- ++NumEntries; // DT_RELA / DT_REL
- ++NumEntries; // DT_RELASZ / DT_RELSZ
- ++NumEntries; // DT_RELAENT / DT_RELENT
+ bool IsRela = Config->Rela;
+ Add({IsRela ? DT_RELA : DT_REL, Out<ELFT>::RelaDyn});
+ Add({IsRela ? DT_RELASZ : DT_RELSZ, Out<ELFT>::RelaDyn->getSize()});
+ Add({IsRela ? DT_RELAENT : DT_RELENT,
+ uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
}
if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) {
- ++NumEntries; // DT_JMPREL
- ++NumEntries; // DT_PLTRELSZ
- ++NumEntries; // DT_PLTGOT / DT_MIPS_PLTGOT
- ++NumEntries; // DT_PLTREL
+ Add({DT_JMPREL, Out<ELFT>::RelaPlt});
+ Add({DT_PLTRELSZ, Out<ELFT>::RelaPlt->getSize()});
+ Add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
+ Out<ELFT>::GotPlt});
+ Add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)});
}
- ++NumEntries; // DT_SYMTAB
- ++NumEntries; // DT_SYMENT
- ++NumEntries; // DT_STRTAB
- ++NumEntries; // DT_STRSZ
+ Add({DT_SYMTAB, Out<ELFT>::DynSymTab});
+ Add({DT_SYMENT, sizeof(Elf_Sym)});
+ Add({DT_STRTAB, Out<ELFT>::DynStrTab});
+ Add({DT_STRSZ, Out<ELFT>::DynStrTab->getSize()});
if (Out<ELFT>::GnuHashTab)
- ++NumEntries; // DT_GNU_HASH
+ Add({DT_GNU_HASH, Out<ELFT>::GnuHashTab});
if (Out<ELFT>::HashTab)
- ++NumEntries; // DT_HASH
+ Add({DT_HASH, Out<ELFT>::HashTab});
- if (!Config->RPath.empty()) {
- ++NumEntries; // DT_RUNPATH / DT_RPATH
- Out<ELFT>::DynStrTab->reserve(Config->RPath);
+ if (PreInitArraySec) {
+ Add({DT_PREINIT_ARRAY, PreInitArraySec});
+ Add({DT_PREINIT_ARRAYSZ, PreInitArraySec->getSize()});
}
-
- if (!Config->SoName.empty()) {
- ++NumEntries; // DT_SONAME
- Out<ELFT>::DynStrTab->reserve(Config->SoName);
+ if (InitArraySec) {
+ Add({DT_INIT_ARRAY, InitArraySec});
+ Add({DT_INIT_ARRAYSZ, (uintX_t)InitArraySec->getSize()});
}
-
- if (PreInitArraySec)
- NumEntries += 2;
- if (InitArraySec)
- NumEntries += 2;
- if (FiniArraySec)
- NumEntries += 2;
-
- for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles()) {
- if (!F->isNeeded())
- continue;
- Out<ELFT>::DynStrTab->reserve(F->getSoName());
- ++NumEntries;
+ if (FiniArraySec) {
+ Add({DT_FINI_ARRAY, FiniArraySec});
+ Add({DT_FINI_ARRAYSZ, (uintX_t)FiniArraySec->getSize()});
}
- if (Symbol *S = SymTab.getSymbols().lookup(Config->Init))
- InitSym = S->Body;
- if (Symbol *S = SymTab.getSymbols().lookup(Config->Fini))
- FiniSym = S->Body;
- if (InitSym)
- ++NumEntries; // DT_INIT
- if (FiniSym)
- ++NumEntries; // DT_FINI
+ if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Init))
+ Add({DT_INIT, B});
+ if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Fini))
+ Add({DT_FINI, B});
+ uint32_t DtFlags = 0;
+ uint32_t DtFlags1 = 0;
if (Config->Bsymbolic)
DtFlags |= DF_SYMBOLIC;
if (Config->ZNodelete)
@@ -626,462 +702,490 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
}
if (DtFlags)
- ++NumEntries; // DT_FLAGS
+ Add({DT_FLAGS, DtFlags});
if (DtFlags1)
- ++NumEntries; // DT_FLAGS_1
+ Add({DT_FLAGS_1, DtFlags1});
if (!Config->Entry.empty())
- ++NumEntries; // DT_DEBUG
+ Add({DT_DEBUG, (uint64_t)0});
+
+ bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0;
+ if (HasVerNeed || Out<ELFT>::VerDef)
+ Add({DT_VERSYM, Out<ELFT>::VerSym});
+ if (Out<ELFT>::VerDef) {
+ Add({DT_VERDEF, Out<ELFT>::VerDef});
+ Add({DT_VERDEFNUM, getVerDefNum()});
+ }
+ if (HasVerNeed) {
+ Add({DT_VERNEED, Out<ELFT>::VerNeed});
+ Add({DT_VERNEEDNUM, Out<ELFT>::VerNeed->getNeedNum()});
+ }
if (Config->EMachine == EM_MIPS) {
- ++NumEntries; // DT_MIPS_RLD_VERSION
- ++NumEntries; // DT_MIPS_FLAGS
- ++NumEntries; // DT_MIPS_BASE_ADDRESS
- ++NumEntries; // DT_MIPS_SYMTABNO
- ++NumEntries; // DT_MIPS_LOCAL_GOTNO
- ++NumEntries; // DT_MIPS_GOTSYM;
- ++NumEntries; // DT_PLTGOT
+ Add({DT_MIPS_RLD_VERSION, 1});
+ Add({DT_MIPS_FLAGS, RHF_NOTPOT});
+ Add({DT_MIPS_BASE_ADDRESS, Config->ImageBase});
+ Add({DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols()});
+ Add({DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum()});
+ if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry())
+ Add({DT_MIPS_GOTSYM, B->DynsymIndex});
+ else
+ Add({DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()});
+ Add({DT_PLTGOT, Out<ELFT>::Got});
if (Out<ELFT>::MipsRldMap)
- ++NumEntries; // DT_MIPS_RLD_MAP
+ Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap});
}
- ++NumEntries; // DT_NULL
-
- Header.sh_size = NumEntries * Header.sh_entsize;
+ // +1 for DT_NULL
+ Header.sh_size = (Entries.size() + 1) * Header.sh_entsize;
}
template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
- auto WritePtr = [&](int32_t Tag, uint64_t Val) {
- P->d_tag = Tag;
- P->d_un.d_ptr = Val;
- ++P;
- };
-
- auto WriteVal = [&](int32_t Tag, uint32_t Val) {
- P->d_tag = Tag;
- P->d_un.d_val = Val;
+ for (const Entry &E : Entries) {
+ P->d_tag = E.Tag;
+ switch (E.Kind) {
+ case Entry::SecAddr:
+ P->d_un.d_ptr = E.OutSec->getVA();
+ break;
+ case Entry::SymAddr:
+ P->d_un.d_ptr = E.Sym->template getVA<ELFT>();
+ break;
+ case Entry::PlainInt:
+ P->d_un.d_val = E.Val;
+ break;
+ }
++P;
- };
-
- if (Out<ELFT>::RelaDyn->hasRelocs()) {
- bool IsRela = Out<ELFT>::RelaDyn->isRela();
- WritePtr(IsRela ? DT_RELA : DT_REL, Out<ELFT>::RelaDyn->getVA());
- WriteVal(IsRela ? DT_RELASZ : DT_RELSZ, Out<ELFT>::RelaDyn->getSize());
- WriteVal(IsRela ? DT_RELAENT : DT_RELENT,
- IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel));
}
- if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) {
- WritePtr(DT_JMPREL, Out<ELFT>::RelaPlt->getVA());
- WriteVal(DT_PLTRELSZ, Out<ELFT>::RelaPlt->getSize());
- // On MIPS, the address of the .got.plt section is stored in
- // the DT_MIPS_PLTGOT entry because the DT_PLTGOT entry points to
- // the .got section. See "Dynamic Section" in the following document:
- // https://sourceware.org/ml/binutils/2008-07/txt00000.txt
- WritePtr((Config->EMachine == EM_MIPS) ? DT_MIPS_PLTGOT : DT_PLTGOT,
- Out<ELFT>::GotPlt->getVA());
- WriteVal(DT_PLTREL, Out<ELFT>::RelaPlt->isRela() ? DT_RELA : DT_REL);
- }
-
- WritePtr(DT_SYMTAB, Out<ELFT>::DynSymTab->getVA());
- WritePtr(DT_SYMENT, sizeof(Elf_Sym));
- WritePtr(DT_STRTAB, Out<ELFT>::DynStrTab->getVA());
- WriteVal(DT_STRSZ, Out<ELFT>::DynStrTab->getSize());
- if (Out<ELFT>::GnuHashTab)
- WritePtr(DT_GNU_HASH, Out<ELFT>::GnuHashTab->getVA());
- if (Out<ELFT>::HashTab)
- WritePtr(DT_HASH, Out<ELFT>::HashTab->getVA());
-
- // If --enable-new-dtags is set, lld emits DT_RUNPATH
- // instead of DT_RPATH. The two tags are functionally
- // equivalent except for the following:
- // - DT_RUNPATH is searched after LD_LIBRARY_PATH, while
- // DT_RPATH is searched before.
- // - DT_RUNPATH is used only to search for direct
- // dependencies of the object it's contained in, while
- // DT_RPATH is used for indirect dependencies as well.
- if (!Config->RPath.empty())
- WriteVal(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
- Out<ELFT>::DynStrTab->addString(Config->RPath));
-
- if (!Config->SoName.empty())
- WriteVal(DT_SONAME, Out<ELFT>::DynStrTab->addString(Config->SoName));
-
- auto WriteArray = [&](int32_t T1, int32_t T2,
- const OutputSectionBase<ELFT> *Sec) {
- if (!Sec)
- return;
- WritePtr(T1, Sec->getVA());
- WriteVal(T2, Sec->getSize());
- };
- WriteArray(DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ, PreInitArraySec);
- WriteArray(DT_INIT_ARRAY, DT_INIT_ARRAYSZ, InitArraySec);
- WriteArray(DT_FINI_ARRAY, DT_FINI_ARRAYSZ, FiniArraySec);
-
- for (const std::unique_ptr<SharedFile<ELFT>> &F : SymTab.getSharedFiles())
- if (F->isNeeded())
- WriteVal(DT_NEEDED, Out<ELFT>::DynStrTab->addString(F->getSoName()));
+}
- if (InitSym)
- WritePtr(DT_INIT, getSymVA<ELFT>(*InitSym));
- if (FiniSym)
- WritePtr(DT_FINI, getSymVA<ELFT>(*FiniSym));
- if (DtFlags)
- WriteVal(DT_FLAGS, DtFlags);
- if (DtFlags1)
- WriteVal(DT_FLAGS_1, DtFlags1);
- if (!Config->Entry.empty())
- WriteVal(DT_DEBUG, 0);
+template <class ELFT>
+EhFrameHeader<ELFT>::EhFrameHeader()
+ : OutputSectionBase<ELFT>(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC) {}
+
+// .eh_frame_hdr contains a binary search table of pointers to FDEs.
+// Each entry of the search table consists of two values,
+// the starting PC from where FDEs covers, and the FDE's address.
+// It is sorted by PC.
+template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
+ const endianness E = ELFT::TargetEndianness;
- // See "Dynamic Section" in Chapter 5 in the following document
- // for detailed description:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (Config->EMachine == EM_MIPS) {
- WriteVal(DT_MIPS_RLD_VERSION, 1);
- WriteVal(DT_MIPS_FLAGS, RHF_NOTPOT);
- WritePtr(DT_MIPS_BASE_ADDRESS, Target->getVAStart());
- WriteVal(DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols());
- WriteVal(DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum());
- if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry())
- WriteVal(DT_MIPS_GOTSYM, B->DynamicSymbolTableIndex);
- else
- WriteVal(DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols());
- WritePtr(DT_PLTGOT, Out<ELFT>::Got->getVA());
- if (Out<ELFT>::MipsRldMap)
- WritePtr(DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap->getVA());
+ // Sort the FDE list by their PC and uniqueify. Usually there is only
+ // one FDE for a PC (i.e. function), but if ICF merges two functions
+ // into one, there can be more than one FDEs pointing to the address.
+ auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; };
+ std::stable_sort(Fdes.begin(), Fdes.end(), Less);
+ auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; };
+ Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end());
+
+ Buf[0] = 1;
+ Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
+ Buf[2] = DW_EH_PE_udata4;
+ Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
+ write32<E>(Buf + 4, Out<ELFT>::EhFrame->getVA() - this->getVA() - 4);
+ write32<E>(Buf + 8, Fdes.size());
+ Buf += 12;
+
+ uintX_t VA = this->getVA();
+ for (FdeData &Fde : Fdes) {
+ write32<E>(Buf, Fde.Pc - VA);
+ write32<E>(Buf + 4, Fde.FdeVA - VA);
+ Buf += 8;
}
+}
+
+template <class ELFT> void EhFrameHeader<ELFT>::finalize() {
+ // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
+ this->Header.sh_size = 12 + Out<ELFT>::EhFrame->NumFdes * 8;
+}
- WriteVal(DT_NULL, 0);
+template <class ELFT>
+void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) {
+ Fdes.push_back({Pc, FdeVA});
}
template <class ELFT>
-OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type,
- uintX_t Flags)
- : OutputSectionBase<ELFT>(Name, Type, Flags) {}
+OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
+ : OutputSectionBase<ELFT>(Name, Type, Flags) {
+ if (Type == SHT_RELA)
+ this->Header.sh_entsize = sizeof(Elf_Rela);
+ else if (Type == SHT_REL)
+ this->Header.sh_entsize = sizeof(Elf_Rel);
+}
+
+template <class ELFT> void OutputSection<ELFT>::finalize() {
+ uint32_t Type = this->Header.sh_type;
+ if (Type != SHT_RELA && Type != SHT_REL)
+ return;
+ this->Header.sh_link = Out<ELFT>::SymTab->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();
+ this->Header.sh_info = S->OutSec->SectionIndex;
+}
template <class ELFT>
void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+ assert(C->Live);
auto *S = cast<InputSection<ELFT>>(C);
Sections.push_back(S);
S->OutSec = this;
- uint32_t Align = S->getAlign();
- if (Align > this->Header.sh_addralign)
- this->Header.sh_addralign = Align;
+ this->updateAlignment(S->Alignment);
+}
- uintX_t Off = this->Header.sh_size;
- Off = align(Off, Align);
- S->OutSecOff = Off;
- Off += S->getSize();
- this->Header.sh_size = Off;
+// If an input string is in the form of "foo.N" where N is a number,
+// return N. Otherwise, returns 65536, which is one greater than the
+// lowest priority.
+static int getPriority(StringRef S) {
+ size_t Pos = S.rfind('.');
+ if (Pos == StringRef::npos)
+ return 65536;
+ int V;
+ if (S.substr(Pos + 1).getAsInteger(10, V))
+ return 65536;
+ return V;
}
-template <class ELFT>
-typename ELFFile<ELFT>::uintX_t elf2::getSymVA(const SymbolBody &S) {
- switch (S.kind()) {
- case SymbolBody::DefinedSyntheticKind: {
- auto &D = cast<DefinedSynthetic<ELFT>>(S);
- return D.Section.getVA() + D.Value;
- }
- case SymbolBody::DefinedRegularKind: {
- const auto &DR = cast<DefinedRegular<ELFT>>(S);
- InputSectionBase<ELFT> *SC = DR.Section;
- if (!SC)
- return DR.Sym.st_value;
-
- // Symbol offsets for AMDGPU need to be the offset in bytes of the symbol
- // from the beginning of the section.
- if (Config->EMachine == EM_AMDGPU)
- return SC->getOffset(DR.Sym);
- if (DR.Sym.getType() == STT_TLS)
- return SC->OutSec->getVA() + SC->getOffset(DR.Sym) -
- Out<ELFT>::TlsPhdr->p_vaddr;
- return SC->OutSec->getVA() + SC->getOffset(DR.Sym);
- }
- case SymbolBody::DefinedCommonKind:
- return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(S).OffsetInBss;
- case SymbolBody::SharedKind: {
- auto &SS = cast<SharedSymbol<ELFT>>(S);
- if (SS.NeedsCopy)
- return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
- return 0;
- }
- case SymbolBody::UndefinedElfKind:
- case SymbolBody::UndefinedKind:
- return 0;
- case SymbolBody::LazyKind:
- assert(S.isUsedInRegularObj() && "Lazy symbol reached writer");
- return 0;
- }
- llvm_unreachable("Invalid symbol kind");
-}
-
-// Returns a VA which a relocatin RI refers to. Used only for local symbols.
-// For non-local symbols, use getSymVA instead.
-template <class ELFT, bool IsRela>
-typename ELFFile<ELFT>::uintX_t
-elf2::getLocalRelTarget(const ObjectFile<ELFT> &File,
- const Elf_Rel_Impl<ELFT, IsRela> &RI,
- typename ELFFile<ELFT>::uintX_t Addend) {
- typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename ELFFile<ELFT>::uintX_t uintX_t;
-
- // PPC64 has a special relocation representing the TOC base pointer
- // that does not have a corresponding symbol.
- if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC)
- return getPPC64TocBase() + Addend;
-
- const Elf_Sym *Sym =
- File.getObj().getRelocationSymbol(&RI, File.getSymbolTable());
-
- if (!Sym)
- error("Unsupported relocation without symbol");
-
- InputSectionBase<ELFT> *Section = File.getSection(*Sym);
-
- if (Sym->getType() == STT_TLS)
- return (Section->OutSec->getVA() + Section->getOffset(*Sym) + Addend) -
- Out<ELFT>::TlsPhdr->p_vaddr;
-
- // 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 (Section == &InputSection<ELFT>::Discarded || !Section->isLive())
- return Addend;
-
- uintX_t VA = Section->OutSec->getVA();
- if (isa<InputSection<ELFT>>(Section))
- return VA + Section->getOffset(*Sym) + Addend;
-
- uintX_t Offset = Sym->st_value;
- if (Sym->getType() == STT_SECTION) {
- Offset += Addend;
- Addend = 0;
+// 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->Header.sh_size;
+ for (InputSection<ELFT> *S : Sections) {
+ Off = alignTo(Off, S->Alignment);
+ S->OutSecOff = Off;
+ Off += S->getSize();
}
- return VA + Section->getOffset(Offset) + Addend;
+ this->Header.sh_size = Off;
}
-// 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.
-bool elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) {
- if (!Body)
- return false; // Body is a local symbol.
- if (Body->isShared())
+// Sorts input sections by section name suffixes, so that .foo.N comes
+// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
+// We want to keep the original order if the priorities are the same
+// 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() {
+ // Sort sections by priority.
+ typedef std::pair<int, InputSection<ELFT> *> Pair;
+ auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
+
+ std::vector<Pair> V;
+ for (InputSection<ELFT> *S : Sections)
+ V.push_back({getPriority(S->getSectionName()), S});
+ std::stable_sort(V.begin(), V.end(), Comp);
+ Sections.clear();
+ for (Pair &P : V)
+ Sections.push_back(P.second);
+}
+
+// Returns true if S matches /Filename.?\.o$/.
+static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
+ if (!S.endswith(".o"))
+ return false;
+ S = S.drop_back(2);
+ if (S.endswith(Filename))
return true;
+ return !S.empty() && S.drop_back().endswith(Filename);
+}
- if (Body->isUndefined()) {
- if (!Body->isWeak())
- return true;
-
- // This is an horrible corner case. Ideally we would like to say that any
- // undefined symbol can be preempted so that the dynamic linker has a
- // chance of finding it at runtime.
- //
- // The problem is that the code sequence used to test for weak undef
- // functions looks like
- // if (func) func()
- // If the code is -fPIC the first reference is a load from the got and
- // everything works.
- // If the code is not -fPIC there is no reasonable way to solve it:
- // * A relocation writing to the text segment will fail (it is ro).
- // * A copy relocation doesn't work for functions.
- // * The trick of using a plt entry as the address would fail here since
- // the plt entry would have a non zero address.
- // Since we cannot do anything better, we just resolve the symbol to 0 and
- // don't produce a dynamic relocation.
- //
- // As an extra hack, assume that if we are producing a shared library the
- // user knows what he or she is doing and can handle a dynamic relocation.
- return Config->Shared || NeedsGot;
- }
- if (!Config->Shared)
+static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
+static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
+
+// .ctors and .dtors are sorted by this priority from highest to lowest.
+//
+// 1. The section was contained in crtbegin (crtbegin contains
+// some sentinel value in its .ctors and .dtors so that the runtime
+// can find the beginning of the sections.)
+//
+// 2. The section has an optional priority value in the form of ".ctors.N"
+// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
+// they are compared as string rather than number.
+//
+// 3. The section is just ".ctors" or ".dtors".
+//
+// 4. The section was contained in crtend, which contains an end marker.
+//
+// In an ideal world, we don't need this function because .init_array and
+// .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());
+ if (BeginA != BeginB)
+ return BeginA;
+ bool EndA = isCrtend(A->getFile()->getName());
+ bool EndB = isCrtend(B->getFile()->getName());
+ if (EndA != EndB)
+ return EndB;
+ StringRef X = A->getSectionName();
+ StringRef Y = B->getSectionName();
+ assert(X.startswith(".ctors") || X.startswith(".dtors"));
+ assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
+ X = X.substr(6);
+ Y = Y.substr(6);
+ if (X.empty() && Y.empty())
return false;
- return Body->getVisibility() == STV_DEFAULT;
+ return X < Y;
}
-template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
- for (InputSection<ELFT> *C : Sections)
- C->writeTo(Buf);
+// 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>);
}
-template <class ELFT>
-EHOutputSection<ELFT>::EHOutputSection(StringRef Name, uint32_t Type,
- uintX_t Flags)
- : OutputSectionBase<ELFT>(Name, Type, Flags) {}
-
-template <class ELFT>
-EHRegion<ELFT>::EHRegion(EHInputSection<ELFT> *S, unsigned Index)
- : S(S), Index(Index) {}
+static void fill(uint8_t *Buf, size_t Size, ArrayRef<uint8_t> A) {
+ size_t I = 0;
+ for (; I + A.size() < Size; I += A.size())
+ memcpy(Buf + I, A.data(), A.size());
+ memcpy(Buf + I, A.data(), Size - I);
+}
-template <class ELFT> StringRef EHRegion<ELFT>::data() const {
- ArrayRef<uint8_t> SecData = S->getSectionData();
- ArrayRef<std::pair<uintX_t, uintX_t>> Offsets = S->Offsets;
- size_t Start = Offsets[Index].first;
- size_t End =
- Index == Offsets.size() - 1 ? SecData.size() : Offsets[Index + 1].first;
- return StringRef((const char *)SecData.data() + Start, End - Start);
+template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
+ ArrayRef<uint8_t> Filler = Script<ELFT>::X->getFiller(this->Name);
+ if (!Filler.empty())
+ fill(Buf, this->getSize(), Filler);
+ if (Config->Threads) {
+ parallel_for_each(Sections.begin(), Sections.end(),
+ [=](InputSection<ELFT> *C) { C->writeTo(Buf); });
+ } else {
+ for (InputSection<ELFT> *C : Sections)
+ C->writeTo(Buf);
+ }
}
template <class ELFT>
-Cie<ELFT>::Cie(EHInputSection<ELFT> *S, unsigned Index)
- : EHRegion<ELFT>(S, Index) {}
+EhOutputSection<ELFT>::EhOutputSection()
+ : OutputSectionBase<ELFT>(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
+
+// Returns the first relocation that points to a region
+// between Begin and Begin+Size.
+template <class IntTy, class RelTy>
+static const RelTy *getReloc(IntTy Begin, IntTy Size, ArrayRef<RelTy> &Rels) {
+ for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
+ if (I->r_offset < Begin)
+ continue;
+
+ // Truncate Rels for fast access. That means we expect that the
+ // relocations are sorted and we are looking up symbols in
+ // sequential order. It is naturally satisfied for .eh_frame.
+ Rels = Rels.slice(I - Rels.begin());
+ if (I->r_offset < Begin + Size)
+ return I;
+ return nullptr;
+ }
+ Rels = ArrayRef<RelTy>();
+ return nullptr;
+}
+// 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 <bool IsRela>
-void EHOutputSection<ELFT>::addSectionAux(
- EHInputSection<ELFT> *S,
- iterator_range<const Elf_Rel_Impl<ELFT, IsRela> *> Rels) {
+template <class RelTy>
+CieRecord *EhOutputSection<ELFT>::addCie(SectionPiece &Piece,
+ EhInputSection<ELFT> *Sec,
+ ArrayRef<RelTy> &Rels) {
const endianness E = ELFT::TargetEndianness;
+ if (read32<E>(Piece.data().data() + 4) != 0)
+ fatal("CIE expected at beginning of .eh_frame: " + Sec->getSectionName());
- S->OutSec = this;
- uint32_t Align = S->getAlign();
- if (Align > this->Header.sh_addralign)
- this->Header.sh_addralign = Align;
+ SymbolBody *Personality = nullptr;
+ if (const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels))
+ Personality = &Sec->getFile()->getRelocTargetSym(*Rel);
- Sections.push_back(S);
+ // Search for an existing CIE by CIE contents/relocation target pair.
+ CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
- ArrayRef<uint8_t> SecData = S->getSectionData();
- ArrayRef<uint8_t> D = SecData;
- uintX_t Offset = 0;
- auto RelI = Rels.begin();
- auto RelE = Rels.end();
+ // If not found, create a new one.
+ if (Cie->Piece == nullptr) {
+ Cie->Piece = &Piece;
+ Cies.push_back(Cie);
+ }
+ return Cie;
+}
- DenseMap<unsigned, unsigned> OffsetToIndex;
- while (!D.empty()) {
- unsigned Index = S->Offsets.size();
- S->Offsets.push_back(std::make_pair(Offset, -1));
+// 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(SectionPiece &Piece,
+ EhInputSection<ELFT> *Sec,
+ ArrayRef<RelTy> &Rels) {
+ const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels);
+ if (!Rel)
+ fatal("FDE doesn't reference another section");
+ 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;
+}
- uintX_t Length = readEntryLength(D);
- StringRef Entry((const char *)D.data(), Length);
+// .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;
- while (RelI != RelE && RelI->r_offset < Offset)
- ++RelI;
- uintX_t NextOffset = Offset + Length;
- bool HasReloc = RelI != RelE && RelI->r_offset < NextOffset;
+ DenseMap<size_t, CieRecord *> OffsetToCie;
+ for (SectionPiece &Piece : Sec->Pieces) {
+ // The empty record is the end marker.
+ if (Piece.size() == 4)
+ return;
- uint32_t ID = read32<E>(D.data() + 4);
+ size_t Offset = Piece.InputOff;
+ uint32_t ID = read32<E>(Piece.data().data() + 4);
if (ID == 0) {
- // CIE
- Cie<ELFT> C(S, Index);
-
- StringRef Personality;
- if (HasReloc) {
- uint32_t SymIndex = RelI->getSymbol(Config->Mips64EL);
- SymbolBody &Body = *S->getFile()->getSymbolBody(SymIndex)->repl();
- Personality = Body.getName();
- }
-
- std::pair<StringRef, StringRef> CieInfo(Entry, Personality);
- auto P = CieMap.insert(std::make_pair(CieInfo, Cies.size()));
- if (P.second) {
- Cies.push_back(C);
- this->Header.sh_size += align(Length, sizeof(uintX_t));
- }
- OffsetToIndex[Offset] = P.first->second;
- } else {
- if (!HasReloc)
- error("FDE doesn't reference another section");
- InputSectionBase<ELFT> *Target = S->getRelocTarget(*RelI);
- if (Target != &InputSection<ELFT>::Discarded && Target->isLive()) {
- uint32_t CieOffset = Offset + 4 - ID;
- auto I = OffsetToIndex.find(CieOffset);
- if (I == OffsetToIndex.end())
- error("Invalid CIE reference");
- Cies[I->second].Fdes.push_back(EHRegion<ELFT>(S, Index));
- this->Header.sh_size += align(Length, sizeof(uintX_t));
- }
+ OffsetToCie[Offset] = addCie(Piece, Sec, Rels);
+ continue;
}
- Offset = NextOffset;
- D = D.slice(Length);
+ uint32_t CieOffset = Offset + 4 - ID;
+ CieRecord *Cie = OffsetToCie[CieOffset];
+ if (!Cie)
+ fatal("invalid CIE reference");
+
+ if (!isFdeLive(Piece, Sec, Rels))
+ continue;
+ Cie->FdePieces.push_back(&Piece);
+ NumFdes++;
}
}
template <class ELFT>
-typename EHOutputSection<ELFT>::uintX_t
-EHOutputSection<ELFT>::readEntryLength(ArrayRef<uint8_t> D) {
- const endianness E = ELFT::TargetEndianness;
+void EhOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *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 (D.size() < 4)
- error("Truncated CIE/FDE length");
- uint64_t Len = read32<E>(D.data());
- if (Len < UINT32_MAX) {
- if (Len > (UINT32_MAX - 4))
- error("CIE/FIE size is too large");
- if (Len + 4 > D.size())
- error("CIE/FIE ends past the end of the section");
- return Len + 4;
+ if (const Elf_Shdr *RelSec = Sec->RelocSection) {
+ ELFFile<ELFT> &Obj = Sec->getFile()->getObj();
+ if (RelSec->sh_type == SHT_RELA)
+ addSectionAux(Sec, Obj.relas(RelSec));
+ else
+ addSectionAux(Sec, Obj.rels(RelSec));
+ return;
}
-
- if (D.size() < 12)
- error("Truncated CIE/FDE length");
- Len = read64<E>(D.data() + 4);
- if (Len > (UINT64_MAX - 12))
- error("CIE/FIE size is too large");
- if (Len + 12 > D.size())
- error("CIE/FIE ends past the end of the section");
- return Len + 12;
+ addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
}
template <class ELFT>
-void EHOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
- auto *S = cast<EHInputSection<ELFT>>(C);
- const Elf_Shdr *RelSec = S->RelocSection;
- if (!RelSec)
- return addSectionAux(
- S, make_range((const Elf_Rela *)nullptr, (const Elf_Rela *)nullptr));
- ELFFile<ELFT> &Obj = S->getFile()->getObj();
- if (RelSec->sh_type == SHT_RELA)
- return addSectionAux(S, Obj.relas(RelSec));
- return addSectionAux(S, Obj.rels(RelSec));
+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>
-static typename ELFFile<ELFT>::uintX_t writeAlignedCieOrFde(StringRef Data,
- uint8_t *Buf) {
- typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+template <class ELFT> void EhOutputSection<ELFT>::finalize() {
+ if (this->Header.sh_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 (SectionPiece *Fde : Cie->FdePieces) {
+ Fde->OutputOff = Off;
+ Off += alignTo(Fde->size(), sizeof(uintX_t));
+ }
+ }
+ this->Header.sh_size = Off;
+}
+
+template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
const endianness E = ELFT::TargetEndianness;
- uint64_t Len = align(Data.size(), sizeof(uintX_t));
- write32<E>(Buf, Len - 4);
- memcpy(Buf + 4, Data.data() + 4, Data.size() - 4);
- return Len;
+ 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");
}
-template <class ELFT> void EHOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+// 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->getVA() + Off;
+ fatal("unknown FDE size relative encoding");
+}
+
+template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
const endianness E = ELFT::TargetEndianness;
- size_t Offset = 0;
- for (const Cie<ELFT> &C : Cies) {
- size_t CieOffset = Offset;
-
- uintX_t CIELen = writeAlignedCieOrFde<ELFT>(C.data(), Buf + Offset);
- C.S->Offsets[C.Index].second = Offset;
- Offset += CIELen;
-
- for (const EHRegion<ELFT> &F : C.Fdes) {
- uintX_t Len = writeAlignedCieOrFde<ELFT>(F.data(), Buf + Offset);
- write32<E>(Buf + Offset + 4, Offset + 4 - CieOffset); // Pointer
- F.S->Offsets[F.Index].second = Offset;
- Offset += Len;
+ for (CieRecord *Cie : Cies) {
+ size_t CieOffset = Cie->Piece->OutputOff;
+ writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
+
+ for (SectionPiece *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) {
- const Elf_Shdr *RelSec = S->RelocSection;
- if (!RelSec)
- continue;
- ELFFile<ELFT> &EObj = S->getFile()->getObj();
- if (RelSec->sh_type == SHT_RELA)
- S->relocate(Buf, nullptr, EObj.relas(RelSec));
- else
- S->relocate(Buf, nullptr, EObj.rels(RelSec));
+ 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 (Out<ELFT>::EhFrameHdr) {
+ for (CieRecord *Cie : Cies) {
+ uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece->data());
+ for (SectionPiece *Fde : Cie->FdePieces) {
+ uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
+ uintX_t FdeVA = this->getVA() + Fde->OutputOff;
+ Out<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
+ }
+ }
}
}
template <class ELFT>
MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
- uintX_t Flags)
- : OutputSectionBase<ELFT>(Name, Type, Flags) {}
+ uintX_t Flags, uintX_t Alignment)
+ : OutputSectionBase<ELFT>(Name, Type, Flags),
+ Builder(StringTableBuilder::RAW, Alignment) {}
template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
if (shouldTailMerge()) {
@@ -1089,58 +1193,32 @@ template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
memcpy(Buf, Data.data(), Data.size());
return;
}
- for (const std::pair<StringRef, size_t> &P : Builder.getMap()) {
- StringRef Data = P.first;
+ for (const std::pair<CachedHash<StringRef>, size_t> &P : Builder.getMap()) {
+ StringRef Data = P.first.Val;
memcpy(Buf + P.second, Data.data(), Data.size());
}
}
-static size_t findNull(StringRef S, size_t EntSize) {
- // Optimize the common case.
- if (EntSize == 1)
- return S.find(0);
-
- for (unsigned I = 0, N = S.size(); I != N; I += EntSize) {
- const char *B = S.begin() + I;
- if (std::all_of(B, B + EntSize, [](char C) { return C == 0; }))
- return I;
- }
- return StringRef::npos;
+static StringRef toStringRef(ArrayRef<uint8_t> A) {
+ return {(const char *)A.data(), A.size()};
}
template <class ELFT>
void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
- auto *S = cast<MergeInputSection<ELFT>>(C);
- S->OutSec = this;
- uint32_t Align = S->getAlign();
- if (Align > this->Header.sh_addralign)
- this->Header.sh_addralign = Align;
-
- ArrayRef<uint8_t> D = S->getSectionData();
- StringRef Data((const char *)D.data(), D.size());
- uintX_t EntSize = S->getSectionHdr()->sh_entsize;
-
- if (this->Header.sh_flags & SHF_STRINGS) {
- uintX_t Offset = 0;
- while (!Data.empty()) {
- size_t End = findNull(Data, EntSize);
- if (End == StringRef::npos)
- error("String is not null terminated");
- StringRef Entry = Data.substr(0, End + EntSize);
- uintX_t OutputOffset = Builder.add(Entry);
- if (shouldTailMerge())
- OutputOffset = -1;
- S->Offsets.push_back(std::make_pair(Offset, OutputOffset));
- uintX_t Size = End + EntSize;
- Data = Data.substr(Size);
- Offset += Size;
- }
- } else {
- for (unsigned I = 0, N = Data.size(); I != N; I += EntSize) {
- StringRef Entry = Data.substr(I, EntSize);
- size_t OutputOffset = Builder.add(Entry);
- S->Offsets.push_back(std::make_pair(I, OutputOffset));
- }
+ auto *Sec = cast<MergeInputSection<ELFT>>(C);
+ Sec->OutSec = this;
+ this->updateAlignment(Sec->Alignment);
+ this->Header.sh_entsize = Sec->getSectionHdr()->sh_entsize;
+ Sections.push_back(Sec);
+
+ bool IsString = this->Header.sh_flags & SHF_STRINGS;
+
+ for (SectionPiece &Piece : Sec->Pieces) {
+ if (!Piece.Live)
+ continue;
+ uintX_t OutputOffset = Builder.add(toStringRef(Piece.data()));
+ if (!IsString || !shouldTailMerge())
+ Piece.OutputOff = OutputOffset;
}
}
@@ -1159,38 +1237,32 @@ template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
this->Header.sh_size = Builder.getSize();
}
+template <class ELFT> void MergeOutputSection<ELFT>::finalizePieces() {
+ for (MergeInputSection<ELFT> *Sec : Sections)
+ Sec->finalizePieces();
+}
+
template <class ELFT>
StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic)
: OutputSectionBase<ELFT>(Name, SHT_STRTAB,
Dynamic ? (uintX_t)SHF_ALLOC : 0),
- Dynamic(Dynamic) {
- this->Header.sh_addralign = 1;
-}
+ Dynamic(Dynamic) {}
-// String tables are created in two phases. First you call reserve()
-// to reserve room in the string table, and then call addString() to actually
-// add that string.
-//
-// Why two phases? We want to know the size of the string table as early as
-// possible to fix file layout. So we have separated finalize(), which
-// determines the size of the section, from writeTo(), which writes the section
-// contents to the output buffer. If we merge reserve() with addString(),
-// we need a plumbing work for finalize() and writeTo() so that offsets
-// we obtained in the former function can be written in the latter.
-// This design eliminated that need.
-template <class ELFT> void StringTableSection<ELFT>::reserve(StringRef S) {
- Reserved += S.size() + 1; // +1 for NUL
-}
-
-// Adds a string to the string table. You must call reserve() with the
-// same string before calling addString().
-template <class ELFT> size_t StringTableSection<ELFT>::addString(StringRef S) {
- size_t Pos = Used;
+// Adds a string to the string table. If HashIt is true we hash and check for
+// duplicates. It is optional because the name of global symbols are already
+// uniqued and hashing them again has a big cost for a small value: uniquing
+// them with some other string that happens to be the same.
+template <class ELFT>
+unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
+ if (HashIt) {
+ auto R = StringMap.insert(std::make_pair(S, Size));
+ if (!R.second)
+ return R.first->second;
+ }
+ unsigned Ret = Size;
+ Size += S.size() + 1;
Strings.push_back(S);
- Used += S.size() + 1;
- Reserved -= S.size() + 1;
- assert((int64_t)Reserved >= 0);
- return Pos;
+ return Ret;
}
template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) {
@@ -1203,42 +1275,34 @@ template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) {
}
template <class ELFT>
-bool elf2::shouldKeepInSymtab(const ObjectFile<ELFT> &File, StringRef SymName,
- const typename ELFFile<ELFT>::Elf_Sym &Sym) {
- if (Sym.getType() == STT_SECTION)
- return false;
-
- InputSectionBase<ELFT> *Sec = File.getSection(Sym);
- // If sym references a section in a discarded group, don't keep it.
- if (Sec == &InputSection<ELFT>::Discarded)
- return false;
-
- if (Config->DiscardNone)
- return true;
-
- // In ELF assembly .L symbols are normally discarded by the assembler.
- // If the assembler fails to do so, the linker discards them if
- // * --discard-locals is used.
- // * The symbol is in a SHF_MERGE section, which is normally the reason for
- // the assembler keeping the .L symbol.
- if (!SymName.startswith(".L") && !SymName.empty())
- return true;
+typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
+ if (OutputSec)
+ return OutputSec->getVA() + OffsetInSec;
+ return InputSec->OutSec->getVA() + InputSec->getOffset(OffsetInSec);
+}
- if (Config->DiscardLocals)
- return false;
+template <class ELFT>
+typename ELFT::uint DynamicReloc<ELFT>::getAddend() const {
+ if (UseSymVA)
+ return Sym->getVA<ELFT>(Addend);
+ return Addend;
+}
- return !(Sec->getSectionHdr()->sh_flags & SHF_MERGE);
+template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const {
+ if (Sym && !UseSymVA)
+ return Sym->DynsymIndex;
+ return 0;
}
template <class ELFT>
SymbolTableSection<ELFT>::SymbolTableSection(
- SymbolTable<ELFT> &Table, StringTableSection<ELFT> &StrTabSec)
+ StringTableSection<ELFT> &StrTabSec)
: OutputSectionBase<ELFT>(StrTabSec.isDynamic() ? ".dynsym" : ".symtab",
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0),
- Table(Table), StrTabSec(StrTabSec) {
+ StrTabSec(StrTabSec) {
this->Header.sh_entsize = sizeof(Elf_Sym);
- this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
+ this->Header.sh_addralign = sizeof(uintX_t);
}
// Orders symbols according to their positions in the GOT,
@@ -1246,10 +1310,25 @@ SymbolTableSection<ELFT>::SymbolTableSection(
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-static bool sortMipsSymbols(SymbolBody *L, SymbolBody *R) {
- if (!L->isInGot() || !R->isInGot())
- return R->isInGot();
- return L->GotIndex < R->GotIndex;
+static bool sortMipsSymbols(const std::pair<SymbolBody *, unsigned> &L,
+ const std::pair<SymbolBody *, unsigned> &R) {
+ // Sort entries related to non-local preemptible symbols by GOT indexes.
+ // All other entries go to the first part of GOT in arbitrary order.
+ bool LIsInLocalGot = !L.first->IsInGlobalMipsGot;
+ bool RIsInLocalGot = !R.first->IsInGlobalMipsGot;
+ if (LIsInLocalGot || RIsInLocalGot)
+ return !RIsInLocalGot;
+ return L.first->GotIndex < R.first->GotIndex;
+}
+
+static uint8_t getSymbolBinding(SymbolBody *Body) {
+ Symbol *S = Body->symbol();
+ uint8_t Visibility = S->Visibility;
+ if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
+ return STB_LOCAL;
+ if (Config->NoGnuUnique && S->Binding == STB_GNU_UNIQUE)
+ return STB_GLOBAL;
+ return S->Binding;
}
template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
@@ -1260,11 +1339,19 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
this->Header.sh_link = StrTabSec.SectionIndex;
this->Header.sh_info = NumLocals + 1;
+ if (Config->Relocatable) {
+ size_t I = NumLocals;
+ for (const std::pair<SymbolBody *, size_t> &P : Symbols)
+ P.first->DynsymIndex = ++I;
+ return;
+ }
+
if (!StrTabSec.isDynamic()) {
std::stable_sort(Symbols.begin(), Symbols.end(),
- [](SymbolBody *L, SymbolBody *R) {
- return getSymbolBinding(L) == STB_LOCAL &&
- getSymbolBinding(R) != STB_LOCAL;
+ [](const std::pair<SymbolBody *, unsigned> &L,
+ const std::pair<SymbolBody *, unsigned> &R) {
+ return getSymbolBinding(L.first) == STB_LOCAL &&
+ getSymbolBinding(R.first) != STB_LOCAL;
});
return;
}
@@ -1274,22 +1361,13 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
else if (Config->EMachine == EM_MIPS)
std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
size_t I = 0;
- for (SymbolBody *B : Symbols)
- B->DynamicSymbolTableIndex = ++I;
+ for (const std::pair<SymbolBody *, size_t> &P : Symbols)
+ P.first->DynsymIndex = ++I;
}
template <class ELFT>
-void SymbolTableSection<ELFT>::addLocalSymbol(StringRef Name) {
- StrTabSec.reserve(Name);
- ++NumVisible;
- ++NumLocals;
-}
-
-template <class ELFT>
-void SymbolTableSection<ELFT>::addSymbol(SymbolBody *Body) {
- StrTabSec.reserve(Body->getName());
- Symbols.push_back(Body);
- ++NumVisible;
+void SymbolTableSection<ELFT>::addSymbol(SymbolBody *B) {
+ Symbols.push_back({B, StrTabSec.addString(B->getName(), false)});
}
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
@@ -1307,123 +1385,311 @@ template <class ELFT>
void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
// Iterate over all input object files to copy their local symbols
// to the output symbol table pointed by Buf.
- for (const std::unique_ptr<ObjectFile<ELFT>> &File : Table.getObjectFiles()) {
- Elf_Sym_Range Syms = File->getLocalSymbols();
- for (const Elf_Sym &Sym : Syms) {
- ErrorOr<StringRef> SymNameOrErr = Sym.getName(File->getStringTable());
- error(SymNameOrErr);
- StringRef SymName = *SymNameOrErr;
- if (!shouldKeepInSymtab<ELFT>(*File, SymName, Sym))
- continue;
-
+ for (const std::unique_ptr<ObjectFile<ELFT>> &File :
+ Symtab<ELFT>::X->getObjectFiles()) {
+ for (const std::pair<const DefinedRegular<ELFT> *, size_t> &P :
+ File->KeptLocalSyms) {
+ const DefinedRegular<ELFT> &Body = *P.first;
+ InputSectionBase<ELFT> *Section = Body.Section;
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
- uintX_t VA = 0;
- if (Sym.st_shndx == SHN_ABS) {
+
+ if (!Section) {
ESym->st_shndx = SHN_ABS;
- VA = Sym.st_value;
+ ESym->st_value = Body.Value;
} else {
- InputSectionBase<ELFT> *Section = File->getSection(Sym);
- if (!Section->isLive())
- continue;
const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
ESym->st_shndx = OutSec->SectionIndex;
- VA = Section->getOffset(Sym);
- // Symbol offsets for AMDGPU need to be the offset in bytes of the
- // symbol from the beginning of the section.
- if (Config->EMachine != EM_AMDGPU)
- VA += OutSec->getVA();
+ ESym->st_value = OutSec->getVA() + Section->getOffset(Body);
}
- ESym->st_name = StrTabSec.addString(SymName);
- ESym->st_size = Sym.st_size;
- ESym->setBindingAndType(Sym.getBinding(), Sym.getType());
- ESym->st_value = VA;
+ ESym->st_name = P.second;
+ ESym->st_size = Body.template getSize<ELFT>();
+ ESym->setBindingAndType(STB_LOCAL, Body.Type);
Buf += sizeof(*ESym);
}
}
}
template <class ELFT>
-static const typename llvm::object::ELFFile<ELFT>::Elf_Sym *
-getElfSym(SymbolBody &Body) {
- if (auto *EBody = dyn_cast<DefinedElf<ELFT>>(&Body))
- return &EBody->Sym;
- if (auto *EBody = dyn_cast<UndefinedElf<ELFT>>(&Body))
- return &EBody->Sym;
- return nullptr;
-}
-
-template <class ELFT>
void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
// Write the internal symbol table contents to the output symbol table
// pointed by Buf.
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
- for (SymbolBody *Body : Symbols) {
- const OutputSectionBase<ELFT> *OutSec = nullptr;
+ for (const std::pair<SymbolBody *, size_t> &P : Symbols) {
+ SymbolBody *Body = P.first;
+ size_t StrOff = P.second;
- switch (Body->kind()) {
- case SymbolBody::DefinedSyntheticKind:
- OutSec = &cast<DefinedSynthetic<ELFT>>(Body)->Section;
- break;
- case SymbolBody::DefinedRegularKind: {
- auto *Sym = cast<DefinedRegular<ELFT>>(Body->repl());
- if (InputSectionBase<ELFT> *Sec = Sym->Section) {
- if (!Sec->isLive())
- continue;
- OutSec = Sec->OutSec;
- }
- break;
- }
- case SymbolBody::DefinedCommonKind:
- OutSec = Out<ELFT>::Bss;
- break;
- case SymbolBody::SharedKind: {
- if (cast<SharedSymbol<ELFT>>(Body)->NeedsCopy)
- OutSec = Out<ELFT>::Bss;
- break;
- }
- case SymbolBody::UndefinedElfKind:
- case SymbolBody::UndefinedKind:
- case SymbolBody::LazyKind:
- break;
- }
-
- StringRef Name = Body->getName();
- ESym->st_name = StrTabSec.addString(Name);
-
- unsigned char Type = STT_NOTYPE;
- uintX_t Size = 0;
- if (const Elf_Sym *InputSym = getElfSym<ELFT>(*Body)) {
- Type = InputSym->getType();
- Size = InputSym->st_size;
- } else if (auto *C = dyn_cast<DefinedCommon>(Body)) {
- Type = STT_OBJECT;
- Size = C->Size;
- }
+ uint8_t Type = Body->Type;
+ uintX_t Size = Body->getSize<ELFT>();
ESym->setBindingAndType(getSymbolBinding(Body), Type);
ESym->st_size = Size;
- ESym->setVisibility(Body->getVisibility());
- ESym->st_value = getSymVA<ELFT>(*Body);
+ ESym->st_name = StrOff;
+ ESym->setVisibility(Body->symbol()->Visibility);
+ ESym->st_value = Body->getVA<ELFT>();
- if (OutSec)
+ if (const OutputSectionBase<ELFT> *OutSec = getOutputSection(Body))
ESym->st_shndx = OutSec->SectionIndex;
else if (isa<DefinedRegular<ELFT>>(Body))
ESym->st_shndx = SHN_ABS;
+ // On MIPS we need to mark symbol which has a PLT entry and requires pointer
+ // equality by STO_MIPS_PLT flag. That is necessary to help dynamic linker
+ // distinguish such symbols and MIPS lazy-binding stubs.
+ // https://sourceware.org/ml/binutils/2008-07/txt00000.txt
+ if (Config->EMachine == EM_MIPS && Body->isInPlt() &&
+ Body->NeedsCopyOrPltAddr)
+ ESym->st_other |= STO_MIPS_PLT;
++ESym;
}
}
template <class ELFT>
-uint8_t SymbolTableSection<ELFT>::getSymbolBinding(SymbolBody *Body) {
- uint8_t Visibility = Body->getVisibility();
- if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
- return STB_LOCAL;
- if (const Elf_Sym *ESym = getElfSym<ELFT>(*Body))
- return ESym->getBinding();
- if (isa<DefinedSynthetic<ELFT>>(Body))
- return STB_LOCAL;
- return Body->isWeak() ? STB_WEAK : STB_GLOBAL;
+const OutputSectionBase<ELFT> *
+SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
+ switch (Sym->kind()) {
+ case SymbolBody::DefinedSyntheticKind:
+ return cast<DefinedSynthetic<ELFT>>(Sym)->Section;
+ case SymbolBody::DefinedRegularKind: {
+ auto &D = cast<DefinedRegular<ELFT>>(*Sym);
+ if (D.Section)
+ return D.Section->OutSec;
+ break;
+ }
+ case SymbolBody::DefinedCommonKind:
+ return Out<ELFT>::Bss;
+ case SymbolBody::SharedKind:
+ if (cast<SharedSymbol<ELFT>>(Sym)->needsCopy())
+ return Out<ELFT>::Bss;
+ break;
+ case SymbolBody::UndefinedKind:
+ case SymbolBody::LazyArchiveKind:
+ case SymbolBody::LazyObjectKind:
+ break;
+ case SymbolBody::DefinedBitcodeKind:
+ llvm_unreachable("should have been replaced");
+ }
+ return nullptr;
+}
+
+template <class ELFT>
+VersionDefinitionSection<ELFT>::VersionDefinitionSection()
+ : OutputSectionBase<ELFT>(".gnu.version_d", SHT_GNU_verdef, SHF_ALLOC) {
+ this->Header.sh_addralign = sizeof(uint32_t);
+}
+
+static StringRef getFileDefName() {
+ if (!Config->SoName.empty())
+ return Config->SoName;
+ return Config->OutputFile;
+}
+
+template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() {
+ FileDefNameOff = Out<ELFT>::DynStrTab->addString(getFileDefName());
+ for (VersionDefinition &V : Config->VersionDefinitions)
+ V.NameOff = Out<ELFT>::DynStrTab->addString(V.Name);
+
+ this->Header.sh_size =
+ (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum();
+ this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
+
+ // sh_info should be set to the number of definitions. This fact is missed in
+ // documentation, but confirmed by binutils community:
+ // https://sourceware.org/ml/binutils/2014-11/msg00355.html
+ this->Header.sh_info = getVerDefNum();
+}
+
+template <class ELFT>
+void VersionDefinitionSection<ELFT>::writeOne(uint8_t *Buf, uint32_t Index,
+ StringRef Name, size_t NameOff) {
+ auto *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
+ Verdef->vd_version = 1;
+ Verdef->vd_cnt = 1;
+ Verdef->vd_aux = sizeof(Elf_Verdef);
+ Verdef->vd_next = sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
+ Verdef->vd_flags = (Index == 1 ? VER_FLG_BASE : 0);
+ Verdef->vd_ndx = Index;
+ Verdef->vd_hash = hashSysv(Name);
+
+ auto *Verdaux = reinterpret_cast<Elf_Verdaux *>(Buf + sizeof(Elf_Verdef));
+ Verdaux->vda_name = NameOff;
+ Verdaux->vda_next = 0;
+}
+
+template <class ELFT>
+void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) {
+ writeOne(Buf, 1, getFileDefName(), FileDefNameOff);
+
+ for (VersionDefinition &V : Config->VersionDefinitions) {
+ Buf += sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
+ writeOne(Buf, V.Id, V.Name, V.NameOff);
+ }
+
+ // Need to terminate the last version definition.
+ Elf_Verdef *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
+ Verdef->vd_next = 0;
+}
+
+template <class ELFT>
+VersionTableSection<ELFT>::VersionTableSection()
+ : OutputSectionBase<ELFT>(".gnu.version", SHT_GNU_versym, SHF_ALLOC) {
+ this->Header.sh_addralign = sizeof(uint16_t);
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::finalize() {
+ this->Header.sh_size =
+ sizeof(Elf_Versym) * (Out<ELFT>::DynSymTab->getSymbols().size() + 1);
+ this->Header.sh_entsize = sizeof(Elf_Versym);
+ // At the moment of june 2016 GNU docs does not mention that sh_link field
+ // should be set, but Sun docs do. Also readelf relies on this field.
+ this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
+ auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
+ for (const std::pair<SymbolBody *, size_t> &P :
+ Out<ELFT>::DynSymTab->getSymbols()) {
+ OutVersym->vs_index = P.first->symbol()->VersionId;
+ ++OutVersym;
+ }
+}
+
+template <class ELFT>
+VersionNeedSection<ELFT>::VersionNeedSection()
+ : OutputSectionBase<ELFT>(".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC) {
+ this->Header.sh_addralign = sizeof(uint32_t);
+
+ // Identifiers in verneed section start at 2 because 0 and 1 are reserved
+ // for VER_NDX_LOCAL and VER_NDX_GLOBAL.
+ // First identifiers are reserved by verdef section if it exist.
+ NextIndex = getVerDefNum() + 1;
+}
+
+template <class ELFT>
+void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) {
+ if (!SS->Verdef) {
+ SS->symbol()->VersionId = VER_NDX_GLOBAL;
+ return;
+ }
+ SharedFile<ELFT> *F = SS->file();
+ // If we don't already know that we need an Elf_Verneed for this DSO, prepare
+ // to create one by adding it to our needed list and creating a dynstr entry
+ // for the soname.
+ if (F->VerdefMap.empty())
+ Needed.push_back({F, Out<ELFT>::DynStrTab->addString(F->getSoName())});
+ typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef];
+ // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
+ // prepare to create one by allocating a version identifier and creating a
+ // dynstr entry for the version name.
+ if (NV.Index == 0) {
+ NV.StrTab = Out<ELFT>::DynStrTab->addString(
+ SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name);
+ NV.Index = NextIndex++;
+ }
+ SS->symbol()->VersionId = NV.Index;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
+ // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs.
+ auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf);
+ auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Needed.size());
+
+ for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed) {
+ // Create an Elf_Verneed for this DSO.
+ Verneed->vn_version = 1;
+ Verneed->vn_cnt = P.first->VerdefMap.size();
+ Verneed->vn_file = P.second;
+ Verneed->vn_aux =
+ reinterpret_cast<char *>(Vernaux) - reinterpret_cast<char *>(Verneed);
+ Verneed->vn_next = sizeof(Elf_Verneed);
+ ++Verneed;
+
+ // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over
+ // VerdefMap, which will only contain references to needed version
+ // definitions. Each Elf_Vernaux is based on the information contained in
+ // the Elf_Verdef in the source DSO. This loop iterates over a std::map of
+ // pointers, but is deterministic because the pointers refer to Elf_Verdef
+ // data structures within a single input file.
+ for (auto &NV : P.first->VerdefMap) {
+ Vernaux->vna_hash = NV.first->vd_hash;
+ Vernaux->vna_flags = 0;
+ Vernaux->vna_other = NV.second.Index;
+ Vernaux->vna_name = NV.second.StrTab;
+ Vernaux->vna_next = sizeof(Elf_Vernaux);
+ ++Vernaux;
+ }
+
+ Vernaux[-1].vna_next = 0;
+ }
+ Verneed[-1].vn_next = 0;
+}
+
+template <class ELFT> void VersionNeedSection<ELFT>::finalize() {
+ this->Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
+ this->Header.sh_info = Needed.size();
+ unsigned Size = Needed.size() * sizeof(Elf_Verneed);
+ for (std::pair<SharedFile<ELFT> *, size_t> &P : Needed)
+ Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux);
+ this->Header.sh_size = Size;
+}
+
+template <class ELFT>
+BuildIdSection<ELFT>::BuildIdSection(size_t HashSize)
+ : OutputSectionBase<ELFT>(".note.gnu.build-id", SHT_NOTE, SHF_ALLOC),
+ HashSize(HashSize) {
+ // 16 bytes for the note section header.
+ this->Header.sh_size = 16 + HashSize;
+}
+
+template <class ELFT> void BuildIdSection<ELFT>::writeTo(uint8_t *Buf) {
+ const endianness E = ELFT::TargetEndianness;
+ write32<E>(Buf, 4); // Name size
+ write32<E>(Buf + 4, HashSize); // Content size
+ write32<E>(Buf + 8, NT_GNU_BUILD_ID); // Type
+ memcpy(Buf + 12, "GNU", 4); // Name string
+ HashBuf = Buf + 16;
+}
+
+template <class ELFT>
+void BuildIdFnv1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
+ const endianness E = ELFT::TargetEndianness;
+
+ // 64-bit FNV-1 hash
+ uint64_t Hash = 0xcbf29ce484222325;
+ for (ArrayRef<uint8_t> Buf : Bufs) {
+ for (uint8_t B : Buf) {
+ Hash *= 0x100000001b3;
+ Hash ^= B;
+ }
+ }
+ write64<E>(this->HashBuf, Hash);
+}
+
+template <class ELFT>
+void BuildIdMd5<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
+ MD5 Hash;
+ for (ArrayRef<uint8_t> Buf : Bufs)
+ Hash.update(Buf);
+ MD5::MD5Result Res;
+ Hash.final(Res);
+ memcpy(this->HashBuf, Res, 16);
+}
+
+template <class ELFT>
+void BuildIdSha1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
+ SHA1 Hash;
+ for (ArrayRef<uint8_t> Buf : Bufs)
+ Hash.update(Buf);
+ memcpy(this->HashBuf, Hash.final().data(), 20);
+}
+
+template <class ELFT>
+BuildIdHexstring<ELFT>::BuildIdHexstring()
+ : BuildIdSection<ELFT>(Config->BuildIdVector.size()) {}
+
+template <class ELFT>
+void BuildIdHexstring<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
+ memcpy(this->HashBuf, Config->BuildIdVector.data(),
+ Config->BuildIdVector.size());
}
template <class ELFT>
@@ -1437,7 +1703,7 @@ MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection()
template <class ELFT>
void MipsReginfoOutputSection<ELFT>::writeTo(uint8_t *Buf) {
auto *R = reinterpret_cast<Elf_Mips_RegInfo *>(Buf);
- R->ri_gp_value = getMipsGpAddr<ELFT>();
+ R->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset;
R->ri_gprmask = GprMask;
}
@@ -1446,15 +1712,136 @@ void MipsReginfoOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
// Copy input object file's .reginfo gprmask to output.
auto *S = cast<MipsReginfoInputSection<ELFT>>(C);
GprMask |= S->Reginfo->ri_gprmask;
+ S->OutSec = this;
+}
+
+template <class ELFT>
+MipsOptionsOutputSection<ELFT>::MipsOptionsOutputSection()
+ : OutputSectionBase<ELFT>(".MIPS.options", SHT_MIPS_OPTIONS,
+ SHF_ALLOC | SHF_MIPS_NOSTRIP) {
+ this->Header.sh_addralign = 8;
+ this->Header.sh_entsize = 1;
+ this->Header.sh_size = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+}
+
+template <class ELFT>
+void MipsOptionsOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+ auto *Opt = reinterpret_cast<Elf_Mips_Options *>(Buf);
+ Opt->kind = ODK_REGINFO;
+ Opt->size = this->Header.sh_size;
+ Opt->section = 0;
+ Opt->info = 0;
+ auto *Reg = reinterpret_cast<Elf_Mips_RegInfo *>(Buf + sizeof(*Opt));
+ Reg->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset;
+ Reg->ri_gprmask = GprMask;
+}
+
+template <class ELFT>
+void MipsOptionsOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+ auto *S = cast<MipsOptionsInputSection<ELFT>>(C);
+ if (S->Reginfo)
+ GprMask |= S->Reginfo->ri_gprmask;
+ S->OutSec = this;
+}
+
+template <class ELFT>
+std::pair<OutputSectionBase<ELFT> *, bool>
+OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
+ StringRef OutsecName) {
+ SectionKey<ELFT::Is64Bits> Key = createKey(C, OutsecName);
+ OutputSectionBase<ELFT> *&Sec = Map[Key];
+ if (Sec)
+ return {Sec, false};
+
+ switch (C->SectionKind) {
+ case InputSectionBase<ELFT>::Regular:
+ Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ break;
+ case InputSectionBase<ELFT>::EHFrame:
+ return {Out<ELFT>::EhFrame, false};
+ case InputSectionBase<ELFT>::Merge:
+ Sec = new MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags,
+ Key.Alignment);
+ break;
+ case InputSectionBase<ELFT>::MipsReginfo:
+ Sec = new MipsReginfoOutputSection<ELFT>();
+ break;
+ case InputSectionBase<ELFT>::MipsOptions:
+ Sec = new MipsOptionsOutputSection<ELFT>();
+ break;
+ }
+ return {Sec, true};
+}
+
+template <class ELFT>
+OutputSectionBase<ELFT> *OutputSectionFactory<ELFT>::lookup(StringRef Name,
+ uint32_t Type,
+ uintX_t Flags) {
+ return Map.lookup({Name, Type, Flags, 0});
+}
+
+template <class ELFT>
+SectionKey<ELFT::Is64Bits>
+OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C,
+ StringRef OutsecName) {
+ const Elf_Shdr *H = C->getSectionHdr();
+ uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED;
+
+ // For SHF_MERGE we create different output sections for each alignment.
+ // This makes each output section simple and keeps a single level mapping from
+ // input to output.
+ uintX_t Alignment = 0;
+ if (isa<MergeInputSection<ELFT>>(C))
+ Alignment = std::max(H->sh_addralign, H->sh_entsize);
+
+ uint32_t Type = H->sh_type;
+ return SectionKey<ELFT::Is64Bits>{OutsecName, Type, Flags, Alignment};
+}
+
+template <bool Is64Bits>
+typename lld::elf::SectionKey<Is64Bits>
+DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getEmptyKey() {
+ return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0, 0};
+}
+
+template <bool Is64Bits>
+typename lld::elf::SectionKey<Is64Bits>
+DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getTombstoneKey() {
+ return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0,
+ 0};
+}
+
+template <bool Is64Bits>
+unsigned
+DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getHashValue(const Key &Val) {
+ return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment);
+}
+
+template <bool Is64Bits>
+bool DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::isEqual(const Key &LHS,
+ const Key &RHS) {
+ return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
+ LHS.Type == RHS.Type && LHS.Flags == RHS.Flags &&
+ LHS.Alignment == RHS.Alignment;
+}
+
+namespace llvm {
+template struct DenseMapInfo<SectionKey<true>>;
+template struct DenseMapInfo<SectionKey<false>>;
}
namespace lld {
-namespace elf2 {
+namespace elf {
template class OutputSectionBase<ELF32LE>;
template class OutputSectionBase<ELF32BE>;
template class OutputSectionBase<ELF64LE>;
template class OutputSectionBase<ELF64BE>;
+template class EhFrameHeader<ELF32LE>;
+template class EhFrameHeader<ELF32BE>;
+template class EhFrameHeader<ELF64LE>;
+template class EhFrameHeader<ELF64BE>;
+
template class GotPltSection<ELF32LE>;
template class GotPltSection<ELF32BE>;
template class GotPltSection<ELF64LE>;
@@ -1500,16 +1887,21 @@ 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 EhOutputSection<ELF32LE>;
+template class EhOutputSection<ELF32BE>;
+template class EhOutputSection<ELF64LE>;
+template class EhOutputSection<ELF64BE>;
template class MipsReginfoOutputSection<ELF32LE>;
template class MipsReginfoOutputSection<ELF32BE>;
template class MipsReginfoOutputSection<ELF64LE>;
template class MipsReginfoOutputSection<ELF64BE>;
+template class MipsOptionsOutputSection<ELF32LE>;
+template class MipsOptionsOutputSection<ELF32BE>;
+template class MipsOptionsOutputSection<ELF64LE>;
+template class MipsOptionsOutputSection<ELF64BE>;
+
template class MergeOutputSection<ELF32LE>;
template class MergeOutputSection<ELF32BE>;
template class MergeOutputSection<ELF64LE>;
@@ -1525,39 +1917,49 @@ template class SymbolTableSection<ELF32BE>;
template class SymbolTableSection<ELF64LE>;
template class SymbolTableSection<ELF64BE>;
-template ELFFile<ELF32LE>::uintX_t getSymVA<ELF32LE>(const SymbolBody &);
-template ELFFile<ELF32BE>::uintX_t getSymVA<ELF32BE>(const SymbolBody &);
-template ELFFile<ELF64LE>::uintX_t getSymVA<ELF64LE>(const SymbolBody &);
-template ELFFile<ELF64BE>::uintX_t getSymVA<ELF64BE>(const SymbolBody &);
-
-template ELFFile<ELF32LE>::uintX_t
-getLocalRelTarget(const ObjectFile<ELF32LE> &,
- const ELFFile<ELF32LE>::Elf_Rel &,
- ELFFile<ELF32LE>::uintX_t Addend);
-template ELFFile<ELF32BE>::uintX_t
-getLocalRelTarget(const ObjectFile<ELF32BE> &,
- const ELFFile<ELF32BE>::Elf_Rel &,
- ELFFile<ELF32BE>::uintX_t Addend);
-template ELFFile<ELF64LE>::uintX_t
-getLocalRelTarget(const ObjectFile<ELF64LE> &,
- const ELFFile<ELF64LE>::Elf_Rel &,
- ELFFile<ELF64LE>::uintX_t Addend);
-template ELFFile<ELF64BE>::uintX_t
-getLocalRelTarget(const ObjectFile<ELF64BE> &,
- const ELFFile<ELF64BE>::Elf_Rel &,
- ELFFile<ELF64BE>::uintX_t Addend);
-
-template bool shouldKeepInSymtab<ELF32LE>(const ObjectFile<ELF32LE> &,
- StringRef,
- const ELFFile<ELF32LE>::Elf_Sym &);
-template bool shouldKeepInSymtab<ELF32BE>(const ObjectFile<ELF32BE> &,
- StringRef,
- const ELFFile<ELF32BE>::Elf_Sym &);
-template bool shouldKeepInSymtab<ELF64LE>(const ObjectFile<ELF64LE> &,
- StringRef,
- const ELFFile<ELF64LE>::Elf_Sym &);
-template bool shouldKeepInSymtab<ELF64BE>(const ObjectFile<ELF64BE> &,
- StringRef,
- const ELFFile<ELF64BE>::Elf_Sym &);
+template class VersionTableSection<ELF32LE>;
+template class VersionTableSection<ELF32BE>;
+template class VersionTableSection<ELF64LE>;
+template class VersionTableSection<ELF64BE>;
+
+template class VersionNeedSection<ELF32LE>;
+template class VersionNeedSection<ELF32BE>;
+template class VersionNeedSection<ELF64LE>;
+template class VersionNeedSection<ELF64BE>;
+
+template class VersionDefinitionSection<ELF32LE>;
+template class VersionDefinitionSection<ELF32BE>;
+template class VersionDefinitionSection<ELF64LE>;
+template class VersionDefinitionSection<ELF64BE>;
+
+template class BuildIdSection<ELF32LE>;
+template class BuildIdSection<ELF32BE>;
+template class BuildIdSection<ELF64LE>;
+template class BuildIdSection<ELF64BE>;
+
+template class BuildIdFnv1<ELF32LE>;
+template class BuildIdFnv1<ELF32BE>;
+template class BuildIdFnv1<ELF64LE>;
+template class BuildIdFnv1<ELF64BE>;
+
+template class BuildIdMd5<ELF32LE>;
+template class BuildIdMd5<ELF32BE>;
+template class BuildIdMd5<ELF64LE>;
+template class BuildIdMd5<ELF64BE>;
+
+template class BuildIdSha1<ELF32LE>;
+template class BuildIdSha1<ELF32BE>;
+template class BuildIdSha1<ELF64LE>;
+template class BuildIdSha1<ELF64BE>;
+
+template class BuildIdHexstring<ELF32LE>;
+template class BuildIdHexstring<ELF32BE>;
+template class BuildIdHexstring<ELF64LE>;
+template class BuildIdHexstring<ELF64BE>;
+
+template class OutputSectionFactory<ELF32LE>;
+template class OutputSectionFactory<ELF32BE>;
+template class OutputSectionFactory<ELF64LE>;
+template class OutputSectionFactory<ELF64BE>;
}
}
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index d7109c580cdc..5fdf8de4cb46 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -10,64 +10,35 @@
#ifndef LLD_ELF_OUTPUT_SECTIONS_H
#define LLD_ELF_OUTPUT_SECTIONS_H
-#include "lld/Core/LLVM.h"
+#include "Config.h"
+#include "Relocations.h"
-#include "llvm/ADT/MapVector.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
-
-#include "Config.h"
-
-#include <type_traits>
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/SHA1.h"
namespace lld {
-namespace elf2 {
+namespace elf {
class SymbolBody;
+struct SectionPiece;
template <class ELFT> class SymbolTable;
template <class ELFT> class SymbolTableSection;
template <class ELFT> class StringTableSection;
-template <class ELFT> class EHInputSection;
+template <class ELFT> class EhInputSection;
template <class ELFT> class InputSection;
template <class ELFT> class InputSectionBase;
template <class ELFT> class MergeInputSection;
template <class ELFT> class MipsReginfoInputSection;
template <class ELFT> class OutputSection;
template <class ELFT> class ObjectFile;
+template <class ELFT> class SharedFile;
+template <class ELFT> class SharedSymbol;
template <class ELFT> class DefinedRegular;
-// Flag to force GOT to be in output if we have relocations
-// that relies on its address.
-extern bool HasGotOffRel;
-
-template <class ELFT>
-static inline typename llvm::object::ELFFile<ELFT>::uintX_t
-getAddend(const typename llvm::object::ELFFile<ELFT>::Elf_Rel &Rel) {
- return 0;
-}
-
-template <class ELFT>
-static inline typename llvm::object::ELFFile<ELFT>::uintX_t
-getAddend(const typename llvm::object::ELFFile<ELFT>::Elf_Rela &Rel) {
- return Rel.r_addend;
-}
-
-template <class ELFT>
-typename llvm::object::ELFFile<ELFT>::uintX_t getSymVA(const SymbolBody &S);
-
-template <class ELFT, bool IsRela>
-typename llvm::object::ELFFile<ELFT>::uintX_t
-getLocalRelTarget(const ObjectFile<ELFT> &File,
- const llvm::object::Elf_Rel_Impl<ELFT, IsRela> &Rel,
- typename llvm::object::ELFFile<ELFT>::uintX_t Addend);
-
-bool canBePreempted(const SymbolBody *Body, bool NeedsGot);
-
-template <class ELFT>
-bool shouldKeepInSymtab(
- const ObjectFile<ELFT> &File, StringRef Name,
- const typename llvm::object::ELFFile<ELFT>::Elf_Sym &Sym);
-
// 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.
@@ -75,13 +46,14 @@ bool shouldKeepInSymtab(
// non-overlapping file offsets and VAs.
template <class ELFT> class OutputSectionBase {
public:
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename ELFT::uint uintX_t;
+ typedef typename ELFT::Shdr Elf_Shdr;
- OutputSectionBase(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
+ OutputSectionBase(StringRef Name, uint32_t Type, uintX_t Flags);
void setVA(uintX_t VA) { Header.sh_addr = VA; }
uintX_t getVA() const { return Header.sh_addr; }
void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
+ void setSHName(unsigned Val) { Header.sh_name = Val; }
void writeHeaderTo(Elf_Shdr *SHdr);
StringRef getName() { return Name; }
@@ -92,21 +64,24 @@ public:
// Returns the size of the section in the output file.
uintX_t getSize() const { return Header.sh_size; }
void setSize(uintX_t Val) { Header.sh_size = Val; }
- uintX_t getFlags() { return Header.sh_flags; }
- uintX_t getFileOff() { return Header.sh_offset; }
- uintX_t getAlign() {
- // The ELF spec states that a value of 0 means the section has no alignment
- // constraits.
- return std::max<uintX_t>(Header.sh_addralign, 1);
- }
- uint32_t getType() { return Header.sh_type; }
- void updateAlign(uintX_t Align) {
- if (Align > Header.sh_addralign)
- Header.sh_addralign = Align;
+ uintX_t getFlags() const { return Header.sh_flags; }
+ uintX_t getFileOff() const { return Header.sh_offset; }
+ uintX_t getAlignment() const { return Header.sh_addralign; }
+ uint32_t getType() const { return Header.sh_type; }
+
+ void updateAlignment(uintX_t Alignment) {
+ if (Alignment > Header.sh_addralign)
+ Header.sh_addralign = Alignment;
}
+ // If true, this section will be page aligned on disk.
+ // Typically the first section of each PT_LOAD segment has this flag.
+ bool PageAlign = false;
+
virtual void finalize() {}
- virtual void writeTo(uint8_t *Buf) = 0;
+ virtual void finalizePieces() {}
+ virtual void assignOffsets() {}
+ virtual void writeTo(uint8_t *Buf) {}
virtual ~OutputSectionBase() = default;
protected:
@@ -116,18 +91,21 @@ protected:
template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> {
typedef OutputSectionBase<ELFT> Base;
- typedef typename Base::uintX_t uintX_t;
+ typedef typename ELFT::uint uintX_t;
public:
GotSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
- void addEntry(SymbolBody *Sym);
- bool addDynTlsEntry(SymbolBody *Sym);
- bool addCurrentModuleTlsIndex();
- bool empty() const { return Entries.empty(); }
- uintX_t getEntryAddr(const SymbolBody &B) const;
+ void addEntry(SymbolBody &Sym);
+ void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
+ bool addDynTlsEntry(SymbolBody &Sym);
+ bool addTlsIndex();
+ bool empty() const { return MipsPageEntries == 0 && Entries.empty(); }
+ uintX_t getMipsLocalPageOffset(uintX_t Addr);
+ uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const;
uintX_t getGlobalDynAddr(const SymbolBody &B) const;
+ uintX_t getGlobalDynOffset(const SymbolBody &B) const;
uintX_t getNumEntries() const { return Entries.size(); }
// Returns the symbol which corresponds to the first entry of the global part
@@ -140,24 +118,52 @@ public:
// the number of reserved entries. This method is MIPS-specific.
unsigned getMipsLocalEntriesNum() const;
- uint32_t getLocalTlsIndexVA() { return Base::getVA() + LocalTlsIndexOff; }
+ // Returns offset of TLS part of the MIPS GOT table. This part goes
+ // after 'local' and 'global' entries.
+ uintX_t getMipsTlsOffset();
+
+ uintX_t getTlsIndexVA() { return Base::getVA() + TlsIndexOff; }
+ uint32_t getTlsIndexOff() { return TlsIndexOff; }
+
+ // Flag to force GOT to be in output if we have relocations
+ // that relies on its address.
+ bool HasGotOffRel = false;
private:
std::vector<const SymbolBody *> Entries;
- uint32_t LocalTlsIndexOff = -1;
+ uint32_t TlsIndexOff = -1;
+ uint32_t MipsPageEntries = 0;
+ // Output sections referenced by MIPS GOT relocations.
+ llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections;
+ llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
+
+ // MIPS ABI requires to create unique GOT entry for each Symbol/Addend
+ // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal`
+ // or `MipsGlobal` vectors. In general it does not have a sence to take in
+ // account addend for preemptible symbols because the corresponding
+ // GOT entries should have one-to-one mapping with dynamic symbols table.
+ // But we use the same container's types for both kind of GOT entries
+ // to handle them uniformly.
+ typedef std::pair<const SymbolBody*, uintX_t> MipsGotEntry;
+ typedef std::vector<MipsGotEntry> MipsGotEntries;
+ llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap;
+ MipsGotEntries MipsLocal;
+ MipsGotEntries MipsGlobal;
+
+ // Write MIPS-specific parts of the GOT.
+ void writeMipsGot(uint8_t *&Buf);
};
template <class ELFT>
class GotPltSection final : public OutputSectionBase<ELFT> {
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ typedef typename ELFT::uint uintX_t;
public:
GotPltSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
- void addEntry(SymbolBody *Sym);
+ void addEntry(SymbolBody &Sym);
bool empty() const;
- uintX_t getEntryAddr(const SymbolBody &B) const;
private:
std::vector<const SymbolBody *> Entries;
@@ -165,156 +171,248 @@ private:
template <class ELFT> class PltSection final : public OutputSectionBase<ELFT> {
typedef OutputSectionBase<ELFT> Base;
- typedef typename Base::uintX_t uintX_t;
+ typedef typename ELFT::uint uintX_t;
public:
PltSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
- void addEntry(SymbolBody *Sym);
+ void addEntry(SymbolBody &Sym);
bool empty() const { return Entries.empty(); }
- uintX_t getEntryAddr(const SymbolBody &B) const;
private:
std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
};
-template <class ELFT> struct DynamicReloc {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- InputSectionBase<ELFT> *C;
- const Elf_Rel *RI;
+template <class ELFT> class DynamicReloc {
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ DynamicReloc(uint32_t Type, const InputSectionBase<ELFT> *InputSec,
+ uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
+ uintX_t Addend)
+ : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
+ UseSymVA(UseSymVA), Addend(Addend) {}
+
+ DynamicReloc(uint32_t Type, const OutputSectionBase<ELFT> *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;
+ uint32_t getSymIndex() const;
+ const OutputSectionBase<ELFT> *getOutputSec() const { return OutputSec; }
+
+ uint32_t Type;
+
+private:
+ SymbolBody *Sym;
+ const InputSectionBase<ELFT> *InputSec = nullptr;
+ const OutputSectionBase<ELFT> *OutputSec = nullptr;
+ uintX_t OffsetInSec;
+ bool UseSymVA;
+ uintX_t Addend;
};
template <class ELFT>
class SymbolTableSection final : public OutputSectionBase<ELFT> {
public:
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
- SymbolTableSection(SymbolTable<ELFT> &Table,
- StringTableSection<ELFT> &StrTabSec);
+ 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;
void writeTo(uint8_t *Buf) override;
- void addLocalSymbol(StringRef Name);
void addSymbol(SymbolBody *Body);
StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
- unsigned getNumSymbols() const { return NumVisible + 1; }
+ unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; }
- ArrayRef<SymbolBody *> getSymbols() const { return Symbols; }
+ ArrayRef<std::pair<SymbolBody *, size_t>> getSymbols() const {
+ return Symbols;
+ }
+
+ unsigned NumLocals = 0;
+ StringTableSection<ELFT> &StrTabSec;
private:
void writeLocalSymbols(uint8_t *&Buf);
void writeGlobalSymbols(uint8_t *Buf);
- static uint8_t getSymbolBinding(SymbolBody *Body);
+ const OutputSectionBase<ELFT> *getOutputSection(SymbolBody *Sym);
- SymbolTable<ELFT> &Table;
- StringTableSection<ELFT> &StrTabSec;
- std::vector<SymbolBody *> Symbols;
- unsigned NumVisible = 0;
- unsigned NumLocals = 0;
+ // A vector of symbols and their string table offsets.
+ std::vector<std::pair<SymbolBody *, size_t>> Symbols;
+};
+
+// For more information about .gnu.version and .gnu.version_r see:
+// https://www.akkadia.org/drepper/symbol-versioning
+
+// The .gnu.version_d section which has a section type of SHT_GNU_verdef shall
+// contain symbol version definitions. The number of entries in this section
+// shall be contained in the DT_VERDEFNUM entry of the .dynamic section.
+// 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 OutputSectionBase<ELFT> {
+ typedef typename ELFT::Verdef Elf_Verdef;
+ typedef typename ELFT::Verdaux Elf_Verdaux;
+
+public:
+ VersionDefinitionSection();
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+
+private:
+ void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff);
+
+ unsigned FileDefNameOff;
+};
+
+// The .gnu.version section specifies the required version of each symbol in the
+// dynamic symbol table. It contains one Elf_Versym for each dynamic symbol
+// table entry. An Elf_Versym is just a 16-bit integer that refers to a version
+// identifier defined in the either .gnu.version_r or .gnu.version_d section.
+// 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 OutputSectionBase<ELFT> {
+ typedef typename ELFT::Versym Elf_Versym;
+
+public:
+ VersionTableSection();
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+};
+
+// The .gnu.version_r section defines the version identifiers used by
+// .gnu.version. It contains a linked list of Elf_Verneed data structures. Each
+// 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 OutputSectionBase<ELFT> {
+ typedef typename ELFT::Verneed Elf_Verneed;
+ typedef typename ELFT::Vernaux Elf_Vernaux;
+
+ // A vector of shared files that need Elf_Verneed data structures and the
+ // string table offsets of their sonames.
+ std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed;
+
+ // The next available version identifier.
+ unsigned NextIndex;
+
+public:
+ VersionNeedSection();
+ void addSymbol(SharedSymbol<ELFT> *SS);
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+ size_t getNeedNum() const { return Needed.size(); }
};
template <class ELFT>
class RelocationSection final : public OutputSectionBase<ELFT> {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ typedef typename ELFT::Rel Elf_Rel;
+ typedef typename ELFT::Rela Elf_Rela;
+ typedef typename ELFT::uint uintX_t;
public:
- RelocationSection(StringRef Name, bool IsRela);
- void addReloc(const DynamicReloc<ELFT> &Reloc) { Relocs.push_back(Reloc); }
+ RelocationSection(StringRef Name, bool Sort);
+ void addReloc(const DynamicReloc<ELFT> &Reloc);
unsigned getRelocOffset();
void finalize() override;
void writeTo(uint8_t *Buf) override;
bool hasRelocs() const { return !Relocs.empty(); }
- bool isRela() const { return IsRela; }
bool Static = false;
private:
- bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type, Elf_Rel *P,
- Elf_Rel *N);
-
+ bool Sort;
std::vector<DynamicReloc<ELFT>> Relocs;
- const bool IsRela;
};
template <class ELFT>
class OutputSection final : public OutputSectionBase<ELFT> {
public:
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
- OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
+ 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(InputSectionBase<ELFT> *C) override;
+ void sortInitFini();
+ void sortCtorsDtors();
void writeTo(uint8_t *Buf) override;
-
-private:
+ void finalize() override;
+ void assignOffsets() override;
std::vector<InputSection<ELFT> *> Sections;
};
template <class ELFT>
class MergeOutputSection final : public OutputSectionBase<ELFT> {
- typedef typename OutputSectionBase<ELFT>::uintX_t uintX_t;
-
- bool shouldTailMerge() const;
+ typedef typename ELFT::uint uintX_t;
public:
- MergeOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
+ MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
+ uintX_t Alignment);
void addSection(InputSectionBase<ELFT> *S) override;
void writeTo(uint8_t *Buf) override;
unsigned getOffset(StringRef Val);
void finalize() override;
+ void finalizePieces() override;
+ bool shouldTailMerge() const;
private:
- llvm::StringTableBuilder Builder{llvm::StringTableBuilder::RAW};
+ llvm::StringTableBuilder Builder;
+ std::vector<MergeInputSection<ELFT> *> Sections;
};
-// FDE or CIE
-template <class ELFT> struct EHRegion {
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
- EHRegion(EHInputSection<ELFT> *S, unsigned Index);
- StringRef data() const;
- EHInputSection<ELFT> *S;
- unsigned Index;
-};
-
-template <class ELFT> struct Cie : public EHRegion<ELFT> {
- Cie(EHInputSection<ELFT> *S, unsigned Index);
- std::vector<EHRegion<ELFT>> Fdes;
+struct CieRecord {
+ SectionPiece *Piece = nullptr;
+ std::vector<SectionPiece *> FdePieces;
};
+// Output section for .eh_frame.
template <class ELFT>
-class EHOutputSection final : public OutputSectionBase<ELFT> {
+class EhOutputSection final : public OutputSectionBase<ELFT> {
+ 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:
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
- EHOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
+ EhOutputSection();
void writeTo(uint8_t *Buf) override;
-
- template <bool IsRela>
- void addSectionAux(
- EHInputSection<ELFT> *S,
- llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, IsRela> *>
- Rels);
+ void finalize() override;
+ bool empty() const { return Sections.empty(); }
void addSection(InputSectionBase<ELFT> *S) override;
+ size_t NumFdes = 0;
+
private:
- uintX_t readEntryLength(ArrayRef<uint8_t> D);
+ template <class RelTy>
+ void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
+
+ template <class RelTy>
+ CieRecord *addCie(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
+ ArrayRef<RelTy> &Rels);
+
+ template <class RelTy>
+ bool isFdeLive(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
+ ArrayRef<RelTy> &Rels);
+
+ uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
- std::vector<EHInputSection<ELFT> *> Sections;
- std::vector<Cie<ELFT>> Cies;
+ std::vector<EhInputSection<ELFT> *> Sections;
+ std::vector<CieRecord *> Cies;
- // Maps CIE content + personality to a index in Cies.
- llvm::DenseMap<std::pair<StringRef, StringRef>, unsigned> CieMap;
+ // CIE records are uniquified by their contents and personality functions.
+ llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
};
template <class ELFT>
@@ -327,25 +425,24 @@ public:
template <class ELFT>
class StringTableSection final : public OutputSectionBase<ELFT> {
public:
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ typedef typename ELFT::uint uintX_t;
StringTableSection(StringRef Name, bool Dynamic);
- void reserve(StringRef S);
- size_t addString(StringRef S);
+ unsigned addString(StringRef S, bool HashIt = true);
void writeTo(uint8_t *Buf) override;
- size_t getSize() const { return Used + Reserved; }
+ unsigned getSize() const { return Size; }
void finalize() override { this->Header.sh_size = getSize(); }
bool isDynamic() const { return Dynamic; }
private:
const bool Dynamic;
+ llvm::DenseMap<StringRef, unsigned> StringMap;
std::vector<StringRef> Strings;
- size_t Used = 1; // ELF string tables start with a NUL byte, so 1.
- size_t Reserved = 0;
+ unsigned Size = 1; // ELF string tables start with a NUL byte, so 1.
};
template <class ELFT>
class HashTableSection final : public OutputSectionBase<ELFT> {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
+ typedef typename ELFT::Word Elf_Word;
public:
HashTableSection();
@@ -357,9 +454,9 @@ public:
// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
template <class ELFT>
class GnuHashTableSection final : public OutputSectionBase<ELFT> {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Off Elf_Off;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ typedef typename ELFT::Off Elf_Off;
+ typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::uint uintX_t;
public:
GnuHashTableSection();
@@ -368,7 +465,7 @@ public:
// Adds symbols to the hash table.
// Sorts the input to satisfy GNU hash section requirements.
- void addSymbols(std::vector<SymbolBody *> &Symbols);
+ void addSymbols(std::vector<std::pair<SymbolBody *, size_t>> &Symbols);
private:
static unsigned calcNBuckets(unsigned NumHashed);
@@ -378,12 +475,13 @@ private:
void writeBloomFilter(uint8_t *&Buf);
void writeHashTable(uint8_t *Buf);
- struct HashedSymbolData {
+ struct SymbolData {
SymbolBody *Body;
+ size_t STName;
uint32_t Hash;
};
- std::vector<HashedSymbolData> HashedSymbols;
+ std::vector<SymbolData> Symbols;
unsigned MaskWords;
unsigned NBuckets;
@@ -393,27 +491,45 @@ private:
template <class ELFT>
class DynamicSection final : public OutputSectionBase<ELFT> {
typedef OutputSectionBase<ELFT> Base;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Dyn Elf_Dyn;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
+ 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
+ // type and value fields. Value are one of plain integers, symbol
+ // addresses, or section addresses. This struct represents the entry.
+ struct Entry {
+ int32_t Tag;
+ union {
+ OutputSectionBase<ELFT> *OutSec;
+ uint64_t Val;
+ const SymbolBody *Sym;
+ };
+ enum KindT { SecAddr, SymAddr, PlainInt } Kind;
+ Entry(int32_t Tag, OutputSectionBase<ELFT> *OutSec)
+ : Tag(Tag), OutSec(OutSec), Kind(SecAddr) {}
+ 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.
+ std::vector<Entry> Entries;
public:
- DynamicSection(SymbolTable<ELFT> &SymTab);
+ explicit DynamicSection();
void finalize() override;
void writeTo(uint8_t *Buf) override;
OutputSectionBase<ELFT> *PreInitArraySec = nullptr;
OutputSectionBase<ELFT> *InitArraySec = nullptr;
OutputSectionBase<ELFT> *FiniArraySec = nullptr;
-
-private:
- SymbolTable<ELFT> &SymTab;
- const SymbolBody *InitSym = nullptr;
- const SymbolBody *FiniSym = nullptr;
- uint32_t DtFlags = 0;
- uint32_t DtFlags1 = 0;
};
template <class ELFT>
@@ -429,17 +545,94 @@ private:
uint32_t GprMask = 0;
};
-inline uint64_t align(uint64_t Value, uint64_t Align) {
- return llvm::RoundUpToAlignment(Value, Align);
-}
+template <class ELFT>
+class MipsOptionsOutputSection final : public OutputSectionBase<ELFT> {
+ typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
+ typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+ MipsOptionsOutputSection();
+ void writeTo(uint8_t *Buf) override;
+ void addSection(InputSectionBase<ELFT> *S) override;
+
+private:
+ uint32_t GprMask = 0;
+};
+
+// --eh-frame-hdr option tells linker to construct a header for all the
+// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
+// and also to a PT_GNU_EH_FRAME segment.
+// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
+// calling dl_iterate_phdr.
+// This section contains a lookup table for quick binary search of FDEs.
+// 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 OutputSectionBase<ELFT> {
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ EhFrameHeader();
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+ void addFde(uint32_t Pc, uint32_t FdeVA);
+
+private:
+ struct FdeData {
+ uint32_t Pc;
+ uint32_t FdeVA;
+ };
+
+ std::vector<FdeData> Fdes;
+};
+
+template <class ELFT> class BuildIdSection : public OutputSectionBase<ELFT> {
+public:
+ void writeTo(uint8_t *Buf) override;
+ virtual void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) = 0;
+
+protected:
+ BuildIdSection(size_t HashSize);
+ size_t HashSize;
+ uint8_t *HashBuf = nullptr;
+};
+
+template <class ELFT> class BuildIdFnv1 final : public BuildIdSection<ELFT> {
+public:
+ BuildIdFnv1() : BuildIdSection<ELFT>(8) {}
+ void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
+};
+
+template <class ELFT> class BuildIdMd5 final : public BuildIdSection<ELFT> {
+public:
+ BuildIdMd5() : BuildIdSection<ELFT>(16) {}
+ void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
+};
+
+template <class ELFT> class BuildIdSha1 final : public BuildIdSection<ELFT> {
+public:
+ BuildIdSha1() : BuildIdSection<ELFT>(20) {}
+ void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
+};
+
+template <class ELFT>
+class BuildIdHexstring final : public BuildIdSection<ELFT> {
+public:
+ BuildIdHexstring();
+ void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override;
+};
// All output sections that are hadnled 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 llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
+ typedef typename ELFT::uint uintX_t;
+ typedef typename ELFT::Phdr Elf_Phdr;
+ static BuildIdSection<ELFT> *BuildId;
static DynamicSection<ELFT> *Dynamic;
+ static EhFrameHeader<ELFT> *EhFrameHdr;
+ static EhOutputSection<ELFT> *EhFrame;
static GnuHashTableSection<ELFT> *GnuHashTab;
static GotPltSection<ELFT> *GotPlt;
static GotSection<ELFT> *Got;
@@ -457,10 +650,47 @@ template <class ELFT> struct Out {
static StringTableSection<ELFT> *StrTab;
static SymbolTableSection<ELFT> *DynSymTab;
static SymbolTableSection<ELFT> *SymTab;
+ static VersionDefinitionSection<ELFT> *VerDef;
+ static VersionTableSection<ELFT> *VerSym;
+ static VersionNeedSection<ELFT> *VerNeed;
static Elf_Phdr *TlsPhdr;
+ static OutputSectionBase<ELFT> *ElfHeader;
+ static OutputSectionBase<ELFT> *ProgramHeaders;
};
+template <bool Is64Bits> struct SectionKey {
+ typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
+ StringRef Name;
+ uint32_t Type;
+ uintX_t Flags;
+ uintX_t Alignment;
+};
+
+// 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;
+ typedef typename elf::SectionKey<ELFT::Is64Bits> Key;
+
+public:
+ std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C,
+ StringRef OutsecName);
+
+ OutputSectionBase<ELFT> *lookup(StringRef Name, uint32_t Type, uintX_t Flags);
+
+private:
+ Key createKey(InputSectionBase<ELFT> *C, StringRef OutsecName);
+
+ llvm::SmallDenseMap<Key, OutputSectionBase<ELFT> *> Map;
+};
+
+template <class ELFT> BuildIdSection<ELFT> *Out<ELFT>::BuildId;
template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
+template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr;
+template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab;
template <class ELFT> GotPltSection<ELFT> *Out<ELFT>::GotPlt;
template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got;
@@ -478,9 +708,25 @@ template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::ShStrTab;
template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab;
template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab;
template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab;
-template <class ELFT> typename Out<ELFT>::Elf_Phdr *Out<ELFT>::TlsPhdr;
-
-} // namespace elf2
+template <class ELFT> VersionDefinitionSection<ELFT> *Out<ELFT>::VerDef;
+template <class ELFT> VersionTableSection<ELFT> *Out<ELFT>::VerSym;
+template <class ELFT> VersionNeedSection<ELFT> *Out<ELFT>::VerNeed;
+template <class ELFT> typename ELFT::Phdr *Out<ELFT>::TlsPhdr;
+template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ElfHeader;
+template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ProgramHeaders;
+
+} // namespace elf
} // namespace lld
-#endif // LLD_ELF_OUTPUT_SECTIONS_H
+namespace llvm {
+template <bool Is64Bits> struct DenseMapInfo<lld::elf::SectionKey<Is64Bits>> {
+ typedef typename lld::elf::SectionKey<Is64Bits> Key;
+
+ static Key getEmptyKey();
+ static Key getTombstoneKey();
+ static unsigned getHashValue(const Key &Val);
+ static bool isEqual(const Key &LHS, const Key &RHS);
+};
+}
+
+#endif
diff --git a/ELF/README.md b/ELF/README.md
index 49b8167bbfe0..f1bfc9c15263 100644
--- a/ELF/README.md
+++ b/ELF/README.md
@@ -1,21 +1 @@
-The New ELF Linker
-==================
-This directory contains a port of the new PE/COFF linker for ELF.
-
-Overall Design
---------------
-See COFF/README.md for details on the design. Note that unlike COFF, we do not
-distinguish chunks from input sections; they are merged together.
-
-Capabilities
-------------
-This linker can link LLVM and Clang on Linux/x86-64 or FreeBSD/x86-64
-"Hello world" can be linked on Linux/PPC64 and on Linux/AArch64 or
-FreeBSD/AArch64.
-
-Performance
------------
-Achieving good performance is one of our goals. It's too early to reach a
-conclusion, but we are optimistic about that as it currently seems to be faster
-than GNU gold. It will be interesting to compare when we are close to feature
-parity.
+See docs/NewLLD.rst
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
new file mode 100644
index 000000000000..c09cf6b2b1ef
--- /dev/null
+++ b/ELF/Relocations.cpp
@@ -0,0 +1,704 @@
+//===- Relocations.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains platform-independent functions to process relocations.
+// I'll describe the overview of this file here.
+//
+// Simple relocations are easy to handle for the linker. For example,
+// for R_X86_64_PC64 relocs, the linker just has to fix up locations
+// with the relative offsets to the target symbols. It would just be
+// reading records from relocation sections and applying them to output.
+//
+// But not all relocations are that easy to handle. For example, for
+// R_386_GOTOFF relocs, the linker has to create new GOT entries for
+// symbols if they don't exist, and fix up locations with GOT entry
+// offsets from the beginning of GOT section. So there is more than
+// fixing addresses in relocation processing.
+//
+// ELF defines a large number of complex relocations.
+//
+// The functions in this file analyze relocations and do whatever needs
+// to be done. It includes, but not limited to, the following.
+//
+// - create GOT/PLT entries
+// - create new relocations in .dynsym to let the dynamic linker resolve
+// them at runtime (since ELF supports dynamic linking, not all
+// relocations can be resolved at link-time)
+// - create COPY relocs and reserve space in .bss
+// - replace expensive relocs (in terms of runtime cost) with cheap ones
+// - error out infeasible combinations such as PIC and non-relative relocs
+//
+// Note that the functions in this file don't actually apply relocations
+// because it doesn't know about the output file nor the output file buffer.
+// It instead stores Relocation objects to InputSection's Relocations
+// vector to let it apply later in InputSection::writeTo.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Relocations.h"
+#include "Config.h"
+#include "OutputSections.h"
+#include "SymbolTable.h"
+#include "Target.h"
+#include "Thunks.h"
+
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+
+namespace lld {
+namespace elf {
+
+static bool refersToGotEntry(RelExpr Expr) {
+ return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL_PAGE ||
+ Expr == R_MIPS_GOT_OFF || Expr == R_MIPS_TLSGD ||
+ Expr == R_MIPS_TLSLD || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC ||
+ Expr == R_GOT_FROM_END || Expr == R_TLSGD || Expr == R_TLSGD_PC ||
+ Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE;
+}
+
+static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
+ // In case of MIPS GP-relative relocations always resolve to a definition
+ // in a regular input file, ignoring the one-definition rule. So we,
+ // for example, should not attempt to create a dynamic relocation even
+ // if the target symbol is preemptible. There are two two MIPS GP-relative
+ // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16
+ // can be against a preemptible symbol.
+ // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all
+ // relocation types occupy eight bit. In case of N64 ABI we extract first
+ // relocation from 3-in-1 packet because only the first relocation can
+ // be against a real symbol.
+ if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16)
+ return false;
+ return Body.isPreemptible();
+}
+
+// This function is similar to the `handleTlsRelocation`. MIPS does not support
+// any relaxations for TLS relocations so by factoring out MIPS handling into
+// the separate function we can simplify the code and does not pollute
+// `handleTlsRelocation` by MIPS `ifs` statements.
+template <class ELFT>
+static unsigned
+handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
+ InputSectionBase<ELFT> &C, typename ELFT::uint Offset,
+ typename ELFT::uint Addend, RelExpr Expr) {
+ if (Expr == R_MIPS_TLSLD) {
+ if (Out<ELFT>::Got->addTlsIndex())
+ Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
+ Out<ELFT>::Got->getTlsIndexOff(), false,
+ nullptr, 0});
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ return 1;
+ }
+ if (Target->isTlsGlobalDynamicRel(Type)) {
+ if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+ typedef typename ELFT::uint uintX_t;
+ uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
+ Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
+ Off + (uintX_t)sizeof(uintX_t), false,
+ &Body, 0});
+ }
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ return 1;
+ }
+ return 0;
+}
+
+// Returns the number of relocations processed.
+template <class ELFT>
+static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
+ InputSectionBase<ELFT> &C,
+ typename ELFT::uint Offset,
+ typename ELFT::uint Addend, RelExpr Expr) {
+ if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC))
+ return 0;
+
+ if (!Body.isTls())
+ return 0;
+
+ typedef typename ELFT::uint uintX_t;
+
+ if (Config->EMachine == EM_MIPS)
+ return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
+
+ if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) &&
+ Config->Shared) {
+ if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+ uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->TlsDescRel, Out<ELFT>::Got, Off, false, &Body, 0});
+ }
+ if (Expr != R_HINT)
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ return 1;
+ }
+
+ if (Expr == R_TLSLD_PC || Expr == R_TLSLD) {
+ // Local-Dynamic relocs can be relaxed to Local-Exec.
+ if (!Config->Shared) {
+ C.Relocations.push_back(
+ {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body});
+ return 2;
+ }
+ if (Out<ELFT>::Got->addTlsIndex())
+ Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
+ Out<ELFT>::Got->getTlsIndexOff(), false,
+ nullptr, 0});
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ return 1;
+ }
+
+ // Local-Dynamic relocs can be relaxed to Local-Exec.
+ if (Target->isTlsLocalDynamicRel(Type) && !Config->Shared) {
+ C.Relocations.push_back(
+ {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body});
+ return 1;
+ }
+
+ if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_HINT ||
+ Target->isTlsGlobalDynamicRel(Type)) {
+ if (Config->Shared) {
+ if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
+ uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body);
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0});
+
+ // If the symbol is preemptible we need the dynamic linker to write
+ // the offset too.
+ if (isPreemptible(Body, Type))
+ Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got,
+ Off + (uintX_t)sizeof(uintX_t), false,
+ &Body, 0});
+ }
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ return 1;
+ }
+
+ // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
+ // depending on the symbol being locally defined or not.
+ if (isPreemptible(Body, Type)) {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
+ &C, Offset, Addend, &Body});
+ if (!Body.isInGot()) {
+ Out<ELFT>::Got->addEntry(Body);
+ Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got,
+ Body.getGotOffset<ELFT>(), false, &Body,
+ 0});
+ }
+ return Target->TlsGdRelaxSkip;
+ }
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, &C,
+ Offset, Addend, &Body});
+ return Target->TlsGdRelaxSkip;
+ }
+
+ // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
+ // defined.
+ if (Target->isTlsInitialExecRel(Type) && !Config->Shared &&
+ !isPreemptible(Body, Type)) {
+ C.Relocations.push_back(
+ {R_RELAX_TLS_IE_TO_LE, Type, &C, Offset, Addend, &Body});
+ return 1;
+ }
+ return 0;
+}
+
+template <endianness E> static int16_t readSignedLo16(const uint8_t *Loc) {
+ return read32<E>(Loc) & 0xffff;
+}
+
+template <class RelTy>
+static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
+ switch (Rel->getType(Config->Mips64EL)) {
+ case R_MIPS_HI16:
+ return R_MIPS_LO16;
+ case R_MIPS_GOT16:
+ return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
+ case R_MIPS_PCHI16:
+ return R_MIPS_PCLO16;
+ case R_MICROMIPS_HI16:
+ return R_MICROMIPS_LO16;
+ default:
+ return R_MIPS_NONE;
+ }
+}
+
+template <class ELFT, class RelTy>
+static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc,
+ SymbolBody &Sym, const RelTy *Rel,
+ const RelTy *End) {
+ uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL);
+ uint32_t Type = getMipsPairType(Rel, Sym);
+
+ // Some MIPS relocations use addend calculated from addend of the relocation
+ // itself and addend of paired relocation. ABI requires to compute such
+ // combined addend in case of REL relocation record format only.
+ // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ if (RelTy::IsRela || Type == R_MIPS_NONE)
+ return 0;
+
+ for (const RelTy *RI = Rel; RI != End; ++RI) {
+ if (RI->getType(Config->Mips64EL) != Type)
+ continue;
+ if (RI->getSymbol(Config->Mips64EL) != SymIndex)
+ continue;
+ const endianness E = ELFT::TargetEndianness;
+ return ((read32<E>(BufLoc) & 0xffff) << 16) +
+ readSignedLo16<E>(Buf + RI->r_offset);
+ }
+ warning("can't find matching " + getRelName(Type) + " relocation for " +
+ getRelName(Rel->getType(Config->Mips64EL)));
+ return 0;
+}
+
+// True if non-preemptable symbol always has the same value regardless of where
+// the DSO is loaded.
+template <class ELFT> static bool isAbsolute(const SymbolBody &Body) {
+ if (Body.isUndefined())
+ return !Body.isLocal() && Body.symbol()->isWeak();
+ if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(&Body))
+ return DR->Section == nullptr; // Absolute symbol.
+ return false;
+}
+
+static bool needsPlt(RelExpr Expr) {
+ return Expr == R_PLT_PC || Expr == R_PPC_PLT_OPD || Expr == R_PLT ||
+ Expr == R_PLT_PAGE_PC || Expr == R_THUNK_PLT_PC;
+}
+
+// True if this expression is of the form Sym - X, where X is a position in the
+// file (PC, or GOT for example).
+static bool isRelExpr(RelExpr Expr) {
+ return Expr == R_PC || Expr == R_GOTREL || Expr == R_PAGE_PC ||
+ Expr == R_RELAX_GOT_PC || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC;
+}
+
+template <class ELFT>
+static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
+ const SymbolBody &Body) {
+ // These expressions always compute a constant
+ if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF ||
+ E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_MIPS_TLSGD ||
+ E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC ||
+ E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE ||
+ E == R_HINT || E == R_THUNK_PC || E == R_THUNK_PLT_PC)
+ return true;
+
+ // These never do, except if the entire file is position dependent or if
+ // only the low bits are used.
+ if (E == R_GOT || E == R_PLT || E == R_TLSDESC)
+ return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
+
+ if (isPreemptible(Body, Type))
+ return false;
+
+ if (!Config->Pic)
+ return true;
+
+ bool AbsVal = isAbsolute<ELFT>(Body) || Body.isTls();
+ bool RelE = isRelExpr(E);
+ if (AbsVal && !RelE)
+ return true;
+ if (!AbsVal && RelE)
+ return true;
+
+ // Relative relocation to an absolute value. This is normally unrepresentable,
+ // but if the relocation refers to a weak undefined symbol, we allow it to
+ // resolve to the image base. This is a little strange, but it allows us to
+ // link function calls to such symbols. Normally such a call will be guarded
+ // with a comparison, which will load a zero from the GOT.
+ if (AbsVal && RelE) {
+ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
+ return true;
+ error("relocation " + getRelName(Type) +
+ " cannot refer to absolute symbol " + Body.getName());
+ return true;
+ }
+
+ return Target->usesOnlyLowPageBits(Type);
+}
+
+static RelExpr toPlt(RelExpr Expr) {
+ if (Expr == R_PPC_OPD)
+ return R_PPC_PLT_OPD;
+ if (Expr == R_PC)
+ return R_PLT_PC;
+ if (Expr == R_PAGE_PC)
+ return R_PLT_PAGE_PC;
+ if (Expr == R_ABS)
+ return R_PLT;
+ return Expr;
+}
+
+static RelExpr fromPlt(RelExpr Expr) {
+ // We decided not to use a plt. Optimize a reference to the plt to a
+ // reference to the symbol itself.
+ if (Expr == R_PLT_PC)
+ return R_PC;
+ if (Expr == R_PPC_PLT_OPD)
+ return R_PPC_OPD;
+ if (Expr == R_PLT)
+ return R_ABS;
+ return Expr;
+}
+
+template <class ELFT> static uint32_t getAlignment(SharedSymbol<ELFT> *SS) {
+ typedef typename ELFT::uint uintX_t;
+
+ uintX_t SecAlign = SS->file()->getSection(SS->Sym)->sh_addralign;
+ uintX_t SymValue = SS->Sym.st_value;
+ int TrailingZeros =
+ std::min(countTrailingZeros(SecAlign), countTrailingZeros(SymValue));
+ return 1 << TrailingZeros;
+}
+
+// Reserve space in .bss for copy relocation.
+template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) {
+ typedef typename ELFT::uint uintX_t;
+ typedef typename ELFT::Sym Elf_Sym;
+
+ // Copy relocation against zero-sized symbol doesn't make sense.
+ uintX_t SymSize = SS->template getSize<ELFT>();
+ if (SymSize == 0)
+ fatal("cannot create a copy relocation for " + SS->getName());
+
+ uintX_t Alignment = getAlignment(SS);
+ uintX_t Off = alignTo(Out<ELFT>::Bss->getSize(), Alignment);
+ Out<ELFT>::Bss->setSize(Off + SymSize);
+ Out<ELFT>::Bss->updateAlignment(Alignment);
+ uintX_t Shndx = SS->Sym.st_shndx;
+ uintX_t Value = SS->Sym.st_value;
+ // Look through the DSO's dynamic symbol table for aliases and create a
+ // dynamic symbol for each one. This causes the copy relocation to correctly
+ // interpose any aliases.
+ for (const Elf_Sym &S : SS->file()->getElfSymbols(true)) {
+ if (S.st_shndx != Shndx || S.st_value != Value)
+ continue;
+ auto *Alias = dyn_cast_or_null<SharedSymbol<ELFT>>(
+ Symtab<ELFT>::X->find(check(S.getName(SS->file()->getStringTable()))));
+ if (!Alias)
+ continue;
+ Alias->OffsetInBss = Off;
+ Alias->NeedsCopyOrPltAddr = true;
+ Alias->symbol()->IsUsedInRegularObj = true;
+ }
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->CopyRel, Out<ELFT>::Bss, SS->OffsetInBss, false, SS, 0});
+}
+
+template <class ELFT>
+static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
+ bool IsWrite, RelExpr Expr, uint32_t Type,
+ const uint8_t *Data) {
+ bool Preemptible = isPreemptible(Body, Type);
+ if (Body.isGnuIFunc()) {
+ Expr = toPlt(Expr);
+ } else if (!Preemptible) {
+ if (needsPlt(Expr))
+ Expr = fromPlt(Expr);
+ if (Expr == R_GOT_PC)
+ Expr = Target->adjustRelaxExpr(Type, Data, Expr);
+ }
+ Expr = Target->getThunkExpr(Expr, Type, File, Body);
+
+ if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body))
+ return Expr;
+
+ // This relocation would require the dynamic linker to write a value to read
+ // only memory. We can hack around it if we are producing an executable and
+ // the refered symbol can be preemepted to refer to the executable.
+ if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) {
+ error("can't create dynamic relocation " + getRelName(Type) +
+ " against readonly segment");
+ return Expr;
+ }
+ if (Body.getVisibility() != STV_DEFAULT) {
+ error("cannot preempt symbol");
+ return Expr;
+ }
+ if (Body.isObject()) {
+ // Produce a copy relocation.
+ auto *B = cast<SharedSymbol<ELFT>>(&Body);
+ if (!B->needsCopy())
+ addCopyRelSymbol(B);
+ return Expr;
+ }
+ if (Body.isFunc()) {
+ // This handles a non PIC program call to function in a shared library. In
+ // an ideal world, we could just report an error saying the relocation can
+ // overflow at runtime. In the real world with glibc, crt1.o has a
+ // R_X86_64_PC32 pointing to libc.so.
+ //
+ // The general idea on how to handle such cases is to create a PLT entry and
+ // use that as the function value.
+ //
+ // For the static linking part, we just return a plt expr and everything
+ // else will use the the PLT entry as the address.
+ //
+ // The remaining problem is making sure pointer equality still works. We
+ // need the help of the dynamic linker for that. We let it know that we have
+ // a direct reference to a so symbol by creating an undefined symbol with a
+ // non zero st_value. Seeing that, the dynamic linker resolves the symbol to
+ // the value of the symbol we created. This is true even for got entries, so
+ // pointer equality is maintained. To avoid an infinite loop, the only entry
+ // that points to the real function is a dedicated got entry used by the
+ // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
+ // R_386_JMP_SLOT, etc).
+ Body.NeedsCopyOrPltAddr = true;
+ return toPlt(Expr);
+ }
+ error("symbol is missing type");
+
+ return Expr;
+}
+
+template <class ELFT, class RelTy>
+static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File,
+ const uint8_t *SectionData,
+ const RelTy *End, const RelTy &RI,
+ RelExpr Expr, SymbolBody &Body) {
+ typedef typename ELFT::uint uintX_t;
+
+ uint32_t Type = RI.getType(Config->Mips64EL);
+ uintX_t Addend = getAddend<ELFT>(RI);
+ const uint8_t *BufLoc = SectionData + RI.r_offset;
+ if (!RelTy::IsRela)
+ Addend += Target->getImplicitAddend(BufLoc, Type);
+ if (Config->EMachine == EM_MIPS) {
+ Addend += findMipsPairedAddend<ELFT>(SectionData, BufLoc, Body, &RI, End);
+ if (Type == R_MIPS_LO16 && Expr == R_PC)
+ // R_MIPS_LO16 expression has R_PC type iif the target is _gp_disp
+ // symbol. In that case we should use the following formula for
+ // calculation "AHL + GP - P + 4". Let's add 4 right here.
+ // For details see p. 4-19 at
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ Addend += 4;
+ if (Expr == R_GOTREL) {
+ Addend -= MipsGPOffset;
+ if (Body.isLocal())
+ Addend += File.getMipsGp0();
+ }
+ }
+ if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC)
+ Addend += getPPC64TocBase();
+ return Addend;
+}
+
+// The reason we have to do this early scan is as follows
+// * To mmap the output file, we need to know the size
+// * For that, we need to know how many dynamic relocs we will have.
+// It might be possible to avoid this by outputting the file with write:
+// * Write the allocated output sections, computing addresses.
+// * Apply relocations, recording which ones require a dynamic reloc.
+// * Write the dynamic relocations.
+// * Write the rest of the file.
+// This would have some drawbacks. For example, we would only know if .rela.dyn
+// is needed after applying relocations. If it is, it will go after rw and rx
+// sections. Given that it is ro, we will need an extra PT_LOAD. This
+// complicates things for the dynamic linker and means we would have to reserve
+// space for the extra PT_LOAD even if we end up not using it.
+template <class ELFT, class RelTy>
+static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
+ typedef typename ELFT::uint uintX_t;
+
+ bool IsWrite = C.getSectionHdr()->sh_flags & SHF_WRITE;
+
+ auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) {
+ Out<ELFT>::RelaDyn->addReloc(Reloc);
+ };
+
+ const elf::ObjectFile<ELFT> &File = *C.getFile();
+ ArrayRef<uint8_t> SectionData = C.getSectionData();
+ const uint8_t *Buf = SectionData.begin();
+ for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
+ const RelTy &RI = *I;
+ SymbolBody &Body = File.getRelocTargetSym(RI);
+ uint32_t Type = RI.getType(Config->Mips64EL);
+
+ RelExpr Expr = Target->getRelExpr(Type, Body);
+ bool Preemptible = isPreemptible(Body, Type);
+ Expr = adjustExpr(File, Body, IsWrite, Expr, Type, Buf + RI.r_offset);
+ if (HasError)
+ continue;
+
+ // Skip a relocation that points to a dead piece
+ // in a mergeable section.
+ if (C.getOffset(RI.r_offset) == (uintX_t)-1)
+ continue;
+
+ // This relocation does not require got entry, but it is relative to got and
+ // needs it to be created. Here we request for that.
+ if (Expr == R_GOTONLY_PC || Expr == R_GOTREL || Expr == R_PPC_TOC)
+ Out<ELFT>::Got->HasGotOffRel = true;
+
+ uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body);
+
+ if (unsigned Processed = handleTlsRelocation<ELFT>(
+ Type, Body, C, RI.r_offset, Addend, Expr)) {
+ I += (Processed - 1);
+ continue;
+ }
+
+ // Ignore "hint" relocation because it is for optional code optimization.
+ if (Expr == R_HINT)
+ continue;
+
+ if (needsPlt(Expr) || Expr == R_THUNK_ABS || Expr == R_THUNK_PC ||
+ Expr == R_THUNK_PLT_PC || refersToGotEntry(Expr) ||
+ !isPreemptible(Body, Type)) {
+ // If the relocation points to something in the file, we can process it.
+ bool Constant = isStaticLinkTimeConstant<ELFT>(Expr, Type, Body);
+
+ // If the output being produced is position independent, the final value
+ // is still not known. In that case we still need some help from the
+ // dynamic linker. We can however do better than just copying the incoming
+ // relocation. We can process some of it and and just ask the dynamic
+ // linker to add the load address.
+ if (!Constant)
+ AddDyn({Target->RelativeRel, &C, RI.r_offset, true, &Body, Addend});
+
+ // If the produced value is a constant, we just remember to write it
+ // when outputting this section. We also have to do it if the format
+ // uses Elf_Rel, since in that case the written value is the addend.
+ if (Constant || !RelTy::IsRela)
+ C.Relocations.push_back({Expr, Type, &C, RI.r_offset, Addend, &Body});
+ } else {
+ // We don't know anything about the finaly symbol. Just ask the dynamic
+ // linker to handle the relocation for us.
+ AddDyn({Target->getDynRel(Type), &C, RI.r_offset, false, &Body, Addend});
+ // MIPS ABI turns using of GOT and dynamic relocations inside out.
+ // While regular ABI uses dynamic relocations to fill up GOT entries
+ // MIPS ABI requires dynamic linker to fills up GOT entries using
+ // specially sorted dynamic symbol table. This affects even dynamic
+ // relocations against symbols which do not require GOT entries
+ // creation explicitly, i.e. do not have any GOT-relocations. So if
+ // a preemptible symbol has a dynamic relocation we anyway have
+ // to create a GOT entry for it.
+ // If a non-preemptible symbol has a dynamic relocation against it,
+ // dynamic linker takes it st_value, adds offset and writes down
+ // result of the dynamic relocation. In case of preemptible symbol
+ // dynamic linker performs symbol resolution, writes the symbol value
+ // to the GOT entry and reads the GOT entry when it needs to perform
+ // a dynamic relocation.
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
+ if (Config->EMachine == EM_MIPS)
+ Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+ continue;
+ }
+
+ // Some targets might require creation of thunks for relocations.
+ // Now we support only MIPS which requires LA25 thunk to call PIC
+ // code from non-PIC one, and ARM which requires interworking.
+ if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) {
+ auto *Sec = cast<InputSection<ELFT>>(&C);
+ addThunk<ELFT>(Type, Body, *Sec);
+ }
+
+ // At this point we are done with the relocated position. Some relocations
+ // also require us to create a got or plt entry.
+
+ // If a relocation needs PLT, we create a PLT and a GOT slot for the symbol.
+ if (needsPlt(Expr)) {
+ if (Body.isInPlt())
+ continue;
+ Out<ELFT>::Plt->addEntry(Body);
+
+ uint32_t Rel;
+ if (Body.isGnuIFunc() && !Preemptible)
+ Rel = Target->IRelativeRel;
+ else
+ Rel = Target->PltRel;
+
+ Out<ELFT>::GotPlt->addEntry(Body);
+ Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
+ Body.getGotPltOffset<ELFT>(), !Preemptible,
+ &Body, 0});
+ continue;
+ }
+
+ if (refersToGotEntry(Expr)) {
+ if (Config->EMachine == EM_MIPS) {
+ // MIPS ABI has special rules to process GOT entries
+ // and doesn't require relocation entries for them.
+ // See "Global Offset Table" in Chapter 5 in the following document
+ // for detailed description:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+ if (Body.isTls())
+ AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
+ !Preemptible, &Body, 0});
+ continue;
+ }
+
+ if (Body.isInGot())
+ continue;
+
+ Out<ELFT>::Got->addEntry(Body);
+ if (Preemptible || (Config->Pic && !isAbsolute<ELFT>(Body))) {
+ uint32_t DynType;
+ if (Body.isTls())
+ DynType = Target->TlsGotRel;
+ else if (Preemptible)
+ DynType = Target->GotRel;
+ else
+ DynType = Target->RelativeRel;
+ AddDyn({DynType, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
+ !Preemptible, &Body, 0});
+ }
+ continue;
+ }
+ }
+}
+
+template <class ELFT> void scanRelocations(InputSection<ELFT> &C) {
+ typedef typename ELFT::Shdr Elf_Shdr;
+
+ // Scan all relocations. Each relocation goes through a series
+ // of tests to determine if it needs special treatment, such as
+ // creating GOT, PLT, copy relocations, etc.
+ // Note that relocations for non-alloc sections are directly
+ // processed by InputSection::relocateNonAlloc.
+ if (C.getSectionHdr()->sh_flags & SHF_ALLOC)
+ for (const Elf_Shdr *RelSec : C.RelocSections)
+ scanRelocations(C, *RelSec);
+}
+
+template <class ELFT>
+void scanRelocations(InputSectionBase<ELFT> &S,
+ const typename ELFT::Shdr &RelSec) {
+ ELFFile<ELFT> &EObj = S.getFile()->getObj();
+ if (RelSec.sh_type == SHT_RELA)
+ scanRelocs(S, EObj.relas(&RelSec));
+ else
+ scanRelocs(S, EObj.rels(&RelSec));
+}
+
+template void scanRelocations<ELF32LE>(InputSection<ELF32LE> &);
+template void scanRelocations<ELF32BE>(InputSection<ELF32BE> &);
+template void scanRelocations<ELF64LE>(InputSection<ELF64LE> &);
+template void scanRelocations<ELF64BE>(InputSection<ELF64BE> &);
+
+template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &,
+ const ELF32LE::Shdr &);
+template void scanRelocations<ELF32BE>(InputSectionBase<ELF32BE> &,
+ const ELF32BE::Shdr &);
+template void scanRelocations<ELF64LE>(InputSectionBase<ELF64LE> &,
+ const ELF64LE::Shdr &);
+template void scanRelocations<ELF64BE>(InputSectionBase<ELF64BE> &,
+ const ELF64BE::Shdr &);
+}
+}
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
new file mode 100644
index 000000000000..4c1c74efb0da
--- /dev/null
+++ b/ELF/Relocations.h
@@ -0,0 +1,93 @@
+//===- Relocations.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_RELOCATIONS_H
+#define LLD_ELF_RELOCATIONS_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+class SymbolBody;
+template <class ELFT> class InputSection;
+template <class ELFT> class InputSectionBase;
+
+enum RelExpr {
+ R_ABS,
+ R_GOT,
+ R_GOTONLY_PC,
+ R_GOTREL,
+ R_GOT_FROM_END,
+ R_GOT_OFF,
+ R_GOT_PAGE_PC,
+ R_GOT_PC,
+ R_HINT,
+ R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOT_OFF,
+ R_MIPS_TLSGD,
+ R_MIPS_TLSLD,
+ R_NEG_TLS,
+ R_PAGE_PC,
+ R_PC,
+ R_PLT,
+ R_PLT_PC,
+ R_PLT_PAGE_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_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_TLSGD,
+ R_TLSGD_PC,
+ R_TLSLD,
+ R_TLSLD_PC
+};
+
+template <class ELFT> struct Relocation {
+ RelExpr Expr;
+ uint32_t Type;
+ InputSectionBase<ELFT> *InputSec;
+ uint64_t Offset;
+ uint64_t Addend;
+ SymbolBody *Sym;
+};
+
+template <class ELFT> void scanRelocations(InputSection<ELFT> &);
+
+template <class ELFT>
+void scanRelocations(InputSectionBase<ELFT> &, const typename ELFT::Shdr &);
+
+template <class ELFT>
+static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) {
+ return 0;
+}
+
+template <class ELFT>
+static inline typename ELFT::uint getAddend(const typename ELFT::Rela &Rel) {
+ return Rel.r_addend;
+}
+}
+}
+
+#endif
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
new file mode 100644
index 000000000000..559ec1be0e39
--- /dev/null
+++ b/ELF/ScriptParser.cpp
@@ -0,0 +1,163 @@
+//===- ScriptParser.cpp ---------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the base parser class for linker script and dynamic
+// list.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptParser.h"
+#include "Error.h"
+#include "llvm/ADT/Twine.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+// Returns the line that the character S[Pos] is in.
+static StringRef getLine(StringRef S, size_t Pos) {
+ size_t Begin = S.rfind('\n', Pos);
+ size_t End = S.find('\n', Pos);
+ Begin = (Begin == StringRef::npos) ? 0 : Begin + 1;
+ if (End == StringRef::npos)
+ End = S.size();
+ // rtrim for DOS-style newlines.
+ return S.substr(Begin, End - Begin).rtrim();
+}
+
+void ScriptParserBase::printErrorPos() {
+ StringRef Tok = Tokens[Pos == 0 ? 0 : Pos - 1];
+ StringRef Line = getLine(Input, Tok.data() - Input.data());
+ size_t Col = Tok.data() - Line.data();
+ error(Line);
+ error(std::string(Col, ' ') + "^");
+}
+
+// We don't want to record cascading errors. Keep only the first one.
+void ScriptParserBase::setError(const Twine &Msg) {
+ if (Error)
+ return;
+ if (Input.empty() || Tokens.empty()) {
+ error(Msg);
+ } else {
+ error("line " + Twine(getPos()) + ": " + Msg);
+ printErrorPos();
+ }
+ Error = true;
+}
+
+// Split S into linker script tokens.
+std::vector<StringRef> ScriptParserBase::tokenize(StringRef S) {
+ std::vector<StringRef> Ret;
+ for (;;) {
+ S = skipSpace(S);
+ if (S.empty())
+ return Ret;
+
+ // Quoted token
+ if (S.startswith("\"")) {
+ size_t E = S.find("\"", 1);
+ if (E == StringRef::npos) {
+ error("unclosed quote");
+ return {};
+ }
+ Ret.push_back(S.substr(1, E - 1));
+ S = S.substr(E + 1);
+ continue;
+ }
+
+ // Unquoted token
+ 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;
+ Ret.push_back(S.substr(0, Pos));
+ S = S.substr(Pos);
+ }
+}
+
+// Skip leading whitespace characters or comments.
+StringRef ScriptParserBase::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 ScriptParserBase::atEOF() { return Error || Tokens.size() == Pos; }
+
+StringRef ScriptParserBase::next() {
+ if (Error)
+ return "";
+ if (atEOF()) {
+ setError("unexpected EOF");
+ return "";
+ }
+ return Tokens[Pos++];
+}
+
+StringRef ScriptParserBase::peek() {
+ StringRef Tok = next();
+ if (Error)
+ return "";
+ --Pos;
+ return Tok;
+}
+
+bool ScriptParserBase::skip(StringRef Tok) {
+ if (Error)
+ return false;
+ if (atEOF()) {
+ setError("unexpected EOF");
+ return false;
+ }
+ if (Tokens[Pos] != Tok)
+ return false;
+ ++Pos;
+ return true;
+}
+
+void ScriptParserBase::expect(StringRef Expect) {
+ if (Error)
+ return;
+ StringRef Tok = next();
+ if (Tok != Expect)
+ setError(Expect + " expected, but got " + Tok);
+}
+
+// Returns the current line number.
+size_t ScriptParserBase::getPos() {
+ if (Pos == 0)
+ return 1;
+ const char *Begin = Input.data();
+ const char *Tok = Tokens[Pos - 1].data();
+ return StringRef(Begin, Tok - Begin).count('\n') + 1;
+}
diff --git a/ELF/ScriptParser.h b/ELF/ScriptParser.h
new file mode 100644
index 000000000000..20735f78da81
--- /dev/null
+++ b/ELF/ScriptParser.h
@@ -0,0 +1,49 @@
+//===- ScriptParser.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_PARSER_H
+#define LLD_ELF_SCRIPT_PARSER_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include <utility>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class ScriptParserBase {
+public:
+ explicit ScriptParserBase(StringRef S) : Input(S), Tokens(tokenize(S)) {}
+ explicit ScriptParserBase(std::vector<StringRef> Tokens)
+ : Input(""), Tokens(std::move(Tokens)) {}
+
+protected:
+ void setError(const Twine &Msg);
+ static std::vector<StringRef> tokenize(StringRef S);
+ static StringRef skipSpace(StringRef S);
+ bool atEOF();
+ StringRef next();
+ StringRef peek();
+ bool skip(StringRef Tok);
+ void expect(StringRef Expect);
+
+ size_t getPos();
+ void printErrorPos();
+
+ StringRef Input;
+ std::vector<StringRef> Tokens;
+ size_t Pos = 0;
+ bool Error = false;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp
new file mode 100644
index 000000000000..0c21e8819d6c
--- /dev/null
+++ b/ELF/Strings.cpp
@@ -0,0 +1,98 @@
+//===- Strings.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Strings.h"
+#include "Error.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/config.h"
+#include <algorithm>
+
+#ifdef HAVE_CXXABI_H
+#include <cxxabi.h>
+#endif
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+// Returns true if S matches T. S can contain glob meta-characters.
+// The asterisk ('*') matches zero or more characters, and the question
+// mark ('?') matches one character.
+bool elf::globMatch(StringRef S, StringRef T) {
+ for (;;) {
+ if (S.empty())
+ return T.empty();
+ if (S[0] == '*') {
+ S = S.substr(1);
+ if (S.empty())
+ // Fast path. If a pattern is '*', it matches anything.
+ return true;
+ for (size_t I = 0, E = T.size(); I < E; ++I)
+ if (globMatch(S, T.substr(I)))
+ return true;
+ return false;
+ }
+ if (T.empty() || (S[0] != T[0] && S[0] != '?'))
+ return false;
+ S = S.substr(1);
+ T = T.substr(1);
+ }
+}
+
+// Converts a hex string (e.g. "deadbeef") to a vector.
+std::vector<uint8_t> elf::parseHex(StringRef S) {
+ std::vector<uint8_t> Hex;
+ while (!S.empty()) {
+ StringRef B = S.substr(0, 2);
+ S = S.substr(2);
+ uint8_t H;
+ if (B.getAsInteger(16, H)) {
+ error("not a hexadecimal value: " + B);
+ return {};
+ }
+ Hex.push_back(H);
+ }
+ return Hex;
+}
+
+static bool isAlpha(char C) {
+ return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_';
+}
+
+static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); }
+
+// Returns true if S is valid as a C language identifier.
+bool elf::isValidCIdentifier(StringRef S) {
+ return !S.empty() && isAlpha(S[0]) &&
+ std::all_of(S.begin() + 1, S.end(), isAlnum);
+}
+
+// Returns the demangled C++ symbol name for Name.
+std::string elf::demangle(StringRef Name) {
+#if !defined(HAVE_CXXABI_H)
+ return Name;
+#else
+ // __cxa_demangle 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
+ // 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"))
+ return Name;
+
+ char *Buf =
+ abi::__cxa_demangle(Name.str().c_str(), nullptr, nullptr, nullptr);
+ if (!Buf)
+ return Name;
+ std::string S(Buf);
+ free(Buf);
+ return S;
+#endif
+}
diff --git a/ELF/Strings.h b/ELF/Strings.h
new file mode 100644
index 000000000000..4948e9dbd56b
--- /dev/null
+++ b/ELF/Strings.h
@@ -0,0 +1,29 @@
+//===- Strings.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_STRINGS_H
+#define LLD_COFF_STRINGS_H
+
+#include "lld/Core/LLVM.h"
+#include <vector>
+
+namespace lld {
+namespace elf {
+bool globMatch(StringRef S, StringRef T);
+std::vector<uint8_t> parseHex(StringRef S);
+bool isValidCIdentifier(StringRef S);
+
+// Returns a demangled C++ symbol name. If Name is not a mangled
+// name or the system does not provide __cxa_demangle function,
+// it returns an unmodified string.
+std::string demangle(StringRef Name);
+}
+}
+
+#endif
diff --git a/ELF/SymbolListFile.cpp b/ELF/SymbolListFile.cpp
new file mode 100644
index 000000000000..9e088025c1b7
--- /dev/null
+++ b/ELF/SymbolListFile.cpp
@@ -0,0 +1,168 @@
+//===- SymbolListFile.cpp -------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the parser/evaluator of the linker script.
+// It does not construct an AST but consume linker script directives directly.
+// Results are written to Driver or Config object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolListFile.h"
+#include "Config.h"
+#include "ScriptParser.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Parse the --dynamic-list argument. A dynamic list is in the form
+//
+// { symbol1; symbol2; [...]; symbolN };
+//
+// Multiple groups can be defined in the same file, and they are merged
+// into a single group.
+
+class DynamicListParser final : public ScriptParserBase {
+public:
+ DynamicListParser(StringRef S) : ScriptParserBase(S) {}
+ void run();
+};
+
+void DynamicListParser::run() {
+ while (!atEOF()) {
+ expect("{");
+ while (!Error) {
+ Config->DynamicList.push_back(next());
+ expect(";");
+ if (skip("}"))
+ break;
+ }
+ expect(";");
+ }
+}
+
+void elf::parseDynamicList(MemoryBufferRef MB) {
+ DynamicListParser(MB.getBuffer()).run();
+}
+
+// Parse the --version-script argument. We currently only accept the following
+// version script syntax:
+//
+// { [ global: symbol1; symbol2; [...]; symbolN; ] local: *; };
+//
+// No wildcards are supported, other than for the local entry. Symbol versioning
+// is also not supported.
+
+class VersionScriptParser final : public ScriptParserBase {
+public:
+ VersionScriptParser(StringRef S) : ScriptParserBase(S) {}
+
+ void run();
+
+private:
+ void parseExtern(std::vector<SymbolVersion> *Globals);
+ void parseVersion(StringRef VerStr);
+ void parseGlobal(StringRef VerStr);
+ void parseLocal();
+};
+
+size_t elf::defineSymbolVersion(StringRef VerStr) {
+ // Identifiers start at 2 because 0 and 1 are reserved
+ // for VER_NDX_LOCAL and VER_NDX_GLOBAL constants.
+ size_t VersionId = Config->VersionDefinitions.size() + 2;
+ Config->VersionDefinitions.push_back({VerStr, VersionId});
+ return VersionId;
+}
+
+void VersionScriptParser::parseVersion(StringRef VerStr) {
+ defineSymbolVersion(VerStr);
+
+ if (skip("global:") || peek() != "local:")
+ parseGlobal(VerStr);
+ if (skip("local:"))
+ parseLocal();
+ expect("}");
+
+ // Each version may have a parent version. For example, "Ver2" defined as
+ // "Ver2 { global: foo; local: *; } Ver1;" has "Ver1" as a parent. This
+ // version hierarchy is, probably against your instinct, purely for human; the
+ // runtime doesn't care about them at all. In LLD, we simply skip the token.
+ if (!VerStr.empty() && peek() != ";")
+ next();
+ expect(";");
+}
+
+void VersionScriptParser::parseLocal() {
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ expect("*");
+ expect(";");
+}
+
+void VersionScriptParser::parseExtern(std::vector<SymbolVersion> *Globals) {
+ expect("C++");
+ expect("{");
+
+ for (;;) {
+ if (peek() == "}" || Error)
+ break;
+ Globals->push_back({next(), true});
+ expect(";");
+ }
+
+ expect("}");
+ expect(";");
+}
+
+void VersionScriptParser::parseGlobal(StringRef VerStr) {
+ std::vector<SymbolVersion> *Globals;
+ if (VerStr.empty())
+ Globals = &Config->VersionScriptGlobals;
+ else
+ Globals = &Config->VersionDefinitions.back().Globals;
+
+ for (;;) {
+ if (skip("extern"))
+ parseExtern(Globals);
+
+ StringRef Cur = peek();
+ if (Cur == "}" || Cur == "local:" || Error)
+ return;
+ next();
+ Globals->push_back({Cur, false});
+ expect(";");
+ }
+}
+
+void VersionScriptParser::run() {
+ StringRef Msg = "anonymous version definition is used in "
+ "combination with other version definitions";
+ if (skip("{")) {
+ parseVersion("");
+ if (!atEOF())
+ setError(Msg);
+ return;
+ }
+
+ while (!atEOF() && !Error) {
+ StringRef VerStr = next();
+ if (VerStr == "{") {
+ setError(Msg);
+ return;
+ }
+ expect("{");
+ parseVersion(VerStr);
+ }
+}
+
+void elf::parseVersionScript(MemoryBufferRef MB) {
+ VersionScriptParser(MB.getBuffer()).run();
+}
diff --git a/ELF/SymbolListFile.h b/ELF/SymbolListFile.h
new file mode 100644
index 000000000000..cf3c4c639ea4
--- /dev/null
+++ b/ELF/SymbolListFile.h
@@ -0,0 +1,27 @@
+//===- SymbolListFile.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_SYMBOL_LIST_FILE_H
+#define LLD_ELF_SYMBOL_LIST_FILE_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace lld {
+namespace elf {
+
+size_t defineSymbolVersion(StringRef Version);
+
+void parseDynamicList(MemoryBufferRef MB);
+void parseVersionScript(MemoryBufferRef MB);
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index 65f5dff9d7a3..78c1298df427 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -17,7 +17,11 @@
#include "SymbolTable.h"
#include "Config.h"
#include "Error.h"
+#include "LinkerScript.h"
+#include "Strings.h"
+#include "SymbolListFile.h"
#include "Symbols.h"
+#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Support/StringSaver.h"
using namespace llvm;
@@ -25,40 +29,48 @@ using namespace llvm::object;
using namespace llvm::ELF;
using namespace lld;
-using namespace lld::elf2;
+using namespace lld::elf;
// All input object files must be for the same architecture
// (e.g. it does not make sense to link x86 object files with
// MIPS object files.) This function checks for that error.
-template <class ELFT>
-static void checkCompatibility(InputFile *FileP) {
- auto *F = dyn_cast<ELFFileBase<ELFT>>(FileP);
- if (!F)
- return;
- if (F->getELFKind() == Config->EKind && F->getEMachine() == Config->EMachine)
- return;
+template <class ELFT> static bool isCompatible(InputFile *F) {
+ if (!isa<ELFFileBase<ELFT>>(F) && !isa<BitcodeFile>(F))
+ return true;
+ if (F->EKind == Config->EKind && F->EMachine == Config->EMachine)
+ return true;
StringRef A = F->getName();
StringRef B = Config->Emulation;
if (B.empty())
B = Config->FirstElf->getName();
error(A + " is incompatible with " + B);
+ return false;
}
// Add symbols in File to the symbol table.
template <class ELFT>
void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
InputFile *FileP = File.get();
- checkCompatibility<ELFT>(FileP);
+ if (!isCompatible<ELFT>(FileP))
+ return;
// .a file
if (auto *F = dyn_cast<ArchiveFile>(FileP)) {
ArchiveFiles.emplace_back(cast<ArchiveFile>(File.release()));
- F->parse();
- for (Lazy &Sym : F->getLazySymbols())
- addLazy(&Sym);
+ F->parse<ELFT>();
return;
}
+ // Lazy object file
+ if (auto *F = dyn_cast<LazyObjectFile>(FileP)) {
+ LazyObjectFiles.emplace_back(cast<LazyObjectFile>(File.release()));
+ F->parse<ELFT>();
+ return;
+ }
+
+ if (Config->Trace)
+ outs() << getFilename(FileP) << "\n";
+
// .so file
if (auto *F = dyn_cast<SharedFile<ELFT>>(FileP)) {
// DSOs are uniquified not by filename but by soname.
@@ -68,189 +80,443 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
SharedFiles.emplace_back(cast<SharedFile<ELFT>>(File.release()));
F->parseRest();
- for (SharedSymbol<ELFT> &B : F->getSharedSymbols())
- resolve(&B);
return;
}
- // .o file
+ // LLVM bitcode file
+ if (auto *F = dyn_cast<BitcodeFile>(FileP)) {
+ BitcodeFiles.emplace_back(cast<BitcodeFile>(File.release()));
+ F->parse<ELFT>(ComdatGroups);
+ return;
+ }
+
+ // Regular object file
auto *F = cast<ObjectFile<ELFT>>(FileP);
ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
F->parse(ComdatGroups);
- for (SymbolBody *B : F->getSymbols())
- resolve(B);
}
-// Add an undefined symbol.
-template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
- auto *Sym = new (Alloc) Undefined(Name, false, STV_DEFAULT, false);
- resolve(Sym);
- return Sym;
-}
+// This function is where all the optimizations of link-time
+// optimization happens. When LTO is in use, some input files are
+// not in native object file format but in the LLVM bitcode format.
+// This function compiles bitcode files into a few big native files
+// using LLVM functions and replaces bitcode symbols with the results.
+// Because all bitcode files that consist of a program are passed
+// to the compiler at once, it can do whole-program optimization.
+template <class ELFT> void SymbolTable<ELFT>::addCombinedLtoObject() {
+ if (BitcodeFiles.empty())
+ return;
-// Add an undefined symbol. Unlike addUndefined, that symbol
-// doesn't have to be resolved, thus "opt" (optional).
-template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) {
- auto *Sym = new (Alloc) Undefined(Name, false, STV_HIDDEN, true);
- resolve(Sym);
- return Sym;
-}
+ // Compile bitcode files.
+ Lto.reset(new BitcodeCompiler);
+ for (const std::unique_ptr<BitcodeFile> &F : BitcodeFiles)
+ Lto->add(*F);
+ std::vector<std::unique_ptr<InputFile>> IFs = Lto->compile();
-template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addAbsolute(StringRef Name, Elf_Sym &ESym) {
- // Pass nullptr because absolute symbols have no corresponding input sections.
- auto *Sym = new (Alloc) DefinedRegular<ELFT>(Name, ESym, nullptr);
- resolve(Sym);
- return Sym;
+ // Replace bitcode symbols.
+ for (auto &IF : IFs) {
+ ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(IF.release());
+
+ DenseSet<StringRef> DummyGroups;
+ Obj->parse(DummyGroups);
+ ObjectFiles.emplace_back(Obj);
+ }
}
template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addSynthetic(StringRef Name,
- OutputSectionBase<ELFT> &Section,
- uintX_t Value) {
- auto *Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, Value, Section);
- resolve(Sym);
- return Sym;
+DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name,
+ uint8_t Visibility) {
+ return cast<DefinedRegular<ELFT>>(
+ addRegular(Name, STB_GLOBAL, Visibility)->body());
}
// Add Name as an "ignored" symbol. An ignored symbol is a regular
-// linker-synthesized defined symbol, but it is not recorded to the output
-// file's symbol table. Such symbols are useful for some linker-defined symbols.
+// linker-synthesized defined symbol, but is only defined if needed.
template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) {
- return addAbsolute(Name, ElfSym<ELFT>::IgnoredWeak);
+DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name,
+ uint8_t Visibility) {
+ if (!find(Name))
+ return nullptr;
+ return addAbsolute(Name, Visibility);
}
-// The 'strong' variant of the addIgnored. Adds symbol which has a global
-// binding and cannot be substituted.
-template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addIgnoredStrong(StringRef Name) {
- return addAbsolute(Name, ElfSym<ELFT>::Ignored);
+// Set a flag for --trace-symbol so that we can print out a log message
+// if a new symbol with the same name is inserted into the symbol table.
+template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) {
+ Symtab.insert({Name, {-1, true}});
}
// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
// Used to implement --wrap.
template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
- if (Symtab.count(Name) == 0)
+ SymbolBody *B = find(Name);
+ if (!B)
return;
StringSaver Saver(Alloc);
- Symbol *Sym = addUndefined(Name)->getSymbol();
- Symbol *Real = addUndefined(Saver.save("__real_" + Name))->getSymbol();
- Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name))->getSymbol();
- Real->Body = Sym->Body;
- Sym->Body = Wrap->Body;
+ Symbol *Sym = B->symbol();
+ Symbol *Real = addUndefined(Saver.save("__real_" + Name));
+ Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
+ // We rename symbols by replacing the old symbol's SymbolBody with the new
+ // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
+ // old symbol to instead refer to the new symbol.
+ memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body));
+ memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body));
+}
+
+static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
+ if (VA == STV_DEFAULT)
+ return VB;
+ if (VB == STV_DEFAULT)
+ return VA;
+ return std::min(VA, VB);
}
-// Returns a file from which symbol B was created.
-// If B does not belong to any file, returns a nullptr.
+// Find an existing symbol or create and insert a new one.
template <class ELFT>
-ELFFileBase<ELFT> *SymbolTable<ELFT>::findFile(SymbolBody *B) {
- for (const std::unique_ptr<ObjectFile<ELFT>> &F : ObjectFiles) {
- ArrayRef<SymbolBody *> Syms = F->getSymbols();
- if (std::find(Syms.begin(), Syms.end(), B) != Syms.end())
- return F.get();
+std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
+ auto P = Symtab.insert({Name, {(int)SymVector.size(), false}});
+ SymIndex &V = P.first->second;
+ bool IsNew = P.second;
+
+ if (V.Idx == -1) {
+ IsNew = true;
+ V = {(int)SymVector.size(), true};
+ }
+
+ Symbol *Sym;
+ if (IsNew) {
+ Sym = new (Alloc) Symbol;
+ Sym->Binding = STB_WEAK;
+ Sym->Visibility = STV_DEFAULT;
+ Sym->IsUsedInRegularObj = false;
+ Sym->ExportDynamic = false;
+ Sym->VersionId = Config->DefaultSymbolVersion;
+ Sym->Traced = V.Traced;
+ SymVector.push_back(Sym);
+ } else {
+ Sym = SymVector[V.Idx];
}
- return nullptr;
+ return {Sym, IsNew};
+}
+
+// Find an existing symbol or create and insert a new one, then apply the given
+// attributes.
+template <class ELFT>
+std::pair<Symbol *, bool>
+SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
+ bool CanOmitFromDynSym, bool IsUsedInRegularObj,
+ InputFile *File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name);
+
+ // 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));
+
+ return {S, WasInserted};
}
// Construct a string in the form of "Sym in File1 and File2".
// Used to construct an error message.
-template <class ELFT>
-std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Old, SymbolBody *New) {
- ELFFileBase<ELFT> *OldFile = findFile(Old);
- ELFFileBase<ELFT> *NewFile = findFile(New);
+template <typename ELFT>
+std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Existing,
+ InputFile *NewFile) {
+ std::string Sym = Existing->getName();
+ if (Config->Demangle)
+ Sym = demangle(Sym);
+ return Sym + " in " + getFilename(Existing->File) + " and " +
+ getFilename(NewFile);
+}
- StringRef Sym = Old->getName();
- StringRef F1 = OldFile ? OldFile->getName() : "(internal)";
- StringRef F2 = NewFile ? NewFile->getName() : "(internal)";
- return (Sym + " in " + F1 + " and " + F2).str();
+template <class ELFT> Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name) {
+ return addUndefined(Name, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0,
+ /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
}
-// This function resolves conflicts if there's an existing symbol with
-// the same name. Decisions are made based on symbol type.
-template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
- Symbol *Sym = insert(New);
- if (Sym->Body == New)
- return;
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ bool CanOmitFromDynSym,
+ InputFile *File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) =
+ insert(Name, Type, StOther & 3, CanOmitFromDynSym,
+ /*IsUsedInRegularObj*/ !File || !isa<BitcodeFile>(File), File);
+ if (WasInserted) {
+ S->Binding = Binding;
+ replaceBody<Undefined>(S, Name, 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 *L = dyn_cast<Lazy>(S->body())) {
+ // An undefined weak will not fetch archive members, but we have to remember
+ // its type. See also comment in addLazyArchive.
+ if (S->isWeak())
+ L->Type = Type;
+ else if (auto F = L->fetch())
+ addFile(std::move(F));
+ }
+ return S;
+}
- SymbolBody *Existing = Sym->Body;
+// We have a new defined symbol with the specified binding. Return 1 if the new
+// symbol should win, -1 if the new symbol should lose, or 0 if both symbols are
+// strong defined symbols.
+static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
+ if (WasInserted)
+ return 1;
+ SymbolBody *Body = S->body();
+ if (Body->isLazy() || Body->isUndefined() || Body->isShared())
+ return 1;
+ if (Binding == STB_WEAK)
+ return -1;
+ if (S->isWeak())
+ return 1;
+ return 0;
+}
- if (Lazy *L = dyn_cast<Lazy>(Existing)) {
- if (auto *Undef = dyn_cast<Undefined>(New)) {
- addMemberFile(Undef, L);
- return;
+// We have a new non-common defined symbol with the specified binding. Return 1
+// if the new symbol should win, -1 if the new symbol should lose, or 0 if there
+// is a conflict. If the new symbol wins, also update the binding.
+static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding) {
+ if (int Cmp = compareDefined(S, WasInserted, Binding)) {
+ if (Cmp > 0)
+ S->Binding = Binding;
+ return Cmp;
+ }
+ if (isa<DefinedCommon>(S->body())) {
+ // Non-common symbols take precedence over common symbols.
+ if (Config->WarnCommon)
+ warning("common " + S->body()->getName() + " is overridden");
+ return 1;
+ }
+ return 0;
+}
+
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
+ uint64_t Alignment, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ InputFile *File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) =
+ insert(N, Type, StOther & 3, /*CanOmitFromDynSym*/ false,
+ /*IsUsedInRegularObj*/ true, File);
+ int Cmp = compareDefined(S, WasInserted, Binding);
+ if (Cmp > 0) {
+ S->Binding = Binding;
+ replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File);
+ } else if (Cmp == 0) {
+ auto *C = dyn_cast<DefinedCommon>(S->body());
+ if (!C) {
+ // Non-common symbols take precedence over common symbols.
+ if (Config->WarnCommon)
+ warning("common " + S->body()->getName() + " is overridden");
+ return S;
}
- // Found a definition for something also in an archive.
- // Ignore the archive definition.
- Sym->Body = New;
- return;
+
+ if (Config->WarnCommon)
+ warning("multiple common of " + S->body()->getName());
+
+ C->Size = std::max(C->Size, Size);
+ C->Alignment = std::max(C->Alignment, Alignment);
}
+ return S;
+}
- if (New->isTls() != Existing->isTls())
- error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New));
-
- // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
- // equivalent (conflicting), or more preferable, respectively.
- int Comp = Existing->compare<ELFT>(New);
- if (Comp == 0) {
- std::string S = "duplicate symbol: " + conflictMsg(Existing, New);
- if (!Config->AllowMultipleDefinition)
- error(S);
- warning(S);
- return;
+template <class ELFT>
+void SymbolTable<ELFT>::reportDuplicate(SymbolBody *Existing,
+ InputFile *NewFile) {
+ std::string Msg = "duplicate symbol: " + conflictMsg(Existing, NewFile);
+ if (Config->AllowMultipleDefinition)
+ warning(Msg);
+ else
+ error(Msg);
+}
+
+template <typename ELFT>
+Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, const Elf_Sym &Sym,
+ InputSectionBase<ELFT> *Section) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) =
+ insert(Name, Sym.getType(), Sym.getVisibility(),
+ /*CanOmitFromDynSym*/ false, /*IsUsedInRegularObj*/ true,
+ Section ? Section->getFile() : nullptr);
+ int Cmp = compareDefinedNonCommon(S, WasInserted, Sym.getBinding());
+ if (Cmp > 0)
+ replaceBody<DefinedRegular<ELFT>>(S, Name, Sym, Section);
+ else if (Cmp == 0)
+ reportDuplicate(S->body(), Section->getFile());
+ return S;
+}
+
+template <typename ELFT>
+Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t Binding,
+ uint8_t StOther) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) =
+ insert(Name, STT_NOTYPE, StOther & 3, /*CanOmitFromDynSym*/ false,
+ /*IsUsedInRegularObj*/ true, nullptr);
+ int Cmp = compareDefinedNonCommon(S, WasInserted, Binding);
+ if (Cmp > 0)
+ replaceBody<DefinedRegular<ELFT>>(S, Name, StOther);
+ else if (Cmp == 0)
+ reportDuplicate(S->body(), nullptr);
+ return S;
+}
+
+template <typename ELFT>
+Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N,
+ OutputSectionBase<ELFT> *Section,
+ uintX_t Value) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) =
+ insert(N, STT_NOTYPE, STV_HIDDEN, /*CanOmitFromDynSym*/ false,
+ /*IsUsedInRegularObj*/ true, nullptr);
+ int Cmp = compareDefinedNonCommon(S, WasInserted, STB_GLOBAL);
+ if (Cmp > 0)
+ replaceBody<DefinedSynthetic<ELFT>>(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,
+ const Elf_Sym &Sym,
+ const typename ELFT::Verdef *Verdef) {
+ // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
+ // as the visibility, which will leave the visibility in the symbol table
+ // unchanged.
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) =
+ insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true,
+ /*IsUsedInRegularObj*/ false, F);
+ // Make sure we preempt DSO symbols with default visibility.
+ if (Sym.getVisibility() == STV_DEFAULT)
+ S->ExportDynamic = true;
+ if (WasInserted || isa<Undefined>(S->body())) {
+ replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
+ if (!S->isWeak())
+ F->IsUsed = true;
}
- if (Comp < 0)
- Sym->Body = New;
}
-// Find an existing symbol or create and insert a new one.
-template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) {
- StringRef Name = New->getName();
- Symbol *&Sym = Symtab[Name];
- if (!Sym)
- Sym = new (Alloc) Symbol{New};
- New->setBackref(Sym);
- return Sym;
+template <class ELFT>
+Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, bool IsWeak,
+ uint8_t StOther, uint8_t Type,
+ bool CanOmitFromDynSym, BitcodeFile *F) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name, Type, StOther & 3, CanOmitFromDynSym,
+ /*IsUsedInRegularObj*/ false, F);
+ int Cmp =
+ compareDefinedNonCommon(S, WasInserted, IsWeak ? STB_WEAK : STB_GLOBAL);
+ if (Cmp > 0)
+ replaceBody<DefinedBitcode>(S, Name, StOther, Type, F);
+ else if (Cmp == 0)
+ reportDuplicate(S->body(), F);
+ return S;
}
template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
auto It = Symtab.find(Name);
if (It == Symtab.end())
return nullptr;
- return It->second->Body;
+ SymIndex V = It->second;
+ if (V.Idx == -1)
+ return nullptr;
+ return SymVector[V.Idx]->body();
+}
+
+// Returns a list of defined symbols that match with a given glob pattern.
+template <class ELFT>
+std::vector<SymbolBody *> SymbolTable<ELFT>::findAll(StringRef Pattern) {
+ std::vector<SymbolBody *> Res;
+ for (Symbol *Sym : SymVector) {
+ SymbolBody *B = Sym->body();
+ if (!B->isUndefined() && globMatch(Pattern, B->getName()))
+ Res.push_back(B);
+ }
+ return Res;
}
-template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *L) {
- Symbol *Sym = insert(L);
- if (Sym->Body == L)
+template <class ELFT>
+void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
+ const object::Archive::Symbol Sym) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Sym.getName());
+ if (WasInserted) {
+ replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType);
+ return;
+ }
+ if (!S->body()->isUndefined())
+ return;
+
+ // Weak undefined symbols should not fetch members from archives. If we were
+ // to keep old symbol we would not know that an archive member was available
+ // if a strong undefined symbol shows up afterwards in the link. If a strong
+ // undefined symbol never shows up, this lazy symbol will get to the end of
+ // the link and must be treated as the weak undefined one. We already marked
+ // this symbol as used when we added it to the symbol table, but we also need
+ // to preserve its type. FIXME: Move the Type field to Symbol.
+ if (S->isWeak()) {
+ replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
return;
- if (auto *Undef = dyn_cast<Undefined>(Sym->Body)) {
- Sym->Body = L;
- addMemberFile(Undef, L);
}
+ MemoryBufferRef MBRef = F->getMember(&Sym);
+ if (!MBRef.getBuffer().empty())
+ addFile(createObjectFile(MBRef, F->getName()));
}
template <class ELFT>
-void SymbolTable<ELFT>::addMemberFile(Undefined *Undef, Lazy *L) {
- // Weak undefined symbols should not fetch members from archives.
- // If we were to keep old symbol we would not know that an archive member was
- // available if a strong undefined symbol shows up afterwards in the link.
- // If a strong undefined symbol never shows up, this lazy symbol will
- // get to the end of the link and must be treated as the weak undefined one.
- // We set UsedInRegularObj in a similar way to what is done with shared
- // symbols and mark it as weak to reduce how many special cases are needed.
- if (Undef->isWeak()) {
- L->setUsedInRegularObj();
- L->setWeak();
+void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name);
+ if (WasInserted) {
+ replaceBody<LazyObject>(S, Name, Obj, SymbolBody::UnknownType);
return;
}
+ if (!S->body()->isUndefined())
+ return;
+
+ // See comment for addLazyArchive above.
+ if (S->isWeak()) {
+ replaceBody<LazyObject>(S, Name, Obj, S->body()->Type);
+ } else {
+ MemoryBufferRef MBRef = Obj.getBuffer();
+ if (!MBRef.getBuffer().empty())
+ addFile(createObjectFile(MBRef));
+ }
+}
- // Fetch a member file that has the definition for L.
- // getMember returns nullptr if the member was already read from the library.
- if (std::unique_ptr<InputFile> File = L->getMember())
- addFile(std::move(File));
+// Process undefined (-u) flags by loading lazy symbols named by those flags.
+template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() {
+ for (StringRef S : Config->Undefined)
+ if (auto *L = dyn_cast_or_null<Lazy>(find(S)))
+ if (std::unique_ptr<InputFile> File = L->fetch())
+ addFile(std::move(File));
}
// This function takes care of the case in which shared libraries depend on
@@ -265,10 +531,183 @@ template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
for (StringRef U : File->getUndefinedSymbols())
if (SymbolBody *Sym = find(U))
if (Sym->isDefined())
- Sym->setUsedInDynamicReloc();
+ Sym->symbol()->ExportDynamic = true;
+}
+
+// This function process the dynamic list option by marking all the symbols
+// to be exported in the dynamic table.
+template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() {
+ for (StringRef S : Config->DynamicList)
+ if (SymbolBody *B = find(S))
+ B->symbol()->ExportDynamic = true;
+}
+
+static bool hasWildcard(StringRef S) {
+ return S.find_first_of("?*") != StringRef::npos;
+}
+
+static void setVersionId(SymbolBody *Body, StringRef VersionName,
+ StringRef Name, uint16_t Version) {
+ if (!Body || Body->isUndefined()) {
+ if (Config->NoUndefinedVersion)
+ error("version script assignment of " + VersionName + " to symbol " +
+ Name + " failed: symbol not defined");
+ return;
+ }
+
+ Symbol *Sym = Body->symbol();
+ if (Sym->VersionId != Config->DefaultSymbolVersion)
+ warning("duplicate symbol " + Name + " in version script");
+ Sym->VersionId = Version;
+}
+
+template <class ELFT>
+std::map<std::string, SymbolBody *> SymbolTable<ELFT>::getDemangledSyms() {
+ std::map<std::string, SymbolBody *> Result;
+ for (Symbol *Sym : SymVector) {
+ SymbolBody *B = Sym->body();
+ Result[demangle(B->getName())] = B;
+ }
+ return Result;
+}
+
+static bool hasExternCpp() {
+ for (VersionDefinition &V : Config->VersionDefinitions)
+ for (SymbolVersion Sym : V.Globals)
+ if (Sym.IsExternCpp)
+ return true;
+ return false;
+}
+
+// This function processes the --version-script option by marking all global
+// symbols with the VersionScriptGlobal flag, which acts as a filter on the
+// dynamic symbol table.
+template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
+ // If version script does not contain versions declarations,
+ // we just should mark global symbols.
+ if (!Config->VersionScriptGlobals.empty()) {
+ for (SymbolVersion &Sym : Config->VersionScriptGlobals)
+ if (SymbolBody *B = find(Sym.Name))
+ B->symbol()->VersionId = VER_NDX_GLOBAL;
+ return;
+ }
+
+ if (Config->VersionDefinitions.empty())
+ return;
+
+ // If we have symbols version declarations, we should
+ // assign version references for each symbol.
+ // Current rules are:
+ // * If there is an exact match for the mangled name or we have extern C++
+ // exact match, then we use it.
+ // * Otherwise, we look through the wildcard patterns. We look through the
+ // version tags in reverse order. We use the first match we find (the last
+ // matching version tag in the file).
+ // Handle exact matches and build a map of demangled externs for
+ // quick search during next step.
+ std::map<std::string, SymbolBody *> Demangled;
+ if (hasExternCpp())
+ Demangled = getDemangledSyms();
+
+ for (VersionDefinition &V : Config->VersionDefinitions) {
+ for (SymbolVersion Sym : V.Globals) {
+ if (hasWildcard(Sym.Name))
+ continue;
+ SymbolBody *B = Sym.IsExternCpp ? Demangled[Sym.Name] : find(Sym.Name);
+ setVersionId(B, V.Name, Sym.Name, V.Id);
+ }
+ }
+
+ // Handle wildcards.
+ for (size_t I = Config->VersionDefinitions.size() - 1; I != (size_t)-1; --I) {
+ VersionDefinition &V = Config->VersionDefinitions[I];
+ for (SymbolVersion &Sym : V.Globals)
+ if (hasWildcard(Sym.Name))
+ for (SymbolBody *B : findAll(Sym.Name))
+ if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
+ B->symbol()->VersionId = V.Id;
+ }
+}
+
+// Returns the size of the longest version name.
+static int getMaxVersionLen() {
+ size_t Len = 0;
+ for (VersionDefinition &V : Config->VersionDefinitions)
+ Len = std::max(Len, V.Name.size());
+ return Len;
+}
+
+// Parses a symbol name in the form of <name>@<version> or <name>@@<version>.
+static std::pair<StringRef, uint16_t>
+getSymbolVersion(SymbolBody *B, int MaxVersionLen) {
+ StringRef S = B->getName();
+
+ // MaxVersionLen was passed so that we don't need to scan
+ // all characters in a symbol name. It is effective because
+ // versions are usually short and symbol names can be very long.
+ size_t Pos = S.find('@', std::max(0, int(S.size()) - MaxVersionLen - 2));
+ if (Pos == 0 || Pos == StringRef::npos)
+ return {"", 0};
+
+ StringRef Name = S.substr(0, Pos);
+ StringRef Verstr = S.substr(Pos + 1);
+ if (Verstr.empty())
+ return {"", 0};
+
+ // '@@' in a symbol name means the default version.
+ // It is usually the most recent one.
+ bool IsDefault = (Verstr[0] == '@');
+ if (IsDefault)
+ Verstr = Verstr.substr(1);
+
+ for (VersionDefinition &V : Config->VersionDefinitions) {
+ if (V.Name == Verstr)
+ return {Name, IsDefault ? V.Id : (V.Id | VERSYM_HIDDEN)};
+ }
+
+ // It is an error if the specified version was not defined.
+ error("symbol " + S + " has undefined version " + Verstr);
+ return {"", 0};
+}
+
+// Versions are usually assigned to symbols using version scripts,
+// but there's another way to assign versions to symbols.
+// If a symbol name contains '@', the string after it is not
+// actually a part of the symbol name but specifies a version.
+// This function takes care of it.
+template <class ELFT> void SymbolTable<ELFT>::scanSymbolVersions() {
+ if (Config->VersionDefinitions.empty())
+ return;
+
+ int MaxVersionLen = getMaxVersionLen();
+
+ // Unfortunately there's no way other than iterating over all
+ // symbols to look for '@' characters in symbol names.
+ // So this is inherently slow. A good news is that we do this
+ // only when versions have been defined.
+ for (Symbol *Sym : SymVector) {
+ // Symbol versions for exported symbols are by nature
+ // only for defined global symbols.
+ SymbolBody *B = Sym->body();
+ if (!B->isDefined())
+ continue;
+ uint8_t Visibility = B->getVisibility();
+ if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
+ continue;
+
+ // Look for '@' in the symbol name.
+ StringRef Name;
+ uint16_t Version;
+ std::tie(Name, Version) = getSymbolVersion(B, MaxVersionLen);
+ if (Name.empty())
+ continue;
+
+ B->setName(Name);
+ Sym->VersionId = Version;
+ }
}
-template class elf2::SymbolTable<ELF32LE>;
-template class elf2::SymbolTable<ELF32BE>;
-template class elf2::SymbolTable<ELF64LE>;
-template class elf2::SymbolTable<ELF64BE>;
+template class elf::SymbolTable<ELF32LE>;
+template class elf::SymbolTable<ELF32BE>;
+template class elf::SymbolTable<ELF64LE>;
+template class elf::SymbolTable<ELF64BE>;
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
index 16ed821bf01a..40415b645a44 100644
--- a/ELF/SymbolTable.h
+++ b/ELF/SymbolTable.h
@@ -11,14 +11,16 @@
#define LLD_ELF_SYMBOL_TABLE_H
#include "InputFiles.h"
-#include "llvm/ADT/MapVector.h"
+#include "LTO.h"
+#include "llvm/ADT/DenseMap.h"
namespace lld {
-namespace elf2 {
+namespace elf {
class Lazy;
template <class ELFT> class OutputSectionBase;
struct Symbol;
-class Undefined;
+
+typedef llvm::CachedHash<StringRef> SymName;
// SymbolTable is a bucket of all known symbols, including defined,
// undefined, or lazy symbols (the last one is symbols in archive
@@ -29,17 +31,18 @@ class Undefined;
// conflicts. For example, obviously, a defined symbol is better than
// an undefined symbol. Or, if there's a conflict between a lazy and a
// undefined, it'll read an archive member to read a real definition
-// to replace the lazy symbol. The logic is implemented in resolve().
+// to replace the lazy symbol. The logic is implemented in the
+// add*() functions, which are called by input files as they are parsed. There
+// is one add* function per symbol type.
template <class ELFT> class SymbolTable {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::uint uintX_t;
public:
void addFile(std::unique_ptr<InputFile> File);
+ void addCombinedLtoObject();
- const llvm::MapVector<StringRef, Symbol *> &getSymbols() const {
- return Symtab;
- }
+ llvm::ArrayRef<Symbol *> getSymbols() const { return SymVector; }
const std::vector<std::unique_ptr<ObjectFile<ELFT>>> &getObjectFiles() const {
return ObjectFiles;
@@ -49,34 +52,69 @@ public:
return SharedFiles;
}
- SymbolBody *addUndefined(StringRef Name);
- SymbolBody *addUndefinedOpt(StringRef Name);
- SymbolBody *addAbsolute(StringRef Name, Elf_Sym &ESym);
- SymbolBody *addSynthetic(StringRef Name, OutputSectionBase<ELFT> &Section,
- uintX_t Value);
- SymbolBody *addIgnored(StringRef Name);
- SymbolBody *addIgnoredStrong(StringRef Name);
-
+ DefinedRegular<ELFT> *addAbsolute(StringRef Name,
+ uint8_t Visibility = llvm::ELF::STV_HIDDEN);
+ DefinedRegular<ELFT> *addIgnored(StringRef Name,
+ uint8_t Visibility = llvm::ELF::STV_HIDDEN);
+
+ Symbol *addUndefined(StringRef Name);
+ Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther,
+ uint8_t Type, bool CanOmitFromDynSym, InputFile *File);
+
+ Symbol *addRegular(StringRef Name, const Elf_Sym &Sym,
+ InputSectionBase<ELFT> *Section);
+ Symbol *addRegular(StringRef Name, uint8_t Binding, uint8_t StOther);
+ Symbol *addSynthetic(StringRef N, OutputSectionBase<ELFT> *Section,
+ uintX_t Value);
+ void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
+ const typename ELFT::Verdef *Verdef);
+
+ void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
+ void addLazyObject(StringRef Name, LazyObjectFile &Obj);
+ Symbol *addBitcode(StringRef Name, bool IsWeak, uint8_t StOther, uint8_t Type,
+ bool CanOmitFromDynSym, BitcodeFile *File);
+
+ Symbol *addCommon(StringRef N, uint64_t Size, uint64_t Alignment,
+ uint8_t Binding, uint8_t StOther, uint8_t Type,
+ InputFile *File);
+
+ void scanUndefinedFlags();
void scanShlibUndefined();
+ void scanDynamicList();
+ void scanVersionScript();
+ void scanSymbolVersions();
+
SymbolBody *find(StringRef Name);
+
+ void trace(StringRef Name);
void wrap(StringRef Name);
- ELFFileBase<ELFT> *findFile(SymbolBody *B);
private:
- Symbol *insert(SymbolBody *New);
- void addLazy(Lazy *New);
- void addMemberFile(Undefined *Undef, Lazy *L);
- void resolve(SymbolBody *Body);
- std::string conflictMsg(SymbolBody *Old, SymbolBody *New);
+ std::vector<SymbolBody *> findAll(StringRef Pattern);
+ std::pair<Symbol *, bool> insert(StringRef Name);
+ std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
+ uint8_t Visibility, bool CanOmitFromDynSym,
+ bool IsUsedInRegularObj, InputFile *File);
+
+ std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile);
+ void reportDuplicate(SymbolBody *Existing, InputFile *NewFile);
+
+ std::map<std::string, SymbolBody *> getDemangledSyms();
+
+ struct SymIndex {
+ int Idx : 31;
+ unsigned Traced : 1;
+ };
// The order the global symbols are in is not defined. We can use an arbitrary
// order, but it has to be reproducible. That is true even when cross linking.
// The default hashing of StringRef produces different results on 32 and 64
- // bit systems so we use a MapVector. That is arbitrary, deterministic but
- // a bit inefficient.
+ // bit systems so we use a map to a vector. That is arbitrary, deterministic
+ // but a bit inefficient.
// FIXME: Experiment with passing in a custom hashing or sorting the symbols
// once symbol resolution is finished.
- llvm::MapVector<StringRef, Symbol *> Symtab;
+ llvm::DenseMap<SymName, SymIndex> Symtab;
+ std::vector<Symbol *> SymVector;
llvm::BumpPtrAllocator Alloc;
// Comdat groups define "link once" sections. If two comdat groups have the
@@ -87,13 +125,20 @@ private:
// The symbol table owns all file objects.
std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles;
+ std::vector<std::unique_ptr<LazyObjectFile>> LazyObjectFiles;
std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles;
+ std::vector<std::unique_ptr<BitcodeFile>> BitcodeFiles;
// Set of .so files to not link the same shared object file more than once.
llvm::DenseSet<StringRef> SoNames;
+
+ std::unique_ptr<BitcodeCompiler> Lto;
};
-} // namespace elf2
+template <class ELFT> struct Symtab { static SymbolTable<ELFT> *X; };
+template <class ELFT> SymbolTable<ELFT> *Symtab<ELFT>::X;
+
+} // namespace elf
} // namespace lld
#endif
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index 3c864cbe2b67..d6a605d11183 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -8,9 +8,11 @@
//===----------------------------------------------------------------------===//
#include "Symbols.h"
-#include "InputSection.h"
#include "Error.h"
#include "InputFiles.h"
+#include "InputSection.h"
+#include "OutputSections.h"
+#include "Target.h"
#include "llvm/ADT/STLExtras.h"
@@ -19,131 +21,316 @@ using namespace llvm::object;
using namespace llvm::ELF;
using namespace lld;
-using namespace lld::elf2;
+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;
+
+ switch (Body.kind()) {
+ case SymbolBody::DefinedSyntheticKind: {
+ auto &D = cast<DefinedSynthetic<ELFT>>(Body);
+ const OutputSectionBase<ELFT> *Sec = D.Section;
+ if (!Sec)
+ return D.Value;
+ if (D.Value == DefinedSynthetic<ELFT>::SectionEnd)
+ return Sec->getVA() + Sec->getSize();
+ return Sec->getVA() + D.Value;
+ }
+ case SymbolBody::DefinedRegularKind: {
+ auto &D = cast<DefinedRegular<ELFT>>(Body);
+ InputSectionBase<ELFT> *SC = D.Section;
+
+ // 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 (SC == &InputSection<ELFT>::Discarded)
+ return 0;
-static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
- if (VA == STV_DEFAULT)
- return VB;
- if (VB == STV_DEFAULT)
+ // This is an absolute symbol.
+ if (!SC)
+ return D.Value;
+
+ uintX_t Offset = D.Value;
+ if (D.isSection()) {
+ Offset += Addend;
+ Addend = 0;
+ }
+ uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset);
+ if (D.isTls())
+ return VA - Out<ELFT>::TlsPhdr->p_vaddr;
return VA;
- return std::min(VA, VB);
+ }
+ case SymbolBody::DefinedCommonKind:
+ return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(Body).OffsetInBss;
+ case SymbolBody::SharedKind: {
+ auto &SS = cast<SharedSymbol<ELFT>>(Body);
+ if (!SS.NeedsCopyOrPltAddr)
+ return 0;
+ if (SS.isFunc())
+ return Body.getPltVA<ELFT>();
+ return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
+ }
+ case SymbolBody::UndefinedKind:
+ return 0;
+ case SymbolBody::LazyArchiveKind:
+ case SymbolBody::LazyObjectKind:
+ assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer");
+ return 0;
+ case SymbolBody::DefinedBitcodeKind:
+ llvm_unreachable("should have been replaced");
+ }
+ llvm_unreachable("invalid symbol kind");
}
-// Returns 1, 0 or -1 if this symbol should take precedence
-// over the Other, tie or lose, respectively.
-template <class ELFT> int SymbolBody::compare(SymbolBody *Other) {
- typedef typename ELFFile<ELFT>::uintX_t uintX_t;
- assert(!isLazy() && !Other->isLazy());
- std::pair<bool, bool> L(isDefined(), !isWeak());
- std::pair<bool, bool> R(Other->isDefined(), !Other->isWeak());
+SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
+ uint8_t Type)
+ : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true),
+ IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
+ NameOffset(NameOffset) {}
+
+SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
+ : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false),
+ IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
+ Name({Name.data(), Name.size()}) {}
- // Normalize
- if (L > R)
- return -Other->compare<ELFT>(this);
+StringRef SymbolBody::getName() const {
+ assert(!isLocal());
+ return StringRef(Name.S, Name.Len);
+}
- Visibility = Other->Visibility =
- getMinVisibility(Visibility, Other->Visibility);
+void SymbolBody::setName(StringRef S) {
+ Name.S = S.data();
+ Name.Len = S.size();
+}
- if (IsUsedInRegularObj || Other->IsUsedInRegularObj)
- IsUsedInRegularObj = Other->IsUsedInRegularObj = true;
+// 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.
+bool SymbolBody::isPreemptible() const {
+ if (isLocal())
+ return false;
- if (L != R)
- return -1;
- if (!L.first || !L.second)
- return 1;
+ // Shared symbols resolve to the definition in the DSO. The exceptions are
+ // symbols with copy relocations (which resolve to .bss) or preempt plt
+ // entries (which resolve to that plt entry).
if (isShared())
- return -1;
- if (Other->isShared())
- return 1;
- if (isCommon()) {
- if (!Other->isCommon())
- return -1;
- auto *ThisC = cast<DefinedCommon>(this);
- auto *OtherC = cast<DefinedCommon>(Other);
- uintX_t Align = std::max(ThisC->MaxAlignment, OtherC->MaxAlignment);
- if (ThisC->Size >= OtherC->Size) {
- ThisC->MaxAlignment = Align;
- return 1;
- }
- OtherC->MaxAlignment = Align;
- return -1;
- }
- if (Other->isCommon())
- return 1;
+ return !NeedsCopyOrPltAddr;
+
+ // That's all that can be preempted in a non-DSO.
+ if (!Config->Shared)
+ return false;
+
+ // Only symbols that appear in dynsym can be preempted.
+ if (!symbol()->includeInDynsym())
+ return false;
+
+ // Only default visibility symbols can be preempted.
+ if (symbol()->Visibility != STV_DEFAULT)
+ return false;
+
+ // -Bsymbolic means that definitions are not preempted.
+ if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc()))
+ return !isDefined();
+ 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);
+ return OutVA + Addend;
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
+ return Out<ELFT>::Got->getVA() + getGotOffset<ELFT>();
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
+ return GotIndex * Target->GotEntrySize;
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
+ return Out<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
+ return GotPltIndex * Target->GotPltEntrySize;
+}
+
+template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
+ return Out<ELFT>::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();
+ 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))
+ return DR->Size;
+ if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
+ return S->Sym.st_size;
return 0;
}
-Defined::Defined(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility,
- bool IsTls)
- : SymbolBody(K, Name, IsWeak, Visibility, IsTls) {}
+Defined::Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
+ : SymbolBody(K, Name, StOther, Type) {}
-Undefined::Undefined(SymbolBody::Kind K, StringRef N, bool IsWeak,
- uint8_t Visibility, bool IsTls)
- : SymbolBody(K, N, IsWeak, Visibility, IsTls), CanKeepUndefined(false) {}
+Defined::Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type)
+ : SymbolBody(K, NameOffset, StOther, Type) {}
-Undefined::Undefined(StringRef N, bool IsWeak, uint8_t Visibility,
- bool CanKeepUndefined)
- : Undefined(SymbolBody::UndefinedKind, N, IsWeak, Visibility,
- /*IsTls*/ false) {
- this->CanKeepUndefined = CanKeepUndefined;
+DefinedBitcode::DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type,
+ BitcodeFile *F)
+ : Defined(DefinedBitcodeKind, Name, StOther, Type) {
+ this->File = F;
}
-template <typename ELFT>
-UndefinedElf<ELFT>::UndefinedElf(StringRef N, const Elf_Sym &Sym)
- : Undefined(SymbolBody::UndefinedElfKind, N,
- Sym.getBinding() == llvm::ELF::STB_WEAK, Sym.getVisibility(),
- Sym.getType() == llvm::ELF::STT_TLS),
- Sym(Sym) {}
+bool DefinedBitcode::classof(const SymbolBody *S) {
+ return S->kind() == DefinedBitcodeKind;
+}
+
+Undefined::Undefined(StringRef Name, uint8_t StOther, uint8_t Type,
+ InputFile *File)
+ : SymbolBody(SymbolBody::UndefinedKind, Name, StOther, Type) {
+ this->File = File;
+}
+
+Undefined::Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type,
+ InputFile *File)
+ : SymbolBody(SymbolBody::UndefinedKind, NameOffset, StOther, Type) {
+ this->File = File;
+}
template <typename ELFT>
DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value,
- OutputSectionBase<ELFT> &Section)
- : Defined(SymbolBody::DefinedSyntheticKind, N, false, STV_DEFAULT, false),
+ OutputSectionBase<ELFT> *Section)
+ : Defined(SymbolBody::DefinedSyntheticKind, N, STV_HIDDEN, 0 /* Type */),
Value(Value), Section(Section) {}
DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment,
- bool IsWeak, uint8_t Visibility)
- : Defined(SymbolBody::DefinedCommonKind, N, IsWeak, Visibility, false) {
- MaxAlignment = Alignment;
- this->Size = Size;
+ uint8_t StOther, uint8_t Type, InputFile *File)
+ : Defined(SymbolBody::DefinedCommonKind, N, StOther, Type),
+ Alignment(Alignment), Size(Size) {
+ this->File = File;
+}
+
+std::unique_ptr<InputFile> Lazy::fetch() {
+ if (auto *S = dyn_cast<LazyArchive>(this))
+ return S->fetch();
+ return cast<LazyObject>(this)->fetch();
}
-std::unique_ptr<InputFile> Lazy::getMember() {
- MemoryBufferRef MBRef = File->getMember(&Sym);
+LazyArchive::LazyArchive(ArchiveFile &File,
+ const llvm::object::Archive::Symbol S, uint8_t Type)
+ : Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) {
+ this->File = &File;
+}
+
+LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type)
+ : Lazy(LazyObjectKind, Name, Type) {
+ this->File = &File;
+}
+
+std::unique_ptr<InputFile> LazyArchive::fetch() {
+ MemoryBufferRef MBRef = file()->getMember(&Sym);
// getMember returns an empty buffer if the member was already
// read from the library.
if (MBRef.getBuffer().empty())
return std::unique_ptr<InputFile>(nullptr);
+ return createObjectFile(MBRef, file()->getName());
+}
+
+std::unique_ptr<InputFile> LazyObject::fetch() {
+ MemoryBufferRef MBRef = file()->getBuffer();
+ if (MBRef.getBuffer().empty())
+ return std::unique_ptr<InputFile>(nullptr);
return createObjectFile(MBRef);
}
-template <class ELFT> static void doInitSymbols() {
- ElfSym<ELFT>::End.setBinding(STB_GLOBAL);
- ElfSym<ELFT>::IgnoredWeak.setBinding(STB_WEAK);
- ElfSym<ELFT>::IgnoredWeak.setVisibility(STV_HIDDEN);
- ElfSym<ELFT>::Ignored.setBinding(STB_GLOBAL);
- ElfSym<ELFT>::Ignored.setVisibility(STV_HIDDEN);
+bool Symbol::includeInDynsym() const {
+ if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
+ return false;
+ return (ExportDynamic && VersionId != VER_NDX_LOCAL) || body()->isShared() ||
+ (body()->isUndefined() && Config->Shared);
}
-void elf2::initSymbols() {
- doInitSymbols<ELF32LE>();
- doInitSymbols<ELF32BE>();
- doInitSymbols<ELF64LE>();
- doInitSymbols<ELF64BE>();
+// Print out a log message for --trace-symbol.
+void elf::printTraceSymbol(Symbol *Sym) {
+ SymbolBody *B = Sym->body();
+ outs() << getFilename(B->File);
+
+ if (B->isUndefined())
+ outs() << ": reference to ";
+ else if (B->isCommon())
+ outs() << ": common definition of ";
+ else
+ outs() << ": definition of ";
+ outs() << B->getName() << "\n";
}
-template int SymbolBody::compare<ELF32LE>(SymbolBody *Other);
-template int SymbolBody::compare<ELF32BE>(SymbolBody *Other);
-template int SymbolBody::compare<ELF64LE>(SymbolBody *Other);
-template int SymbolBody::compare<ELF64BE>(SymbolBody *Other);
+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 class elf2::UndefinedElf<ELF32LE>;
-template class elf2::UndefinedElf<ELF32BE>;
-template class elf2::UndefinedElf<ELF64LE>;
-template class elf2::UndefinedElf<ELF64BE>;
+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 elf2::DefinedSynthetic<ELF32LE>;
-template class elf2::DefinedSynthetic<ELF32BE>;
-template class elf2::DefinedSynthetic<ELF64LE>;
-template class elf2::DefinedSynthetic<ELF64BE>;
+template class elf::DefinedSynthetic<ELF32LE>;
+template class elf::DefinedSynthetic<ELF32BE>;
+template class elf::DefinedSynthetic<ELF64LE>;
+template class elf::DefinedSynthetic<ELF64BE>;
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index 6f65ea1a72e4..aa9a87d3b4f7 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -10,14 +10,6 @@
// All symbols are handled as SymbolBodies regardless of their types.
// This file defines various types of SymbolBodies.
//
-// File-scope symbols in ELF objects are the only exception of SymbolBody
-// instantiation. We will never create SymbolBodies for them for performance
-// reason. They are often represented as nullptrs. This is fine for symbol
-// resolution because the symbol table naturally cares only about
-// externally-visible symbols. For relocations, you have to deal with both
-// local and non-local functions, and we have two different functions
-// where we need them.
-//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_SYMBOLS_H
@@ -28,28 +20,22 @@
#include "lld/Core/LLVM.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
+#include "llvm/Support/AlignOf.h"
namespace lld {
-namespace elf2 {
+namespace elf {
class ArchiveFile;
+class BitcodeFile;
class InputFile;
+class LazyObjectFile;
class SymbolBody;
template <class ELFT> class ObjectFile;
template <class ELFT> class OutputSection;
template <class ELFT> class OutputSectionBase;
template <class ELFT> class SharedFile;
-// Initializes global objects defined in this file.
-// Called at the beginning of main().
-void initSymbols();
-
-// A real symbol object, SymbolBody, is usually accessed indirectly
-// through a Symbol. There's always one Symbol for each symbol name.
-// The resolver updates SymbolBody pointers as it resolves symbols.
-struct Symbol {
- SymbolBody *Body;
-};
+struct Symbol;
// The base class for real symbol classes.
class SymbolBody {
@@ -58,115 +44,134 @@ public:
DefinedFirst,
DefinedRegularKind = DefinedFirst,
SharedKind,
- DefinedElfLast = SharedKind,
DefinedCommonKind,
+ DefinedBitcodeKind,
DefinedSyntheticKind,
DefinedLast = DefinedSyntheticKind,
- UndefinedElfKind,
UndefinedKind,
- LazyKind
+ LazyArchiveKind,
+ LazyObjectKind,
};
- Kind kind() const { return static_cast<Kind>(SymbolKind); }
+ SymbolBody(Kind K) : SymbolKind(K) {}
- bool isWeak() const { return IsWeak; }
- bool isUndefined() const {
- return SymbolKind == UndefinedKind || SymbolKind == UndefinedElfKind;
+ Symbol *symbol();
+ const Symbol *symbol() const {
+ return const_cast<SymbolBody *>(this)->symbol();
}
+
+ Kind kind() const { return static_cast<Kind>(SymbolKind); }
+
+ bool isUndefined() const { return SymbolKind == UndefinedKind; }
bool isDefined() const { return SymbolKind <= DefinedLast; }
bool isCommon() const { return SymbolKind == DefinedCommonKind; }
- bool isLazy() const { return SymbolKind == LazyKind; }
+ bool isLazy() const {
+ return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
+ }
bool isShared() const { return SymbolKind == SharedKind; }
- bool isUsedInRegularObj() const { return IsUsedInRegularObj; }
- bool isUsedInDynamicReloc() const { return IsUsedInDynamicReloc; }
- void setUsedInDynamicReloc() { IsUsedInDynamicReloc = true; }
- bool isTls() const { return IsTls; }
+ bool isLocal() const { return IsLocal; }
+ bool isPreemptible() const;
- // Returns the symbol name.
- StringRef getName() const { return Name; }
+ StringRef getName() const;
+ void setName(StringRef S);
- uint8_t getVisibility() const { return Visibility; }
+ uint32_t getNameOffset() const {
+ assert(isLocal());
+ return NameOffset;
+ }
- unsigned DynamicSymbolTableIndex = 0;
- uint32_t GlobalDynIndex = -1;
+ uint8_t getVisibility() const { return StOther & 0x3; }
+
+ unsigned DynsymIndex = 0;
uint32_t GotIndex = -1;
uint32_t GotPltIndex = -1;
uint32_t PltIndex = -1;
- bool hasGlobalDynIndex() { return GlobalDynIndex != uint32_t(-1); }
+ uint32_t GlobalDynIndex = -1;
bool isInGot() const { return GotIndex != -1U; }
- bool isInGotPlt() const { return GotPltIndex != -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;
+
+ template <class ELFT> typename ELFT::uint 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;
+ template <class ELFT> typename ELFT::uint getSize() const;
- // A SymbolBody has a backreference to a Symbol. Originally they are
- // doubly-linked. A backreference will never change. But the pointer
- // in the Symbol may be mutated by the resolver. If you have a
- // pointer P to a SymbolBody and are not sure whether the resolver
- // has chosen the object among other objects having the same name,
- // you can access P->Backref->Body to get the resolver's result.
- void setBackref(Symbol *P) { Backref = P; }
- SymbolBody *repl() { return Backref ? Backref->Body : this; }
- Symbol *getSymbol() { return Backref; }
-
- // Decides which symbol should "win" in the symbol table, this or
- // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if
- // they are duplicate (conflicting) symbols.
- template <class ELFT> int compare(SymbolBody *Other);
+ // The file from which this symbol was created.
+ InputFile *File = nullptr;
protected:
- SymbolBody(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility,
- bool IsTls)
- : SymbolKind(K), IsWeak(IsWeak), Visibility(Visibility), IsTls(IsTls),
- Name(Name) {
- IsUsedInRegularObj = K != SharedKind && K != LazyKind;
- IsUsedInDynamicReloc = 0;
- }
+ SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type);
+
+ SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
const unsigned SymbolKind : 8;
- unsigned IsWeak : 1;
- unsigned Visibility : 2;
- // True if the symbol was used for linking and thus need to be
- // added to the output file's symbol table. It is usually true,
- // but if it is a shared symbol that were not referenced by anyone,
- // it can be false.
- unsigned IsUsedInRegularObj : 1;
+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 this is a local symbol.
+ unsigned IsLocal : 1;
+
+ // True if this symbol has an entry in the global part of MIPS GOT.
+ unsigned IsInGlobalMipsGot : 1;
- // If true, the symbol is added to .dynsym symbol table.
- unsigned IsUsedInDynamicReloc : 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
- unsigned IsTls : 1;
- StringRef Name;
- Symbol *Backref = nullptr;
+ // The Type field may also have this value. It means that we have not yet seen
+ // a non-Lazy symbol with this name, so we don't know what its type is. The
+ // Type field is normally set to this value for Lazy symbols unless we saw a
+ // weak undefined symbol first, in which case we need to remember the original
+ // symbol's type in order to check for TLS mismatches.
+ enum { UnknownType = 255 };
+
+ bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
+ bool isTls() const { return Type == llvm::ELF::STT_TLS; }
+ bool isFunc() const { return Type == llvm::ELF::STT_FUNC; }
+ bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
+ bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
+ bool isFile() const { return Type == llvm::ELF::STT_FILE; }
+
+protected:
+ struct Str {
+ const char *S;
+ size_t Len;
+ };
+ union {
+ Str Name;
+ uint32_t NameOffset;
+ };
};
// The base class for any defined symbols.
class Defined : public SymbolBody {
public:
- Defined(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility, bool IsTls);
+ Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type);
+ Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
static bool classof(const SymbolBody *S) { return S->isDefined(); }
};
-// Any defined symbol from an ELF file.
-template <class ELFT> class DefinedElf : public Defined {
-protected:
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
-
+// The defined symbol in LLVM bitcode files.
+class DefinedBitcode : public Defined {
public:
- DefinedElf(Kind K, StringRef N, const Elf_Sym &Sym)
- : Defined(K, N, Sym.getBinding() == llvm::ELF::STB_WEAK,
- Sym.getVisibility(), Sym.getType() == llvm::ELF::STT_TLS),
- Sym(Sym) {}
-
- const Elf_Sym &Sym;
- static bool classof(const SymbolBody *S) {
- return S->kind() <= DefinedElfLast;
- }
+ DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type, BitcodeFile *F);
+ static bool classof(const SymbolBody *S);
+ BitcodeFile *file() { return (BitcodeFile *)this->File; }
};
class DefinedCommon : public Defined {
public:
- DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, bool IsWeak,
- uint8_t Visibility);
+ DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t StOther,
+ uint8_t Type, InputFile *File);
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedCommonKind;
@@ -177,95 +182,137 @@ public:
uint64_t OffsetInBss;
// The maximum alignment we have seen for this symbol.
- uint64_t MaxAlignment;
+ uint64_t Alignment;
uint64_t Size;
};
// Regular defined symbols read from object file symbol tables.
-template <class ELFT> class DefinedRegular : public DefinedElf<ELFT> {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
+template <class ELFT> class DefinedRegular : public Defined {
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::uint uintX_t;
public:
- DefinedRegular(StringRef N, const Elf_Sym &Sym,
+ DefinedRegular(StringRef Name, const Elf_Sym &Sym,
InputSectionBase<ELFT> *Section)
- : DefinedElf<ELFT>(SymbolBody::DefinedRegularKind, N, Sym),
- Section(Section) {}
+ : Defined(SymbolBody::DefinedRegularKind, Name, Sym.st_other,
+ Sym.getType()),
+ Value(Sym.st_value), Size(Sym.st_size),
+ Section(Section ? Section->Repl : NullInputSection) {
+ if (Section)
+ this->File = Section->getFile();
+ }
+
+ DefinedRegular(const Elf_Sym &Sym, InputSectionBase<ELFT> *Section)
+ : Defined(SymbolBody::DefinedRegularKind, Sym.st_name, Sym.st_other,
+ Sym.getType()),
+ Value(Sym.st_value), Size(Sym.st_size),
+ Section(Section ? Section->Repl : NullInputSection) {
+ assert(isLocal());
+ if (Section)
+ this->File = Section->getFile();
+ }
+
+ DefinedRegular(StringRef Name, uint8_t StOther)
+ : Defined(SymbolBody::DefinedRegularKind, Name, StOther,
+ llvm::ELF::STT_NOTYPE),
+ Value(0), Size(0), Section(NullInputSection) {}
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedRegularKind;
}
- // If this is null, the symbol is absolute.
- InputSectionBase<ELFT> *Section;
+ 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.
template <class ELFT> class DefinedSynthetic : public Defined {
public:
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ typedef typename ELFT::uint uintX_t;
DefinedSynthetic(StringRef N, uintX_t Value,
- OutputSectionBase<ELFT> &Section);
+ OutputSectionBase<ELFT> *Section);
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedSyntheticKind;
}
+ // Special value designates that the symbol 'points'
+ // to the end of the section.
+ static const uintX_t SectionEnd = uintX_t(-1);
+
uintX_t Value;
- const OutputSectionBase<ELFT> &Section;
+ const OutputSectionBase<ELFT> *Section;
};
-// Undefined symbol.
class Undefined : public SymbolBody {
- typedef SymbolBody::Kind Kind;
- bool CanKeepUndefined;
-
-protected:
- Undefined(Kind K, StringRef N, bool IsWeak, uint8_t Visibility, bool IsTls);
-
-public:
- Undefined(StringRef N, bool IsWeak, uint8_t Visibility,
- bool CanKeepUndefined);
-
- static bool classof(const SymbolBody *S) { return S->isUndefined(); }
-
- bool canKeepUndefined() const { return CanKeepUndefined; }
-};
-
-template <class ELFT> class UndefinedElf : public Undefined {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
-
public:
- UndefinedElf(StringRef N, const Elf_Sym &Sym);
- const Elf_Sym &Sym;
+ Undefined(StringRef Name, uint8_t StOther, uint8_t Type, InputFile *F);
+ Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type, InputFile *F);
static bool classof(const SymbolBody *S) {
- return S->kind() == SymbolBody::UndefinedElfKind;
+ return S->kind() == UndefinedKind;
}
+
+ InputFile *file() { return this->File; }
};
-template <class ELFT> class SharedSymbol : public DefinedElf<ELFT> {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+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;
public:
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::SharedKind;
}
- SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym)
- : DefinedElf<ELFT>(SymbolBody::SharedKind, Name, Sym), File(F) {}
+ SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
+ const Elf_Verdef *Verdef)
+ : Defined(SymbolBody::SharedKind, Name, Sym.st_other, Sym.getType()),
+ Sym(Sym), Verdef(Verdef) {
+ // IFuncs defined in DSOs are treated as functions by the static linker.
+ if (isGnuIFunc())
+ Type = llvm::ELF::STT_FUNC;
+ this->File = F;
+ }
- SharedFile<ELFT> *File;
+ SharedFile<ELFT> *file() { return (SharedFile<ELFT> *)this->File; }
- // True if the linker has to generate a copy relocation for this shared
- // symbol. OffsetInBss is significant only when NeedsCopy is true.
- bool NeedsCopy = false;
+ const Elf_Sym &Sym;
+
+ // This field is a pointer to the symbol's version definition.
+ const Elf_Verdef *Verdef;
+
+ // OffsetInBss is significant only when needsCopy() is true.
uintX_t OffsetInBss = 0;
+
+ // 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(); }
};
// This class represents a symbol defined in an archive file. It is
@@ -275,58 +322,153 @@ public:
// the same name, it will ask the Lazy to load a file.
class Lazy : public SymbolBody {
public:
- Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S)
- : SymbolBody(LazyKind, S.getName(), false, llvm::ELF::STV_DEFAULT, false),
- File(F), Sym(S) {}
-
- static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; }
+ static bool classof(const SymbolBody *S) { return S->isLazy(); }
// Returns an object file for this symbol, or a nullptr if the file
// was already returned.
- std::unique_ptr<InputFile> getMember();
+ std::unique_ptr<InputFile> fetch();
- void setWeak() { IsWeak = true; }
- void setUsedInRegularObj() { IsUsedInRegularObj = true; }
+protected:
+ Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type)
+ : SymbolBody(K, Name, llvm::ELF::STV_DEFAULT, Type) {}
+};
+
+// LazyArchive symbols represents symbols in archive files.
+class LazyArchive : public Lazy {
+public:
+ LazyArchive(ArchiveFile &File, const llvm::object::Archive::Symbol S,
+ uint8_t Type);
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == LazyArchiveKind;
+ }
+
+ ArchiveFile *file() { return (ArchiveFile *)this->File; }
+ std::unique_ptr<InputFile> fetch();
private:
- ArchiveFile *File;
const llvm::object::Archive::Symbol Sym;
};
+// LazyObject symbols represents symbols in object files between
+// --start-lib and --end-lib options.
+class LazyObject : public Lazy {
+public:
+ LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type);
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == LazyObjectKind;
+ }
+
+ LazyObjectFile *file() { return (LazyObjectFile *)this->File; }
+ std::unique_ptr<InputFile> fetch();
+};
+
// Some linker-generated symbols need to be created as
-// DefinedRegular symbols, so they need Elf_Sym symbols.
-// Here we allocate such Elf_Sym symbols statically.
+// DefinedRegular symbols.
template <class ELFT> struct ElfSym {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
+ // The content for _etext and etext symbols.
+ static DefinedRegular<ELFT> *Etext;
+ static DefinedRegular<ELFT> *Etext2;
- // Used to represent an undefined symbol which we don't want
- // to add to the output file's symbol table. The `IgnoredWeak`
- // has weak binding and can be substituted. The `Ignore` has
- // global binding and gets priority over symbols from shared libs.
- static Elf_Sym IgnoredWeak;
- static Elf_Sym Ignored;
+ // The content for _edata and edata symbols.
+ static DefinedRegular<ELFT> *Edata;
+ static DefinedRegular<ELFT> *Edata2;
// The content for _end and end symbols.
- static Elf_Sym End;
+ static DefinedRegular<ELFT> *End;
+ static DefinedRegular<ELFT> *End2;
- // The content for _gp symbol for MIPS target.
- static Elf_Sym MipsGp;
+ // The content for _gp_disp symbol for MIPS target.
+ static SymbolBody *MipsGpDisp;
+};
+
+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> SymbolBody *ElfSym<ELFT>::MipsGpDisp;
+
+// 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
+// holds computed properties of symbol names.
+struct Symbol {
+ // Symbol binding. This is on the Symbol to track changes during resolution.
+ // In particular:
+ // An undefined weak is still weak when it resolves to a shared library.
+ // An undefined weak will not fetch archive members, but we have to remember
+ // it is weak.
+ uint8_t Binding;
+
+ // Version definition index.
+ uint16_t VersionId;
+
+ // Symbol visibility. This is the computed minimum visibility of all
+ // observed non-DSO symbols.
+ unsigned Visibility : 2;
+
+ // True if the symbol was used for linking and thus need to be added to the
+ // output file's symbol table. This is true for all symbols except for
+ // unreferenced DSO symbols and bitcode symbols that are unreferenced except
+ // by other bitcode objects.
+ unsigned IsUsedInRegularObj : 1;
- // __rel_iplt_start/__rel_iplt_end for signaling
- // where R_[*]_IRELATIVE relocations do live.
- static Elf_Sym RelaIpltStart;
- static Elf_Sym RelaIpltEnd;
+ // If this flag is true and the symbol has protected or default visibility, it
+ // will appear in .dynsym. This flag is set by interposable DSO symbols in
+ // executables, by most symbols in DSOs and executables built with
+ // --export-dynamic, and by dynamic lists.
+ unsigned ExportDynamic : 1;
+
+ // True if this symbol is specified by --trace-symbol option.
+ unsigned Traced : 1;
+
+ bool includeInDynsym() const;
+ bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
+
+ // 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<
+ DefinedBitcode, DefinedCommon, DefinedRegular<llvm::object::ELF64LE>,
+ DefinedSynthetic<llvm::object::ELF64LE>, Undefined,
+ SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject>
+ Body;
+
+ SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
+ const SymbolBody *body() const { return const_cast<Symbol *>(this)->body(); }
};
-template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::IgnoredWeak;
-template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::Ignored;
-template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::End;
-template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::MipsGp;
-template <class ELFT>
-typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::RelaIpltStart;
-template <class ELFT> typename ElfSym<ELFT>::Elf_Sym ElfSym<ELFT>::RelaIpltEnd;
+void printTraceSymbol(Symbol *Sym);
+
+template <typename T, typename... ArgT>
+void replaceBody(Symbol *S, ArgT &&... Arg) {
+ static_assert(sizeof(T) <= sizeof(S->Body), "Body too small");
+ static_assert(llvm::AlignOf<T>::Alignment <=
+ llvm::AlignOf<decltype(S->Body)>::Alignment,
+ "Body not aligned enough");
+ assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr &&
+ "Not a SymbolBody");
+
+ new (S->Body.buffer) T(std::forward<ArgT>(Arg)...);
+
+ // Print out a log message if --trace-symbol was specified.
+ // This is for debugging.
+ if (S->Traced)
+ printTraceSymbol(S);
+}
+
+inline Symbol *SymbolBody::symbol() {
+ assert(!isLocal());
+ return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) -
+ offsetof(Symbol, Body));
+}
-} // namespace elf2
+} // namespace elf
} // namespace lld
#endif
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 6d42dbe86e54..466d1b47ce12 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -11,14 +11,25 @@
// GOT or PLT entries, etc., are handled in this file.
//
// Refer the ELF spec for the single letter varaibles, S, A or P, used
-// in this file. SA is S+A.
+// in this file.
+//
+// Some functions defined in this file has "relaxTls" as part of their names.
+// They do peephole optimization for TLS variables by rewriting instructions.
+// They are not part of the ABI but optional optimization, so you can skip
+// them if you are not interested in how TLS variables are optimized.
+// See the following paper for the details.
+//
+// Ulrich Drepper, ELF Handling For Thread-Local Storage
+// http://www.akkadia.org/drepper/tls.pdf
//
//===----------------------------------------------------------------------===//
#include "Target.h"
#include "Error.h"
+#include "InputFiles.h"
#include "OutputSections.h"
#include "Symbols.h"
+#include "Thunks.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/ELF.h"
@@ -31,215 +42,169 @@ using namespace llvm::support::endian;
using namespace llvm::ELF;
namespace lld {
-namespace elf2 {
+namespace elf {
-std::unique_ptr<TargetInfo> Target;
+TargetInfo *Target;
-template <endianness E> static void add32(void *P, int32_t V) {
- write32<E>(P, read32<E>(P) + V);
-}
-
-static void add32le(uint8_t *P, int32_t V) { add32<support::little>(P, V); }
static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
+StringRef getRelName(uint32_t Type) {
+ return getELFRelocationTypeName(Config->EMachine, Type);
+}
+
template <unsigned N> static void checkInt(int64_t V, uint32_t Type) {
- if (isInt<N>(V))
- return;
- StringRef S = getELFRelocationTypeName(Config->EMachine, Type);
- error("Relocation " + S + " out of range");
+ if (!isInt<N>(V))
+ error("relocation " + getRelName(Type) + " out of range");
}
template <unsigned N> static void checkUInt(uint64_t V, uint32_t Type) {
- if (isUInt<N>(V))
- return;
- StringRef S = getELFRelocationTypeName(Config->EMachine, Type);
- error("Relocation " + S + " out of range");
+ if (!isUInt<N>(V))
+ error("relocation " + getRelName(Type) + " out of range");
}
template <unsigned N> static void checkIntUInt(uint64_t V, uint32_t Type) {
- if (isInt<N>(V) || isUInt<N>(V))
- return;
- StringRef S = getELFRelocationTypeName(Config->EMachine, Type);
- error("Relocation " + S + " out of range");
+ if (!isInt<N>(V) && !isUInt<N>(V))
+ error("relocation " + getRelName(Type) + " out of range");
}
template <unsigned N> static void checkAlignment(uint64_t V, uint32_t Type) {
- if ((V & (N - 1)) == 0)
- return;
- StringRef S = getELFRelocationTypeName(Config->EMachine, Type);
- error("Improper alignment for relocation " + S);
+ if ((V & (N - 1)) != 0)
+ error("improper alignment for relocation " + getRelName(Type));
}
-template <class ELFT> bool isGnuIFunc(const SymbolBody &S) {
- if (auto *SS = dyn_cast<DefinedElf<ELFT>>(&S))
- return SS->Sym.getType() == STT_GNU_IFUNC;
- return false;
+static void errorDynRel(uint32_t Type) {
+ error("relocation " + getRelName(Type) +
+ " cannot be used against shared object; recompile with -fPIC.");
}
-template bool isGnuIFunc<ELF32LE>(const SymbolBody &S);
-template bool isGnuIFunc<ELF32BE>(const SymbolBody &S);
-template bool isGnuIFunc<ELF64LE>(const SymbolBody &S);
-template bool isGnuIFunc<ELF64BE>(const SymbolBody &S);
-
namespace {
class X86TargetInfo final : public TargetInfo {
public:
X86TargetInfo();
- void writeGotPltHeaderEntries(uint8_t *Buf) const override;
- unsigned getDynReloc(unsigned Type) const override;
- unsigned getTlsGotReloc(unsigned Type) const override;
- bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override;
- void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const override;
- void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const override;
- bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsDynRelative(unsigned Type) const override;
- bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
- uint64_t SA, uint64_t ZA = 0,
- uint8_t *PairedLoc = nullptr) const override;
- bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override;
- unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
- uint64_t P, uint64_t SA,
- const SymbolBody &S) const override;
- bool isGotRelative(uint32_t Type) const override;
-
-private:
- void relocateTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const;
- void relocateTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const;
- void relocateTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const;
- void relocateTlsIeToLe(unsigned Type, uint8_t *Loc, uint8_t *BufEnd,
- uint64_t P, uint64_t SA) const;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ uint64_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 writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+
+ RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
-class X86_64TargetInfo final : public TargetInfo {
+template <class ELFT> class X86_64TargetInfo final : public TargetInfo {
public:
X86_64TargetInfo();
- bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override;
- void writeGotPltHeaderEntries(uint8_t *Buf) const override;
- void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const override;
- void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const override;
- bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
- uint64_t SA, uint64_t ZA = 0,
- uint8_t *PairedLoc = nullptr) const override;
- bool isRelRelative(uint32_t Type) const override;
- bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override;
- bool isSizeReloc(uint32_t Type) const override;
- unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
- uint64_t P, uint64_t SA,
- const SymbolBody &S) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) 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 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,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+
+ RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxGot(uint8_t *Loc, uint64_t Val) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
private:
- void relocateTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const;
- void relocateTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const;
- void relocateTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const;
- void relocateTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const;
+ void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
+ uint8_t ModRm) const;
};
class PPCTargetInfo final : public TargetInfo {
public:
PPCTargetInfo();
- void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const override;
- void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const override;
- bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
- uint64_t SA, uint64_t ZA = 0,
- uint8_t *PairedLoc = nullptr) const override;
- bool isRelRelative(uint32_t Type) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
};
class PPC64TargetInfo final : public TargetInfo {
public:
PPC64TargetInfo();
- void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const override;
- void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const override;
- bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
- uint64_t SA, uint64_t ZA = 0,
- uint8_t *PairedLoc = nullptr) const override;
- bool isRelRelative(uint32_t Type) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
class AArch64TargetInfo final : public TargetInfo {
public:
AArch64TargetInfo();
- unsigned getDynReloc(unsigned Type) const override;
- void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const override;
- void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const override;
- unsigned getTlsGotReloc(unsigned Type = -1) const override;
- bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override;
- bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
- uint64_t SA, uint64_t ZA = 0,
- uint8_t *PairedLoc = nullptr) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ uint32_t getDynRel(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,
+ 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;
+ RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
class AMDGPUTargetInfo final : public TargetInfo {
public:
AMDGPUTargetInfo();
- void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const override;
- void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const override;
- bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
- uint64_t SA, uint64_t ZA = 0,
- uint8_t *PairedLoc = nullptr) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+};
+
+class ARMTargetInfo final : public TargetInfo {
+public:
+ ARMTargetInfo();
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ uint32_t getDynRel(uint32_t Type) const override;
+ uint64_t getImplicitAddend(const uint8_t *Buf, 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,
+ int32_t Index, unsigned RelOff) const override;
+ RelExpr getThunkExpr(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();
- void writeGotHeaderEntries(uint8_t *Buf) const override;
- void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
- void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const override;
- void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const override;
- bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
- bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
- uint64_t SA, uint64_t ZA = 0,
- uint8_t *PairedLoc = nullptr) const override;
- bool isRelRelative(uint32_t Type) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ uint64_t getImplicitAddend(const uint8_t *Buf, 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,
+ int32_t Index, unsigned RelOff) const override;
+ RelExpr getThunkExpr(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;
};
} // anonymous namespace
@@ -251,80 +216,153 @@ TargetInfo *createTarget() {
return new AArch64TargetInfo();
case EM_AMDGPU:
return new AMDGPUTargetInfo();
+ case EM_ARM:
+ return new ARMTargetInfo();
case EM_MIPS:
switch (Config->EKind) {
case ELF32LEKind:
return new MipsTargetInfo<ELF32LE>();
case ELF32BEKind:
return new MipsTargetInfo<ELF32BE>();
+ case ELF64LEKind:
+ return new MipsTargetInfo<ELF64LE>();
+ case ELF64BEKind:
+ return new MipsTargetInfo<ELF64BE>();
default:
- error("Unsupported MIPS target");
+ fatal("unsupported MIPS target");
}
case EM_PPC:
return new PPCTargetInfo();
case EM_PPC64:
return new PPC64TargetInfo();
case EM_X86_64:
- return new X86_64TargetInfo();
+ if (Config->EKind == ELF32LEKind)
+ return new X86_64TargetInfo<ELF32LE>();
+ return new X86_64TargetInfo<ELF64LE>();
}
- error("Unknown target machine");
+ fatal("unknown target machine");
}
TargetInfo::~TargetInfo() {}
-bool TargetInfo::isTlsOptimized(unsigned Type, const SymbolBody *S) const {
- return false;
+uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf,
+ uint32_t Type) const {
+ return 0;
}
-uint64_t TargetInfo::getVAStart() const { return Config->Shared ? 0 : VAStart; }
+bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
-bool TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
+RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
+ const InputFile &File,
+ const SymbolBody &S) const {
+ return Expr;
+}
+
+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;
}
-bool TargetInfo::isGotRelative(uint32_t Type) const { return false; }
+RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ return Expr;
+}
-bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
+void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
+}
-bool TargetInfo::isSizeReloc(uint32_t Type) const { return false; }
+void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
+}
-unsigned TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd,
- uint32_t Type, uint64_t P, uint64_t SA,
- const SymbolBody &S) const {
- return 0;
+void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
}
-void TargetInfo::writeGotHeaderEntries(uint8_t *Buf) const {}
+void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
+}
-void TargetInfo::writeGotPltHeaderEntries(uint8_t *Buf) const {}
+void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ llvm_unreachable("Should not have claimed to be relaxable");
+}
X86TargetInfo::X86TargetInfo() {
- CopyReloc = R_386_COPY;
- PCRelReloc = R_386_PC32;
- GotReloc = R_386_GLOB_DAT;
- PltReloc = R_386_JUMP_SLOT;
- IRelativeReloc = R_386_IRELATIVE;
- RelativeReloc = R_386_RELATIVE;
- TlsGotReloc = R_386_TLS_TPOFF;
- TlsGlobalDynamicReloc = R_386_TLS_GD;
- TlsLocalDynamicReloc = R_386_TLS_LDM;
- TlsModuleIndexReloc = R_386_TLS_DTPMOD32;
- TlsOffsetReloc = R_386_TLS_DTPOFF32;
- LazyRelocations = true;
+ CopyRel = R_386_COPY;
+ GotRel = R_386_GLOB_DAT;
+ PltRel = R_386_JUMP_SLOT;
+ IRelativeRel = R_386_IRELATIVE;
+ RelativeRel = R_386_RELATIVE;
+ TlsGotRel = R_386_TLS_TPOFF;
+ TlsModuleIndexRel = R_386_TLS_DTPMOD32;
+ TlsOffsetRel = R_386_TLS_DTPOFF32;
+ GotEntrySize = 4;
+ GotPltEntrySize = 4;
PltEntrySize = 16;
- PltZeroEntrySize = 16;
+ PltHeaderSize = 16;
+ TlsGdRelaxSkip = 2;
}
-void X86TargetInfo::writeGotPltHeaderEntries(uint8_t *Buf) const {
+RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_386_TLS_GD:
+ return R_TLSGD;
+ case R_386_TLS_LDM:
+ return R_TLSLD;
+ case R_386_PLT32:
+ return R_PLT_PC;
+ case R_386_PC32:
+ return R_PC;
+ case R_386_GOTPC:
+ return R_GOTONLY_PC;
+ case R_386_TLS_IE:
+ return R_GOT;
+ case R_386_GOT32:
+ case R_386_GOT32X:
+ case R_386_TLS_GOTIE:
+ return R_GOT_FROM_END;
+ case R_386_GOTOFF:
+ return R_GOTREL;
+ case R_386_TLS_LE:
+ return R_TLS;
+ case R_386_TLS_LE_32:
+ return R_NEG_TLS;
+ }
+}
+
+RelExpr X86TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ switch (Expr) {
+ default:
+ return Expr;
+ case R_RELAX_TLS_GD_TO_IE:
+ return R_RELAX_TLS_GD_TO_IE_END;
+ case R_RELAX_TLS_GD_TO_LE:
+ return R_RELAX_TLS_GD_TO_LE_NEG;
+ }
+}
+
+void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
write32le(Buf, Out<ELF32LE>::Dynamic->getVA());
}
-void X86TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {
- // Skip 6 bytes of "pushl (GOT+4)"
- write32le(Buf, Plt + 6);
+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);
}
-unsigned X86TargetInfo::getDynReloc(unsigned Type) const {
+uint32_t X86TargetInfo::getDynRel(uint32_t Type) const {
if (Type == R_386_TLS_LE)
return R_386_TLS_TPOFF;
if (Type == R_386_TLS_LE_32)
@@ -332,30 +370,26 @@ unsigned X86TargetInfo::getDynReloc(unsigned Type) const {
return Type;
}
-unsigned X86TargetInfo::getTlsGotReloc(unsigned Type) const {
- if (Type == R_386_TLS_IE)
- return Type;
- return TlsGotReloc;
+bool X86TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
+ return Type == R_386_TLS_GD;
}
-bool X86TargetInfo::isTlsDynReloc(unsigned Type, const SymbolBody &S) const {
- if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32 ||
- Type == R_386_TLS_GOTIE)
- return Config->Shared;
- if (Type == R_386_TLS_IE)
- return canBePreempted(&S, true);
- 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;
}
-void X86TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const {
+bool X86TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
+ return Type == R_386_TLS_IE || Type == R_386_TLS_GOTIE;
+}
+
+void X86TargetInfo::writePltHeader(uint8_t *Buf) const {
// Executable files and shared object files have
// separate procedure linkage tables.
- if (Config->Shared) {
+ 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, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx)
+ 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
};
memcpy(Buf, V, sizeof(V));
return;
@@ -363,283 +397,229 @@ void X86TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
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, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOT+8)
+ 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
};
memcpy(Buf, PltData, sizeof(PltData));
- write32le(Buf + 2, GotEntryAddr + 4); // GOT+4
- write32le(Buf + 8, GotEntryAddr + 8); // GOT+8
+ uint32_t Got = Out<ELF32LE>::GotPlt->getVA();
+ write32le(Buf + 2, Got + 4);
+ write32le(Buf + 8, Got + 8);
}
-void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
- uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const {
+void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
const uint8_t Inst[] = {
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx)
0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset
0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0@PC
};
memcpy(Buf, Inst, sizeof(Inst));
+
// jmp *foo@GOT(%ebx) or jmp *foo_in_GOT
- Buf[1] = Config->Shared ? 0xa3 : 0x25;
- write32le(Buf + 2, Config->Shared ? (GotEntryAddr - GotAddr) : GotEntryAddr);
+ Buf[1] = Config->Pic ? 0xa3 : 0x25;
+ uint32_t Got = Out<ELF32LE>::GotPlt->getVA();
+ write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
write32le(Buf + 7, RelOff);
- write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16);
+ write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
}
-bool X86TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
- if (Type == R_386_32 || Type == R_386_16 || Type == R_386_8)
- if (auto *SS = dyn_cast<SharedSymbol<ELF32LE>>(&S))
- return SS->Sym.getType() == STT_OBJECT;
- return false;
-}
-
-bool X86TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
- if (S.isTls() && Type == R_386_TLS_GD)
- return Target->isTlsOptimized(Type, &S) && canBePreempted(&S, true);
- if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE)
- return !isTlsOptimized(Type, &S);
- return Type == R_386_GOT32 || relocNeedsPlt(Type, S);
-}
-
-bool X86TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
- return isGnuIFunc<ELF32LE>(S) ||
- (Type == R_386_PLT32 && canBePreempted(&S, true)) ||
- (Type == R_386_PC32 && S.isShared());
-}
-
-bool X86TargetInfo::isGotRelative(uint32_t Type) const {
- // This relocation does not require got entry,
- // but it is relative to got and needs it to be created.
- // Here we request for that.
- return Type == R_386_GOTOFF;
-}
-
-void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
- uint64_t P, uint64_t SA, uint64_t ZA,
- uint8_t *PairedLoc) const {
+uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
+ uint32_t Type) const {
switch (Type) {
+ default:
+ return 0;
case R_386_32:
- add32le(Loc, SA);
- break;
case R_386_GOT32:
+ case R_386_GOT32X:
case R_386_GOTOFF:
- add32le(Loc, SA - Out<ELF32LE>::Got->getVA());
- break;
case R_386_GOTPC:
- add32le(Loc, SA + Out<ELF32LE>::Got->getVA() - P);
- break;
case R_386_PC32:
case R_386_PLT32:
- add32le(Loc, SA - P);
- break;
- case R_386_TLS_GD:
- case R_386_TLS_LDM:
- case R_386_TLS_TPOFF: {
- uint64_t V = SA - Out<ELF32LE>::Got->getVA() -
- Out<ELF32LE>::Got->getNumEntries() * 4;
- checkInt<32>(V, Type);
- write32le(Loc, V);
- break;
+ return read32le(Buf);
}
- case R_386_TLS_IE:
- case R_386_TLS_LDO_32:
- write32le(Loc, SA);
- break;
- case R_386_TLS_LE:
- write32le(Loc, SA - Out<ELF32LE>::TlsPhdr->p_memsz);
- break;
- case R_386_TLS_LE_32:
- write32le(Loc, Out<ELF32LE>::TlsPhdr->p_memsz - SA);
- break;
- default:
- error("unrecognized reloc " + Twine(Type));
- }
-}
-
-bool X86TargetInfo::isTlsOptimized(unsigned Type, const SymbolBody *S) const {
- if (Config->Shared || (S && !S->isTls()))
- return false;
- return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM ||
- Type == R_386_TLS_GD ||
- (Type == R_386_TLS_IE && !canBePreempted(S, true)) ||
- (Type == R_386_TLS_GOTIE && !canBePreempted(S, true));
}
-bool X86TargetInfo::relocNeedsDynRelative(unsigned Type) const {
- return Config->Shared && Type == R_386_TLS_IE;
+void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ checkInt<32>(Val, Type);
+ write32le(Loc, Val);
}
-unsigned X86TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd,
- uint32_t Type, uint64_t P,
- uint64_t SA,
- const SymbolBody &S) const {
- switch (Type) {
- case R_386_TLS_GD:
- if (canBePreempted(&S, true))
- relocateTlsGdToIe(Loc, BufEnd, P, SA);
- else
- relocateTlsGdToLe(Loc, BufEnd, P, SA);
- // The next relocation should be against __tls_get_addr, so skip it
- return 1;
- case R_386_TLS_GOTIE:
- case R_386_TLS_IE:
- relocateTlsIeToLe(Type, Loc, BufEnd, P, SA);
- return 0;
- case R_386_TLS_LDM:
- relocateTlsLdToLe(Loc, BufEnd, P, SA);
- // The next relocation should be against __tls_get_addr, so skip it
- return 1;
- case R_386_TLS_LDO_32:
- relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA);
- return 0;
- }
- llvm_unreachable("Unknown TLS optimization");
-}
-
-// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.1
-// IA-32 Linker Optimizations, http://www.akkadia.org/drepper/tls.pdf) shows
-// how GD can be optimized to IE:
-// leal x@tlsgd(, %ebx, 1),
-// call __tls_get_addr@plt
-// Is converted to:
-// movl %gs:0, %eax
-// addl x@gotntpoff(%ebx), %eax
-void X86TargetInfo::relocateTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const {
+void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // Convert
+ // leal x@tlsgd(, %ebx, 1),
+ // call __tls_get_addr@plt
+ // to
+ // movl %gs:0,%eax
+ // subl $x@ntpoff,%eax
const uint8_t Inst[] = {
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
- 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax
+ 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax
};
memcpy(Loc - 3, Inst, sizeof(Inst));
- relocateOne(Loc + 5, BufEnd, R_386_32, P,
- SA - Out<ELF32LE>::Got->getVA() -
- Out<ELF32LE>::Got->getNumEntries() * 4);
-}
-
-// GD can be optimized to LE:
-// leal x@tlsgd(, %ebx, 1),
-// call __tls_get_addr@plt
-// Can be converted to:
-// movl %gs:0,%eax
-// addl $x@ntpoff,%eax
-// But gold emits subl $foo@tpoff,%eax instead of addl.
-// These instructions are completely equal in behavior.
-// This method generates subl to be consistent with gold.
-void X86TargetInfo::relocateTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const {
+ relocateOne(Loc + 5, R_386_32, Val);
+}
+
+void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // Convert
+ // leal x@tlsgd(, %ebx, 1),
+ // call __tls_get_addr@plt
+ // to
+ // movl %gs:0, %eax
+ // addl x@gotntpoff(%ebx), %eax
const uint8_t Inst[] = {
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
- 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax
+ 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax
};
memcpy(Loc - 3, Inst, sizeof(Inst));
- relocateOne(Loc + 5, BufEnd, R_386_32, P,
- Out<ELF32LE>::TlsPhdr->p_memsz - SA);
-}
-
-// LD can be optimized to LE:
-// leal foo(%reg),%eax
-// call ___tls_get_addr
-// Is converted to:
-// movl %gs:0,%eax
-// nop
-// leal 0(%esi,1),%esi
-void X86TargetInfo::relocateTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const {
- const uint8_t Inst[] = {
- 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
- 0x90, // nop
- 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi
- };
- memcpy(Loc - 2, Inst, sizeof(Inst));
+ relocateOne(Loc + 5, R_386_32, Val);
}
// In some conditions, relocations can be optimized to avoid using GOT.
// This function does that for Initial Exec to Local Exec case.
-// Read "ELF Handling For Thread-Local Storage, 5.1
-// IA-32 Linker Optimizations" (http://www.akkadia.org/drepper/tls.pdf)
-// by Ulrich Drepper for details.
-void X86TargetInfo::relocateTlsIeToLe(unsigned Type, uint8_t *Loc,
- uint8_t *BufEnd, uint64_t P,
- uint64_t SA) const {
+void X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
// Ulrich's document section 6.2 says that @gotntpoff can
// be used with MOVL or ADDL instructions.
// @indntpoff is similar to @gotntpoff, but for use in
// position dependent code.
- uint8_t *Inst = Loc - 2;
- uint8_t *Op = Loc - 1;
uint8_t Reg = (Loc[-1] >> 3) & 7;
- bool IsMov = *Inst == 0x8b;
+
if (Type == R_386_TLS_IE) {
- // For R_386_TLS_IE relocation we perform the next transformations:
- // MOVL foo@INDNTPOFF,%EAX is transformed to MOVL $foo,%EAX
- // MOVL foo@INDNTPOFF,%REG is transformed to MOVL $foo,%REG
- // ADDL foo@INDNTPOFF,%REG is transformed to ADDL $foo,%REG
- // First one is special because when EAX is used the sequence is 5 bytes
- // long, otherwise it is 6 bytes.
- if (*Op == 0xa1) {
- *Op = 0xb8;
+ if (Loc[-1] == 0xa1) {
+ // "movl foo@indntpoff,%eax" -> "movl $foo,%eax"
+ // This case is different from the generic case below because
+ // this is a 5 byte instruction while below is 6 bytes.
+ Loc[-1] = 0xb8;
+ } else if (Loc[-2] == 0x8b) {
+ // "movl foo@indntpoff,%reg" -> "movl $foo,%reg"
+ Loc[-2] = 0xc7;
+ Loc[-1] = 0xc0 | Reg;
} else {
- *Inst = IsMov ? 0xc7 : 0x81;
- *Op = 0xc0 | ((*Op >> 3) & 7);
+ // "addl foo@indntpoff,%reg" -> "addl $foo,%reg"
+ Loc[-2] = 0x81;
+ Loc[-1] = 0xc0 | Reg;
}
} else {
- // R_386_TLS_GOTIE relocation can be optimized to
- // R_386_TLS_LE so that it does not use GOT.
- // "MOVL foo@GOTTPOFF(%RIP), %REG" is transformed to "MOVL $foo, %REG".
- // "ADDL foo@GOTNTPOFF(%RIP), %REG" is transformed to "LEAL foo(%REG), %REG"
- // Note: gold converts to ADDL instead of LEAL.
- *Inst = IsMov ? 0xc7 : 0x8d;
- if (IsMov)
- *Op = 0xc0 | ((*Op >> 3) & 7);
- else
- *Op = 0x80 | Reg | (Reg << 3);
+ assert(Type == R_386_TLS_GOTIE);
+ if (Loc[-2] == 0x8b) {
+ // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg"
+ Loc[-2] = 0xc7;
+ Loc[-1] = 0xc0 | Reg;
+ } else {
+ // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg"
+ Loc[-2] = 0x8d;
+ Loc[-1] = 0x80 | (Reg << 3) | Reg;
+ }
+ }
+ relocateOne(Loc, R_386_TLS_LE, 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);
+ return;
}
- relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA);
-}
-
-X86_64TargetInfo::X86_64TargetInfo() {
- CopyReloc = R_X86_64_COPY;
- PCRelReloc = R_X86_64_PC32;
- GotReloc = R_X86_64_GLOB_DAT;
- PltReloc = R_X86_64_JUMP_SLOT;
- RelativeReloc = R_X86_64_RELATIVE;
- IRelativeReloc = R_X86_64_IRELATIVE;
- TlsGotReloc = R_X86_64_TPOFF64;
- TlsLocalDynamicReloc = R_X86_64_TLSLD;
- TlsGlobalDynamicReloc = R_X86_64_TLSGD;
- TlsModuleIndexReloc = R_X86_64_DTPMOD64;
- TlsOffsetReloc = R_X86_64_DTPOFF64;
- LazyRelocations = true;
+
+ // Convert
+ // leal foo(%reg),%eax
+ // call ___tls_get_addr
+ // to
+ // movl %gs:0,%eax
+ // nop
+ // leal 0(%esi,1),%esi
+ const uint8_t Inst[] = {
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
+ 0x90, // nop
+ 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi
+ };
+ memcpy(Loc - 2, Inst, sizeof(Inst));
+}
+
+template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() {
+ CopyRel = R_X86_64_COPY;
+ GotRel = R_X86_64_GLOB_DAT;
+ PltRel = R_X86_64_JUMP_SLOT;
+ RelativeRel = R_X86_64_RELATIVE;
+ IRelativeRel = R_X86_64_IRELATIVE;
+ TlsGotRel = R_X86_64_TPOFF64;
+ TlsModuleIndexRel = R_X86_64_DTPMOD64;
+ TlsOffsetRel = R_X86_64_DTPOFF64;
+ GotEntrySize = 8;
+ GotPltEntrySize = 8;
PltEntrySize = 16;
- PltZeroEntrySize = 16;
+ PltHeaderSize = 16;
+ TlsGdRelaxSkip = 2;
}
-void X86_64TargetInfo::writeGotPltHeaderEntries(uint8_t *Buf) const {
- write64le(Buf, Out<ELF64LE>::Dynamic->getVA());
+template <class ELFT>
+RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
+ const SymbolBody &S) const {
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_X86_64_TPOFF32:
+ return R_TLS;
+ case R_X86_64_TLSLD:
+ return R_TLSLD_PC;
+ case R_X86_64_TLSGD:
+ return R_TLSGD_PC;
+ case R_X86_64_SIZE32:
+ case R_X86_64_SIZE64:
+ return R_SIZE;
+ case R_X86_64_PLT32:
+ return R_PLT_PC;
+ case R_X86_64_PC32:
+ case R_X86_64_PC64:
+ return R_PC;
+ case R_X86_64_GOT32:
+ return R_GOT_FROM_END;
+ case R_X86_64_GOTPCREL:
+ case R_X86_64_GOTPCRELX:
+ case R_X86_64_REX_GOTPCRELX:
+ case R_X86_64_GOTTPOFF:
+ return R_GOT_PC;
+ }
}
-void X86_64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {
- // Skip 6 bytes of "jmpq *got(%rip)"
- write32le(Buf, Plt + 6);
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
+ // The first entry holds the value of _DYNAMIC. It is not clear why that is
+ // required, but it is documented in the psabi and the glibc dynamic linker
+ // seems to use it (note that this is relevant for linking ld.so, not any
+ // other program).
+ write64le(Buf, Out<ELFT>::Dynamic->getVA());
}
-void X86_64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const {
+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);
+}
+
+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)
};
memcpy(Buf, PltData, sizeof(PltData));
- write32le(Buf + 2, GotEntryAddr - PltEntryAddr + 2); // GOT+8
- write32le(Buf + 8, GotEntryAddr - PltEntryAddr + 4); // GOT+16
+ uint64_t Got = Out<ELFT>::GotPlt->getVA();
+ uint64_t Plt = Out<ELFT>::Plt->getVA();
+ write32le(Buf + 2, Got - Plt + 2); // GOT+8
+ write32le(Buf + 8, Got - Plt + 4); // GOT+16
}
-void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
- uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
const uint8_t Inst[] = {
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index>
@@ -649,277 +629,318 @@ void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6);
write32le(Buf + 7, Index);
- write32le(Buf + 12, -Index * PltEntrySize - PltZeroEntrySize - 16);
-}
-
-bool X86_64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
- if (Type == R_X86_64_32S || Type == R_X86_64_32 || Type == R_X86_64_PC32 ||
- Type == R_X86_64_64)
- if (auto *SS = dyn_cast<SharedSymbol<ELF64LE>>(&S))
- return SS->Sym.getType() == STT_OBJECT;
- return false;
-}
-
-bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
- if (Type == R_X86_64_TLSGD)
- return Target->isTlsOptimized(Type, &S) && canBePreempted(&S, true);
- if (Type == R_X86_64_GOTTPOFF)
- return !isTlsOptimized(Type, &S);
- return Type == R_X86_64_GOTPCREL || relocNeedsPlt(Type, S);
-}
-
-bool X86_64TargetInfo::isTlsDynReloc(unsigned Type, const SymbolBody &S) const {
- return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD;
+ write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
}
-bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
- if (needsCopyRel(Type, S))
- return false;
- if (isGnuIFunc<ELF64LE>(S))
- return true;
-
- switch (Type) {
- default:
- return false;
- case R_X86_64_32:
- case R_X86_64_64:
- case R_X86_64_PC32:
- // This relocation is defined to have a value of (S + A - P).
- // The problems start when a non PIC program calls a function in a shared
- // library.
- // In an ideal world, we could just report an error saying the relocation
- // can overflow at runtime.
- // In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to
- // libc.so.
- //
- // The general idea on how to handle such cases is to create a PLT entry
- // and use that as the function value.
- //
- // For the static linking part, we just return true and everything else
- // will use the the PLT entry as the address.
- //
- // The remaining (unimplemented) problem is making sure pointer equality
- // still works. We need the help of the dynamic linker for that. We
- // let it know that we have a direct reference to a so symbol by creating
- // an undefined symbol with a non zero st_value. Seeing that, the
- // dynamic linker resolves the symbol to the value of the symbol we created.
- // This is true even for got entries, so pointer equality is maintained.
- // To avoid an infinite loop, the only entry that points to the
- // real function is a dedicated got entry used by the plt. That is
- // identified by special relocation types (R_X86_64_JUMP_SLOT,
- // R_386_JMP_SLOT, etc).
- return S.isShared();
- case R_X86_64_PLT32:
- return canBePreempted(&S, true);
- }
+template <class ELFT>
+uint32_t X86_64TargetInfo<ELFT>::getDynRel(uint32_t Type) const {
+ if (Type == R_X86_64_PC32 || Type == R_X86_64_32)
+ errorDynRel(Type);
+ return Type;
}
-bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
- switch (Type) {
- default:
- return false;
- case R_X86_64_DTPOFF32:
- case R_X86_64_DTPOFF64:
- case R_X86_64_PC8:
- case R_X86_64_PC16:
- case R_X86_64_PC32:
- case R_X86_64_PC64:
- case R_X86_64_PLT32:
- return true;
- }
+template <class ELFT>
+bool X86_64TargetInfo<ELFT>::isTlsInitialExecRel(uint32_t Type) const {
+ return Type == R_X86_64_GOTTPOFF;
}
-bool X86_64TargetInfo::isSizeReloc(uint32_t Type) const {
- return Type == R_X86_64_SIZE32 || Type == R_X86_64_SIZE64;
+template <class ELFT>
+bool X86_64TargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
+ return Type == R_X86_64_TLSGD;
}
-bool X86_64TargetInfo::isTlsOptimized(unsigned Type,
- const SymbolBody *S) const {
- if (Config->Shared || (S && !S->isTls()))
- return false;
- return Type == R_X86_64_TLSGD || Type == R_X86_64_TLSLD ||
- Type == R_X86_64_DTPOFF32 ||
- (Type == R_X86_64_GOTTPOFF && !canBePreempted(S, true));
-}
-
-// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5
-// x86-x64 linker optimizations, http://www.akkadia.org/drepper/tls.pdf) shows
-// how LD can be optimized to LE:
-// leaq bar@tlsld(%rip), %rdi
-// callq __tls_get_addr@PLT
-// leaq bar@dtpoff(%rax), %rcx
-// Is converted to:
-// .word 0x6666
-// .byte 0x66
-// mov %fs:0,%rax
-// leaq bar@tpoff(%rax), %rcx
-void X86_64TargetInfo::relocateTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd,
- uint64_t P, uint64_t SA) const {
- const uint8_t Inst[] = {
- 0x66, 0x66, //.word 0x6666
- 0x66, //.byte 0x66
- 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax
- };
- memcpy(Loc - 3, Inst, sizeof(Inst));
+template <class ELFT>
+bool X86_64TargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
+ return Type == R_X86_64_DTPOFF32 || Type == R_X86_64_DTPOFF64 ||
+ Type == R_X86_64_TLSLD;
}
-// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5
-// x86-x64 linker optimizations, http://www.akkadia.org/drepper/tls.pdf) shows
-// how GD can be optimized to LE:
-// .byte 0x66
-// leaq x@tlsgd(%rip), %rdi
-// .word 0x6666
-// rex64
-// call __tls_get_addr@plt
-// Is converted to:
-// mov %fs:0x0,%rax
-// lea x@tpoff,%rax
-void X86_64TargetInfo::relocateTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd,
- uint64_t P, uint64_t SA) const {
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // Convert
+ // .byte 0x66
+ // leaq x@tlsgd(%rip), %rdi
+ // .word 0x6666
+ // rex64
+ // call __tls_get_addr@plt
+ // to
+ // mov %fs:0x0,%rax
+ // lea x@tpoff,%rax
const uint8_t Inst[] = {
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax
};
memcpy(Loc - 4, Inst, sizeof(Inst));
- relocateOne(Loc + 8, BufEnd, R_X86_64_TPOFF32, P, SA);
-}
-
-// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5
-// x86-x64 linker optimizations, http://www.akkadia.org/drepper/tls.pdf) shows
-// how GD can be optimized to IE:
-// .byte 0x66
-// leaq x@tlsgd(%rip), %rdi
-// .word 0x6666
-// rex64
-// call __tls_get_addr@plt
-// Is converted to:
-// mov %fs:0x0,%rax
-// addq x@tpoff,%rax
-void X86_64TargetInfo::relocateTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd,
- uint64_t P, uint64_t SA) const {
+ // 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);
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // Convert
+ // .byte 0x66
+ // leaq x@tlsgd(%rip), %rdi
+ // .word 0x6666
+ // rex64
+ // call __tls_get_addr@plt
+ // to
+ // mov %fs:0x0,%rax
+ // addq x@tpoff,%rax
const uint8_t Inst[] = {
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax
};
memcpy(Loc - 4, Inst, sizeof(Inst));
- relocateOne(Loc + 8, BufEnd, R_X86_64_TPOFF64, P + 12, SA);
+ // 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);
}
// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
// R_X86_64_TPOFF32 so that it does not use GOT.
-// This function does that. Read "ELF Handling For Thread-Local Storage,
-// 5.5 x86-x64 linker optimizations" (http://www.akkadia.org/drepper/tls.pdf)
-// by Ulrich Drepper for details.
-void X86_64TargetInfo::relocateTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd,
- uint64_t P, uint64_t SA) const {
- // Ulrich's document section 6.5 says that @gottpoff(%rip) must be
- // used in MOVQ or ADDQ instructions only.
- // "MOVQ foo@GOTTPOFF(%RIP), %REG" is transformed to "MOVQ $foo, %REG".
- // "ADDQ foo@GOTTPOFF(%RIP), %REG" is transformed to "LEAQ foo(%REG), %REG"
- // (if the register is not RSP/R12) or "ADDQ $foo, %RSP".
- // Opcodes info can be found at http://ref.x86asm.net/coder64.html#x48.
- uint8_t *Prefix = Loc - 3;
- uint8_t *Inst = Loc - 2;
- uint8_t *RegSlot = Loc - 1;
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ uint8_t *Inst = Loc - 3;
uint8_t Reg = Loc[-1] >> 3;
- bool IsMov = *Inst == 0x8b;
- bool RspAdd = !IsMov && Reg == 4;
- // r12 and rsp registers requires special handling.
- // Problem is that for other registers, for example leaq 0xXXXXXXXX(%r11),%r11
- // result out is 7 bytes: 4d 8d 9b XX XX XX XX,
- // but leaq 0xXXXXXXXX(%r12),%r12 is 8 bytes: 4d 8d a4 24 XX XX XX XX.
- // The same true for rsp. So we convert to addq for them, saving 1 byte that
- // we dont have.
- if (RspAdd)
- *Inst = 0x81;
- else
- *Inst = IsMov ? 0xc7 : 0x8d;
- if (*Prefix == 0x4c)
- *Prefix = (IsMov || RspAdd) ? 0x49 : 0x4d;
- *RegSlot = (IsMov || RspAdd) ? (0xc0 | Reg) : (0x80 | Reg | (Reg << 3));
- relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA);
-}
-
-// This function applies a TLS relocation with an optimization as described
-// in the Ulrich's document. As a result of rewriting instructions at the
-// relocation target, relocations immediately follow the TLS relocation (which
-// would be applied to rewritten instructions) may have to be skipped.
-// This function returns a number of relocations that need to be skipped.
-unsigned X86_64TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd,
- uint32_t Type, uint64_t P,
- uint64_t SA,
- const SymbolBody &S) const {
- switch (Type) {
- case R_X86_64_DTPOFF32:
- relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA);
- return 0;
- case R_X86_64_GOTTPOFF:
- relocateTlsIeToLe(Loc, BufEnd, P, SA);
- return 0;
- case R_X86_64_TLSGD: {
- if (canBePreempted(&S, true))
- relocateTlsGdToIe(Loc, BufEnd, P, SA);
- else
- relocateTlsGdToLe(Loc, BufEnd, P, SA);
- // The next relocation should be against __tls_get_addr, so skip it
- return 1;
+ uint8_t *RegSlot = Loc - 1;
+
+ // Note that ADD with RSP or R12 is converted to ADD instead of LEA
+ // because LEA with these registers needs 4 bytes to encode and thus
+ // wouldn't fit the space.
+
+ if (memcmp(Inst, "\x48\x03\x25", 3) == 0) {
+ // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
+ memcpy(Inst, "\x48\x81\xc4", 3);
+ } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) {
+ // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12"
+ memcpy(Inst, "\x49\x81\xc4", 3);
+ } else if (memcmp(Inst, "\x4c\x03", 2) == 0) {
+ // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
+ memcpy(Inst, "\x4d\x8d", 2);
+ *RegSlot = 0x80 | (Reg << 3) | Reg;
+ } else if (memcmp(Inst, "\x48\x03", 2) == 0) {
+ // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
+ memcpy(Inst, "\x48\x8d", 2);
+ *RegSlot = 0x80 | (Reg << 3) | Reg;
+ } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) {
+ // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
+ memcpy(Inst, "\x49\xc7", 2);
+ *RegSlot = 0xc0 | Reg;
+ } else if (memcmp(Inst, "\x48\x8b", 2) == 0) {
+ // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg"
+ memcpy(Inst, "\x48\xc7", 2);
+ *RegSlot = 0xc0 | Reg;
+ } else {
+ fatal("R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
}
- case R_X86_64_TLSLD:
- relocateTlsLdToLe(Loc, BufEnd, P, SA);
- // The next relocation should be against __tls_get_addr, so skip it
- return 1;
+
+ // 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);
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // Convert
+ // leaq bar@tlsld(%rip), %rdi
+ // callq __tls_get_addr@PLT
+ // leaq bar@dtpoff(%rax), %rcx
+ // to
+ // .word 0x6666
+ // .byte 0x66
+ // mov %fs:0,%rax
+ // leaq bar@tpoff(%rax), %rcx
+ if (Type == R_X86_64_DTPOFF64) {
+ write64le(Loc, Val);
+ return;
}
- llvm_unreachable("Unknown TLS optimization");
+ if (Type == R_X86_64_DTPOFF32) {
+ relocateOne(Loc, R_X86_64_TPOFF32, Val);
+ return;
+ }
+
+ const uint8_t Inst[] = {
+ 0x66, 0x66, // .word 0x6666
+ 0x66, // .byte 0x66
+ 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax
+ };
+ memcpy(Loc - 3, Inst, sizeof(Inst));
}
-void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
- uint64_t P, uint64_t SA, uint64_t ZA,
- uint8_t *PairedLoc) const {
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
switch (Type) {
case R_X86_64_32:
- checkUInt<32>(SA, Type);
- write32le(Loc, SA);
+ checkUInt<32>(Val, Type);
+ write32le(Loc, Val);
break;
case R_X86_64_32S:
- checkInt<32>(SA, Type);
- write32le(Loc, SA);
- break;
- case R_X86_64_64:
- write64le(Loc, SA);
- break;
- case R_X86_64_DTPOFF32:
- write32le(Loc, SA);
- break;
- case R_X86_64_DTPOFF64:
- write64le(Loc, SA);
- break;
+ case R_X86_64_TPOFF32:
+ case R_X86_64_GOT32:
case R_X86_64_GOTPCREL:
+ case R_X86_64_GOTPCRELX:
+ case R_X86_64_REX_GOTPCRELX:
case R_X86_64_PC32:
+ case R_X86_64_GOTTPOFF:
case R_X86_64_PLT32:
case R_X86_64_TLSGD:
case R_X86_64_TLSLD:
- write32le(Loc, SA - P);
- break;
+ case R_X86_64_DTPOFF32:
case R_X86_64_SIZE32:
- write32le(Loc, ZA);
- break;
- case R_X86_64_SIZE64:
- write64le(Loc, ZA);
- break;
- case R_X86_64_TPOFF32: {
- uint64_t Val = SA - Out<ELF64LE>::TlsPhdr->p_memsz;
checkInt<32>(Val, Type);
write32le(Loc, Val);
break;
- }
- case R_X86_64_TPOFF64:
- write32le(Loc, SA - P);
+ case R_X86_64_64:
+ case R_X86_64_DTPOFF64:
+ case R_X86_64_SIZE64:
+ case R_X86_64_PC64:
+ write64le(Loc, Val);
break;
default:
- error("unrecognized reloc " + Twine(Type));
+ fatal("unrecognized reloc " + Twine(Type));
}
}
+template <class ELFT>
+RelExpr X86_64TargetInfo<ELFT>::adjustRelaxExpr(uint32_t Type,
+ const uint8_t *Data,
+ RelExpr RelExpr) const {
+ if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX)
+ 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;
+
+ // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor.
+ // If PIC then no relaxation is available.
+ // We also don't relax test/binop instructions without REX byte,
+ // they are 32bit operations and not common to have.
+ assert(Type == R_X86_64_REX_GOTPCRELX);
+ return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC;
+}
+
+// A subset of relaxations can only be applied for no-PIC. This method
+// handles such relaxations. Instructions encoding information was taken from:
+// "Intel 64 and IA-32 Architectures Software Developer's Manual V2"
+// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
+// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val,
+ uint8_t Op, uint8_t ModRm) const {
+ const uint8_t Rex = Loc[-3];
+ // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg".
+ if (Op == 0x85) {
+ // See "TEST-Logical Compare" (4-428 Vol. 2B),
+ // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension).
+
+ // ModR/M byte has form XX YYY ZZZ, where
+ // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1).
+ // XX has different meanings:
+ // 00: The operand's memory address is in reg1.
+ // 01: The operand's memory address is reg1 + a byte-sized displacement.
+ // 10: The operand's memory address is reg1 + a word-sized displacement.
+ // 11: The operand is reg1 itself.
+ // If an instruction requires only one operand, the unused reg2 field
+ // holds extra opcode bits rather than a register code
+ // 0xC0 == 11 000 000 binary.
+ // 0x38 == 00 111 000 binary.
+ // We transfer reg2 to reg1 here as operand.
+ // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3).
+ Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte.
+
+ // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32
+ // See "TEST-Logical Compare" (4-428 Vol. 2B).
+ Loc[-2] = 0xf7;
+
+ // Move R bit to the B bit in REX byte.
+ // REX byte is encoded as 0100WRXB, where
+ // 0100 is 4bit fixed pattern.
+ // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the
+ // default operand size is used (which is 32-bit for most but not all
+ // instructions).
+ // REX.R This 1-bit value is an extension to the MODRM.reg field.
+ // REX.X This 1-bit value is an extension to the SIB.index field.
+ // REX.B This 1-bit value is an extension to the MODRM.rm field or the
+ // 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);
+ return;
+ }
+
+ // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub
+ // or xor operations.
+
+ // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg".
+ // Logic is close to one for test instruction above, but we also
+ // write opcode extension here, see below for details.
+ Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte.
+
+ // Primary opcode is 0x81, opcode extension is one of:
+ // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB,
+ // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP.
+ // This value was wrote to MODRM.reg in a line above.
+ // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15),
+ // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for
+ // descriptions about each operation.
+ Loc[-2] = 0x81;
+ Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
+ relocateOne(Loc, R_X86_64_PC32, Val);
+}
+
+template <class ELFT>
+void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
+ const uint8_t Op = Loc[-2];
+ const uint8_t ModRm = Loc[-1];
+
+ // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg".
+ if (Op == 0x8b) {
+ Loc[-2] = 0x8d;
+ relocateOne(Loc, R_X86_64_PC32, Val);
+ return;
+ }
+
+ if (Op != 0xff) {
+ // We are relaxing a rip relative to an absolute, so compensate
+ // for the old -4 addend.
+ assert(!Config->Pic);
+ relaxGotNoPic(Loc, Val + 4, Op, ModRm);
+ return;
+ }
+
+ // Convert call/jmp instructions.
+ if (ModRm == 0x15) {
+ // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo".
+ // Instead we convert to "addr32 call foo" where addr32 is an instruction
+ // 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);
+ return;
+ }
+
+ // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop".
+ // jmp doesn't return, so it is fine to use nop here, it is just a stub.
+ assert(ModRm == 0x25);
+ Loc[-2] = 0xe9; // jmp
+ Loc[3] = 0x90; // nop
+ relocateOne(Loc - 1, R_X86_64_PC32, Val + 1);
+}
+
// Relocation masks following the #lo(value), #hi(value), #ha(value),
// #higher(value), #highera(value), #highest(value), and #highesta(value)
// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
@@ -933,41 +954,32 @@ static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
PPCTargetInfo::PPCTargetInfo() {}
-void PPCTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {}
-void PPCTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const {}
-void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
- uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {}
-bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
- return false;
-}
-bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
- return false;
-}
-bool PPCTargetInfo::isRelRelative(uint32_t Type) const { return false; }
-void PPCTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
- uint64_t P, uint64_t SA, uint64_t ZA,
- uint8_t *PairedLoc) const {
+void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
switch (Type) {
case R_PPC_ADDR16_HA:
- write16be(Loc, applyPPCHa(SA));
+ write16be(Loc, applyPPCHa(Val));
break;
case R_PPC_ADDR16_LO:
- write16be(Loc, applyPPCLo(SA));
+ write16be(Loc, applyPPCLo(Val));
break;
default:
- error("unrecognized reloc " + Twine(Type));
+ fatal("unrecognized reloc " + Twine(Type));
}
}
+RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+ return R_ABS;
+}
+
PPC64TargetInfo::PPC64TargetInfo() {
- PCRelReloc = R_PPC64_REL24;
- GotReloc = R_PPC64_GLOB_DAT;
- RelativeReloc = R_PPC64_RELATIVE;
+ PltRel = GotRel = R_PPC64_GLOB_DAT;
+ RelativeRel = R_PPC64_RELATIVE;
+ GotEntrySize = 8;
+ GotPltEntrySize = 8;
PltEntrySize = 32;
+ PltHeaderSize = 0;
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
@@ -981,33 +993,46 @@ PPC64TargetInfo::PPC64TargetInfo() {
//
// And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
// use 0x10000000 as the starting address.
- VAStart = 0x10000000;
+ DefaultImageBase = 0x10000000;
}
-uint64_t getPPC64TocBase() {
- // The TOC consists of sections .got, .toc, .tocbss, .plt in that
- // order. The TOC starts where the first of these sections starts.
+static uint64_t PPC64TocOffset = 0x8000;
- // FIXME: This obviously does not do the right thing when there is no .got
- // section, but there is a .toc or .tocbss section.
+uint64_t getPPC64TocBase() {
+ // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
+ // TOC starts where the first of these sections starts. We always create a
+ // .got when we see a relocation that uses it, so for us the start is always
+ // the .got.
uint64_t TocVA = Out<ELF64BE>::Got->getVA();
- if (!TocVA)
- TocVA = Out<ELF64BE>::Plt->getVA();
// Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
// thus permitting a full 64 Kbytes segment. Note that the glibc startup
// code (crt1.o) assumes that you can get from the TOC base to the
// start of the .toc section with only a single (signed) 16-bit relocation.
- return TocVA + 0x8000;
+ return TocVA + PPC64TocOffset;
}
-void PPC64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {}
-void PPC64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const {}
-void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
- uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
+RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_LO_DS:
+ return R_GOTREL;
+ case R_PPC64_TOC:
+ return R_PPC_TOC;
+ case R_PPC64_REL24:
+ return R_PPC_PLT_OPD;
+ }
+}
+
+void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
uint64_t Off = GotEntryAddr - getPPC64TocBase();
// FIXME: What we should do, in theory, is get the offset of the function
@@ -1026,181 +1051,193 @@ void PPC64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
write32be(Buf + 28, 0x4e800420); // bctr
}
-bool PPC64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
- if (relocNeedsPlt(Type, S))
- return true;
-
+static std::pair<uint32_t, uint64_t> toAddr16Rel(uint32_t Type, uint64_t Val) {
+ uint64_t V = Val - PPC64TocOffset;
switch (Type) {
- default: return false;
- case R_PPC64_GOT16:
- case R_PPC64_GOT16_DS:
- case R_PPC64_GOT16_HA:
- case R_PPC64_GOT16_HI:
- case R_PPC64_GOT16_LO:
- case R_PPC64_GOT16_LO_DS:
- return true;
+ case R_PPC64_TOC16: return {R_PPC64_ADDR16, V};
+ case R_PPC64_TOC16_DS: return {R_PPC64_ADDR16_DS, V};
+ case R_PPC64_TOC16_HA: return {R_PPC64_ADDR16_HA, V};
+ case R_PPC64_TOC16_HI: return {R_PPC64_ADDR16_HI, V};
+ case R_PPC64_TOC16_LO: return {R_PPC64_ADDR16_LO, V};
+ case R_PPC64_TOC16_LO_DS: return {R_PPC64_ADDR16_LO_DS, V};
+ default: return {Type, Val};
}
}
-bool PPC64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
- // These are function calls that need to be redirected through a PLT stub.
- return Type == R_PPC64_REL24 && canBePreempted(&S, false);
-}
-
-bool PPC64TargetInfo::isRelRelative(uint32_t Type) const {
- switch (Type) {
- default:
- return true;
- case R_PPC64_ADDR64:
- case R_PPC64_TOC:
- return false;
- }
-}
-
-void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
- uint64_t P, uint64_t SA, uint64_t ZA,
- uint8_t *PairedLoc) const {
- uint64_t TB = getPPC64TocBase();
-
- // For a TOC-relative relocation, adjust the addend and proceed in terms of
- // the corresponding ADDR16 relocation type.
- switch (Type) {
- case R_PPC64_TOC16: Type = R_PPC64_ADDR16; SA -= TB; break;
- case R_PPC64_TOC16_DS: Type = R_PPC64_ADDR16_DS; SA -= TB; break;
- case R_PPC64_TOC16_HA: Type = R_PPC64_ADDR16_HA; SA -= TB; break;
- case R_PPC64_TOC16_HI: Type = R_PPC64_ADDR16_HI; SA -= TB; break;
- case R_PPC64_TOC16_LO: Type = R_PPC64_ADDR16_LO; SA -= TB; break;
- case R_PPC64_TOC16_LO_DS: Type = R_PPC64_ADDR16_LO_DS; SA -= TB; break;
- default: break;
- }
+void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // For a TOC-relative relocation, proceed in terms of the corresponding
+ // ADDR16 relocation type.
+ std::tie(Type, Val) = toAddr16Rel(Type, Val);
switch (Type) {
case R_PPC64_ADDR14: {
- checkAlignment<4>(SA, Type);
+ checkAlignment<4>(Val, Type);
// Preserve the AA/LK bits in the branch instruction
uint8_t AALK = Loc[3];
- write16be(Loc + 2, (AALK & 3) | (SA & 0xfffc));
+ write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
break;
}
case R_PPC64_ADDR16:
- checkInt<16>(SA, Type);
- write16be(Loc, SA);
+ checkInt<16>(Val, Type);
+ write16be(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
- checkInt<16>(SA, Type);
- write16be(Loc, (read16be(Loc) & 3) | (SA & ~3));
+ checkInt<16>(Val, Type);
+ write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
break;
case R_PPC64_ADDR16_HA:
- write16be(Loc, applyPPCHa(SA));
+ case R_PPC64_REL16_HA:
+ write16be(Loc, applyPPCHa(Val));
break;
case R_PPC64_ADDR16_HI:
- write16be(Loc, applyPPCHi(SA));
+ case R_PPC64_REL16_HI:
+ write16be(Loc, applyPPCHi(Val));
break;
case R_PPC64_ADDR16_HIGHER:
- write16be(Loc, applyPPCHigher(SA));
+ write16be(Loc, applyPPCHigher(Val));
break;
case R_PPC64_ADDR16_HIGHERA:
- write16be(Loc, applyPPCHighera(SA));
+ write16be(Loc, applyPPCHighera(Val));
break;
case R_PPC64_ADDR16_HIGHEST:
- write16be(Loc, applyPPCHighest(SA));
+ write16be(Loc, applyPPCHighest(Val));
break;
case R_PPC64_ADDR16_HIGHESTA:
- write16be(Loc, applyPPCHighesta(SA));
+ write16be(Loc, applyPPCHighesta(Val));
break;
case R_PPC64_ADDR16_LO:
- write16be(Loc, applyPPCLo(SA));
+ write16be(Loc, applyPPCLo(Val));
break;
case R_PPC64_ADDR16_LO_DS:
- write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(SA) & ~3));
+ case R_PPC64_REL16_LO:
+ write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3));
break;
case R_PPC64_ADDR32:
- checkInt<32>(SA, Type);
- write32be(Loc, SA);
+ case R_PPC64_REL32:
+ checkInt<32>(Val, Type);
+ write32be(Loc, Val);
break;
case R_PPC64_ADDR64:
- write64be(Loc, SA);
- break;
- case R_PPC64_REL16_HA:
- write16be(Loc, applyPPCHa(SA - P));
- break;
- case R_PPC64_REL16_HI:
- write16be(Loc, applyPPCHi(SA - P));
- break;
- case R_PPC64_REL16_LO:
- write16be(Loc, applyPPCLo(SA - P));
+ case R_PPC64_REL64:
+ case R_PPC64_TOC:
+ write64be(Loc, Val);
break;
case R_PPC64_REL24: {
- // If we have an undefined weak symbol, we might get here with a symbol
- // address of zero. That could overflow, but the code must be unreachable,
- // so don't bother doing anything at all.
- if (!SA)
- break;
-
- uint64_t PltStart = Out<ELF64BE>::Plt->getVA();
- uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize();
- bool InPlt = PltStart <= SA && SA < PltEnd;
-
- if (!InPlt && Out<ELF64BE>::Opd) {
- // If this is a local call, and we currently have the address of a
- // function-descriptor, get the underlying code address instead.
- uint64_t OpdStart = Out<ELF64BE>::Opd->getVA();
- uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
- bool InOpd = OpdStart <= SA && SA < OpdEnd;
-
- if (InOpd)
- SA = read64be(&Out<ELF64BE>::OpdBuf[SA - OpdStart]);
- }
-
uint32_t Mask = 0x03FFFFFC;
- checkInt<24>(SA - P, Type);
- write32be(Loc, (read32be(Loc) & ~Mask) | ((SA - P) & Mask));
-
- uint32_t Nop = 0x60000000;
- if (InPlt && Loc + 8 <= BufEnd && read32be(Loc + 4) == Nop)
- write32be(Loc + 4, 0xe8410028); // ld %r2, 40(%r1)
+ checkInt<24>(Val, Type);
+ write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
break;
}
- case R_PPC64_REL32:
- checkInt<32>(SA - P, Type);
- write32be(Loc, SA - P);
- break;
- case R_PPC64_REL64:
- write64be(Loc, SA - P);
- break;
- case R_PPC64_TOC:
- write64be(Loc, SA);
- break;
default:
- error("unrecognized reloc " + Twine(Type));
+ fatal("unrecognized reloc " + Twine(Type));
}
}
AArch64TargetInfo::AArch64TargetInfo() {
- CopyReloc = R_AARCH64_COPY;
- IRelativeReloc = R_AARCH64_IRELATIVE;
- GotReloc = R_AARCH64_GLOB_DAT;
- PltReloc = R_AARCH64_JUMP_SLOT;
- TlsGotReloc = R_AARCH64_TLS_TPREL64;
- LazyRelocations = true;
+ CopyRel = R_AARCH64_COPY;
+ RelativeRel = R_AARCH64_RELATIVE;
+ IRelativeRel = R_AARCH64_IRELATIVE;
+ GotRel = R_AARCH64_GLOB_DAT;
+ PltRel = R_AARCH64_JUMP_SLOT;
+ TlsDescRel = R_AARCH64_TLSDESC;
+ TlsGotRel = R_AARCH64_TLS_TPREL64;
+ GotEntrySize = 8;
+ GotPltEntrySize = 8;
PltEntrySize = 16;
- PltZeroEntrySize = 32;
+ PltHeaderSize = 32;
+
+ // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant
+ // 1 of the tls structures and the tcb size is 16.
+ TcbSize = 16;
+}
+
+RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
+ const SymbolBody &S) const {
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ return R_TLSDESC_PAGE;
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ return R_TLSDESC;
+ case R_AARCH64_TLSDESC_CALL:
+ return R_HINT;
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ return R_TLS;
+ case R_AARCH64_CALL26:
+ case R_AARCH64_CONDBR19:
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_TSTBR14:
+ return R_PLT_PC;
+ case R_AARCH64_PREL16:
+ case R_AARCH64_PREL32:
+ case R_AARCH64_PREL64:
+ case R_AARCH64_ADR_PREL_LO21:
+ return R_PC;
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ return R_PAGE_PC;
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ return R_GOT;
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ return R_GOT_PAGE_PC;
+ }
}
-unsigned AArch64TargetInfo::getDynReloc(unsigned Type) const {
+RelExpr AArch64TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ if (Expr == R_RELAX_TLS_GD_TO_IE) {
+ if (Type == R_AARCH64_TLSDESC_ADR_PAGE21)
+ return R_RELAX_TLS_GD_TO_IE_PAGE_PC;
+ return R_RELAX_TLS_GD_TO_IE_ABS;
+ }
+ return Expr;
+}
+
+bool AArch64TargetInfo::usesOnlyLowPageBits(uint32_t Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ return true;
+ }
+}
+
+bool AArch64TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
+ return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
+ Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
+}
+
+uint32_t AArch64TargetInfo::getDynRel(uint32_t Type) const {
if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64)
return Type;
- StringRef S = getELFRelocationTypeName(EM_AARCH64, Type);
- error("Relocation " + S + " cannot be used when making a shared object; "
- "recompile with -fPIC.");
+ // Keep it going with a dummy value so that we can find more reloc errors.
+ errorDynRel(Type);
+ return R_AARCH64_ABS32;
}
-void AArch64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {
+void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
write64le(Buf, Out<ELF64LE>::Plt->getVA());
}
-void AArch64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const {
+static uint64_t getAArch64Page(uint64_t Expr) {
+ return Expr & (~static_cast<uint64_t>(0xFFF));
+}
+
+void AArch64TargetInfo::writePltHeader(uint8_t *Buf) const {
const uint8_t PltData[] = {
0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]!
0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2]))
@@ -1213,18 +1250,17 @@ void AArch64TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
};
memcpy(Buf, PltData, sizeof(PltData));
- relocateOne(Buf + 4, Buf + 8, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr + 4,
- GotEntryAddr + 16);
- relocateOne(Buf + 8, Buf + 12, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 8,
- GotEntryAddr + 16);
- relocateOne(Buf + 12, Buf + 16, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 12,
- GotEntryAddr + 16);
+ uint64_t Got = Out<ELF64LE>::GotPlt->getVA();
+ uint64_t Plt = Out<ELF64LE>::Plt->getVA();
+ relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
+ getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
+ relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
+ relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
}
-void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
- uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
+void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
const uint8_t Inst[] = {
0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))]
@@ -1233,377 +1269,851 @@ void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
};
memcpy(Buf, Inst, sizeof(Inst));
- relocateOne(Buf, Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr,
- GotEntryAddr);
- relocateOne(Buf + 4, Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 4,
- GotEntryAddr);
- relocateOne(Buf + 8, Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 8,
- GotEntryAddr);
+ 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);
}
-unsigned AArch64TargetInfo::getTlsGotReloc(unsigned Type) const {
- if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
- Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC)
- return Type;
- return TlsGotReloc;
-}
-
-bool AArch64TargetInfo::isTlsDynReloc(unsigned Type,
- const SymbolBody &S) const {
- return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
- Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
-}
-
-bool AArch64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
- if (Config->Shared)
- return false;
- switch (Type) {
- default:
- return false;
- case R_AARCH64_ABS16:
- case R_AARCH64_ABS32:
- case R_AARCH64_ABS64:
- case R_AARCH64_ADD_ABS_LO12_NC:
- case R_AARCH64_ADR_PREL_LO21:
- case R_AARCH64_ADR_PREL_PG_HI21:
- case R_AARCH64_LDST8_ABS_LO12_NC:
- case R_AARCH64_LDST32_ABS_LO12_NC:
- case R_AARCH64_LDST64_ABS_LO12_NC:
- if (auto *SS = dyn_cast<SharedSymbol<ELF64LE>>(&S))
- return SS->Sym.getType() == STT_OBJECT;
- return false;
- }
-}
-
-bool AArch64TargetInfo::relocNeedsGot(uint32_t Type,
- const SymbolBody &S) const {
- switch (Type) {
- case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- case R_AARCH64_ADR_GOT_PAGE:
- case R_AARCH64_LD64_GOT_LO12_NC:
- return true;
- default:
- return relocNeedsPlt(Type, S);
- }
-}
-
-bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type,
- const SymbolBody &S) const {
- if (isGnuIFunc<ELF64LE>(S))
- return true;
- switch (Type) {
- default:
- return false;
- case R_AARCH64_CALL26:
- case R_AARCH64_CONDBR19:
- case R_AARCH64_JUMP26:
- case R_AARCH64_TSTBR14:
- return canBePreempted(&S, true);
- }
-}
-
-static void updateAArch64Adr(uint8_t *L, uint64_t Imm) {
+static void updateAArch64Addr(uint8_t *L, uint64_t Imm) {
uint32_t ImmLo = (Imm & 0x3) << 29;
- uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5;
- uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5);
+ uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
+ uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
}
-// Page(Expr) is the page address of the expression Expr, defined
-// as (Expr & ~0xFFF). (This applies even if the machine page size
-// supported by the platform has a different value.)
-static uint64_t getAArch64Page(uint64_t Expr) {
- return Expr & (~static_cast<uint64_t>(0xFFF));
+static inline void updateAArch64Add(uint8_t *L, uint64_t Imm) {
+ or32le(L, (Imm & 0xFFF) << 10);
}
-void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
- uint32_t Type, uint64_t P, uint64_t SA,
- uint64_t ZA, uint8_t *PairedLoc) const {
+void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
switch (Type) {
case R_AARCH64_ABS16:
- checkIntUInt<16>(SA, Type);
- write16le(Loc, SA);
+ case R_AARCH64_PREL16:
+ checkIntUInt<16>(Val, Type);
+ write16le(Loc, Val);
break;
case R_AARCH64_ABS32:
- checkIntUInt<32>(SA, Type);
- write32le(Loc, SA);
+ case R_AARCH64_PREL32:
+ checkIntUInt<32>(Val, Type);
+ write32le(Loc, Val);
break;
case R_AARCH64_ABS64:
- write64le(Loc, SA);
+ case R_AARCH64_PREL64:
+ write64le(Loc, Val);
break;
case R_AARCH64_ADD_ABS_LO12_NC:
// This relocation stores 12 bits and there's no instruction
// to do it. Instead, we do a 32 bits store of the value
// of r_addend bitwise-or'ed Loc. This assumes that the addend
// bits in Loc are zero.
- or32le(Loc, (SA & 0xFFF) << 10);
- break;
- case R_AARCH64_ADR_GOT_PAGE: {
- uint64_t X = getAArch64Page(SA) - getAArch64Page(P);
- checkInt<33>(X, Type);
- updateAArch64Adr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12]
- break;
- }
- case R_AARCH64_ADR_PREL_LO21: {
- uint64_t X = SA - P;
- checkInt<21>(X, Type);
- updateAArch64Adr(Loc, X & 0x1FFFFF);
+ or32le(Loc, (Val & 0xFFF) << 10);
break;
- }
+ case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_ADR_PREL_PG_HI21:
- case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: {
- uint64_t X = getAArch64Page(SA) - getAArch64Page(P);
- checkInt<33>(X, Type);
- updateAArch64Adr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12]
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ checkInt<33>(Val, Type);
+ updateAArch64Addr(Loc, Val >> 12);
+ break;
+ case R_AARCH64_ADR_PREL_LO21:
+ checkInt<21>(Val, Type);
+ updateAArch64Addr(Loc, Val);
break;
- }
case R_AARCH64_CALL26:
- case R_AARCH64_JUMP26: {
- uint64_t X = SA - P;
- checkInt<28>(X, Type);
- or32le(Loc, (X & 0x0FFFFFFC) >> 2);
+ case R_AARCH64_JUMP26:
+ checkInt<28>(Val, Type);
+ or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
break;
- }
- case R_AARCH64_CONDBR19: {
- uint64_t X = SA - P;
- checkInt<21>(X, Type);
- or32le(Loc, (X & 0x1FFFFC) << 3);
+ case R_AARCH64_CONDBR19:
+ checkInt<21>(Val, Type);
+ or32le(Loc, (Val & 0x1FFFFC) << 3);
break;
- }
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- checkAlignment<8>(SA, Type);
- or32le(Loc, (SA & 0xFF8) << 7);
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
+ checkAlignment<8>(Val, Type);
+ or32le(Loc, (Val & 0xFF8) << 7);
+ break;
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ or32le(Loc, (Val & 0x0FF8) << 6);
+ break;
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ or32le(Loc, (Val & 0x0FFC) << 9);
break;
case R_AARCH64_LDST8_ABS_LO12_NC:
- or32le(Loc, (SA & 0xFFF) << 10);
+ or32le(Loc, (Val & 0xFFF) << 10);
break;
case R_AARCH64_LDST32_ABS_LO12_NC:
- or32le(Loc, (SA & 0xFFC) << 8);
+ or32le(Loc, (Val & 0xFFC) << 8);
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
- or32le(Loc, (SA & 0xFF8) << 7);
+ or32le(Loc, (Val & 0xFF8) << 7);
break;
- case R_AARCH64_PREL16:
- checkIntUInt<16>(SA - P, Type);
- write16le(Loc, SA - P);
+ case R_AARCH64_TSTBR14:
+ checkInt<16>(Val, Type);
+ or32le(Loc, (Val & 0xFFFC) << 3);
break;
- case R_AARCH64_PREL32:
- checkIntUInt<32>(SA - P, Type);
- write32le(Loc, SA - P);
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ checkInt<24>(Val, Type);
+ updateAArch64Add(Loc, Val >> 12);
break;
- case R_AARCH64_PREL64:
- write64le(Loc, SA - P);
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ updateAArch64Add(Loc, Val);
break;
- case R_AARCH64_TSTBR14: {
- uint64_t X = SA - P;
- checkInt<16>(X, Type);
- or32le(Loc, (X & 0xFFFC) << 3);
+ default:
+ fatal("unrecognized reloc " + Twine(Type));
+ }
+}
+
+void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // TLSDESC Global-Dynamic relocation are in the form:
+ // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
+ // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC]
+ // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC]
+ // .tlsdesccall [R_AARCH64_TLSDESC_CALL]
+ // blr x1
+ // And it can optimized to:
+ // movz x0, #0x0, lsl #16
+ // movk x0, #0x10
+ // nop
+ // nop
+ checkUInt<32>(Val, Type);
+
+ switch (Type) {
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ case R_AARCH64_TLSDESC_CALL:
+ write32le(Loc, 0xd503201f); // nop
+ return;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz
+ return;
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
+ write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk
+ return;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // TLSDESC Global-Dynamic relocation are in the form:
+ // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
+ // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC]
+ // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC]
+ // .tlsdesccall [R_AARCH64_TLSDESC_CALL]
+ // blr x1
+ // And it can optimized to:
+ // adrp x0, :gottprel:v
+ // ldr x0, [x0, :gottprel_lo12:v]
+ // nop
+ // nop
+
+ switch (Type) {
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ case R_AARCH64_TLSDESC_CALL:
+ write32le(Loc, 0xd503201f); // nop
+ break;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ write32le(Loc, 0x90000000); // adrp
+ relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val);
+ break;
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
+ write32le(Loc, 0xf9400000); // ldr
+ relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ checkUInt<32>(Val, Type);
+
+ if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
+ // Generate MOVZ.
+ uint32_t RegNo = read32le(Loc) & 0x1f;
+ write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5));
+ return;
+ }
+ if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) {
+ // Generate MOVK.
+ uint32_t RegNo = read32le(Loc) & 0x1f;
+ write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5));
+ return;
+ }
+ llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
+}
+
+AMDGPUTargetInfo::AMDGPUTargetInfo() {
+ GotRel = R_AMDGPU_ABS64;
+ GotEntrySize = 8;
+}
+
+void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ switch (Type) {
+ case R_AMDGPU_GOTPCREL:
+ case R_AMDGPU_REL32:
+ write32le(Loc, Val);
break;
+ default:
+ fatal("unrecognized reloc " + Twine(Type));
}
+}
+
+RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+ switch (Type) {
+ case R_AMDGPU_REL32:
+ return R_PC;
+ case R_AMDGPU_GOTPCREL:
+ return R_GOT_PC;
default:
- error("unrecognized reloc " + Twine(Type));
+ fatal("do not know how to handle relocation " + Twine(Type));
}
}
-AMDGPUTargetInfo::AMDGPUTargetInfo() {}
+ARMTargetInfo::ARMTargetInfo() {
+ CopyRel = R_ARM_COPY;
+ RelativeRel = R_ARM_RELATIVE;
+ IRelativeRel = R_ARM_IRELATIVE;
+ GotRel = R_ARM_GLOB_DAT;
+ PltRel = R_ARM_JUMP_SLOT;
+ TlsGotRel = R_ARM_TLS_TPOFF32;
+ TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
+ TlsOffsetRel = R_ARM_TLS_DTPOFF32;
+ GotEntrySize = 4;
+ GotPltEntrySize = 4;
+ PltEntrySize = 16;
+ PltHeaderSize = 20;
+}
-void AMDGPUTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {
- llvm_unreachable("not implemented");
+RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_ARM_THM_JUMP11:
+ return R_PC;
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_CALL:
+ return R_PLT_PC;
+ case R_ARM_GOTOFF32:
+ // (S + A) - GOT_ORG
+ return R_GOTREL;
+ case R_ARM_GOT_BREL:
+ // GOT(S) + A - GOT_ORG
+ return R_GOT_OFF;
+ case R_ARM_GOT_PREL:
+ // GOT(S) + - GOT_ORG
+ return R_GOT_PC;
+ case R_ARM_BASE_PREL:
+ // B(S) + A - P
+ // FIXME: currently B(S) assumed to be .got, this may not hold for all
+ // platforms.
+ return R_GOTONLY_PC;
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL:
+ case R_ARM_PREL31:
+ case R_ARM_REL32:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL:
+ return R_PC;
+ }
}
-void AMDGPUTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const {
- llvm_unreachable("not implemented");
+uint32_t ARMTargetInfo::getDynRel(uint32_t Type) const {
+ if (Type == R_ARM_ABS32)
+ return Type;
+ // Keep it going with a dummy value so that we can find more reloc errors.
+ errorDynRel(Type);
+ return R_ARM_ABS32;
}
-void AMDGPUTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
- uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
- llvm_unreachable("not implemented");
+void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+ write32le(Buf, Out<ELF32LE>::Plt->getVA());
}
-bool AMDGPUTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
- return false;
+void ARMTargetInfo::writePltHeader(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]!
+ 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2
+ 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr
+ 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8]
+ 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t GotPlt = Out<ELF32LE>::GotPlt->getVA();
+ uint64_t L1 = Out<ELF32LE>::Plt->getVA() + 8;
+ write32le(Buf + 16, GotPlt - L1 - 8);
}
-bool AMDGPUTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
- return false;
+void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ // FIXME: Using simple code sequence with simple relocations.
+ // There is a more optimal sequence but it requires support for the group
+ // relocations. See ELF for the ARM Architecture Appendix A.3
+ const uint8_t PltData[] = {
+ 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2
+ 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+ 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t L1 = PltEntryAddr + 4;
+ write32le(Buf + 12, GotEntryAddr - L1 - 8);
+}
+
+RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
+ const InputFile &File,
+ const SymbolBody &S) const {
+ // 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.
+ switch (RelocType) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ 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;
+ 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;
+ break;
+ }
+ return Expr;
}
-// Implementing relocations for AMDGPU is low priority since most
-// programs don't use relocations now. Thus, this function is not
-// actually called (relocateOne is called for each relocation).
-// That's why the AMDGPU port works without implementing this function.
-void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
- uint64_t P, uint64_t SA, uint64_t ZA,
- uint8_t *PairedLoc) const {
- llvm_unreachable("not implemented");
+void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ switch (Type) {
+ case R_ARM_NONE:
+ break;
+ case R_ARM_ABS32:
+ case R_ARM_BASE_PREL:
+ case R_ARM_GOTOFF32:
+ case R_ARM_GOT_BREL:
+ case R_ARM_GOT_PREL:
+ case R_ARM_REL32:
+ write32le(Loc, Val);
+ break;
+ case R_ARM_PREL31:
+ checkInt<31>(Val, Type);
+ write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
+ break;
+ case R_ARM_CALL:
+ // R_ARM_CALL is used for BL and BLX instructions, depending on the
+ // value of bit 0 of Val, we must select a BL or BLX instruction
+ if (Val & 1) {
+ // If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
+ // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
+ checkInt<26>(Val, Type);
+ write32le(Loc, 0xfa000000 | // opcode
+ ((Val & 2) << 23) | // H
+ ((Val >> 2) & 0x00ffffff)); // imm24
+ break;
+ }
+ if ((read32le(Loc) & 0xfe000000) == 0xfa000000)
+ // BLX (always unconditional) instruction to an ARM Target, select an
+ // unconditional BL.
+ write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff));
+ // fall through as BL encoding is shared with B
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ checkInt<26>(Val, Type);
+ write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
+ break;
+ case R_ARM_THM_JUMP11:
+ checkInt<12>(Val, Type);
+ write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
+ break;
+ case R_ARM_THM_JUMP19:
+ // Encoding T3: Val = S:J2:J1:imm6:imm11:0
+ checkInt<21>(Val, Type);
+ write16le(Loc,
+ (read16le(Loc) & 0xfbc0) | // opcode cond
+ ((Val >> 10) & 0x0400) | // S
+ ((Val >> 12) & 0x003f)); // imm6
+ write16le(Loc + 2,
+ 0x8000 | // opcode
+ ((Val >> 8) & 0x0800) | // J2
+ ((Val >> 5) & 0x2000) | // J1
+ ((Val >> 1) & 0x07ff)); // imm11
+ break;
+ case R_ARM_THM_CALL:
+ // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the
+ // value of bit 0 of Val, we must select a BL or BLX instruction
+ if ((Val & 1) == 0) {
+ // Ensure BLX destination is 4-byte aligned. As BLX instruction may
+ // only be two byte aligned. This must be done before overflow check
+ Val = alignTo(Val, 4);
+ }
+ // Bit 12 is 0 for BLX, 1 for BL
+ write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12);
+ // Fall through as rest of encoding is the same as B.W
+ case R_ARM_THM_JUMP24:
+ // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
+ // FIXME: Use of I1 and I2 require v6T2ops
+ checkInt<25>(Val, Type);
+ write16le(Loc,
+ 0xf000 | // opcode
+ ((Val >> 14) & 0x0400) | // S
+ ((Val >> 12) & 0x03ff)); // imm10
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0xd000) | // opcode
+ (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1
+ (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2
+ ((Val >> 1) & 0x07ff)); // imm11
+ break;
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVW_PREL_NC:
+ write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) |
+ (Val & 0x0fff));
+ break;
+ case R_ARM_MOVT_ABS:
+ case R_ARM_MOVT_PREL:
+ checkInt<32>(Val, Type);
+ write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
+ (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
+ break;
+ case R_ARM_THM_MOVT_ABS:
+ case R_ARM_THM_MOVT_PREL:
+ // Encoding T1: A = imm4:i:imm3:imm8
+ checkInt<32>(Val, Type);
+ write16le(Loc,
+ 0xf2c0 | // opcode
+ ((Val >> 17) & 0x0400) | // i
+ ((Val >> 28) & 0x000f)); // imm4
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0x8f00) | // opcode
+ ((Val >> 12) & 0x7000) | // imm3
+ ((Val >> 16) & 0x00ff)); // imm8
+ break;
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVW_PREL_NC:
+ // Encoding T3: A = imm4:i:imm3:imm8
+ write16le(Loc,
+ 0xf240 | // opcode
+ ((Val >> 1) & 0x0400) | // i
+ ((Val >> 12) & 0x000f)); // imm4
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0x8f00) | // opcode
+ ((Val << 4) & 0x7000) | // imm3
+ (Val & 0x00ff)); // imm8
+ break;
+ default:
+ fatal("unrecognized reloc " + Twine(Type));
+ }
+}
+
+uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
+ uint32_t Type) const {
+ switch (Type) {
+ default:
+ return 0;
+ case R_ARM_ABS32:
+ case R_ARM_BASE_PREL:
+ case R_ARM_GOTOFF32:
+ case R_ARM_GOT_BREL:
+ case R_ARM_GOT_PREL:
+ case R_ARM_REL32:
+ return SignExtend64<32>(read32le(Buf));
+ case R_ARM_PREL31:
+ return SignExtend64<31>(read32le(Buf));
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ return SignExtend64<26>(read32le(Buf) << 2);
+ case R_ARM_THM_JUMP11:
+ return SignExtend64<12>(read16le(Buf) << 1);
+ case R_ARM_THM_JUMP19: {
+ // Encoding T3: A = S:J2:J1:imm10:imm6:0
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<20>(((Hi & 0x0400) << 10) | // S
+ ((Lo & 0x0800) << 8) | // J2
+ ((Lo & 0x2000) << 5) | // J1
+ ((Hi & 0x003f) << 12) | // imm6
+ ((Lo & 0x07ff) << 1)); // imm11:0
+ }
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24: {
+ // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0
+ // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)
+ // FIXME: I1 and I2 require v6T2ops
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<24>(((Hi & 0x0400) << 14) | // S
+ (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1
+ (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2
+ ((Hi & 0x003ff) << 12) | // imm0
+ ((Lo & 0x007ff) << 1)); // imm11:0
+ }
+ // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and
+ // MOVT is in the range -32768 <= A < 32768
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL: {
+ uint64_t Val = read32le(Buf) & 0x000f0fff;
+ return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff));
+ }
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL: {
+ // Encoding T3: A = imm4:i:imm3:imm8
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4
+ ((Hi & 0x0400) << 1) | // i
+ ((Lo & 0x7000) >> 4) | // imm3
+ (Lo & 0x00ff)); // imm8
+ }
+ }
}
template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
+ GotPltHeaderEntriesNum = 2;
PageSize = 65536;
- GotHeaderEntriesNum = 2;
+ GotEntrySize = sizeof(typename ELFT::uint);
+ GotPltEntrySize = sizeof(typename ELFT::uint);
+ PltEntrySize = 16;
+ PltHeaderSize = 32;
+ CopyRel = R_MIPS_COPY;
+ PltRel = R_MIPS_JUMP_SLOT;
+ if (ELFT::Is64Bits) {
+ RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
+ TlsGotRel = R_MIPS_TLS_TPREL64;
+ TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64;
+ TlsOffsetRel = R_MIPS_TLS_DTPREL64;
+ } else {
+ RelativeRel = R_MIPS_REL32;
+ TlsGotRel = R_MIPS_TLS_TPREL32;
+ TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32;
+ TlsOffsetRel = R_MIPS_TLS_DTPREL32;
+ }
}
template <class ELFT>
-void MipsTargetInfo<ELFT>::writeGotHeaderEntries(uint8_t *Buf) const {
- typedef typename ELFFile<ELFT>::Elf_Off Elf_Off;
- auto *P = reinterpret_cast<Elf_Off *>(Buf);
- // Module pointer
- P[1] = ELFT::Is64Bits ? 0x8000000000000000 : 0x80000000;
+RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
+ const SymbolBody &S) const {
+ if (ELFT::Is64Bits)
+ // See comment in the calculateMips64RelChain.
+ Type &= 0xff;
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_MIPS_JALR:
+ return R_HINT;
+ case R_MIPS_GPREL16:
+ case R_MIPS_GPREL32:
+ return R_GOTREL;
+ case R_MIPS_26:
+ return R_PLT;
+ case R_MIPS_HI16:
+ case R_MIPS_LO16:
+ case R_MIPS_GOT_OFST:
+ // MIPS _gp_disp designates offset between start of function and 'gp'
+ // pointer into GOT. __gnu_local_gp is equal to the current value of
+ // the 'gp'. Therefore any relocations against them do not require
+ // dynamic relocation.
+ if (&S == ElfSym<ELFT>::MipsGpDisp)
+ return R_PC;
+ return R_ABS;
+ case R_MIPS_PC32:
+ case R_MIPS_PC16:
+ case R_MIPS_PC19_S2:
+ case R_MIPS_PC21_S2:
+ case R_MIPS_PC26_S2:
+ case R_MIPS_PCHI16:
+ case R_MIPS_PCLO16:
+ return R_PC;
+ case R_MIPS_GOT16:
+ if (S.isLocal())
+ return R_MIPS_GOT_LOCAL_PAGE;
+ // fallthrough
+ case R_MIPS_CALL16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_TLS_GOTTPREL:
+ return R_MIPS_GOT_OFF;
+ case R_MIPS_GOT_PAGE:
+ return R_MIPS_GOT_LOCAL_PAGE;
+ case R_MIPS_TLS_GD:
+ return R_MIPS_TLSGD;
+ case R_MIPS_TLS_LDM:
+ return R_MIPS_TLSLD;
+ }
}
template <class ELFT>
-void MipsTargetInfo<ELFT>::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {}
-template <class ELFT>
-void MipsTargetInfo<ELFT>::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const {}
+uint32_t MipsTargetInfo<ELFT>::getDynRel(uint32_t Type) const {
+ if (Type == R_MIPS_32 || Type == R_MIPS_64)
+ return RelativeRel;
+ // Keep it going with a dummy value so that we can find more reloc errors.
+ errorDynRel(Type);
+ return R_MIPS_32;
+}
+
template <class ELFT>
-void MipsTargetInfo<ELFT>::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
- uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {}
+bool MipsTargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
+ return Type == R_MIPS_TLS_LDM;
+}
template <class ELFT>
-bool MipsTargetInfo<ELFT>::relocNeedsGot(uint32_t Type,
- const SymbolBody &S) const {
- return Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16;
+bool MipsTargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
+ return Type == R_MIPS_TLS_GD;
}
template <class ELFT>
-bool MipsTargetInfo<ELFT>::relocNeedsPlt(uint32_t Type,
- const SymbolBody &S) const {
- return false;
+void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+ write32<ELFT::TargetEndianness>(Buf, Out<ELFT>::Plt->getVA());
}
static uint16_t mipsHigh(uint64_t V) { return (V + 0x8000) >> 16; }
-template <endianness E, uint8_t BSIZE>
-static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t P,
- uint64_t SA) {
- uint32_t Mask = ~(0xffffffff << BSIZE);
+template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
+static int64_t getPcRelocAddend(const uint8_t *Loc) {
+ uint32_t Instr = read32<E>(Loc);
+ uint32_t Mask = 0xffffffff >> (32 - BSIZE);
+ return SignExtend64<BSIZE + SHIFT>((Instr & Mask) << SHIFT);
+}
+
+template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
+static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) {
+ uint32_t Mask = 0xffffffff >> (32 - BSIZE);
uint32_t Instr = read32<E>(Loc);
- int64_t A = SignExtend64<BSIZE + 2>((Instr & Mask) << 2);
- checkAlignment<4>(SA + A, Type);
- int64_t V = SA + A - P;
- checkInt<BSIZE + 2>(V, Type);
- write32<E>(Loc, (Instr & ~Mask) | ((V >> 2) & Mask));
+ if (SHIFT > 0)
+ checkAlignment<(1 << SHIFT)>(V, Type);
+ checkInt<BSIZE + SHIFT>(V, Type);
+ write32<E>(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask));
+}
+
+template <endianness E>
+static void writeMipsHi16(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(V));
+}
+
+template <endianness E>
+static void writeMipsLo16(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
}
template <class ELFT>
-void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
- uint32_t Type, uint64_t P, uint64_t SA,
- uint64_t ZA, uint8_t *PairedLoc) const {
+void MipsTargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
+ const endianness E = ELFT::TargetEndianness;
+ write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
+ 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 = Out<ELFT>::GotPlt->getVA();
+ writeMipsHi16<E>(Buf, Got);
+ writeMipsLo16<E>(Buf + 4, Got);
+ writeMipsLo16<E>(Buf + 8, Got);
+}
+
+template <class ELFT>
+void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const endianness E = ELFT::TargetEndianness;
+ write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
+ write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
+ write32<E>(Buf + 8, 0x03200008); // jr $25
+ 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);
+}
+
+template <class ELFT>
+RelExpr MipsTargetInfo<ELFT>::getThunkExpr(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);
+ if (!F)
+ return Expr;
+ // 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);
+ if (!D || !D->Section)
+ return Expr;
+ // LA25 is required if target file has PIC code
+ // or target symbol is a PIC symbol.
+ const ELFFile<ELFT> &DefFile = D->Section->getFile()->getObj();
+ bool PicFile = DefFile.getHeader()->e_flags & EF_MIPS_PIC;
+ bool PicSym = (D->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC;
+ return (PicFile || PicSym) ? R_THUNK_ABS : Expr;
+}
+
+template <class ELFT>
+uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
+ uint32_t Type) const {
const endianness E = ELFT::TargetEndianness;
switch (Type) {
+ default:
+ return 0;
case R_MIPS_32:
- add32<E>(Loc, SA);
- break;
- case R_MIPS_CALL16:
- case R_MIPS_GOT16: {
- int64_t V = SA - getMipsGpAddr<ELFT>();
- if (Type == R_MIPS_GOT16)
- checkInt<16>(V, Type);
- write32<E>(Loc, (read32<E>(Loc) & 0xffff0000) | (V & 0xffff));
- break;
- }
- case R_MIPS_GPREL16: {
- uint32_t Instr = read32<E>(Loc);
- int64_t V = SA + SignExtend64<16>(Instr & 0xffff) - getMipsGpAddr<ELFT>();
- checkInt<16>(V, Type);
- write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
- break;
+ case R_MIPS_GPREL32:
+ return 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:
+ // ((A << 2) | (P & 0xf0000000)) >> 2
+ return SignExtend64<28>(read32<E>(Buf) << 2);
+ case R_MIPS_GPREL16:
+ case R_MIPS_LO16:
+ case R_MIPS_PCLO16:
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS_TLS_TPREL_LO16:
+ return SignExtend64<16>(read32<E>(Buf));
+ case R_MIPS_PC16:
+ return getPcRelocAddend<E, 16, 2>(Buf);
+ case R_MIPS_PC19_S2:
+ return getPcRelocAddend<E, 19, 2>(Buf);
+ case R_MIPS_PC21_S2:
+ return getPcRelocAddend<E, 21, 2>(Buf);
+ case R_MIPS_PC26_S2:
+ return getPcRelocAddend<E, 26, 2>(Buf);
+ case R_MIPS_PC32:
+ return getPcRelocAddend<E, 32, 0>(Buf);
}
+}
+
+static std::pair<uint32_t, uint64_t> calculateMips64RelChain(uint32_t Type,
+ uint64_t Val) {
+ // MIPS N64 ABI packs multiple relocations into the single relocation
+ // record. In general, all up to three relocations can have arbitrary
+ // types. In fact, Clang and GCC uses only a few combinations. For now,
+ // we support two of them. That is allow to pass at least all LLVM
+ // test suite cases.
+ // <any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16
+ // <any relocation> / R_MIPS_64 / R_MIPS_NONE
+ // The first relocation is a 'real' relocation which is calculated
+ // using the corresponding symbol's value. The second and the third
+ // relocations used to modify result of the first one: extend it to
+ // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation
+ // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf
+ uint32_t Type2 = (Type >> 8) & 0xff;
+ uint32_t Type3 = (Type >> 16) & 0xff;
+ if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE)
+ return std::make_pair(Type, Val);
+ if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE)
+ return std::make_pair(Type2, Val);
+ if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
+ return std::make_pair(Type3, -Val);
+ error("unsupported relocations combination " + Twine(Type));
+ return std::make_pair(Type & 0xff, Val);
+}
+
+template <class ELFT>
+void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ const endianness E = ELFT::TargetEndianness;
+ // Thread pointer and DRP offsets from the start of TLS data area.
+ // https://www.linux-mips.org/wiki/NPTL
+ if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16)
+ Val -= 0x8000;
+ else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16)
+ Val -= 0x7000;
+ if (ELFT::Is64Bits)
+ std::tie(Type, Val) = calculateMips64RelChain(Type, Val);
+ switch (Type) {
+ case R_MIPS_32:
case R_MIPS_GPREL32:
- write32<E>(Loc, SA + int32_t(read32<E>(Loc)) - getMipsGpAddr<ELFT>());
- break;
- case R_MIPS_HI16: {
- uint32_t Instr = read32<E>(Loc);
- if (PairedLoc) {
- uint64_t AHL = ((Instr & 0xffff) << 16) +
- SignExtend64<16>(read32<E>(PairedLoc) & 0xffff);
- write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(SA + AHL));
- } else {
- warning("Can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16");
- write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(SA));
- }
+ write32<E>(Loc, Val);
+ break;
+ case R_MIPS_64:
+ write64<E>(Loc, Val);
+ break;
+ case R_MIPS_26:
+ write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | (Val >> 2));
+ 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:
+ checkInt<16>(Val, Type);
+ // fallthrough
+ case R_MIPS_CALL16:
+ case R_MIPS_GOT_OFST:
+ case R_MIPS_LO16:
+ case R_MIPS_PCLO16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_GOTTPREL:
+ case R_MIPS_TLS_TPREL_LO16:
+ writeMipsLo16<E>(Loc, Val);
+ break;
+ case R_MIPS_HI16:
+ case R_MIPS_PCHI16:
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_TPREL_HI16:
+ writeMipsHi16<E>(Loc, Val);
break;
- }
case R_MIPS_JALR:
// Ignore this optimization relocation for now
break;
- case R_MIPS_LO16: {
- uint32_t Instr = read32<E>(Loc);
- int64_t AHL = SignExtend64<16>(Instr & 0xffff);
- write32<E>(Loc, (Instr & 0xffff0000) | ((SA + AHL) & 0xffff));
- break;
- }
case R_MIPS_PC16:
- applyMipsPcReloc<E, 16>(Loc, Type, P, SA);
+ applyMipsPcReloc<E, 16, 2>(Loc, Type, Val);
break;
case R_MIPS_PC19_S2:
- applyMipsPcReloc<E, 19>(Loc, Type, P, SA);
+ applyMipsPcReloc<E, 19, 2>(Loc, Type, Val);
break;
case R_MIPS_PC21_S2:
- applyMipsPcReloc<E, 21>(Loc, Type, P, SA);
+ applyMipsPcReloc<E, 21, 2>(Loc, Type, Val);
break;
case R_MIPS_PC26_S2:
- applyMipsPcReloc<E, 26>(Loc, Type, P, SA);
- break;
- case R_MIPS_PCHI16: {
- uint32_t Instr = read32<E>(Loc);
- if (PairedLoc) {
- uint64_t AHL = ((Instr & 0xffff) << 16) +
- SignExtend64<16>(read32<E>(PairedLoc) & 0xffff);
- write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(SA + AHL - P));
- } else {
- warning("Can't find matching R_MIPS_PCLO16 relocation for R_MIPS_PCHI16");
- write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(SA - P));
- }
+ applyMipsPcReloc<E, 26, 2>(Loc, Type, Val);
break;
- }
- case R_MIPS_PCLO16: {
- uint32_t Instr = read32<E>(Loc);
- int64_t AHL = SignExtend64<16>(Instr & 0xffff);
- write32<E>(Loc, (Instr & 0xffff0000) | ((SA + AHL - P) & 0xffff));
+ case R_MIPS_PC32:
+ applyMipsPcReloc<E, 32, 0>(Loc, Type, Val);
break;
- }
default:
- error("unrecognized reloc " + Twine(Type));
+ fatal("unrecognized reloc " + Twine(Type));
}
}
template <class ELFT>
-bool MipsTargetInfo<ELFT>::isRelRelative(uint32_t Type) const {
- switch (Type) {
- default:
- return false;
- case R_MIPS_PC16:
- case R_MIPS_PC19_S2:
- case R_MIPS_PC21_S2:
- case R_MIPS_PC26_S2:
- case R_MIPS_PCHI16:
- case R_MIPS_PCLO16:
- return true;
- }
+bool MipsTargetInfo<ELFT>::usesOnlyLowPageBits(uint32_t Type) const {
+ return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST;
}
-
-// _gp is a MIPS-specific ABI-defined symbol which points to
-// a location that is relative to GOT. This function returns
-// the value for the symbol.
-template <class ELFT> typename ELFFile<ELFT>::uintX_t getMipsGpAddr() {
- unsigned GPOffset = 0x7ff0;
- if (uint64_t V = Out<ELFT>::Got->getVA())
- return V + GPOffset;
- return 0;
-}
-
-template uint32_t getMipsGpAddr<ELF32LE>();
-template uint32_t getMipsGpAddr<ELF32BE>();
-template uint64_t getMipsGpAddr<ELF64LE>();
-template uint64_t getMipsGpAddr<ELF64BE>();
}
}
diff --git a/ELF/Target.h b/ELF/Target.h
index e9c5f4b31ae4..d335c1e051b7 100644
--- a/ELF/Target.h
+++ b/ELF/Target.h
@@ -10,76 +10,57 @@
#ifndef LLD_ELF_TARGET_H
#define LLD_ELF_TARGET_H
+#include "InputSection.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/ELF.h"
#include <memory>
namespace lld {
-namespace elf2 {
+namespace elf {
+class InputFile;
class SymbolBody;
class TargetInfo {
public:
- unsigned getPageSize() const { return PageSize; }
- uint64_t getVAStart() const;
- unsigned getCopyReloc() const { return CopyReloc; }
- unsigned getGotReloc() const { return GotReloc; }
- unsigned getPltReloc() const { return PltReloc; }
- unsigned getRelativeReloc() const { return RelativeReloc; }
- unsigned getIRelativeReloc() const { return IRelativeReloc; }
- bool isTlsLocalDynamicReloc(unsigned Type) const {
- return Type == TlsLocalDynamicReloc;
- }
- bool isTlsGlobalDynamicReloc(unsigned Type) const {
- return Type == TlsGlobalDynamicReloc;
- }
- unsigned getTlsModuleIndexReloc() const { return TlsModuleIndexReloc; }
- unsigned getTlsOffsetReloc() const { return TlsOffsetReloc; }
- unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; }
- unsigned getPltEntrySize() const { return PltEntrySize; }
- bool supportsLazyRelocations() const { return LazyRelocations; }
- unsigned getGotHeaderEntriesNum() const { return GotHeaderEntriesNum; }
- unsigned getGotPltHeaderEntriesNum() const { return GotPltHeaderEntriesNum; }
- virtual unsigned getDynReloc(unsigned Type) const { return Type; }
- virtual bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const {
- return false;
- }
- virtual unsigned getTlsGotReloc(unsigned Type = -1) const {
- return TlsGotReloc;
- }
- virtual void writeGotHeaderEntries(uint8_t *Buf) const;
- virtual void writeGotPltHeaderEntries(uint8_t *Buf) const;
- virtual void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const = 0;
- virtual void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr) const = 0;
- virtual void writePltEntry(uint8_t *Buf, uint64_t GotAddr,
- uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const = 0;
-
- // Returns true if a relocation is relative to the place being relocated,
- // such as relocations used for PC-relative instructions. Such relocations
- // need not be fixed up if an image is loaded to a different address than
- // the link-time address. So we don't have to emit a relocation for the
- // dynamic linker if isRelRelative returns true.
- virtual bool isRelRelative(uint32_t Type) const;
-
- virtual bool isSizeReloc(uint32_t Type) const;
- virtual bool relocNeedsDynRelative(unsigned Type) const { return false; }
- virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0;
- virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0;
- virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
- uint64_t P, uint64_t SA, uint64_t ZA = 0,
- uint8_t *PairedLoc = nullptr) const = 0;
- virtual bool isGotRelative(uint32_t Type) const;
- virtual bool isTlsOptimized(unsigned Type, const SymbolBody *S) const;
- virtual bool needsCopyRel(uint32_t Type, const SymbolBody &S) const;
- virtual unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd,
- uint32_t Type, uint64_t P, uint64_t SA,
- const SymbolBody &S) const;
+ virtual bool isTlsInitialExecRel(uint32_t Type) const;
+ virtual bool isTlsLocalDynamicRel(uint32_t Type) const;
+ virtual bool isTlsGlobalDynamicRel(uint32_t Type) const;
+ 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 uint64_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
+ // they are called. This function writes that code.
+ virtual void writePltHeader(uint8_t *Buf) const {}
+
+ virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) 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
+ // bits will always have the same value at runtime and we don't have to emit
+ // a dynamic relocation.
+ 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