aboutsummaryrefslogtreecommitdiffstats
path: root/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:19:15 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:19:15 +0000
commitd93e1dfac8711cfed1a9d9cd1876a788b83945cd (patch)
tree5896fa6c02a262a6148b215487e545d937de58b7 /ELF
parent8d43286d630f9224de07809ea253e83ebb9cdee6 (diff)
downloadsrc-d93e1dfac8711cfed1a9d9cd1876a788b83945cd.tar.gz
src-d93e1dfac8711cfed1a9d9cd1876a788b83945cd.zip
Vendor import of lld trunk r290819:vendor/lld/lld-trunk-r290819
Notes
Notes: svn path=/vendor/lld/dist/; revision=311125 svn path=/vendor/lld/lld-trunk-r290819/; revision=311126; tag=vendor/lld/lld-trunk-r290819
Diffstat (limited to 'ELF')
-rw-r--r--ELF/CMakeLists.txt17
-rw-r--r--ELF/Config.h67
-rw-r--r--ELF/Driver.cpp553
-rw-r--r--ELF/Driver.h51
-rw-r--r--ELF/DriverUtils.cpp222
-rw-r--r--ELF/EhFrame.cpp147
-rw-r--r--ELF/EhFrame.h8
-rw-r--r--ELF/Error.cpp91
-rw-r--r--ELF/Error.h44
-rw-r--r--ELF/GdbIndex.cpp205
-rw-r--r--ELF/GdbIndex.h99
-rw-r--r--ELF/ICF.cpp508
-rw-r--r--ELF/InputFiles.cpp727
-rw-r--r--ELF/InputFiles.h123
-rw-r--r--ELF/InputSection.cpp677
-rw-r--r--ELF/InputSection.h295
-rw-r--r--ELF/LTO.cpp376
-rw-r--r--ELF/LTO.h24
-rw-r--r--ELF/LinkerScript.cpp2060
-rw-r--r--ELF/LinkerScript.h275
-rw-r--r--ELF/MarkLive.cpp150
-rw-r--r--ELF/Memory.h67
-rw-r--r--ELF/Mips.cpp369
-rw-r--r--ELF/Options.td111
-rw-r--r--ELF/OutputSections.cpp1768
-rw-r--r--ELF/OutputSections.h659
-rw-r--r--ELF/Relocations.cpp501
-rw-r--r--ELF/Relocations.h49
-rw-r--r--ELF/ScriptParser.cpp133
-rw-r--r--ELF/ScriptParser.h24
-rw-r--r--ELF/Strings.cpp80
-rw-r--r--ELF/Strings.h65
-rw-r--r--ELF/SymbolListFile.cpp168
-rw-r--r--ELF/SymbolListFile.h27
-rw-r--r--ELF/SymbolTable.cpp581
-rw-r--r--ELF/SymbolTable.h91
-rw-r--r--ELF/Symbols.cpp176
-rw-r--r--ELF/Symbols.h153
-rw-r--r--ELF/SyntheticSections.cpp1990
-rw-r--r--ELF/SyntheticSections.h747
-rw-r--r--ELF/Target.cpp608
-rw-r--r--ELF/Target.h20
-rw-r--r--ELF/Threads.h90
-rw-r--r--ELF/Thunks.cpp37
-rw-r--r--ELF/Writer.cpp1742
-rw-r--r--ELF/Writer.h48
46 files changed, 10920 insertions, 6103 deletions
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
index a1b65adc7400..2e9d2b941fd9 100644
--- a/ELF/CMakeLists.txt
+++ b/ELF/CMakeLists.txt
@@ -2,24 +2,30 @@ set(LLVM_TARGET_DEFINITIONS Options.td)
tablegen(LLVM Options.inc -gen-opt-parser-defs)
add_public_tablegen_target(ELFOptionsTableGen)
+if(NOT LLD_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
add_lld_library(lldELF
Driver.cpp
DriverUtils.cpp
EhFrame.cpp
Error.cpp
+ GdbIndex.cpp
ICF.cpp
InputFiles.cpp
InputSection.cpp
LTO.cpp
LinkerScript.cpp
MarkLive.cpp
+ Mips.cpp
OutputSections.cpp
Relocations.cpp
ScriptParser.cpp
Strings.cpp
- SymbolListFile.cpp
SymbolTable.cpp
Symbols.cpp
+ SyntheticSections.cpp
Target.cpp
Thunks.cpp
Writer.cpp
@@ -31,6 +37,8 @@ add_lld_library(lldELF
BitWriter
Codegen
Core
+ DebugInfoDWARF
+ Demangle
IPO
Linker
LTO
@@ -44,7 +52,10 @@ add_lld_library(lldELF
LINK_LIBS
lldConfig
+ lldCore
${PTHREAD_LIB}
- )
-add_dependencies(lldELF intrinsics_gen ELFOptionsTableGen)
+ DEPENDS
+ ELFOptionsTableGen
+ ${tablegen_deps}
+ )
diff --git a/ELF/Config.h b/ELF/Config.h
index 2ccd95e88775..b828cdb25047 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -12,6 +12,7 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Support/ELF.h"
#include <vector>
@@ -30,21 +31,36 @@ enum ELFKind {
ELF64BEKind
};
-enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring };
+// For --build-id.
+enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
-enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore };
+// For --discard-{all,locals,none} and --retain-symbols-file.
+enum class DiscardPolicy { Default, All, Locals, RetainFile, None };
+
+// For --strip-{all,debug}.
+enum class StripPolicy { None, All, Debug };
+
+// For --unresolved-symbols.
+enum class UnresolvedPolicy { NoUndef, ReportError, Warn, Ignore };
+
+// For --sort-section and linkerscript sorting rules.
+enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
+
+// For --target2
+enum class Target2Policy { Abs, Rel, GotRel };
struct SymbolVersion {
llvm::StringRef Name;
bool IsExternCpp;
+ bool HasWildcard;
};
// 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) {}
+ VersionDefinition(llvm::StringRef Name, uint16_t Id) : Name(Name), Id(Id) {}
llvm::StringRef Name;
- size_t Id;
+ uint16_t Id;
std::vector<SymbolVersion> Globals;
size_t NameOff; // Offset in string table.
};
@@ -54,75 +70,92 @@ struct VersionDefinition {
// and such fields have the same name as the corresponding options.
// Most fields are initialized by the driver.
struct Configuration {
- Symbol *EntrySym = nullptr;
InputFile *FirstElf = nullptr;
+ uint8_t OSABI = 0;
+ llvm::StringMap<uint64_t> SectionStartMap;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
llvm::StringRef Emulation;
llvm::StringRef Fini;
llvm::StringRef Init;
- llvm::StringRef LtoAAPipeline;
- llvm::StringRef LtoNewPmPasses;
+ llvm::StringRef LTOAAPipeline;
+ llvm::StringRef LTONewPmPasses;
llvm::StringRef OutputFile;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
+ llvm::StringSet<> RetainSymbolsFile;
std::string RPath;
std::vector<VersionDefinition> VersionDefinitions;
- std::vector<llvm::StringRef> DynamicList;
+ std::vector<llvm::StringRef> AuxiliaryList;
std::vector<llvm::StringRef> SearchPaths;
+ std::vector<llvm::StringRef> SymbolOrderingFile;
std::vector<llvm::StringRef> Undefined;
std::vector<SymbolVersion> VersionScriptGlobals;
+ std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
bool AllowMultipleDefinition;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
+ bool ColorDiagnostics = false;
bool Demangle = true;
bool DisableVerify;
- bool DiscardAll;
- bool DiscardLocals;
- bool DiscardNone;
bool EhFrameHdr;
bool EnableNewDtags;
bool ExportDynamic;
bool FatalWarnings;
bool GcSections;
+ bool GdbIndex;
bool GnuHash = false;
bool ICF;
bool Mips64EL = false;
+ bool MipsN32Abi = false;
bool NoGnuUnique;
bool NoUndefinedVersion;
+ bool Nostdlib;
+ bool OFormatBinary;
+ bool OMagic;
bool Pic;
bool Pie;
bool PrintGcSections;
bool Rela;
bool Relocatable;
bool SaveTemps;
+ bool SingleRoRx;
bool Shared;
bool Static = false;
- bool StripAll;
- bool StripDebug;
bool SysvHash = true;
+ bool Target1Rel;
bool Threads;
bool Trace;
bool Verbose;
bool WarnCommon;
+ bool WarnMissingEntry;
bool ZCombreloc;
- bool ZExecStack;
+ bool ZExecstack;
bool ZNodelete;
bool ZNow;
bool ZOrigin;
bool ZRelro;
+ bool ExitEarly;
+ bool ZWxneeded;
+ DiscardPolicy Discard;
+ SortSectionPolicy SortSection;
+ StripPolicy Strip = StripPolicy::None;
UnresolvedPolicy UnresolvedSymbols;
+ Target2Policy Target2 = Target2Policy::GotRel;
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;
+ uint64_t ErrorLimit = 20;
uint64_t ImageBase;
- unsigned LtoJobs;
- unsigned LtoO;
+ uint64_t MaxPageSize;
+ uint64_t ZStackSize;
+ unsigned LTOPartitions;
+ unsigned LTOO;
unsigned Optimize;
+ unsigned ThinLTOJobs;
};
// The only instance of Configuration struct.
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index c6ca2639236f..a11dbc7cc47f 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -14,14 +14,17 @@
#include "InputFiles.h"
#include "InputSection.h"
#include "LinkerScript.h"
+#include "Memory.h"
#include "Strings.h"
-#include "SymbolListFile.h"
#include "SymbolTable.h"
#include "Target.h"
+#include "Threads.h"
#include "Writer.h"
+#include "lld/Config/Version.h"
#include "lld/Driver/Driver.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
@@ -38,48 +41,59 @@ using namespace lld::elf;
Configuration *elf::Config;
LinkerDriver *elf::Driver;
-bool elf::link(ArrayRef<const char *> Args, raw_ostream &Error) {
- HasError = false;
+BumpPtrAllocator elf::BAlloc;
+StringSaver elf::Saver{BAlloc};
+std::vector<SpecificAllocBase *> elf::SpecificAllocBase::Instances;
+
+bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
+ raw_ostream &Error) {
+ ErrorCount = 0;
ErrorOS = &Error;
+ Argv0 = Args[0];
- Configuration C;
- LinkerDriver D;
- ScriptConfiguration SC;
- Config = &C;
- Driver = &D;
- ScriptConfig = &SC;
+ Config = make<Configuration>();
+ Driver = make<LinkerDriver>();
+ ScriptConfig = make<ScriptConfiguration>();
- Driver->main(Args);
- return !HasError;
+ Driver->main(Args, CanExitEarly);
+ freeArena();
+ return !ErrorCount;
}
// Parses a linker -m option.
-static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) {
- if (S.endswith("_fbsd"))
+static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
+ uint8_t OSABI = 0;
+ StringRef S = Emul;
+ if (S.endswith("_fbsd")) {
S = S.drop_back(5);
+ OSABI = ELFOSABI_FREEBSD;
+ }
std::pair<ELFKind, uint16_t> Ret =
StringSwitch<std::pair<ELFKind, uint16_t>>(S)
- .Case("aarch64linux", {ELF64LEKind, EM_AARCH64})
+ .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
.Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.Case("elf32btsmip", {ELF32BEKind, EM_MIPS})
.Case("elf32ltsmip", {ELF32LEKind, EM_MIPS})
+ .Case("elf32btsmipn32", {ELF32BEKind, EM_MIPS})
+ .Case("elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
.Case("elf32ppc", {ELF32BEKind, EM_PPC})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
.Case("elf64ppc", {ELF64BEKind, EM_PPC64})
+ .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
.Case("elf_i386", {ELF32LEKind, EM_386})
- .Case("elf_x86_64", {ELF64LEKind, EM_X86_64})
+ .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})
.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);
+ error("Windows targets are not supported on the ELF frontend: " + Emul);
else
- error("unknown emulation: " + S);
+ error("unknown emulation: " + Emul);
}
- return Ret;
+ return std::make_tuple(Ret.first, Ret.second, OSABI);
}
// Returns slices of MB by parsing MB as an archive file.
@@ -87,25 +101,28 @@ static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) {
std::vector<MemoryBufferRef>
LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
std::unique_ptr<Archive> File =
- check(Archive::create(MB), "failed to parse archive");
+ check(Archive::create(MB),
+ MB.getBufferIdentifier() + ": failed to parse archive");
std::vector<MemoryBufferRef> V;
- Error Err;
+ Error Err = Error::success();
for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
- Archive::Child C = check(COrErr, "could not get the child of the archive " +
- File->getFileName());
+ Archive::Child C =
+ check(COrErr, MB.getBufferIdentifier() +
+ ": could not get the child of the archive");
MemoryBufferRef MBRef =
check(C.getMemoryBufferRef(),
- "could not get the buffer for a child of the archive " +
- File->getFileName());
+ MB.getBufferIdentifier() +
+ ": could not get the buffer for a child of the archive");
V.push_back(MBRef);
}
if (Err)
- Error(Err);
+ fatal(MB.getBufferIdentifier() + ": Archive::children failed: " +
+ toString(std::move(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));
+ make<std::unique_ptr<MemoryBuffer>>(std::move(MB));
return V;
}
@@ -114,25 +131,28 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
// Newly created memory buffers are owned by this driver.
void LinkerDriver::addFile(StringRef Path) {
using namespace sys::fs;
- if (Config->Verbose)
- outs() << Path << "\n";
Optional<MemoryBufferRef> Buffer = readFile(Path);
if (!Buffer.hasValue())
return;
MemoryBufferRef MBRef = *Buffer;
+ if (InBinary) {
+ Files.push_back(make<BinaryFile>(MBRef));
+ return;
+ }
+
switch (identify_magic(MBRef.getBuffer())) {
case file_magic::unknown:
readLinkerScript(MBRef);
return;
case file_magic::archive:
- if (WholeArchive) {
+ if (InWholeArchive) {
for (MemoryBufferRef MB : getArchiveMembers(MBRef))
Files.push_back(createObjectFile(MB, Path));
return;
}
- Files.push_back(make_unique<ArchiveFile>(MBRef));
+ Files.push_back(make<ArchiveFile>(MBRef));
return;
case file_magic::elf_shared_object:
if (Config->Relocatable) {
@@ -143,13 +163,16 @@ void LinkerDriver::addFile(StringRef Path) {
return;
default:
if (InLib)
- Files.push_back(make_unique<LazyObjectFile>(MBRef));
+ Files.push_back(make<LazyObjectFile>(MBRef));
else
Files.push_back(createObjectFile(MBRef));
}
}
Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) {
+ if (Config->Verbose)
+ outs() << Path << "\n";
+
auto MBOrErr = MemoryBuffer::getFile(Path);
if (auto EC = MBOrErr.getError()) {
error(EC, "cannot open " + Path);
@@ -157,7 +180,7 @@ Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) {
}
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
MemoryBufferRef MBRef = MB->getMemBufferRef();
- OwningMBs.push_back(std::move(MB)); // take MB ownership
+ make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
if (Cpio)
Cpio->append(relativeToRoot(Path), MBRef.getBuffer());
@@ -167,11 +190,10 @@ Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) {
// 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);
+ if (Optional<std::string> Path = searchLibrary(Name))
+ addFile(*Path);
else
- addFile(Path);
+ error("unable to find library -l" + Name);
}
// This function is called on startup. We need this for LTO since
@@ -184,12 +206,6 @@ static void initLLVM(opt::InputArgList &Args) {
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)");
@@ -206,9 +222,6 @@ static void checkOptions(opt::InputArgList &Args) {
if (Config->EMachine == EM_MIPS && Config->GnuHash)
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");
@@ -224,8 +237,8 @@ static void checkOptions(opt::InputArgList &Args) {
}
}
-static StringRef
-getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") {
+static StringRef getString(opt::InputArgList &Args, unsigned Key,
+ StringRef Default = "") {
if (auto *Arg = Args.getLastArg(Key))
return Arg->getValue();
return Default;
@@ -254,33 +267,64 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
return false;
}
-void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
+static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key,
+ uint64_t Default) {
+ for (auto *Arg : Args.filtered(OPT_z)) {
+ StringRef Value = Arg->getValue();
+ size_t Pos = Value.find("=");
+ if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) {
+ Value = Value.substr(Pos + 1);
+ uint64_t Result;
+ if (Value.getAsInteger(0, Result))
+ error("invalid " + Key + ": " + Value);
+ return Result;
+ }
+ }
+ return Default;
+}
+
+void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
ELFOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
+
+ // Interpret this flag early because error() depends on them.
+ Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20);
+
+ // Handle -help
if (Args.hasArg(OPT_help)) {
printHelp(ArgsArr[0]);
return;
}
- if (Args.hasArg(OPT_version)) {
- outs() << getVersionString();
+
+ // GNU linkers disagree here. Though both -version and -v are mentioned
+ // in help to print the version information, GNU ld just normally exits,
+ // while gold can continue linking. We are compatible with ld.bfd here.
+ if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v))
+ outs() << getLLDVersion() << "\n";
+ if (Args.hasArg(OPT_version))
return;
- }
+
+ Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown);
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) {
+ ErrorOr<CpioFile *> F = CpioFile::create(Path);
+ if (F) {
+ Cpio.reset(*F);
Cpio->append("response.txt", createResponseFile(Args));
- Cpio->append("version.txt", getVersionString());
- }
+ Cpio->append("version.txt", getLLDVersion() + "\n");
+ } else
+ error(F.getError(),
+ Twine("--reproduce: failed to open ") + Path + ".cpio");
}
readConfigs(Args);
initLLVM(Args);
createFiles(Args);
+ inferMachineType();
checkOptions(Args);
- if (HasError)
+ if (ErrorCount)
return;
switch (Config->EKind) {
@@ -297,7 +341,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
link<ELF64BE>(Args);
return;
default:
- error("-m or at least a .o file required");
+ llvm_unreachable("unknown Config->EKind");
}
}
@@ -314,10 +358,115 @@ static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) {
if (S == "ignore-all" || S == "ignore-in-object-files")
return UnresolvedPolicy::Ignore;
if (S == "ignore-in-shared-libs" || S == "report-all")
- return UnresolvedPolicy::Error;
+ return UnresolvedPolicy::ReportError;
error("unknown --unresolved-symbols value: " + S);
}
- return UnresolvedPolicy::Error;
+ return UnresolvedPolicy::ReportError;
+}
+
+static Target2Policy getTarget2Option(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_target2)) {
+ StringRef S = Arg->getValue();
+ if (S == "rel")
+ return Target2Policy::Rel;
+ if (S == "abs")
+ return Target2Policy::Abs;
+ if (S == "got-rel")
+ return Target2Policy::GotRel;
+ error("unknown --target2 option: " + S);
+ }
+ return Target2Policy::GotRel;
+}
+
+static bool isOutputFormatBinary(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_oformat)) {
+ StringRef S = Arg->getValue();
+ if (S == "binary")
+ return true;
+ error("unknown --oformat value: " + S);
+ }
+ return false;
+}
+
+static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
+ bool Default) {
+ if (auto *Arg = Args.getLastArg(K1, K2))
+ return Arg->getOption().getID() == K1;
+ return Default;
+}
+
+static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
+ if (Config->Relocatable)
+ return DiscardPolicy::None;
+ auto *Arg =
+ Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none);
+ if (!Arg)
+ return DiscardPolicy::Default;
+ if (Arg->getOption().getID() == OPT_discard_all)
+ return DiscardPolicy::All;
+ if (Arg->getOption().getID() == OPT_discard_locals)
+ return DiscardPolicy::Locals;
+ return DiscardPolicy::None;
+}
+
+static StripPolicy getStripOption(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug)) {
+ if (Arg->getOption().getID() == OPT_strip_all)
+ return StripPolicy::All;
+ return StripPolicy::Debug;
+ }
+ return StripPolicy::None;
+}
+
+static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) {
+ uint64_t VA = 0;
+ if (S.startswith("0x"))
+ S = S.drop_front(2);
+ if (S.getAsInteger(16, VA))
+ error("invalid argument: " + stringize(Arg));
+ return VA;
+}
+
+static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) {
+ StringMap<uint64_t> Ret;
+ for (auto *Arg : Args.filtered(OPT_section_start)) {
+ StringRef Name;
+ StringRef Addr;
+ std::tie(Name, Addr) = StringRef(Arg->getValue()).split('=');
+ Ret[Name] = parseSectionAddress(Addr, Arg);
+ }
+
+ if (auto *Arg = Args.getLastArg(OPT_Ttext))
+ Ret[".text"] = parseSectionAddress(Arg->getValue(), Arg);
+ if (auto *Arg = Args.getLastArg(OPT_Tdata))
+ Ret[".data"] = parseSectionAddress(Arg->getValue(), Arg);
+ if (auto *Arg = Args.getLastArg(OPT_Tbss))
+ Ret[".bss"] = parseSectionAddress(Arg->getValue(), Arg);
+ return Ret;
+}
+
+static SortSectionPolicy getSortKind(opt::InputArgList &Args) {
+ StringRef S = getString(Args, OPT_sort_section);
+ if (S == "alignment")
+ return SortSectionPolicy::Alignment;
+ if (S == "name")
+ return SortSectionPolicy::Name;
+ if (!S.empty())
+ error("unknown --sort-section rule: " + S);
+ return SortSectionPolicy::Default;
+}
+
+static std::vector<StringRef> getLines(MemoryBufferRef MB) {
+ SmallVector<StringRef, 0> Arr;
+ MB.getBuffer().split(Arr, '\n');
+
+ std::vector<StringRef> Ret;
+ for (StringRef S : Arr) {
+ S = S.trim();
+ if (!S.empty())
+ Ret.push_back(S);
+ }
+ return Ret;
}
// Initializes Config members by the command line options.
@@ -334,34 +483,37 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_m)) {
// Parse ELF{32,64}{LE,BE} and CPU type.
StringRef S = Arg->getValue();
- std::tie(Config->EKind, Config->EMachine) = parseEmulation(S);
+ std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
+ parseEmulation(S);
+ Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");
Config->Emulation = S;
}
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
- Config->Demangle = !Args.hasArg(OPT_no_demangle);
+ Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
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->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false);
+ Config->GdbIndex = Args.hasArg(OPT_gdb_index);
Config->ICF = Args.hasArg(OPT_icf);
Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
- Config->Pie = Args.hasArg(OPT_pie);
+ Config->Nostdlib = Args.hasArg(OPT_nostdlib);
+ Config->OMagic = Args.hasArg(OPT_omagic);
+ Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false);
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
Config->Relocatable = Args.hasArg(OPT_relocatable);
+ Config->Discard = getDiscardOption(Args);
Config->SaveTemps = Args.hasArg(OPT_save_temps);
+ Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
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->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false);
+ Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true);
Config->Trace = Args.hasArg(OPT_trace);
Config->Verbose = Args.hasArg(OPT_verbose);
Config->WarnCommon = Args.hasArg(OPT_warn_common);
@@ -370,33 +522,47 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
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->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)
+ 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->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
+ if (Config->LTOPartitions == 0)
+ error("--lto-partitions: number of threads must be > 0");
+ Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
+ if (Config->ThinLTOJobs == 0)
+ error("--thinlto-jobs: number of threads must be > 0");
Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
- Config->ZExecStack = hasZOption(Args, "execstack");
+ Config->ZExecstack = hasZOption(Args, "execstack");
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNow = hasZOption(Args, "now");
Config->ZOrigin = hasZOption(Args, "origin");
Config->ZRelro = !hasZOption(Args, "norelro");
+ Config->ZStackSize = getZOptionValue(Args, "stack-size", -1);
+ Config->ZWxneeded = hasZOption(Args, "wxneeded");
- if (Config->Relocatable)
- Config->StripAll = false;
+ Config->OFormatBinary = isOutputFormatBinary(Args);
+ Config->SectionStartMap = getSectionStartMap(Args);
+ Config->SortSection = getSortKind(Args);
+ Config->Target2 = getTarget2Option(Args);
+ Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args);
+
+ // --omagic is an option to create old-fashioned executables in which
+ // .text segments are writable. Today, the option is still in use to
+ // create special-purpose programs such as boot loaders. It doesn't
+ // make sense to create PT_GNU_RELRO for such executables.
+ if (Config->OMagic)
+ Config->ZRelro = false;
- // --strip-all implies --strip-debug.
- if (Config->StripAll)
- Config->StripDebug = true;
+ if (!Config->Relocatable)
+ Config->Strip = getStripOption(Args);
// Config->Pic is true if we are generating position-independent code.
Config->Pic = Config->Pie || Config->Shared;
@@ -414,13 +580,15 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
// Parse --build-id or --build-id=<style>.
if (Args.hasArg(OPT_build_id))
- Config->BuildId = BuildIdKind::Fnv1;
+ Config->BuildId = BuildIdKind::Fast;
if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {
StringRef S = Arg->getValue();
if (S == "md5") {
Config->BuildId = BuildIdKind::Md5;
- } else if (S == "sha1") {
+ } else if (S == "sha1" || S == "tree") {
Config->BuildId = BuildIdKind::Sha1;
+ } else if (S == "uuid") {
+ Config->BuildId = BuildIdKind::Uuid;
} else if (S == "none") {
Config->BuildId = BuildIdKind::None;
} else if (S.startswith("0x")) {
@@ -431,21 +599,58 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
}
}
+ for (auto *Arg : Args.filtered(OPT_auxiliary))
+ Config->AuxiliaryList.push_back(Arg->getValue());
+ if (!Config->Shared && !Config->AuxiliaryList.empty())
+ error("-f may not be used without -shared");
+
for (auto *Arg : Args.filtered(OPT_undefined))
Config->Undefined.push_back(Arg->getValue());
- Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args);
-
if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- parseDynamicList(*Buffer);
+ readDynamicList(*Buffer);
+
+ if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ Config->SymbolOrderingFile = getLines(*Buffer);
+
+ // If --retain-symbol-file is used, we'll retail only the symbols listed in
+ // the file and discard all others.
+ if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) {
+ Config->Discard = DiscardPolicy::RetainFile;
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ for (StringRef S : getLines(*Buffer))
+ Config->RetainSymbolsFile.insert(S);
+ }
for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
- Config->DynamicList.push_back(Arg->getValue());
+ Config->VersionScriptGlobals.push_back(
+ {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
+
+ // Dynamic lists are a simplified linker script that doesn't need the
+ // "global:" and implicitly ends with a "local:*". Set the variables needed to
+ // simulate that.
+ if (Args.hasArg(OPT_dynamic_list) || Args.hasArg(OPT_export_dynamic_symbol)) {
+ Config->ExportDynamic = true;
+ if (!Config->Shared)
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ }
if (auto *Arg = Args.getLastArg(OPT_version_script))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- parseVersionScript(*Buffer);
+ readVersionScript(*Buffer);
+}
+
+// Returns a value of "-format" option.
+static bool getBinaryOption(StringRef S) {
+ if (S == "binary")
+ return true;
+ if (S == "elf" || S == "default")
+ return false;
+ error("unknown -format value: " + S +
+ " (supported formats: elf, default, binary)");
+ return false;
}
void LinkerDriver::createFiles(opt::InputArgList &Args) {
@@ -454,14 +659,20 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
case OPT_l:
addLibrary(Arg->getValue());
break;
- case OPT_alias_script_T:
case OPT_INPUT:
- case OPT_script:
addFile(Arg->getValue());
break;
+ case OPT_alias_script_T:
+ case OPT_script:
+ if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue()))
+ readLinkerScript(*MB);
+ break;
case OPT_as_needed:
Config->AsNeeded = true;
break;
+ case OPT_format:
+ InBinary = getBinaryOption(Arg->getValue());
+ break;
case OPT_no_as_needed:
Config->AsNeeded = false;
break;
@@ -472,10 +683,10 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
Config->Static = false;
break;
case OPT_whole_archive:
- WholeArchive = true;
+ InWholeArchive = true;
break;
case OPT_no_whole_archive:
- WholeArchive = false;
+ InWholeArchive = false;
break;
case OPT_start_lib:
InLib = true;
@@ -486,19 +697,55 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
}
}
- if (Files.empty() && !HasError)
- error("no input files.");
+ if (Files.empty() && ErrorCount == 0)
+ 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;
- }
+// If -m <machine_type> was not given, infer it from object files.
+void LinkerDriver::inferMachineType() {
+ if (Config->EKind != ELFNoneKind)
+ return;
+
+ for (InputFile *F : Files) {
+ if (F->EKind == ELFNoneKind)
+ continue;
+ Config->EKind = F->EKind;
+ Config->EMachine = F->EMachine;
+ Config->OSABI = F->OSABI;
+ Config->MipsN32Abi = Config->EMachine == EM_MIPS && isMipsN32Abi(F);
+ return;
}
+ error("target emulation unknown: -m or at least one .o file required");
+}
+
+// Parse -z max-page-size=<value>. The default value is defined by
+// each target.
+static uint64_t getMaxPageSize(opt::InputArgList &Args) {
+ uint64_t Val =
+ getZOptionValue(Args, "max-page-size", Target->DefaultMaxPageSize);
+ if (!isPowerOf2_64(Val))
+ error("max-page-size: value isn't a power of 2");
+ return Val;
+}
+
+// Parses -image-base option.
+static uint64_t getImageBase(opt::InputArgList &Args) {
+ // Use default if no -image-base option is given.
+ // Because we are using "Target" here, this function
+ // has to be called after the variable is initialized.
+ auto *Arg = Args.getLastArg(OPT_image_base);
+ if (!Arg)
+ return Config->Pic ? 0 : Target->DefaultImageBase;
+
+ StringRef S = Arg->getValue();
+ uint64_t V;
+ if (S.getAsInteger(0, V)) {
+ error("-image-base: number expected, but got " + S);
+ return 0;
+ }
+ if ((V % Config->MaxPageSize) != 0)
+ warn("-image-base: address isn't multiple of page size: " + S);
+ return V;
}
// Do actual linking. Note that when this function is called,
@@ -506,66 +753,70 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
SymbolTable<ELFT> Symtab;
elf::Symtab<ELFT>::X = &Symtab;
+ Target = createTarget();
+ ScriptBase = Script<ELFT>::X = make<LinkerScript<ELFT>>();
- 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->Rela =
+ ELFT::Is64Bits || Config->EMachine == EM_X86_64 || Config->MipsN32Abi;
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";
+ Config->MaxPageSize = getMaxPageSize(Args);
+ Config->ImageBase = getImageBase(Args);
// Default output filename is "a.out" by the Unix tradition.
if (Config->OutputFile.empty())
Config->OutputFile = "a.out";
+ // Use default entry point name if no name was given via the command
+ // line nor linker scripts. For some reason, MIPS entry point name is
+ // different from others.
+ Config->WarnMissingEntry =
+ (!Config->Entry.empty() || (!Config->Shared && !Config->Relocatable));
+ if (Config->Entry.empty() && !Config->Relocatable)
+ Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start";
+
// 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()) {
- StringRef S = Config->Entry;
- if (S.getAsInteger(0, Config->EntryAddr))
- Config->EntrySym = Symtab.addUndefined(S);
- }
+ // Add all files to the symbol table. This will add almost all
+ // symbols that we need to the symbol table.
+ for (InputFile *F : Files)
+ Symtab.addFile(F);
- // 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;
- }
+ // If an entry symbol is in a static archive, pull out that file now
+ // to complete the symbol table. After this, no new names except a
+ // few linker-synthesized ones will be added to the symbol table.
+ if (Symtab.find(Config->Entry))
+ Symtab.addUndefined(Config->Entry);
- for (std::unique_ptr<InputFile> &F : Files)
- Symtab.addFile(std::move(F));
- if (HasError)
- return; // There were duplicate symbols or incompatible files
+ // Return if there were name resolution errors.
+ if (ErrorCount)
+ return;
Symtab.scanUndefinedFlags();
Symtab.scanShlibUndefined();
- Symtab.scanDynamicList();
Symtab.scanVersionScript();
- Symtab.scanSymbolVersions();
- Symtab.addCombinedLtoObject();
- if (HasError)
+ Symtab.addCombinedLTOObject();
+ if (ErrorCount)
return;
for (auto *Arg : Args.filtered(OPT_wrap))
Symtab.wrap(Arg->getValue());
- // Write the result to the file.
+ // Now that we have a complete list of input files.
+ // Beyond this point, no new files are added.
+ // Aggregate all input sections into one place.
+ for (elf::ObjectFile<ELFT> *F : Symtab.getObjectFiles())
+ for (InputSectionBase<ELFT> *S : F->getSections())
+ if (S && S != &InputSection<ELFT>::Discarded)
+ Symtab.Sections.push_back(S);
+ for (BinaryFile *F : Symtab.getBinaryFiles())
+ for (InputSectionData *S : F->getSections())
+ Symtab.Sections.push_back(cast<InputSection<ELFT>>(S));
+
+ // Do size optimizations: garbage collection and identical code folding.
if (Config->GcSections)
markLive<ELFT>();
if (Config->ICF)
@@ -573,16 +824,16 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// 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();
- }
+ forEach(Symtab.Sections.begin(), Symtab.Sections.end(),
+ [](InputSectionBase<ELFT> *S) {
+ if (!S->Live)
+ return;
+ if (S->isCompressed())
+ S->uncompress();
+ if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S))
+ MS->splitIntoPieces();
+ });
- writeResult<ELFT>(&Symtab);
+ // Write the result to the file.
+ writeResult<ELFT>();
}
diff --git a/ELF/Driver.h b/ELF/Driver.h
index 6b9b9bb208e5..cba1eb164fdd 100644
--- a/ELF/Driver.h
+++ b/ELF/Driver.h
@@ -12,6 +12,7 @@
#include "SymbolTable.h"
#include "lld/Core/LLVM.h"
+#include "lld/Core/Reproduce.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
@@ -23,14 +24,11 @@ namespace elf {
extern class LinkerDriver *Driver;
-class CpioFile;
-
class LinkerDriver {
public:
- void main(ArrayRef<const char *> Args);
+ void main(ArrayRef<const char *> Args, bool CanExitEarly);
void addFile(StringRef Path);
void addLibrary(StringRef Name);
- llvm::LLVMContext Context; // to parse bitcode ifles
std::unique_ptr<CpioFile> Cpio; // for reproduce
private:
@@ -38,17 +36,19 @@ private:
llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
void readConfigs(llvm::opt::InputArgList &Args);
void createFiles(llvm::opt::InputArgList &Args);
+ void inferMachineType();
template <class ELFT> void link(llvm::opt::InputArgList &Args);
// True if we are in --whole-archive and --no-whole-archive.
- bool WholeArchive = false;
+ bool InWholeArchive = 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;
+ // True if we are in -format=binary and -format=elf.
+ bool InBinary = false;
+
+ std::vector<InputFile *> Files;
};
// Parses command line options.
@@ -56,9 +56,6 @@ 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
@@ -69,41 +66,13 @@ enum {
#undef OPTION
};
-// 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);
+llvm::Optional<std::string> findFromSearchPaths(StringRef Path);
+llvm::Optional<std::string> searchLibrary(StringRef Path);
} // namespace elf
} // namespace lld
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
index 3f18259b4ae7..a81b133f674b 100644
--- a/ELF/DriverUtils.cpp
+++ b/ELF/DriverUtils.cpp
@@ -15,14 +15,18 @@
#include "Driver.h"
#include "Error.h"
+#include "Memory.h"
+#include "ScriptParser.h"
#include "lld/Config/Version.h"
+#include "lld/Core/Reproduce.h"
+#include "llvm/ADT/Optional.h"
#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"
+#include "llvm/Support/Process.h"
using namespace llvm;
using namespace llvm::sys;
@@ -40,16 +44,37 @@ using namespace lld::elf;
// Create table mapping all options defined in Options.td
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 \
- },
+ {X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, \
+ X8, X7, OPT_##GROUP, OPT_##ALIAS, X6},
#include "Options.inc"
#undef OPTION
};
ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
+// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics.
+static bool getColorDiagnostics(opt::InputArgList &Args) {
+ bool Default = (ErrorOS == &errs() && Process::StandardErrHasColors());
+
+ auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+ OPT_no_color_diagnostics);
+ if (!Arg)
+ return Default;
+ if (Arg->getOption().getID() == OPT_color_diagnostics)
+ return true;
+ if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+ return false;
+
+ StringRef S = Arg->getValue();
+ if (S == "auto")
+ return Default;
+ if (S == "always")
+ return true;
+ if (S != "never")
+ error("unknown option: -color-diagnostics=" + S);
+ return false;
+}
+
static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
StringRef S = Arg->getValue();
@@ -76,16 +101,16 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// --rsp-quoting.
opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
- // Expand response files. '@<filename>' is replaced by the file's contents.
- StringSaver Saver(Alloc);
+ // Expand response files (arguments in the form of @<filename>)
+ // and then parse the argument again.
cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
-
- // Parse options and then do error checking.
Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+
+ // Interpret -color-diagnostics early so that error messages
+ // for unknown flags are colored.
+ Config->ColorDiagnostics = getColorDiagnostics(Args);
if (MissingCount)
- error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) +
- "\", expected " + Twine(MissingCount) +
- (MissingCount == 1 ? " argument.\n" : " arguments"));
+ error(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
error("unknown argument: " + Arg->getSpelling());
@@ -97,115 +122,6 @@ void elf::printHelp(const char *Argv0) {
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) {
@@ -226,8 +142,8 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) {
case OPT_alias_script_T:
case OPT_script:
case OPT_version_script:
- OS << Arg->getSpelling() << " "
- << quote(rewritePath(Arg->getValue())) << "\n";
+ OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue()))
+ << "\n";
break;
default:
OS << stringize(Arg) << "\n";
@@ -236,41 +152,39 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) {
return Data.str();
}
-std::string elf::findFromSearchPaths(StringRef Path) {
- for (StringRef Dir : Config->SearchPaths) {
- std::string FullPath = buildSysrootedPath(Dir, Path);
- if (fs::exists(FullPath))
- return FullPath;
- }
- return "";
+// Find a file by concatenating given paths. If a resulting path
+// starts with "=", the character is replaced with a --sysroot value.
+static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
+ SmallString<128> S;
+ if (Path1.startswith("="))
+ path::append(S, Config->Sysroot, Path1.substr(1), Path2);
+ else
+ path::append(S, Path1, Path2);
+
+ if (fs::exists(S))
+ return S.str().str();
+ return None;
+}
+
+Optional<std::string> elf::findFromSearchPaths(StringRef Path) {
+ for (StringRef Dir : Config->SearchPaths)
+ if (Optional<std::string> S = findFile(Dir, Path))
+ return S;
+ return None;
}
-// 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 elf::searchLibrary(StringRef Path) {
- if (Path.startswith(":"))
- return findFromSearchPaths(Path.substr(1));
+// This is for -lfoo. We'll look for libfoo.so or libfoo.a from
+// search paths.
+Optional<std::string> elf::searchLibrary(StringRef Name) {
+ if (Name.startswith(":"))
+ return findFromSearchPaths(Name.substr(1));
+
for (StringRef Dir : Config->SearchPaths) {
- if (!Config->Static) {
- std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".so").str());
- if (fs::exists(S))
+ if (!Config->Static)
+ if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".so"))
return S;
- }
- std::string S = buildSysrootedPath(Dir, ("lib" + Path + ".a").str());
- if (fs::exists(S))
+ if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
return S;
}
- 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 elf::buildSysrootedPath(StringRef Dir, StringRef File) {
- SmallString<128> Path;
- if (Dir.startswith("="))
- path::append(Path, Config->Sysroot, Dir.substr(1), File);
- else
- path::append(Path, Dir, File);
- return Path.str();
+ return None;
}
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
index b130ac1ca22d..2428473d9012 100644
--- a/ELF/EhFrame.cpp
+++ b/ELF/EhFrame.cpp
@@ -18,6 +18,9 @@
#include "EhFrame.h"
#include "Error.h"
+#include "InputSection.h"
+#include "Relocations.h"
+#include "Strings.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Dwarf.h"
@@ -29,49 +32,93 @@ using namespace llvm::dwarf;
using namespace llvm::object;
using namespace llvm::support::endian;
-namespace lld {
-namespace elf {
+using namespace lld;
+using namespace lld::elf;
+namespace {
+template <class ELFT> class EhReader {
+public:
+ EhReader(InputSectionBase<ELFT> *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
+ size_t readEhRecordSize();
+ uint8_t getFdeEncoding();
+
+private:
+ template <class P> void failOn(const P *Loc, const Twine &Msg) {
+ fatal(IS->getLocation((const uint8_t *)Loc - IS->Data.data()) + ": " + Msg);
+ }
+
+ uint8_t readByte();
+ void skipBytes(size_t Count);
+ StringRef readString();
+ void skipLeb128();
+ void skipAugP();
+
+ InputSectionBase<ELFT> *IS;
+ ArrayRef<uint8_t> D;
+};
+}
+
+template <class ELFT>
+size_t elf::readEhRecordSize(InputSectionBase<ELFT> *S, size_t Off) {
+ return EhReader<ELFT>(S, S->Data.slice(Off)).readEhRecordSize();
+}
// .eh_frame section is a sequence of records. Each record starts with
// a 4 byte length field. This function reads the length.
-template <class ELFT> size_t readEhRecordSize(ArrayRef<uint8_t> D) {
+template <class ELFT> size_t EhReader<ELFT>::readEhRecordSize() {
const endianness E = ELFT::TargetEndianness;
if (D.size() < 4)
- fatal("CIE/FDE too small");
+ failOn(D.data(), "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");
+ failOn(D.data(), "CIE/FDE too large");
uint64_t Size = V + 4;
if (Size > D.size())
- fatal("CIE/FIE ends past the end of the section");
+ failOn(D.data(), "CIE/FDE 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) {
+template <class ELFT> uint8_t EhReader<ELFT>::readByte() {
if (D.empty())
- fatal("corrupted or unsupported CIE information");
+ failOn(D.data(), "unexpected end of CIE");
uint8_t B = D.front();
D = D.slice(1);
return B;
}
+template <class ELFT> void EhReader<ELFT>::skipBytes(size_t Count) {
+ if (D.size() < Count)
+ failOn(D.data(), "CIE is too small");
+ D = D.slice(Count);
+}
+
+// Read a null-terminated string.
+template <class ELFT> StringRef EhReader<ELFT>::readString() {
+ const uint8_t *End = std::find(D.begin(), D.end(), '\0');
+ if (End == D.end())
+ failOn(D.data(), "corrupted CIE (failed to read string)");
+ StringRef S = toStringRef(D.slice(0, End - D.begin()));
+ D = D.slice(S.size() + 1);
+ return S;
+}
+
// 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) {
+template <class ELFT> void EhReader<ELFT>::skipLeb128() {
+ const uint8_t *ErrPos = D.data();
while (!D.empty()) {
uint8_t Val = D.front();
D = D.slice(1);
if ((Val & 0x80) == 0)
return;
}
- fatal("corrupted or unsupported CIE information");
+ failOn(ErrPos, "corrupted CIE (failed to read LEB128)");
}
template <class ELFT> static size_t getAugPSize(unsigned Enc) {
@@ -89,79 +136,79 @@ template <class ELFT> static size_t getAugPSize(unsigned Enc) {
case DW_EH_PE_sdata8:
return 8;
}
- fatal("unknown FDE encoding");
+ return 0;
}
-template <class ELFT> static void skipAugP(ArrayRef<uint8_t> &D) {
- uint8_t Enc = readByte(D);
+template <class ELFT> void EhReader<ELFT>::skipAugP() {
+ uint8_t Enc = readByte();
if ((Enc & 0xf0) == DW_EH_PE_aligned)
- fatal("DW_EH_PE_aligned encoding is not supported");
+ failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported");
size_t Size = getAugPSize<ELFT>(Enc);
+ if (Size == 0)
+ failOn(D.data() - 1, "unknown FDE encoding");
if (Size >= D.size())
- fatal("corrupted CIE");
+ failOn(D.data() - 1, "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);
+template <class ELFT> uint8_t elf::getFdeEncoding(EhSectionPiece *P) {
+ auto *IS = static_cast<InputSectionBase<ELFT> *>(P->ID);
+ return EhReader<ELFT>(IS, P->data()).getFdeEncoding();
+}
- uint8_t Version = readByte(D);
+template <class ELFT> uint8_t EhReader<ELFT>::getFdeEncoding() {
+ skipBytes(8);
+ int Version = readByte();
if (Version != 1 && Version != 3)
- fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version));
+ failOn(D.data() - 1,
+ "FDE version 1 or 3 expected, but got " + Twine(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);
+ StringRef Aug = readString();
- // 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 code and data alignment factors.
+ skipLeb128();
+ skipLeb128();
// 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);
+ readByte();
else
- skipLeb128(D);
+ skipLeb128();
// 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);
+ return readByte();
if (C == 'z') {
- skipLeb128(D);
+ skipLeb128();
continue;
}
if (C == 'P') {
- skipAugP<ELFT>(D);
+ skipAugP();
continue;
}
if (C == 'L') {
- readByte(D);
+ readByte();
continue;
}
- fatal("unknown .eh_frame augmentation string: " + Aug);
+ failOn(Aug.data(), "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>);
-}
-}
+template size_t elf::readEhRecordSize<ELF32LE>(InputSectionBase<ELF32LE> *S,
+ size_t Off);
+template size_t elf::readEhRecordSize<ELF32BE>(InputSectionBase<ELF32BE> *S,
+ size_t Off);
+template size_t elf::readEhRecordSize<ELF64LE>(InputSectionBase<ELF64LE> *S,
+ size_t Off);
+template size_t elf::readEhRecordSize<ELF64BE>(InputSectionBase<ELF64BE> *S,
+ size_t Off);
+
+template uint8_t elf::getFdeEncoding<ELF32LE>(EhSectionPiece *P);
+template uint8_t elf::getFdeEncoding<ELF32BE>(EhSectionPiece *P);
+template uint8_t elf::getFdeEncoding<ELF64LE>(EhSectionPiece *P);
+template uint8_t elf::getFdeEncoding<ELF64BE>(EhSectionPiece *P);
diff --git a/ELF/EhFrame.h b/ELF/EhFrame.h
index 0d5a2ff2f417..cadc93d3a2e4 100644
--- a/ELF/EhFrame.h
+++ b/ELF/EhFrame.h
@@ -14,8 +14,12 @@
namespace lld {
namespace elf {
-template <class ELFT> size_t readEhRecordSize(ArrayRef<uint8_t> Data);
-template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> Data);
+template <class ELFT> class InputSectionBase;
+struct EhSectionPiece;
+
+template <class ELFT>
+size_t readEhRecordSize(InputSectionBase<ELFT> *S, size_t Off);
+template <class ELFT> uint8_t getFdeEncoding(EhSectionPiece *P);
}
}
diff --git a/ELF/Error.cpp b/ELF/Error.cpp
index 59a49c17b97c..6e30f08143ed 100644
--- a/ELF/Error.cpp
+++ b/ELF/Error.cpp
@@ -12,54 +12,95 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
+#include <mutex>
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#endif
+
+using namespace lld::elf;
using namespace llvm;
namespace lld {
-namespace elf {
-bool HasError;
-raw_ostream *ErrorOS;
+uint64_t elf::ErrorCount;
+raw_ostream *elf::ErrorOS;
+StringRef elf::Argv0;
+
+// The functions defined in this file can be called from multiple threads,
+// but outs() or errs() are not thread-safe. We protect them using a mutex.
+static std::mutex Mu;
+
+static void print(StringRef S, raw_ostream::Colors C) {
+ *ErrorOS << Argv0 + ": ";
+ if (Config->ColorDiagnostics) {
+ ErrorOS->changeColor(C, true);
+ *ErrorOS << S;
+ ErrorOS->resetColor();
+ } else {
+ *ErrorOS << S;
+ }
+}
-void log(const Twine &Msg) {
+void elf::log(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
if (Config->Verbose)
- outs() << Msg << "\n";
+ outs() << Argv0 << ": " << Msg << "\n";
}
-void warning(const Twine &Msg) {
- if (Config->FatalWarnings)
+void elf::warn(const Twine &Msg) {
+ if (Config->FatalWarnings) {
error(Msg);
- else
- *ErrorOS << Msg << "\n";
+ return;
+ }
+ std::lock_guard<std::mutex> Lock(Mu);
+ print("warning: ", raw_ostream::MAGENTA);
+ *ErrorOS << Msg << "\n";
}
-void error(const Twine &Msg) {
- *ErrorOS << Msg << "\n";
- HasError = true;
+void elf::error(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+
+ if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << Msg << "\n";
+ } else if (ErrorCount == Config->ErrorLimit) {
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << "too many errors emitted, stopping now"
+ << " (use -error-limit=0 to see all errors)\n";
+ if (Config->ExitEarly)
+ exitLld(1);
+ }
+
+ ++ErrorCount;
}
-void error(std::error_code EC, const Twine &Prefix) {
+void elf::error(std::error_code EC, const Twine &Prefix) {
error(Prefix + ": " + EC.message());
}
-void fatal(const Twine &Msg) {
- *ErrorOS << Msg << "\n";
- exit(1);
-}
+void elf::exitLld(int Val) {
+ // Dealloc/destroy ManagedStatic variables before calling
+ // _exit(). In a non-LTO build, this is a nop. In an LTO
+ // build allows us to get the output of -time-passes.
+ llvm_shutdown();
-void fatal(const Twine &Msg, const Twine &Prefix) {
- fatal(Prefix + ": " + Msg);
+ outs().flush();
+ errs().flush();
+ _exit(Val);
}
-void check(std::error_code EC) {
- if (EC)
- fatal(EC.message());
+void elf::fatal(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << Msg << "\n";
+ exitLld(1);
}
-void check(Error Err) {
- check(errorToErrorCode(std::move(Err)));
+void elf::fatal(std::error_code EC, const Twine &Prefix) {
+ fatal(Prefix + ": " + EC.message());
}
-} // namespace elf
} // namespace lld
diff --git a/ELF/Error.h b/ELF/Error.h
index 552f50498464..1ec683595cf4 100644
--- a/ELF/Error.h
+++ b/ELF/Error.h
@@ -6,31 +6,47 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+//
+// In LLD, we have three levels of errors: fatal, error or warn.
+//
+// Fatal makes the program exit immediately with an error message.
+// You shouldn't use it except for reporting a corrupted input file.
+//
+// Error prints out an error message and increment a global variable
+// ErrorCount to record the fact that we met an error condition. It does
+// not exit, so it is safe for a lld-as-a-library use case. It is generally
+// useful because it can report more than one errors in a single run.
+//
+// Warn doesn't do anything but printing out a given message.
+//
+//===----------------------------------------------------------------------===//
-#ifndef LLD_COFF_ERROR_H
-#define LLD_COFF_ERROR_H
+#ifndef LLD_ELF_ERROR_H
+#define LLD_ELF_ERROR_H
#include "lld/Core/LLVM.h"
+#include "llvm/Support/Error.h"
+
namespace lld {
namespace elf {
-extern bool HasError;
+extern uint64_t ErrorCount;
extern llvm::raw_ostream *ErrorOS;
+extern llvm::StringRef Argv0;
void log(const Twine &Msg);
-void warning(const Twine &Msg);
+void warn(const Twine &Msg);
void error(const Twine &Msg);
void error(std::error_code EC, const Twine &Prefix);
-template <typename T> void error(const ErrorOr<T> &V, const Twine &Prefix) {
- error(V.getError(), Prefix);
-}
-
+LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
-LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg, const Twine &Prefix);
+LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
+// check() functions are convenient functions to strip errors
+// from error-or-value objects.
template <class T> T check(ErrorOr<T> E) {
if (auto EC = E.getError())
fatal(EC.message());
@@ -39,19 +55,23 @@ template <class T> T check(ErrorOr<T> E) {
template <class T> T check(Expected<T> E) {
if (!E)
- fatal(errorToErrorCode(E.takeError()).message());
+ handleAllErrors(std::move(E.takeError()),
+ [](llvm::ErrorInfoBase &EIB) -> Error {
+ fatal(EIB.message());
+ return Error::success();
+ });
return std::move(*E);
}
template <class T> T check(ErrorOr<T> E, const Twine &Prefix) {
if (auto EC = E.getError())
- fatal(EC.message(), Prefix);
+ fatal(Prefix + ": " + EC.message());
return std::move(*E);
}
template <class T> T check(Expected<T> E, const Twine &Prefix) {
if (!E)
- fatal(errorToErrorCode(E.takeError()).message(), Prefix);
+ fatal(Prefix + ": " + errorToErrorCode(E.takeError()).message());
return std::move(*E);
}
diff --git a/ELF/GdbIndex.cpp b/ELF/GdbIndex.cpp
new file mode 100644
index 000000000000..762144dd0a96
--- /dev/null
+++ b/ELF/GdbIndex.cpp
@@ -0,0 +1,205 @@
+//===- GdbIndex.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// File contains classes for implementation of --gdb-index command line option.
+//
+// If that option is used, linker should emit a .gdb_index section that allows
+// debugger to locate and read .dwo files, containing neccessary debug
+// information.
+// More information about implementation can be found in DWARF specification,
+// latest version is available at http://dwarfstd.org.
+//
+// .gdb_index section format:
+// (Information is based on/taken from
+// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html (*))
+//
+// A mapped index consists of several areas, laid out in order:
+// 1) The file header.
+// 2) "The CU (compilation unit) list. This is a sequence of pairs of 64-bit
+// little-endian values, sorted by the CU offset. The first element in each
+// pair is the offset of a CU in the .debug_info section. The second element
+// in each pair is the length of that CU. References to a CU elsewhere in the
+// map are done using a CU index, which is just the 0-based index into this
+// table. Note that if there are type CUs, then conceptually CUs and type CUs
+// form a single list for the purposes of CU indices."(*)
+// 3) The types CU list. Depricated as .debug_types does not appear in the DWARF
+// v5 specification.
+// 4) The address area. The address area is a sequence of address
+// entries, where each entrie contains low address, high address and CU
+// index.
+// 5) "The symbol table. This is an open-addressed hash table. The size of the
+// hash table is always a power of 2. Each slot in the hash table consists of
+// a pair of offset_type values. The first value is the offset of the
+// symbol's name in the constant pool. The second value is the offset of the
+// CU vector in the constant pool."(*)
+// 6) "The constant pool. This is simply a bunch of bytes. It is organized so
+// that alignment is correct: CU vectors are stored first, followed by
+// strings." (*)
+//
+// For constructing the .gdb_index section following steps should be performed:
+// 1) For file header nothing special should be done. It contains the offsets to
+// the areas below.
+// 2) Scan the compilation unit headers of the .debug_info sections to build a
+// list of compilation units.
+// 3) CU Types are no longer needed as DWARF skeleton type units never made it
+// into the standard. lld does nothing to support parsing of .debug_types
+// and generates empty types CU area in .gdb_index section.
+// 4) Address area entries are extracted from DW_TAG_compile_unit DIEs of
+// .debug_info sections.
+// 5) For building the symbol table linker extracts the public names from the
+// .debug_gnu_pubnames and .debug_gnu_pubtypes sections. Then it builds the
+// hashtable in according to .gdb_index format specification.
+// 6) Constant pool is populated at the same time as symbol table.
+//===----------------------------------------------------------------------===//
+
+#include "GdbIndex.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/Object/ELFObjectFile.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace lld::elf;
+
+template <class ELFT>
+GdbIndexBuilder<ELFT>::GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec)
+ : DebugInfoSec(DebugInfoSec) {
+ if (Expected<std::unique_ptr<object::ObjectFile>> Obj =
+ object::ObjectFile::createObjectFile(DebugInfoSec->getFile()->MB))
+ Dwarf.reset(new DWARFContextInMemory(*Obj.get(), this));
+ else
+ error(toString(DebugInfoSec->getFile()) + ": error creating DWARF context");
+}
+
+template <class ELFT>
+std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>>
+GdbIndexBuilder<ELFT>::readCUList() {
+ std::vector<std::pair<uintX_t, uintX_t>> Ret;
+ for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units())
+ Ret.push_back(
+ {DebugInfoSec->OutSecOff + CU->getOffset(), CU->getLength() + 4});
+ return Ret;
+}
+
+template <class ELFT>
+std::vector<std::pair<StringRef, uint8_t>>
+GdbIndexBuilder<ELFT>::readPubNamesAndTypes() {
+ const bool IsLE = ELFT::TargetEndianness == llvm::support::little;
+ StringRef Data[] = {Dwarf->getGnuPubNamesSection(),
+ Dwarf->getGnuPubTypesSection()};
+
+ std::vector<std::pair<StringRef, uint8_t>> Ret;
+ for (StringRef D : Data) {
+ DWARFDebugPubTable PubTable(D, IsLE, true);
+ for (const DWARFDebugPubTable::Set &S : PubTable.getData())
+ for (const DWARFDebugPubTable::Entry &E : S.Entries)
+ Ret.push_back({E.Name, E.Descriptor.toBits()});
+ }
+ return Ret;
+}
+
+std::pair<bool, GdbSymbol *> GdbHashTab::add(uint32_t Hash, size_t Offset) {
+ if (Size * 4 / 3 >= Table.size())
+ expand();
+
+ GdbSymbol **Slot = findSlot(Hash, Offset);
+ bool New = false;
+ if (*Slot == nullptr) {
+ ++Size;
+ *Slot = new (Alloc) GdbSymbol(Hash, Offset);
+ New = true;
+ }
+ return {New, *Slot};
+}
+
+void GdbHashTab::expand() {
+ if (Table.empty()) {
+ Table.resize(InitialSize);
+ return;
+ }
+ std::vector<GdbSymbol *> NewTable(Table.size() * 2);
+ NewTable.swap(Table);
+
+ for (GdbSymbol *Sym : NewTable) {
+ if (!Sym)
+ continue;
+ GdbSymbol **Slot = findSlot(Sym->NameHash, Sym->NameOffset);
+ *Slot = Sym;
+ }
+}
+
+// Methods finds a slot for symbol with given hash. The step size used to find
+// the next candidate slot when handling a hash collision is specified in
+// .gdb_index section format. The hash value for a table entry is computed by
+// applying an iterative hash function to the symbol's name.
+GdbSymbol **GdbHashTab::findSlot(uint32_t Hash, size_t Offset) {
+ uint32_t Index = Hash & (Table.size() - 1);
+ uint32_t Step = ((Hash * 17) & (Table.size() - 1)) | 1;
+
+ for (;;) {
+ GdbSymbol *S = Table[Index];
+ if (!S || ((S->NameOffset == Offset) && (S->NameHash == Hash)))
+ return &Table[Index];
+ Index = (Index + Step) & (Table.size() - 1);
+ }
+}
+
+template <class ELFT>
+static InputSectionBase<ELFT> *
+findSection(ArrayRef<InputSectionBase<ELFT> *> Arr, uint64_t Offset) {
+ for (InputSectionBase<ELFT> *S : Arr)
+ if (S && S != &InputSection<ELFT>::Discarded)
+ if (Offset >= S->Offset && Offset < S->Offset + S->getSize())
+ return S;
+ return nullptr;
+}
+
+template <class ELFT>
+std::vector<AddressEntry<ELFT>>
+GdbIndexBuilder<ELFT>::readAddressArea(size_t CurrentCU) {
+ std::vector<AddressEntry<ELFT>> Ret;
+ for (const auto &CU : Dwarf->compile_units()) {
+ DWARFAddressRangesVector Ranges;
+ CU->collectAddressRanges(Ranges);
+
+ ArrayRef<InputSectionBase<ELFT> *> Sections =
+ DebugInfoSec->getFile()->getSections();
+
+ for (std::pair<uint64_t, uint64_t> &R : Ranges)
+ if (InputSectionBase<ELFT> *S = findSection(Sections, R.first))
+ Ret.push_back(
+ {S, R.first - S->Offset, R.second - S->Offset, CurrentCU});
+ ++CurrentCU;
+ }
+ return Ret;
+}
+
+// We return file offset as load address for allocatable sections. That is
+// currently used for collecting address ranges in readAddressArea(). We are
+// able then to find section index that range belongs to.
+template <class ELFT>
+uint64_t GdbIndexBuilder<ELFT>::getSectionLoadAddress(
+ const object::SectionRef &Sec) const {
+ if (static_cast<const ELFSectionRef &>(Sec).getFlags() & ELF::SHF_ALLOC)
+ return static_cast<const ELFSectionRef &>(Sec).getOffset();
+ return 0;
+}
+
+template <class ELFT>
+std::unique_ptr<LoadedObjectInfo> GdbIndexBuilder<ELFT>::clone() const {
+ return {};
+}
+
+namespace lld {
+namespace elf {
+template class GdbIndexBuilder<ELF32LE>;
+template class GdbIndexBuilder<ELF32BE>;
+template class GdbIndexBuilder<ELF64LE>;
+template class GdbIndexBuilder<ELF64BE>;
+}
+}
diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h
new file mode 100644
index 000000000000..c761ea173a8d
--- /dev/null
+++ b/ELF/GdbIndex.h
@@ -0,0 +1,99 @@
+//===- GdbIndex.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_GDB_INDEX_H
+#define LLD_ELF_GDB_INDEX_H
+
+#include "InputFiles.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class InputSection;
+
+// Struct represents single entry of address area of gdb index.
+template <class ELFT> struct AddressEntry {
+ InputSectionBase<ELFT> *Section;
+ uint64_t LowAddress;
+ uint64_t HighAddress;
+ size_t CuIndex;
+};
+
+// GdbIndexBuilder is a helper class used for extracting data required
+// for building .gdb_index section from objects.
+template <class ELFT> class GdbIndexBuilder : public llvm::LoadedObjectInfo {
+ typedef typename ELFT::uint uintX_t;
+
+ InputSection<ELFT> *DebugInfoSec;
+
+ std::unique_ptr<llvm::DWARFContext> Dwarf;
+
+public:
+ GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec);
+
+ // Extracts the compilation units. Each first element of pair is a offset of a
+ // CU in the .debug_info section and second is the length of that CU.
+ std::vector<std::pair<uintX_t, uintX_t>> readCUList();
+
+ // Extracts the vector of address area entries. Accepts global index of last
+ // parsed CU.
+ std::vector<AddressEntry<ELFT>> readAddressArea(size_t CurrentCU);
+
+ // Method extracts public names and types. It returns list of name and
+ // gnu_pub* kind pairs.
+ std::vector<std::pair<StringRef, uint8_t>> readPubNamesAndTypes();
+
+private:
+ // Method returns section file offset as a load addres for DWARF parser. That
+ // allows to find the target section index for address ranges.
+ uint64_t
+ getSectionLoadAddress(const llvm::object::SectionRef &Sec) const override;
+ std::unique_ptr<llvm::LoadedObjectInfo> clone() const override;
+};
+
+// Element of GdbHashTab hash table.
+struct GdbSymbol {
+ GdbSymbol(uint32_t Hash, size_t Offset)
+ : NameHash(Hash), NameOffset(Offset) {}
+ uint32_t NameHash;
+ size_t NameOffset;
+ size_t CuVectorIndex;
+};
+
+// This class manages the hashed symbol table for the .gdb_index section.
+// The hash value for a table entry is computed by applying an iterative hash
+// function to the symbol's name.
+class GdbHashTab final {
+public:
+ std::pair<bool, GdbSymbol *> add(uint32_t Hash, size_t Offset);
+
+ size_t getCapacity() { return Table.size(); }
+ GdbSymbol *getSymbol(size_t I) { return Table[I]; }
+
+private:
+ void expand();
+
+ GdbSymbol **findSlot(uint32_t Hash, size_t Offset);
+
+ llvm::BumpPtrAllocator Alloc;
+ std::vector<GdbSymbol *> Table;
+
+ // Size keeps the amount of filled entries in Table.
+ size_t Size = 0;
+
+ // Initial size must be a power of 2.
+ static const int32_t InitialSize = 1024;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index 10a2603b3b3e..32cd0f8a185c 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -7,63 +7,82 @@
//
//===----------------------------------------------------------------------===//
//
-// 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 short for Identical Code Folding. This is a size optimization to
+// identify and merge two or more read-only sections (typically functions)
+// that happened to have the same contents. It usually reduces output size
+// by a few percent.
//
-// 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.
+// In ICF, two sections are considered identical if they have the same
+// section flags, section data, and relocations. Relocations are tricky,
+// because two relocations are considered the same if they have the same
+// relocation types, values, and if they point to the same sections *in
+// terms of ICF*.
//
-// What we do in this file is this. We split sections into groups. Sections
-// in the same group are considered identical.
+// Here is an example. If foo and bar defined below are compiled to the
+// same machine instructions, ICF can and should merge the two, although
+// their relocations point to each other.
//
-// 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.
+// void foo() { bar(); }
+// void bar() { foo(); }
//
-// 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.
+// If you merge the two, their relocations point to the same section and
+// thus you know they are mergeable, but how do you know they are
+// mergeable in the first place? This is not an easy problem to solve.
//
-// 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.)
+// What we are doing in LLD is to partition sections into equivalence
+// classes. Sections in the same equivalence class when the algorithm
+// terminates are considered identical. Here are details:
//
-// Our algorithm is smart enough to merge the following mutually-recursive
-// functions.
+// 1. First, we partition sections using their hash values as keys. Hash
+// values contain section types, section contents and numbers of
+// relocations. During this step, relocation targets are not taken into
+// account. We just put sections that apparently differ into different
+// equivalence classes.
//
-// void foo() { bar(); }
-// void bar() { foo(); }
+// 2. Next, for each equivalence class, we visit sections to compare
+// relocation targets. Relocation targets are considered equivalent if
+// their targets are in the same equivalence class. Sections with
+// different relocation targets are put into different equivalence
+// clases.
+//
+// 3. If we split an equivalence class in step 2, two relocations
+// previously target the same equivalence class may now target
+// different equivalence classes. Therefore, we repeat step 2 until a
+// convergence is obtained.
+//
+// 4. For each equivalence class C, pick an arbitrary section in C, and
+// merge all the other sections in C with it.
+//
+// For small programs, this algorithm needs 3-5 iterations. For large
+// programs such as Chromium, it takes more than 20 iterations.
+//
+// This algorithm was mentioned as an "optimistic algorithm" in [1],
+// though gold implements a different algorithm than this.
+//
+// We parallelize each step so that multiple threads can work on different
+// equivalence classes concurrently. That gave us a large performance
+// boost when applying ICF on large programs. For example, MSVC link.exe
+// or GNU gold takes 10-20 seconds to apply ICF on Chromium, whose output
+// size is about 1.5 GB, but LLD can finish it in less than 2 seconds on a
+// 2.8 GHz 40 core machine. Even without threading, LLD's ICF is still
+// faster than MSVC or gold though.
//
-// 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.)
+// [1] Safe ICF: Pointer Safe and Unwinding aware Identical Code Folding
+// in the Gold Linker
+// http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36912.pdf
//
//===----------------------------------------------------------------------===//
#include "ICF.h"
#include "Config.h"
-#include "OutputSections.h"
#include "SymbolTable.h"
+#include "Threads.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ELF.h"
-#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <atomic>
using namespace lld;
using namespace lld::elf;
@@ -71,143 +90,132 @@ using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
-namespace lld {
-namespace elf {
+namespace {
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);
+ void segregate(size_t Begin, size_t End, bool Constant);
template <class RelTy>
- static bool relocationEq(ArrayRef<RelTy> RA, ArrayRef<RelTy> RB);
+ bool constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB);
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);
+ bool variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
+ const InputSection<ELFT> *B, ArrayRef<RelTy> RelsB);
+
+ bool equalsConstant(const InputSection<ELFT> *A, const InputSection<ELFT> *B);
+ bool equalsVariable(const InputSection<ELFT> *A, const InputSection<ELFT> *B);
+
+ size_t findBoundary(size_t Begin, size_t End);
+
+ void forEachClassRange(size_t Begin, size_t End,
+ std::function<void(size_t, size_t)> Fn);
+
+ void forEachClass(std::function<void(size_t, size_t)> Fn);
+
+ std::vector<InputSection<ELFT> *> Sections;
+
+ // We repeat the main loop while `Repeat` is true.
+ std::atomic<bool> Repeat;
+
+ // The main loop counter.
+ int Cnt = 0;
+
+ // We have two locations for equivalence classes. On the first iteration
+ // of the main loop, Class[0] has a valid value, and Class[1] contains
+ // garbage. We read equivalence classes from slot 0 and write to slot 1.
+ // So, Class[0] represents the current class, and Class[1] represents
+ // the next class. On each iteration, we switch their roles and use them
+ // alternately.
+ //
+ // Why are we doing this? Recall that other threads may be working on
+ // other equivalence classes in parallel. They may read sections that we
+ // are updating. We cannot update equivalence classes in place because
+ // it breaks the invariance that all possibly-identical sections must be
+ // in the same equivalence class at any moment. In other words, the for
+ // loop to update equivalence classes is not atomic, and that is
+ // observable from other threads. By writing new classes to other
+ // places, we can keep the invariance.
+ //
+ // Below, `Current` has the index of the current class, and `Next` has
+ // the index of the next class. If threading is enabled, they are either
+ // (0, 1) or (1, 0).
+ //
+ // Note on single-thread: if that's the case, they are always (0, 0)
+ // because we can safely read the next class without worrying about race
+ // conditions. Using the same location makes this algorithm converge
+ // faster because it uses results of the same iteration earlier.
+ int Current = 0;
+ int Next = 0;
};
}
-}
// 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;
+template <class ELFT> static uint32_t getHash(InputSection<ELFT> *S) {
+ return hash_combine(S->Flags, S->getSize(), S->NumRelocations);
}
-// 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;
-
+// Returns true if section S is subject of ICF.
+template <class ELFT> static bool isEligible(InputSection<ELFT> *S) {
// .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;
+ return S->Live && (S->Flags & SHF_ALLOC) && !(S->Flags & SHF_WRITE) &&
+ S->Name != ".init" && S->Name != ".fini";
}
-// 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.
+// Split an equivalence class into smaller classes.
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;
+void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) {
+ // This loop rearranges sections in [Begin, End) so that all sections
+ // that are equal in terms of equals{Constant,Variable} are contiguous
+ // in [Begin, End).
+ //
+ // The algorithm is quadratic in the worst case, but that is not an
+ // issue in practice because the number of the distinct sections in
+ // each range is usually very small.
+
+ while (Begin < End) {
+ // Divide [Begin, End) into two. Let Mid be the start index of the
+ // second group.
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;
+ Sections.begin() + Begin + 1, Sections.begin() + End,
+ [&](InputSection<ELFT> *S) {
+ if (Constant)
+ return equalsConstant(Sections[Begin], S);
+ return equalsVariable(Sections[Begin], S);
+ });
+ size_t Mid = Bound - Sections.begin();
+
+ // Now we split [Begin, End) into [Begin, Mid) and [Mid, End) by
+ // updating the sections in [Begin, End). We use Mid as an equivalence
+ // class ID because every group ends with a unique index.
+ for (size_t I = Begin; I < Mid; ++I)
+ Sections[I]->Class[Next] = Mid;
+
+ // If we created a group, we need to iterate the main loop again.
+ if (Mid != End)
+ Repeat = true;
+
+ Begin = Mid;
}
}
// 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;
+bool ICF<ELFT>::constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
+ auto Eq = [](const RelTy &A, const RelTy &B) {
+ return A.r_offset == B.r_offset &&
+ A.getType(Config->Mips64EL) == B.getType(Config->Mips64EL) &&
+ getAddend<ELFT>(A) == getAddend<ELFT>(B);
+ };
+
+ return RelsA.size() == RelsB.size() &&
+ std::equal(RelsA.begin(), RelsA.end(), RelsB.begin(), Eq);
}
// Compare "non-moving" part of two InputSections, namely everything
@@ -215,125 +223,155 @@ bool ICF<ELFT>::relocationEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
template <class ELFT>
bool ICF<ELFT>::equalsConstant(const InputSection<ELFT> *A,
const InputSection<ELFT> *B) {
- if (A->RelocSections.size() != B->RelocSections.size())
+ if (A->NumRelocations != B->NumRelocations || A->Flags != B->Flags ||
+ A->getSize() != B->getSize() || A->Data != B->Data)
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();
+ if (A->AreRelocsRela)
+ return constantEq(A->relas(), B->relas());
+ return constantEq(A->rels(), B->rels());
}
+// Compare two lists of relocations. Returns true if all pairs of
+// relocations point to the same section in terms of ICF.
template <class ELFT>
template <class RelTy>
-bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A,
- 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);
+bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
+ const InputSection<ELFT> *B, ArrayRef<RelTy> RelsB) {
+ auto Eq = [&](const RelTy &RA, const RelTy &RB) {
+ // The two sections must be identical.
+ SymbolBody &SA = A->getFile()->getRelocTargetSym(RA);
+ SymbolBody &SB = B->getFile()->getRelocTargetSym(RB);
if (&SA == &SB)
- continue;
+ return true;
- // Or, the symbols should be pointing to the same section
- // in terms of the group ID.
+ // Or, the two sections must be in the same equivalence class.
auto *DA = dyn_cast<DefinedRegular<ELFT>>(&SA);
auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB);
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;
+
+ auto *X = dyn_cast<InputSection<ELFT>>(DA->Section);
+ auto *Y = dyn_cast<InputSection<ELFT>>(DB->Section);
+ if (!X || !Y)
+ return false;
+
+ // Ineligible sections are in the special equivalence class 0.
+ // They can never be the same in terms of the equivalence class.
+ if (X->Class[Current] == 0)
+ return false;
+
+ return X->Class[Current] == Y->Class[Current];
+ };
+
+ return std::equal(RelsA.begin(), RelsA.end(), RelsB.begin(), Eq);
}
// 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;
- }
+ if (A->AreRelocsRela)
+ return variableEq(A, A->relas(), B, B->relas());
+ return variableEq(A, A->rels(), B, B->rels());
+}
+
+template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
+ uint32_t Class = Sections[Begin]->Class[Current];
+ for (size_t I = Begin + 1; I < End; ++I)
+ if (Class != Sections[I]->Class[Current])
+ return I;
+ return End;
+}
+
+// Sections in the same equivalence class are contiguous in Sections
+// vector. Therefore, Sections vector can be considered as contiguous
+// groups of sections, grouped by the class.
+//
+// This function calls Fn on every group that starts within [Begin, End).
+// Note that a group must starts in that range but doesn't necessarily
+// have to end before End.
+template <class ELFT>
+void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
+ std::function<void(size_t, size_t)> Fn) {
+ if (Begin > 0)
+ Begin = findBoundary(Begin - 1, End);
+
+ while (Begin < End) {
+ size_t Mid = findBoundary(Begin, Sections.size());
+ Fn(Begin, Mid);
+ Begin = Mid;
}
- return true;
+}
+
+// Call Fn on each equivalence class.
+template <class ELFT>
+void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
+ // If threading is disabled or the number of sections are
+ // too small to use threading, call Fn sequentially.
+ if (!Config->Threads || Sections.size() < 1024) {
+ forEachClassRange(0, Sections.size(), Fn);
+ ++Cnt;
+ return;
+ }
+
+ Current = Cnt % 2;
+ Next = (Cnt + 1) % 2;
+
+ // Split sections into 256 shards and call Fn in parallel.
+ size_t NumShards = 256;
+ size_t Step = Sections.size() / NumShards;
+ forLoop(0, NumShards,
+ [&](size_t I) { forEachClassRange(I * Step, (I + 1) * Step, Fn); });
+ forEachClassRange(Step * NumShards, Sections.size(), Fn);
+ ++Cnt;
}
// 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(),
+ // Collect sections to merge.
+ for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections)
+ if (auto *S = dyn_cast<InputSection<ELFT>>(Sec))
+ if (isEligible(S))
+ Sections.push_back(S);
+
+ // Initially, we use hash values to partition sections.
+ for (InputSection<ELFT> *S : Sections)
+ // Set MSB to 1 to avoid collisions with non-hash IDs.
+ S->Class[0] = getHash(S) | (1 << 31);
+
+ // From now on, sections in Sections vector are ordered so that sections
+ // in the same equivalence class are consecutive in the vector.
+ std::stable_sort(Sections.begin(), Sections.end(),
[](InputSection<ELFT> *A, InputSection<ELFT> *B) {
- return A->GroupId < B->GroupId;
+ return A->Class[0] < B->Class[0];
});
// Compare static contents and assign unique IDs for each static content.
- forEachGroup(V, equalsConstant);
+ forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
- // 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);
+ // Split groups by comparing relocations until convergence is obtained.
+ do {
+ Repeat = false;
+ forEachClass(
+ [&](size_t Begin, size_t End) { segregate(Begin, End, false); });
+ } while (Repeat);
+
+ log("ICF needed " + Twine(Cnt) + " iterations");
+
+ // Merge sections by the equivalence class.
+ forEachClass([&](size_t Begin, size_t End) {
+ if (End - Begin == 1)
+ return;
+
+ log("selected " + Sections[Begin]->Name);
+ for (size_t I = Begin + 1; I < End; ++I) {
+ log(" removed " + Sections[I]->Name);
+ Sections[Begin]->replace(Sections[I]);
}
- }
+ });
}
// ICF entry point function.
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 426d9c39715d..2a8659921463 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -11,13 +11,20 @@
#include "Driver.h"
#include "Error.h"
#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Memory.h"
#include "SymbolTable.h"
#include "Symbols.h"
+#include "SyntheticSections.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/CodeGen/Analysis.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -29,8 +36,68 @@ using namespace llvm::sys::fs;
using namespace lld;
using namespace lld::elf;
+namespace {
+// In ELF object file all section addresses are zero. If we have multiple
+// .text sections (when using -ffunction-section or comdat group) then
+// LLVM DWARF parser will not be able to parse .debug_line correctly, unless
+// we assign each section some unique address. This callback method assigns
+// each section an address equal to its offset in ELF object file.
+class ObjectInfo : public LoadedObjectInfo {
+public:
+ uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override {
+ return static_cast<const ELFSectionRef &>(Sec).getOffset();
+ }
+ std::unique_ptr<LoadedObjectInfo> clone() const override {
+ return std::unique_ptr<LoadedObjectInfo>();
+ }
+};
+}
+
+template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
+ std::unique_ptr<object::ObjectFile> Obj =
+ check(object::ObjectFile::createObjectFile(this->MB),
+ "createObjectFile failed");
+
+ ObjectInfo ObjInfo;
+ DWARFContextInMemory Dwarf(*Obj, &ObjInfo);
+ DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs));
+ DataExtractor LineData(Dwarf.getLineSection().Data,
+ ELFT::TargetEndianness == support::little,
+ ELFT::Is64Bits ? 8 : 4);
+
+ // The second parameter is offset in .debug_line section
+ // for compilation unit (CU) of interest. We have only one
+ // CU (object file), so offset is always 0.
+ DwarfLine->getOrParseLineTable(LineData, 0);
+}
+
+// Returns source line information for a given offset
+// using DWARF debug info.
+template <class ELFT>
+std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase<ELFT> *S,
+ uintX_t Offset) {
+ if (!DwarfLine)
+ initializeDwarfLine();
+
+ // The offset to CU is 0.
+ const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
+ if (!Tbl)
+ return "";
+
+ // Use fake address calcuated by adding section file offset and offset in
+ // section. See comments for ObjectInfo class.
+ DILineInfo Info;
+ Tbl->getFileLineInfoForAddress(
+ S->Offset + Offset, nullptr,
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info);
+ if (Info.Line == 0)
+ return "";
+ return convertToUnixPathSeparator(Info.FileName) + ":" +
+ std::to_string(Info.Line);
+}
+
// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
-std::string elf::getFilename(const InputFile *F) {
+std::string elf::toString(const InputFile *F) {
if (!F)
return "(internal)";
if (!F->ArchiveName.empty())
@@ -38,15 +105,6 @@ std::string elf::getFilename(const InputFile *F) {
return F->getName();
}
-template <class ELFT>
-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> static ELFKind getELFKind() {
if (ELFT::TargetEndianness == support::little)
return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
@@ -54,41 +112,31 @@ template <class ELFT> static ELFKind getELFKind() {
}
template <class ELFT>
-ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB)
- : InputFile(K, MB), ELFObj(createELFObj<ELFT>(MB)) {
+ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) {
EKind = getELFKind<ELFT>();
- EMachine = ELFObj.getHeader()->e_machine;
+ EMachine = getObj().getHeader()->e_machine;
+ OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI];
}
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)
- fatal(getFilename(this) + ": invalid sh_info in symbol table");
-
- if (OnlyGlobals)
- return makeArrayRef(Syms.begin() + FirstNonLocal, Syms.end());
- return makeArrayRef(Syms.begin(), Syms.end());
+typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalSymbols() {
+ return makeArrayRef(Symbols.begin() + FirstNonLocal, Symbols.end());
}
template <class ELFT>
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)
- return 0;
- return I;
+ return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX));
}
-template <class ELFT> void ELFFileBase<ELFT>::initStringTable() {
- if (!Symtab)
- return;
- StringTable = check(ELFObj.getStringTableForSymtab(*Symtab));
+template <class ELFT>
+void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Shdr *Symtab) {
+ FirstNonLocal = Symtab->sh_info;
+ Symbols = check(getObj().symbols(Symtab));
+ if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size())
+ fatal(toString(this) + ": invalid sh_info in symbol table");
+
+ StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections));
}
template <class ELFT>
@@ -97,37 +145,25 @@ elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef 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);
+ return makeArrayRef(this->SymbolBodies).slice(this->FirstNonLocal);
}
template <class ELFT>
ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() {
- if (!this->Symtab)
+ if (this->SymbolBodies.empty())
return this->SymbolBodies;
- uint32_t FirstNonLocal = this->Symtab->sh_info;
- return makeArrayRef(this->SymbolBodies).slice(1, FirstNonLocal - 1);
+ return makeArrayRef(this->SymbolBodies).slice(1, this->FirstNonLocal - 1);
}
template <class ELFT>
ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() {
- if (!this->Symtab)
+ if (this->SymbolBodies.empty())
return this->SymbolBodies;
return makeArrayRef(this->SymbolBodies).slice(1);
}
-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>
-void elf::ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) {
+void elf::ObjectFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
// Read section and symbol tables.
initializeSections(ComdatGroups);
initializeSymbols();
@@ -137,22 +173,25 @@ void elf::ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) {
// They are identified and deduplicated by group name. This function
// returns a group name.
template <class ELFT>
-StringRef elf::ObjectFile<ELFT>::getShtGroupSignature(const Elf_Shdr &Sec) {
- const ELFFile<ELFT> &Obj = this->ELFObj;
- 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));
+StringRef
+elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Shdr &Sec) {
+ if (this->Symbols.empty())
+ this->initSymtab(Sections,
+ check(object::getSection<ELFT>(Sections, Sec.sh_link)));
+ const Elf_Sym *Sym =
+ check(object::getSymbol<ELFT>(this->Symbols, Sec.sh_info));
+ return check(Sym->getName(this->StringTable));
}
template <class ELFT>
ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word>
elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
- const ELFFile<ELFT> &Obj = this->ELFObj;
+ const ELFFile<ELFT> &Obj = this->getObj();
ArrayRef<Elf_Word> Entries =
check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec));
if (Entries.empty() || Entries[0] != GRP_COMDAT)
- fatal(getFilename(this) + ": unsupported SHT_GROUP format");
+ fatal(toString(this) + ": unsupported SHT_GROUP format");
return Entries.slice(1);
}
@@ -163,15 +202,39 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
if (Config->Optimize == 0)
return false;
+ // Do not merge sections if generating a relocatable object. It makes
+ // the code simpler because we do not need to update relocation addends
+ // to reflect changes introduced by merging. Instead of that we write
+ // such "merge" sections into separate OutputSections and keep SHF_MERGE
+ // / SHF_STRINGS flags and sh_entsize value to be able to perform merging
+ // later during a final linking.
+ if (Config->Relocatable)
+ return false;
+
+ // A mergeable section with size 0 is useless because they don't have
+ // any data to merge. A mergeable string section with size 0 can be
+ // argued as invalid because it doesn't end with a null character.
+ // We'll avoid a mess by handling them as if they were non-mergeable.
+ if (Sec.sh_size == 0)
+ return false;
+
+ // Check for sh_entsize. The ELF spec is not clear about the zero
+ // sh_entsize. It says that "the member [sh_entsize] contains 0 if
+ // the section does not hold a table of fixed-size entries". We know
+ // that Rust 1.13 produces a string mergeable section with a zero
+ // sh_entsize. Here we just accept it rather than being picky about it.
+ uintX_t EntSize = Sec.sh_entsize;
+ if (EntSize == 0)
+ return false;
+ if (Sec.sh_size % EntSize)
+ fatal(toString(this) +
+ ": SHF_MERGE section size must be a multiple of sh_entsize");
+
uintX_t Flags = Sec.sh_flags;
if (!(Flags & SHF_MERGE))
return false;
if (Flags & SHF_WRITE)
- fatal(getFilename(this) + ": writable SHF_MERGE section is not supported");
- uintX_t EntSize = Sec.sh_entsize;
- if (!EntSize || Sec.sh_size % EntSize)
- fatal(getFilename(this) +
- ": SHF_MERGE section size must be a multiple of sh_entsize");
+ fatal(toString(this) + ": writable SHF_MERGE section is not supported");
// Don't try to merge if the alignment is larger than the sh_entsize and this
// is not SHF_STRINGS.
@@ -187,74 +250,61 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
template <class ELFT>
void elf::ObjectFile<ELFT>::initializeSections(
- DenseSet<StringRef> &ComdatGroups) {
- uint64_t Size = this->ELFObj.getNumSections();
+ DenseSet<CachedHashStringRef> &ComdatGroups) {
+ ArrayRef<Elf_Shdr> ObjSections = check(this->getObj().sections());
+ const ELFFile<ELFT> &Obj = this->getObj();
+ uint64_t Size = ObjSections.size();
Sections.resize(Size);
unsigned I = -1;
- const ELFFile<ELFT> &Obj = this->ELFObj;
- for (const Elf_Shdr &Sec : Obj.sections()) {
+ StringRef SectionStringTable = check(Obj.getSectionStringTable(ObjSections));
+ for (const Elf_Shdr &Sec : ObjSections) {
++I;
if (Sections[I] == &InputSection<ELFT>::Discarded)
continue;
+ // SHF_EXCLUDE'ed sections are discarded by the linker. However,
+ // if -r is given, we'll let the final link discard such sections.
+ // This is compatible with GNU.
+ if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) {
+ Sections[I] = &InputSection<ELFT>::Discarded;
+ continue;
+ }
+
switch (Sec.sh_type) {
case SHT_GROUP:
Sections[I] = &InputSection<ELFT>::Discarded;
- if (ComdatGroups.insert(getShtGroupSignature(Sec)).second)
+ if (ComdatGroups.insert(CachedHashStringRef(
+ getShtGroupSignature(ObjSections, Sec)))
+ .second)
continue;
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
if (SecIndex >= Size)
- fatal(getFilename(this) + ": invalid section index in group: " +
+ fatal(toString(this) + ": invalid section index in group: " +
Twine(SecIndex));
Sections[SecIndex] = &InputSection<ELFT>::Discarded;
}
break;
case SHT_SYMTAB:
- this->Symtab = &Sec;
+ this->initSymtab(ObjSections, &Sec);
break;
case SHT_SYMTAB_SHNDX:
- this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec));
+ this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, ObjSections));
break;
case SHT_STRTAB:
case SHT_NULL:
break;
- case SHT_RELA:
- case SHT_REL: {
- // 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);
- break;
- }
- if (auto *S = dyn_cast<EhInputSection<ELFT>>(Target)) {
- if (S->RelocSection)
- fatal(
- getFilename(this) +
- ": multiple relocation sections to .eh_frame are not supported");
- S->RelocSection = &Sec;
- 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);
+ Sections[I] = createInputSection(Sec, SectionStringTable);
+ }
+
+ // .ARM.exidx sections have a reverse dependency on the InputSection they
+ // have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
+ if (Sec.sh_flags & SHF_LINK_ORDER) {
+ if (Sec.sh_link >= Sections.size())
+ fatal(toString(this) + ": invalid sh_link index: " +
+ Twine(Sec.sh_link));
+ auto *IS = cast<InputSection<ELFT>>(Sections[Sec.sh_link]);
+ IS->DependentSection = Sections[I];
}
}
}
@@ -264,8 +314,7 @@ 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));
+ fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx));
InputSectionBase<ELFT> *Target = Sections[Idx];
// Strictly speaking, a relocation section must be included in the
@@ -275,14 +324,65 @@ elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
return nullptr;
if (!Target)
- fatal(getFilename(this) + ": unsupported relocation reference");
+ fatal(toString(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));
+elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
+ StringRef SectionStringTable) {
+ StringRef Name =
+ check(this->getObj().getSectionName(&Sec, SectionStringTable));
+
+ switch (Sec.sh_type) {
+ case SHT_ARM_ATTRIBUTES:
+ // FIXME: ARM meta-data section. Retain the first attribute section
+ // we see. The eglibc ARM dynamic loaders require the presence of an
+ // attribute section for dlopen to work.
+ // In a full implementation we would merge all attribute sections.
+ if (In<ELFT>::ARMAttributes == nullptr) {
+ In<ELFT>::ARMAttributes = make<InputSection<ELFT>>(this, &Sec, Name);
+ return In<ELFT>::ARMAttributes;
+ }
+ return &InputSection<ELFT>::Discarded;
+ case SHT_RELA:
+ case SHT_REL: {
+ // This section contains relocation information.
+ // If -r is given, we do not interpret or apply relocation
+ // but just copy relocation sections to output.
+ if (Config->Relocatable)
+ return make<InputSection<ELFT>>(this, &Sec, Name);
+
+ // Find the relocation target section and associate this
+ // section with it.
+ InputSectionBase<ELFT> *Target = getRelocTarget(Sec);
+ if (!Target)
+ return nullptr;
+ if (Target->FirstRelocation)
+ fatal(toString(this) +
+ ": multiple relocation sections to one section are not supported");
+ if (!isa<InputSection<ELFT>>(Target) && !isa<EhInputSection<ELFT>>(Target))
+ fatal(toString(this) +
+ ": relocations pointing to SHF_MERGE are not supported");
+
+ size_t NumRelocations;
+ if (Sec.sh_type == SHT_RELA) {
+ ArrayRef<Elf_Rela> Rels = check(this->getObj().relas(&Sec));
+ Target->FirstRelocation = Rels.begin();
+ NumRelocations = Rels.size();
+ Target->AreRelocsRela = true;
+ } else {
+ ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec));
+ Target->FirstRelocation = Rels.begin();
+ NumRelocations = Rels.size();
+ Target->AreRelocsRela = false;
+ }
+ assert(isUInt<31>(NumRelocations));
+ Target->NumRelocations = NumRelocations;
+ return nullptr;
+ }
+ }
// .note.GNU-stack is a marker section to control the presence of
// PT_GNU_STACK segment in outputs. Since the presence of the segment
@@ -296,39 +396,23 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
return &InputSection<ELFT>::Discarded;
}
- if (Config->StripDebug && Name.startswith(".debug"))
+ if (Config->Strip != StripPolicy::None && 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);
+ return make<EhInputSection<ELFT>>(this, &Sec, Name);
if (shouldMerge(Sec))
- return new (MAlloc.Allocate()) MergeInputSection<ELFT>(this, &Sec);
- return new (IAlloc.Allocate()) InputSection<ELFT>(this, &Sec);
+ return make<MergeInputSection<ELFT>>(this, &Sec, Name);
+ return make<InputSection<ELFT>>(this, &Sec, Name);
}
template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
- this->initStringTable();
- 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.reserve(this->Symbols.size());
+ for (const Elf_Sym &Sym : this->Symbols)
SymbolBodies.push_back(createSymbolBody(&Sym));
}
@@ -336,12 +420,23 @@ template <class ELFT>
InputSectionBase<ELFT> *
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])
- fatal(getFilename(this) + ": invalid section index: " + Twine(Index));
+ if (Index >= Sections.size())
+ fatal(toString(this) + ": invalid section index: " + Twine(Index));
InputSectionBase<ELFT> *S = Sections[Index];
- if (S == &InputSectionBase<ELFT>::Discarded)
+
+ // We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could
+ // generate broken objects. STT_SECTION/STT_NOTYPE symbols can be
+ // associated with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections.
+ // In this case it is fine for section to be null here as we do not
+ // allocate sections of these types.
+ if (!S) {
+ if (Index == 0 || Sym.getType() == STT_SECTION ||
+ Sym.getType() == STT_NOTYPE)
+ return nullptr;
+ fatal(toString(this) + ": invalid section index: " + Twine(Index));
+ }
+
+ if (S == &InputSection<ELFT>::Discarded)
return S;
return S->Repl;
}
@@ -350,11 +445,26 @@ template <class ELFT>
SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
int Binding = Sym->getBinding();
InputSectionBase<ELFT> *Sec = getSection(*Sym);
+
+ uint8_t StOther = Sym->st_other;
+ uint8_t Type = Sym->getType();
+ uintX_t Value = Sym->st_value;
+ uintX_t Size = Sym->st_size;
+
if (Binding == STB_LOCAL) {
+ if (Sym->getType() == STT_FILE)
+ SourceFile = check(Sym->getName(this->StringTable));
+
+ if (this->StringTable.size() <= Sym->st_name)
+ fatal(toString(this) + ": invalid symbol name offset");
+
+ StringRefZ Name = this->StringTable.data() + Sym->st_name;
if (Sym->st_shndx == SHN_UNDEF)
- return new (this->Alloc)
- Undefined(Sym->st_name, Sym->st_other, Sym->getType(), this);
- return new (this->Alloc) DefinedRegular<ELFT>(*Sym, Sec);
+ return new (BAlloc)
+ Undefined(Name, /*IsLocal=*/true, StOther, Type, this);
+
+ return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther,
+ Type, Value, Size, Sec, this);
}
StringRef Name = check(Sym->getName(this->StringTable));
@@ -362,33 +472,38 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
switch (Sym->st_shndx) {
case SHN_UNDEF:
return elf::Symtab<ELFT>::X
- ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(),
- /*CanOmitFromDynSym*/ false, this)
+ ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type,
+ /*CanOmitFromDynSym=*/false, this)
->body();
case SHN_COMMON:
+ if (Value == 0 || Value >= UINT32_MAX)
+ fatal(toString(this) + ": common symbol '" + Name +
+ "' has invalid alignment: " + Twine(Value));
return elf::Symtab<ELFT>::X
- ->addCommon(Name, Sym->st_size, Sym->st_value, Binding, Sym->st_other,
- Sym->getType(), this)
+ ->addCommon(Name, Size, Value, Binding, StOther, Type, this)
->body();
}
switch (Binding) {
default:
- fatal(getFilename(this) + ": unexpected binding: " + Twine(Binding));
+ fatal(toString(this) + ": unexpected binding: " + Twine(Binding));
case STB_GLOBAL:
case STB_WEAK:
case STB_GNU_UNIQUE:
if (Sec == &InputSection<ELFT>::Discarded)
return elf::Symtab<ELFT>::X
- ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(),
- /*CanOmitFromDynSym*/ false, this)
+ ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type,
+ /*CanOmitFromDynSym=*/false, this)
->body();
- return elf::Symtab<ELFT>::X->addRegular(Name, *Sym, Sec)->body();
+ return elf::Symtab<ELFT>::X
+ ->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this)
+ ->body();
}
}
template <class ELFT> void ArchiveFile::parse() {
- File = check(Archive::create(MB), "failed to parse archive");
+ File = check(Archive::create(MB),
+ MB.getBufferIdentifier() + ": failed to parse archive");
// Read the symbol table to construct Lazy objects.
for (const Archive::Symbol &Sym : File->symbols())
@@ -396,13 +511,14 @@ template <class ELFT> void ArchiveFile::parse() {
}
// Returns a buffer pointing to a member file containing a given symbol.
-MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
+std::pair<MemoryBufferRef, uint64_t>
+ArchiveFile::getMember(const Archive::Symbol *Sym) {
Archive::Child C =
check(Sym->getMember(),
"could not get the member for symbol " + Sym->getName());
if (!Seen.insert(C.getChildOffset()).second)
- return MemoryBufferRef();
+ return {MemoryBufferRef(), 0};
MemoryBufferRef Ret =
check(C.getMemoryBufferRef(),
@@ -412,8 +528,9 @@ MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
if (C.getParent()->isThin() && Driver->Cpio)
Driver->Cpio->append(relativeToRoot(check(C.getFullName())),
Ret.getBuffer());
-
- return Ret;
+ if (C.getParent()->isThin())
+ return {Ret, 0};
+ return {Ret, C.getChildOffset()};
}
template <class ELFT>
@@ -423,32 +540,29 @@ SharedFile<ELFT>::SharedFile(MemoryBufferRef M)
template <class ELFT>
const typename ELFT::Shdr *
SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
- uint32_t Index = this->getSectionIndex(Sym);
- if (Index == 0)
- return nullptr;
- return check(this->ELFObj.getSection(Index));
+ return check(
+ this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX));
}
// Partially parse the shared object file so that we can call
// getSoName on this object.
template <class ELFT> void SharedFile<ELFT>::parseSoName() {
- typedef typename ELFT::Dyn Elf_Dyn;
- typedef typename ELFT::uint uintX_t;
const Elf_Shdr *DynamicSec = nullptr;
- const ELFFile<ELFT> Obj = this->ELFObj;
- for (const Elf_Shdr &Sec : Obj.sections()) {
+ const ELFFile<ELFT> Obj = this->getObj();
+ ArrayRef<Elf_Shdr> Sections = check(Obj.sections());
+ for (const Elf_Shdr &Sec : Sections) {
switch (Sec.sh_type) {
default:
continue;
case SHT_DYNSYM:
- this->Symtab = &Sec;
+ this->initSymtab(Sections, &Sec);
break;
case SHT_DYNAMIC:
DynamicSec = &Sec;
break;
case SHT_SYMTAB_SHNDX:
- this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec));
+ this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, Sections));
break;
case SHT_GNU_versym:
this->VersymSec = &Sec;
@@ -459,20 +573,25 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
}
}
- this->initStringTable();
+ if (this->VersymSec && this->Symbols.empty())
+ error("SHT_GNU_versym should be associated with symbol table");
+
+ // DSOs are identified by soname, and they usually contain
+ // DT_SONAME tag in their header. But if they are missing,
+ // filenames are used as default sonames.
SoName = sys::path::filename(this->getName());
if (!DynamicSec)
return;
- auto *Begin =
- reinterpret_cast<const Elf_Dyn *>(Obj.base() + DynamicSec->sh_offset);
- const Elf_Dyn *End = Begin + DynamicSec->sh_size / sizeof(Elf_Dyn);
- for (const Elf_Dyn &Dyn : make_range(Begin, End)) {
+ ArrayRef<Elf_Dyn> Arr =
+ check(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec),
+ toString(this) + ": getSectionContentsAsArray failed");
+ for (const Elf_Dyn &Dyn : Arr) {
if (Dyn.d_tag == DT_SONAME) {
uintX_t Val = Dyn.getVal();
if (Val >= this->StringTable.size())
- fatal(getFilename(this) + ": invalid DT_SONAME entry");
+ fatal(toString(this) + ": invalid DT_SONAME entry");
SoName = StringRef(this->StringTable.data() + Val);
return;
}
@@ -494,9 +613,9 @@ SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
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;
+ const char *Base = this->MB.getBuffer().data();
+ Versym = reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) +
+ this->FirstNonLocal;
// We cannot determine the largest verdef identifier without inspecting
// every Elf_Verdef, but both bfd and gold assign verdef identifiers
@@ -507,7 +626,7 @@ SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) {
// 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;
+ const char *Verdef = Base + VerdefSec->sh_offset;
for (unsigned I = 0; I != VerdefCount; ++I) {
auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
Verdef += CurVerdef->vd_next;
@@ -526,7 +645,7 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
const Elf_Versym *Versym = nullptr;
std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym);
- Elf_Sym_Range Syms = this->getElfSymbols(true);
+ Elf_Sym_Range Syms = this->getGlobalSymbols();
for (const Elf_Sym &Sym : Syms) {
unsigned VersymIndex = 0;
if (Versym) {
@@ -552,18 +671,16 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
}
}
-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;
+static ELFKind getBitcodeELFKind(MemoryBufferRef MB) {
+ Triple T(check(getBitcodeTargetTriple(MB)));
+ if (T.isLittleEndian())
+ return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind;
+ return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind;
}
-static uint8_t getMachineKind(MemoryBufferRef MB) {
- std::string TripleStr = getBitcodeTargetTriple(MB, Driver->Context);
- switch (Triple(TripleStr).getArch()) {
+static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) {
+ Triple T(check(getBitcodeTargetTriple(MB)));
+ switch (T.getArch()) {
case Triple::aarch64:
return EM_AARCH64;
case Triple::arm:
@@ -578,23 +695,22 @@ static uint8_t getMachineKind(MemoryBufferRef MB) {
case Triple::ppc64:
return EM_PPC64;
case Triple::x86:
- return EM_386;
+ return T.isOSIAMCU() ? EM_IAMCU : EM_386;
case Triple::x86_64:
return EM_X86_64;
default:
fatal(MB.getBufferIdentifier() +
- ": could not infer e_machine from bitcode target triple " +
- TripleStr);
+ ": could not infer e_machine from bitcode target triple " + T.str());
}
}
BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) {
- EKind = getELFKind(MB);
- EMachine = getMachineKind(MB);
+ EKind = getBitcodeELFKind(MB);
+ EMachine = getBitcodeMachineKind(MB);
}
-static uint8_t getGvVisibility(const GlobalValue *GV) {
- switch (GV->getVisibility()) {
+static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
+ switch (GvVisibility) {
case GlobalValue::DefaultVisibility:
return STV_DEFAULT;
case GlobalValue::HiddenVisibility:
@@ -606,124 +722,134 @@ static uint8_t getGvVisibility(const GlobalValue *GV) {
}
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);
+static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
+ const lto::InputFile::Symbol &ObjSym,
+ BitcodeFile *F) {
+ StringRef NameRef = Saver.save(ObjSym.getName());
+ uint32_t Flags = ObjSym.getFlags();
+ uint32_t Binding = (Flags & BasicSymbolRef::SF_Weak) ? STB_WEAK : STB_GLOBAL;
+
+ uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
+ uint8_t Visibility = mapVisibility(ObjSym.getVisibility());
+ bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable();
+
+ int C = check(ObjSym.getComdatIndex());
+ if (C != -1 && !KeptComdats[C])
+ return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
+ Visibility, Type, CanOmitFromDynSym,
+ F);
- 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 Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
+ Visibility, Type, CanOmitFromDynSym,
+ F);
+
+ if (Flags & BasicSymbolRef::SF_Common)
+ return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(),
+ ObjSym.getCommonAlignment(), Binding,
+ Visibility, STT_OBJECT, F);
-bool BitcodeFile::shouldSkip(uint32_t Flags) {
- return !(Flags & BasicSymbolRef::SF_Global) ||
- (Flags & BasicSymbolRef::SF_FormatSpecific);
+ return Symtab<ELFT>::X->addBitcode(NameRef, Binding, Visibility, Type,
+ CanOmitFromDynSym, F);
}
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);
+void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
+
+ // Here we pass a new MemoryBufferRef which is identified by ArchiveName
+ // (the fully resolved path of the archive) + member name + offset of the
+ // member in the archive.
+ // ThinLTO uses the MemoryBufferRef identifier to access its internal
+ // data structures and if two archives define two members with the same name,
+ // this causes a collision which result in only one of the objects being
+ // taken into consideration at LTO time (which very likely causes undefined
+ // symbols later in the link stage).
+ Obj = check(lto::InputFile::create(MemoryBufferRef(
+ MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() +
+ utostr(OffsetInArchive)))));
+
+ std::vector<bool> KeptComdats;
+ for (StringRef S : Obj->getComdatTable()) {
+ StringRef N = Saver.save(S);
+ KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(N)).second);
}
- for (const BasicSymbolRef &Sym : Obj->symbols())
- if (!shouldSkip(Sym.getFlags()))
- Symbols.push_back(createSymbol<ELFT>(KeptComdats, *Obj, Sym));
+ for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
+ Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this));
}
template <template <class> class T>
-static std::unique_ptr<InputFile> createELFFile(MemoryBufferRef MB) {
+static InputFile *createELFFile(MemoryBufferRef MB) {
unsigned char Size;
unsigned char Endian;
std::tie(Size, Endian) = getElfArchType(MB.getBuffer());
if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB)
- fatal("invalid data encoding: " + MB.getBufferIdentifier());
+ fatal(MB.getBufferIdentifier() + ": invalid data encoding");
+
+ size_t BufSize = MB.getBuffer().size();
+ if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) ||
+ (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr)))
+ fatal(MB.getBufferIdentifier() + ": file is too short");
- std::unique_ptr<InputFile> Obj;
+ InputFile *Obj;
if (Size == ELFCLASS32 && Endian == ELFDATA2LSB)
- Obj.reset(new T<ELF32LE>(MB));
+ Obj = make<T<ELF32LE>>(MB);
else if (Size == ELFCLASS32 && Endian == ELFDATA2MSB)
- Obj.reset(new T<ELF32BE>(MB));
+ Obj = make<T<ELF32BE>>(MB);
else if (Size == ELFCLASS64 && Endian == ELFDATA2LSB)
- Obj.reset(new T<ELF64LE>(MB));
+ Obj = make<T<ELF64LE>>(MB);
else if (Size == ELFCLASS64 && Endian == ELFDATA2MSB)
- Obj.reset(new T<ELF64BE>(MB));
+ Obj = make<T<ELF64BE>>(MB);
else
- fatal("invalid file class: " + MB.getBufferIdentifier());
+ fatal(MB.getBufferIdentifier() + ": invalid file class");
if (!Config->FirstElf)
- Config->FirstElf = Obj.get();
+ Config->FirstElf = Obj;
return Obj;
}
+template <class ELFT> void BinaryFile::parse() {
+ StringRef Buf = MB.getBuffer();
+ ArrayRef<uint8_t> Data =
+ makeArrayRef<uint8_t>((const uint8_t *)Buf.data(), Buf.size());
+
+ std::string Filename = MB.getBufferIdentifier();
+ std::transform(Filename.begin(), Filename.end(), Filename.begin(),
+ [](char C) { return isalnum(C) ? C : '_'; });
+ Filename = "_binary_" + Filename;
+ StringRef StartName = Saver.save(Twine(Filename) + "_start");
+ StringRef EndName = Saver.save(Twine(Filename) + "_end");
+ StringRef SizeName = Saver.save(Twine(Filename) + "_size");
+
+ auto *Section =
+ make<InputSection<ELFT>>(SHF_ALLOC, SHT_PROGBITS, 8, Data, ".data");
+ Sections.push_back(Section);
+
+ elf::Symtab<ELFT>::X->addRegular(StartName, STV_DEFAULT, STT_OBJECT, 0, 0,
+ STB_GLOBAL, Section, nullptr);
+ elf::Symtab<ELFT>::X->addRegular(EndName, STV_DEFAULT, STT_OBJECT,
+ Data.size(), 0, STB_GLOBAL, Section,
+ nullptr);
+ elf::Symtab<ELFT>::X->addRegular(SizeName, STV_DEFAULT, STT_OBJECT,
+ Data.size(), 0, STB_GLOBAL, nullptr,
+ nullptr);
+}
+
static bool isBitcode(MemoryBufferRef MB) {
using namespace sys::fs;
return identify_magic(MB.getBuffer()) == file_magic::bitcode;
}
-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);
+InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
+ uint64_t OffsetInArchive) {
+ InputFile *F =
+ isBitcode(MB) ? make<BitcodeFile>(MB) : createELFFile<ObjectFile>(MB);
F->ArchiveName = ArchiveName;
+ F->OffsetInArchive = OffsetInArchive;
return F;
}
-std::unique_ptr<InputFile> elf::createSharedFile(MemoryBufferRef MB) {
+InputFile *elf::createSharedFile(MemoryBufferRef MB) {
return createELFFile<SharedFile>(MB);
}
@@ -734,8 +860,7 @@ MemoryBufferRef LazyObjectFile::getBuffer() {
return MB;
}
-template <class ELFT>
-void LazyObjectFile::parse() {
+template <class ELFT> void LazyObjectFile::parse() {
for (StringRef Sym : getSymbols())
Symtab<ELFT>::X->addLazyObject(Sym, *this);
}
@@ -745,13 +870,14 @@ template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
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()) {
+ const ELFFile<ELFT> Obj(this->MB.getBuffer());
+ ArrayRef<Elf_Shdr> Sections = check(Obj.sections());
+ for (const Elf_Shdr &Sec : Sections) {
if (Sec.sh_type != SHT_SYMTAB)
continue;
- Elf_Sym_Range Syms = Obj.symbols(&Sec);
+ Elf_Sym_Range Syms = check(Obj.symbols(&Sec));
uint32_t FirstNonLocal = Sec.sh_info;
- StringRef StringTable = check(Obj.getStringTableForSymtab(Sec));
+ StringRef StringTable = check(Obj.getStringTableForSymtab(Sec, Sections));
std::vector<StringRef> V;
for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
if (Sym.st_shndx != SHN_UNDEF)
@@ -762,21 +888,11 @@ template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
}
std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
- LLVMContext Context;
- std::unique_ptr<IRObjectFile> Obj =
- check(IRObjectFile::create(this->MB, Context));
+ std::unique_ptr<lto::InputFile> Obj = check(lto::InputFile::create(this->MB));
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)));
- }
+ for (const lto::InputFile::Symbol &Sym : Obj->symbols())
+ if (!(Sym.getFlags() & BasicSymbolRef::SF_Undefined))
+ V.push_back(Saver.save(Sym.getName()));
return V;
}
@@ -803,10 +919,10 @@ 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 BitcodeFile::parse<ELF32LE>(DenseSet<CachedHashStringRef> &);
+template void BitcodeFile::parse<ELF32BE>(DenseSet<CachedHashStringRef> &);
+template void BitcodeFile::parse<ELF64LE>(DenseSet<CachedHashStringRef> &);
+template void BitcodeFile::parse<ELF64BE>(DenseSet<CachedHashStringRef> &);
template void LazyObjectFile::parse<ELF32LE>();
template void LazyObjectFile::parse<ELF32BE>();
@@ -827,3 +943,8 @@ template class elf::SharedFile<ELF32LE>;
template class elf::SharedFile<ELF32BE>;
template class elf::SharedFile<ELF64LE>;
template class elf::SharedFile<ELF64BE>;
+
+template void BinaryFile::parse<ELF32LE>();
+template void BinaryFile::parse<ELF32BE>();
+template void BinaryFile::parse<ELF64LE>();
+template void BinaryFile::parse<ELF64BE>();
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 79cb751494b3..aba1d71379b0 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -16,16 +16,24 @@
#include "Symbols.h"
#include "lld/Core/LLVM.h"
+#include "lld/Core/Reproduce.h"
+#include "llvm/ADT/CachedHashString.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 llvm {
+class DWARFDebugLine;
+namespace lto {
+class InputFile;
+}
+}
+
namespace lld {
namespace elf {
@@ -44,6 +52,7 @@ public:
LazyObjectKind,
ArchiveKind,
BitcodeKind,
+ BinaryKind,
};
Kind kind() const { return FileKind; }
@@ -56,10 +65,17 @@ public:
// string for creating error messages.
StringRef ArchiveName;
+ // If this file is in an archive, the member contains the offset of
+ // the file in the archive. Otherwise, it's just zero. We store this
+ // field so that we can pass it to lib/LTO in order to disambiguate
+ // between objects.
+ uint64_t OffsetInArchive;
+
// If this is an architecture-specific file, the following members
// have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
ELFKind EKind = ELFNoneKind;
uint16_t EMachine = llvm::ELF::EM_NONE;
+ uint8_t OSABI = 0;
protected:
InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
@@ -69,7 +85,7 @@ private:
};
// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
-std::string getFilename(const InputFile *F);
+std::string toString(const InputFile *F);
template <typename ELFT> class ELFFileBase : public InputFile {
public:
@@ -84,37 +100,37 @@ public:
return K == ObjectKind || K == SharedKind;
}
- const llvm::object::ELFFile<ELFT> &getObj() const { return ELFObj; }
- llvm::object::ELFFile<ELFT> &getObj() { return ELFObj; }
-
- uint8_t getOSABI() const {
- return getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI];
+ llvm::object::ELFFile<ELFT> getObj() const {
+ return llvm::object::ELFFile<ELFT>(MB.getBuffer());
}
StringRef getStringTable() const { return StringTable; }
uint32_t getSectionIndex(const Elf_Sym &Sym) const;
- Elf_Sym_Range getElfSymbols(bool OnlyGlobals);
+ Elf_Sym_Range getGlobalSymbols();
protected:
- llvm::object::ELFFile<ELFT> ELFObj;
- const Elf_Shdr *Symtab = nullptr;
+ ArrayRef<Elf_Sym> Symbols;
+ uint32_t FirstNonLocal = 0;
ArrayRef<Elf_Word> SymtabSHNDX;
StringRef StringTable;
- void initStringTable();
+ void initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab);
};
// .o file.
template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
typedef ELFFileBase<ELFT> Base;
+ typedef typename ELFT::Rel Elf_Rel;
+ typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::Word Elf_Word;
typedef typename ELFT::uint uintX_t;
- StringRef getShtGroupSignature(const Elf_Shdr &Sec);
+ StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
+ const Elf_Shdr &Sec);
ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec);
public:
@@ -127,40 +143,49 @@ public:
ArrayRef<SymbolBody *> getNonLocalSymbols();
explicit ObjectFile(MemoryBufferRef M);
- void parse(llvm::DenseSet<StringRef> &ComdatGroups);
+ void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
SymbolBody &getSymbolBody(uint32_t SymbolIndex) const {
+ if (SymbolIndex >= SymbolBodies.size())
+ fatal(toString(this) + ": invalid symbol index");
return *SymbolBodies[SymbolIndex];
}
- template <typename RelT> SymbolBody &getRelocTargetSym(const RelT &Rel) const {
+ 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; };
+ // Returns source line information for a given offset.
+ // If no information is available, returns "".
+ std::string getLineInfo(InputSectionBase<ELFT> *S, uintX_t Offset);
- // Get MIPS GP0 value defined by this file. This value represents the gp value
+ // MIPS GP0 value defined by this file. This value represents the gp value
// used to create the relocatable object and required to support
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
- uint32_t getMipsGp0() const;
+ uint32_t MipsGp0 = 0;
// 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;
+ // Name of source file obtained from STT_FILE symbol value,
+ // or empty string if there is no such symbol in object file
+ // symbol table.
+ StringRef SourceFile;
private:
- void initializeSections(llvm::DenseSet<StringRef> &ComdatGroups);
+ void
+ initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
void initializeSymbols();
+ void initializeDwarfLine();
InputSectionBase<ELFT> *getRelocTarget(const Elf_Shdr &Sec);
- InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec);
+ InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec,
+ StringRef SectionStringTable);
bool shouldMerge(const Elf_Shdr &Sec);
SymbolBody *createSymbolBody(const Elf_Sym *Sym);
@@ -171,14 +196,11 @@ private:
// List of all symbols referenced or defined by this file.
std::vector<SymbolBody *> SymbolBodies;
- // MIPS .reginfo section defined by this file.
- std::unique_ptr<MipsReginfoInputSection<ELFT>> MipsReginfo;
- // MIPS .MIPS.options section defined by this file.
- std::unique_ptr<MipsOptionsInputSection<ELFT>> MipsOptions;
-
- llvm::SpecificBumpPtrAllocator<InputSection<ELFT>> IAlloc;
- llvm::SpecificBumpPtrAllocator<MergeInputSection<ELFT>> MAlloc;
- llvm::SpecificBumpPtrAllocator<EhInputSection<ELFT>> EHAlloc;
+ // Debugging information to retrieve source file and line for error
+ // reporting. Linker may find reasonable number of errors in a
+ // single object file, so we cache debugging information in order to
+ // parse it only once for each object file we link.
+ std::unique_ptr<llvm::DWARFDebugLine> DwarfLine;
};
// LazyObjectFile is analogous to ArchiveFile in the sense that
@@ -204,8 +226,6 @@ private:
template <class ELFT> std::vector<StringRef> getElfSymbols();
std::vector<StringRef> getBitcodeSymbols();
- llvm::BumpPtrAllocator Alloc;
- llvm::StringSaver Saver{Alloc};
bool Seen = false;
};
@@ -216,10 +236,11 @@ public:
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
template <class ELFT> void parse();
- // Returns a memory buffer for a given symbol. An empty memory buffer
+ // Returns a memory buffer for a given symbol and the offset in the archive
+ // for the member. An empty memory buffer and an offset of zero
// 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);
+ std::pair<MemoryBufferRef, uint64_t> getMember(const Archive::Symbol *Sym);
private:
std::unique_ptr<Archive> File;
@@ -231,30 +252,25 @@ public:
explicit BitcodeFile(MemoryBufferRef M);
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
template <class ELFT>
- void parse(llvm::DenseSet<StringRef> &ComdatGroups);
+ void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
ArrayRef<Symbol *> getSymbols() { return Symbols; }
- static bool shouldSkip(uint32_t Flags);
- std::unique_ptr<llvm::object::IRObjectFile> Obj;
+ std::unique_ptr<llvm::lto::InputFile> 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 ELFT::Dyn Elf_Dyn;
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;
+ typedef typename ELFT::Versym Elf_Versym;
+ typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::uint uintX_t;
std::vector<StringRef> Undefs;
StringRef SoName;
@@ -294,9 +310,20 @@ public:
bool isNeeded() const { return !AsNeeded || IsUsed; }
};
-std::unique_ptr<InputFile> createObjectFile(MemoryBufferRef MB,
- StringRef ArchiveName = "");
-std::unique_ptr<InputFile> createSharedFile(MemoryBufferRef MB);
+class BinaryFile : public InputFile {
+public:
+ explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {}
+ static bool classof(const InputFile *F) { return F->kind() == BinaryKind; }
+ template <class ELFT> void parse();
+ ArrayRef<InputSectionData *> getSections() const { return Sections; }
+
+private:
+ std::vector<InputSectionData *> Sections;
+};
+
+InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "",
+ uint64_t OffsetInArchive = 0);
+InputFile *createSharedFile(MemoryBufferRef MB);
} // namespace elf
} // namespace lld
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 6564e7995a89..805e51dab507 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -13,103 +13,187 @@
#include "Error.h"
#include "InputFiles.h"
#include "LinkerScript.h"
+#include "Memory.h"
#include "OutputSections.h"
+#include "Relocations.h"
+#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
-
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
+#include <mutex>
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
+using namespace llvm::support;
using namespace llvm::support::endian;
using namespace lld;
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);
+// Returns a string to construct an error message.
+template <class ELFT>
+std::string elf::toString(const InputSectionBase<ELFT> *Sec) {
+ return (Sec->getFile()->getName() + ":(" + Sec->Name + ")").str();
+}
+
+template <class ELFT>
+static ArrayRef<uint8_t> getSectionContents(elf::ObjectFile<ELFT> *File,
+ const typename ELFT::Shdr *Hdr) {
+ if (!File || Hdr->sh_type == SHT_NOBITS)
+ return makeArrayRef<uint8_t>(nullptr, Hdr->sh_size);
+ return check(File->getObj().getSectionContents(Hdr));
}
template <class ELFT>
InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
- const Elf_Shdr *Header,
+ uintX_t Flags, uint32_t Type,
+ uintX_t Entsize, uint32_t Link,
+ uint32_t Info, uintX_t Addralign,
+ ArrayRef<uint8_t> Data, StringRef Name,
Kind 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;
+ : InputSectionData(SectionKind, Name, Data,
+ !Config->GcSections || !(Flags & SHF_ALLOC)),
+ File(File), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link),
+ Info(Info), Repl(this) {
+ NumRelocations = 0;
+ AreRelocsRela = false;
// 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);
+ uint64_t V = std::max<uint64_t>(Addralign, 1);
+ if (!isPowerOf2_64(V))
+ fatal(toString(File) + ": section sh_addralign is not a power of 2");
+
+ // We reject object files having insanely large alignments even though
+ // they are allowed by the spec. I think 4GB is a reasonable limitation.
+ // We might want to relax this in the future.
+ if (V > UINT32_MAX)
+ fatal(toString(File) + ": section sh_addralign is too large");
+ Alignment = V;
+
+ // If it is not a mergeable section, overwrite the flag so that the flag
+ // is consistent with the class. This inconsistency could occur when
+ // string merging is disabled using -O0 flag.
+ if (!Config->Relocatable && !isa<MergeInputSection<ELFT>>(this))
+ this->Flags &= ~(SHF_MERGE | SHF_STRINGS);
+}
+
+template <class ELFT>
+InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
+ const Elf_Shdr *Hdr, StringRef Name,
+ Kind SectionKind)
+ : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK, Hdr->sh_type,
+ Hdr->sh_entsize, Hdr->sh_link, Hdr->sh_info,
+ Hdr->sh_addralign, getSectionContents(File, Hdr), Name,
+ SectionKind) {
+ this->Offset = Hdr->sh_offset;
}
template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const {
+ if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this))
+ return S->getSize();
+
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 {
- return check(File->getObj().getSectionName(this->Header));
+ return Data.size();
}
-template <class ELFT>
-ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const {
- if (Compressed)
- return ArrayRef<uint8_t>((const uint8_t *)Uncompressed.data(),
- Uncompressed.size());
- return check(this->File->getObj().getSectionContents(this->Header));
+// Returns a string for an error message.
+template <class SectionT> static std::string getName(SectionT *Sec) {
+ return (Sec->getFile()->getName() + ":(" + Sec->Name + ")").str();
}
template <class ELFT>
typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const {
- switch (SectionKind) {
+ switch (kind()) {
case Regular:
return cast<InputSection<ELFT>>(this)->OutSecOff + Offset;
+ case Synthetic:
+ // For synthetic sections we treat offset -1 as the end of the section.
+ // The same approach is used for synthetic symbols (DefinedSynthetic).
+ return cast<InputSection<ELFT>>(this)->OutSecOff +
+ (Offset == uintX_t(-1) ? getSize() : Offset);
case EHFrame:
- return cast<EhInputSection<ELFT>>(this)->getOffset(Offset);
+ // 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.
+ return Offset;
case Merge:
return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
- case MipsReginfo:
- 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");
}
-template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
- if (!zlib::isAvailable())
- fatal("build lld with zlib to enable compressed sections support");
+template <class ELFT> bool InputSectionBase<ELFT>::isCompressed() const {
+ return (Flags & SHF_COMPRESSED) || Name.startswith(".zdebug");
+}
- // 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));
+// Returns compressed data and its size when uncompressed.
+template <class ELFT>
+std::pair<ArrayRef<uint8_t>, uint64_t>
+InputSectionBase<ELFT>::getElfCompressedData(ArrayRef<uint8_t> Data) {
+ // Compressed section with Elf_Chdr is the ELF standard.
if (Data.size() < sizeof(Elf_Chdr))
- fatal("corrupt compressed section");
-
+ fatal(toString(this) + ": corrupted 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");
+ fatal(toString(this) + ": unsupported compression type");
+ return {Data.slice(sizeof(*Hdr)), Hdr->ch_size};
+}
- StringRef Buf((const char *)Data.data(), Data.size());
- if (zlib::uncompress(Buf, Uncompressed, Hdr->ch_size) != zlib::StatusOK)
- fatal("error uncompressing section");
+// Returns compressed data and its size when uncompressed.
+template <class ELFT>
+std::pair<ArrayRef<uint8_t>, uint64_t>
+InputSectionBase<ELFT>::getRawCompressedData(ArrayRef<uint8_t> Data) {
+ // Compressed sections without Elf_Chdr header contain this header
+ // instead. This is a GNU extension.
+ struct ZlibHeader {
+ char Magic[4]; // Should be "ZLIB"
+ char Size[8]; // Uncompressed size in big-endian
+ };
+
+ if (Data.size() < sizeof(ZlibHeader))
+ fatal(toString(this) + ": corrupted compressed section");
+ auto *Hdr = reinterpret_cast<const ZlibHeader *>(Data.data());
+ if (memcmp(Hdr->Magic, "ZLIB", 4))
+ fatal(toString(this) + ": broken ZLIB-compressed section");
+ return {Data.slice(sizeof(*Hdr)), read64be(Hdr->Size)};
+}
+
+// Uncompress section contents. Note that this function is called
+// from parallel_for_each, so it must be thread-safe.
+template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
+ if (!zlib::isAvailable())
+ fatal(toString(this) +
+ ": build lld with zlib to enable compressed sections support");
+
+ // This section is compressed. Here we decompress it. Ideally, all
+ // compressed sections have SHF_COMPRESSED bit and their contents
+ // start with headers of Elf_Chdr type. However, sections whose
+ // names start with ".zdebug_" don't have the bit and contains a raw
+ // ZLIB-compressed data (which is a bad thing because section names
+ // shouldn't be significant in ELF.) We need to be able to read both.
+ ArrayRef<uint8_t> Buf; // Compressed data
+ size_t Size; // Uncompressed size
+ if (Flags & SHF_COMPRESSED)
+ std::tie(Buf, Size) = getElfCompressedData(Data);
+ else
+ std::tie(Buf, Size) = getRawCompressedData(Data);
+
+ // Uncompress Buf.
+ char *OutputBuf;
+ {
+ static std::mutex Mu;
+ std::lock_guard<std::mutex> Lock(Mu);
+ OutputBuf = BAlloc.Allocate<char>(Size);
+ }
+ if (zlib::uncompress(toStringRef(Buf), OutputBuf, Size) != zlib::StatusOK)
+ fatal(toString(this) + ": error while uncompressing section");
+ Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size);
}
template <class ELFT>
@@ -119,29 +203,71 @@ InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const {
}
template <class ELFT>
+InputSectionBase<ELFT> *InputSectionBase<ELFT>::getLinkOrderDep() const {
+ if ((Flags & SHF_LINK_ORDER) && Link != 0)
+ return getFile()->getSections()[Link];
+ return nullptr;
+}
+
+// Returns a source location string. Used to construct an error message.
+template <class ELFT>
+std::string InputSectionBase<ELFT>::getLocation(typename ELFT::uint Offset) {
+ // First check if we can get desired values from debugging information.
+ std::string LineInfo = File->getLineInfo(this, Offset);
+ if (!LineInfo.empty())
+ return LineInfo;
+
+ // File->SourceFile contains STT_FILE symbol that contains a
+ // source file name. If it's missing, we use an object file name.
+ std::string SrcFile = File->SourceFile;
+ if (SrcFile.empty())
+ SrcFile = toString(File);
+
+ // Find a function symbol that encloses a given location.
+ for (SymbolBody *B : File->getSymbols())
+ if (auto *D = dyn_cast<DefinedRegular<ELFT>>(B))
+ if (D->Section == this && D->Type == STT_FUNC)
+ if (D->Value <= Offset && Offset < D->Value + D->Size)
+ return SrcFile + ":(function " + toString(*D) + ")";
+
+ // If there's no symbol, print out the offset in the section.
+ return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
+}
+
+template <class ELFT>
+InputSection<ELFT>::InputSection() : InputSectionBase<ELFT>() {}
+
+template <class ELFT>
+InputSection<ELFT>::InputSection(uintX_t Flags, uint32_t Type,
+ uintX_t Addralign, ArrayRef<uint8_t> Data,
+ StringRef Name, Kind K)
+ : InputSectionBase<ELFT>(nullptr, Flags, Type,
+ /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Addralign,
+ Data, Name, K) {}
+
+template <class ELFT>
InputSection<ELFT>::InputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header)
- : InputSectionBase<ELFT>(F, Header, Base::Regular) {}
+ const Elf_Shdr *Header, StringRef Name)
+ : InputSectionBase<ELFT>(F, Header, Name, Base::Regular) {}
template <class ELFT>
-bool InputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
- return S->SectionKind == Base::Regular;
+bool InputSection<ELFT>::classof(const InputSectionData *S) {
+ return S->kind() == Base::Regular || S->kind() == Base::Synthetic;
}
template <class ELFT>
InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
- assert(this->Header->sh_type == SHT_RELA || this->Header->sh_type == SHT_REL);
+ assert(this->Type == SHT_RELA || this->Type == SHT_REL);
ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections();
- return Sections[this->Header->sh_info];
+ return Sections[this->Info];
}
-template <class ELFT>
-void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) {
+template <class ELFT> 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;
+ return this->Data.size();
}
template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const {
@@ -163,35 +289,62 @@ void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
uint32_t Type = Rel.getType(Config->Mips64EL);
SymbolBody &Body = this->File->getRelocTargetSym(Rel);
- RelTy *P = reinterpret_cast<RelTy *>(Buf);
+ Elf_Rela *P = reinterpret_cast<Elf_Rela *>(Buf);
Buf += sizeof(RelTy);
+ if (Config->Rela)
+ P->r_addend = getAddend<ELFT>(Rel);
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));
+static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A,
+ uint32_t P) {
+ switch (Type) {
+ case R_ARM_THM_JUMP11:
+ return P + 2;
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_PREL31:
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ return P + 4;
+ case R_ARM_THM_CALL:
+ // We don't want an interworking BLX to ARM
+ return P + 5;
+ default:
+ return A;
+ }
}
-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;
+static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
+ uint64_t P) {
+ switch (Type) {
+ case R_AARCH64_CALL26:
+ case R_AARCH64_CONDBR19:
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_TSTBR14:
+ return P + 4;
+ default:
+ return A;
+ }
+}
+template <class ELFT>
+static typename ELFT::uint
+getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
+ const SymbolBody &Body, RelExpr Expr) {
switch (Expr) {
case R_HINT:
+ case R_TLSDESC_CALL:
llvm_unreachable("cannot relocate hint relocs");
case R_TLSLD:
- return Out<ELFT>::Got->getTlsIndexOff() + A -
- Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+ return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
case R_TLSLD_PC:
- return Out<ELFT>::Got->getTlsIndexVA() + A - P;
+ return In<ELFT>::Got->getTlsIndexVA() + A - P;
case R_THUNK_ABS:
return Body.getThunkVA<ELFT>() + A;
case R_THUNK_PC:
@@ -200,14 +353,14 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
case R_PPC_TOC:
return getPPC64TocBase() + A;
case R_TLSGD:
- return Out<ELFT>::Got->getGlobalDynOffset(Body) + A -
- Out<ELFT>::Got->getNumEntries() * sizeof(uintX_t);
+ return In<ELFT>::Got->getGlobalDynOffset(Body) + A -
+ In<ELFT>::Got->getSize();
case R_TLSGD_PC:
- return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+ return In<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
case R_TLSDESC:
- return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
+ return In<ELFT>::Got->getGlobalDynAddr(Body) + A;
case R_TLSDESC_PAGE:
- return getAArch64Page(Out<ELFT>::Got->getGlobalDynAddr(Body) + A) -
+ return getAArch64Page(In<ELFT>::Got->getGlobalDynAddr(Body) + A) -
getAArch64Page(P);
case R_PLT:
return Body.getPltVA<ELFT>() + A;
@@ -217,11 +370,13 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
case R_SIZE:
return Body.getSize<ELFT>() + A;
case R_GOTREL:
- return Body.getVA<ELFT>(A) - Out<ELFT>::Got->getVA();
+ return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA();
+ case R_GOTREL_FROM_END:
+ return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA() -
+ In<ELFT>::Got->getSize();
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);
+ return Body.getGotOffset<ELFT>() + A - In<ELFT>::Got->getSize();
case R_RELAX_TLS_GD_TO_IE_ABS:
case R_GOT:
return Body.getGotVA<ELFT>() + A;
@@ -232,11 +387,21 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
case R_GOT_PC:
return Body.getGotVA<ELFT>() + A - P;
case R_GOTONLY_PC:
- return Out<ELFT>::Got->getVA() + A - P;
+ return In<ELFT>::Got->getVA() + A - P;
+ case R_GOTONLY_PC_FROM_END:
+ return In<ELFT>::Got->getVA() + A - P + In<ELFT>::Got->getSize();
case R_RELAX_TLS_LD_TO_LE:
case R_RELAX_TLS_IE_TO_LE:
case R_RELAX_TLS_GD_TO_LE:
case R_TLS:
+ // A weak undefined TLS symbol resolves to the base of the TLS
+ // block, i.e. gets a value of zero. If we pass --gc-sections to
+ // lld and .tbss is not referenced, it gets reclaimed and we don't
+ // create a TLS program header. Therefore, we resolve this
+ // statically to zero.
+ if (Body.isTls() && (Body.isLazy() || Body.isUndefined()) &&
+ Body.symbol()->isWeak())
+ return 0;
if (Target->TcbSize)
return Body.getVA<ELFT>(A) +
alignTo(Target->TcbSize, Out<ELFT>::TlsPhdr->p_align);
@@ -253,18 +418,26 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
// 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));
+ return In<ELFT>::MipsGot->getVA() +
+ In<ELFT>::MipsGot->getPageEntryOffset(Body, A) -
+ In<ELFT>::MipsGot->getGp();
case R_MIPS_GOT_OFF:
+ case R_MIPS_GOT_OFF32:
// 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);
+ return In<ELFT>::MipsGot->getVA() +
+ In<ELFT>::MipsGot->getBodyEntryOffset(Body, A) -
+ In<ELFT>::MipsGot->getGp();
+ case R_MIPS_GOTREL:
+ return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getGp();
case R_MIPS_TLSGD:
- return Out<ELFT>::Got->getGlobalDynOffset(Body) +
- Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+ return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
+ In<ELFT>::MipsGot->getGlobalDynOffset(Body) -
+ In<ELFT>::MipsGot->getGp();
case R_MIPS_TLSLD:
- return Out<ELFT>::Got->getTlsIndexOff() +
- Out<ELFT>::Got->getMipsTlsOffset() - MipsGPOffset;
+ return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
+ In<ELFT>::MipsGot->getTlsIndexOff() - In<ELFT>::MipsGot->getGp();
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
@@ -275,8 +448,8 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
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();
+ uint64_t OpdStart = Out<ELF64BE>::Opd->Addr;
+ uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->Size;
bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
if (InOpd)
SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]);
@@ -284,10 +457,20 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
return SymVA - P;
}
case R_PC:
+ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) {
+ // On ARM and AArch64 a branch to an undefined weak resolves to the
+ // next instruction, otherwise the place.
+ if (Config->EMachine == EM_ARM)
+ return getARMUndefinedRelativeWeakVA(Type, A, P);
+ if (Config->EMachine == EM_AARCH64)
+ return getAArch64UndefinedRelativeWeakVA(Type, A, P);
+ }
case R_RELAX_GOT_PC:
return Body.getVA<ELFT>(A) - P;
case R_PLT_PAGE_PC:
case R_PAGE_PC:
+ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
+ return getAArch64Page(A);
return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
}
llvm_unreachable("Invalid expression");
@@ -303,7 +486,6 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A,
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);
@@ -314,13 +496,15 @@ void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
SymbolBody &Sym = this->File->getRelocTargetSym(Rel);
if (Target->getRelExpr(Type, Sym) != R_ABS) {
- error(this->getSectionName() + " has non-ABS reloc");
+ error(this->getLocation(Offset) + ": has non-ABS reloc");
return;
}
- uintX_t AddrLoc = this->OutSec->getVA() + Offset;
- uint64_t SymVA =
- SignExtend64<Bits>(getSymVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS));
+ uintX_t AddrLoc = this->OutSec->Addr + Offset;
+ uint64_t SymVA = 0;
+ if (!Sym.isTls() || Out<ELFT>::TlsPhdr)
+ SymVA = SignExtend64<sizeof(uintX_t) * 8>(
+ getRelocTargetVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS));
Target->relocateOne(BufLoc, Type, SymVA);
}
}
@@ -331,78 +515,80 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
// 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));
- }
+ if (IS && !(IS->Flags & SHF_ALLOC)) {
+ if (IS->AreRelocsRela)
+ IS->relocateNonAlloc(Buf, IS->relas());
+ else
+ IS->relocateNonAlloc(Buf, IS->rels());
return;
}
const unsigned Bits = sizeof(uintX_t) * 8;
- for (const Relocation<ELFT> &Rel : Relocations) {
- uintX_t Offset = Rel.InputSec->getOffset(Rel.Offset);
+ for (const Relocation &Rel : Relocations) {
+ uintX_t Offset = getOffset(Rel.Offset);
uint8_t *BufLoc = Buf + Offset;
uint32_t Type = Rel.Type;
uintX_t A = Rel.Addend;
- uintX_t AddrLoc = OutSec->getVA() + Offset;
+ uintX_t AddrLoc = OutSec->Addr + Offset;
RelExpr Expr = Rel.Expr;
- uint64_t SymVA =
- SignExtend64<Bits>(getSymVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr));
+ uint64_t TargetVA = SignExtend64<Bits>(
+ getRelocTargetVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr));
switch (Expr) {
case R_RELAX_GOT_PC:
case R_RELAX_GOT_PC_NOPIC:
- Target->relaxGot(BufLoc, SymVA);
+ Target->relaxGot(BufLoc, TargetVA);
break;
case R_RELAX_TLS_IE_TO_LE:
- Target->relaxTlsIeToLe(BufLoc, Type, SymVA);
+ Target->relaxTlsIeToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_LD_TO_LE:
- Target->relaxTlsLdToLe(BufLoc, Type, SymVA);
+ Target->relaxTlsLdToLe(BufLoc, Type, TargetVA);
break;
case R_RELAX_TLS_GD_TO_LE:
case R_RELAX_TLS_GD_TO_LE_NEG:
- Target->relaxTlsGdToLe(BufLoc, Type, SymVA);
+ Target->relaxTlsGdToLe(BufLoc, Type, TargetVA);
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);
+ Target->relaxTlsGdToIe(BufLoc, Type, TargetVA);
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
+ // fallthrough
default:
- Target->relocateOne(BufLoc, Type, SymVA);
+ Target->relocateOne(BufLoc, Type, TargetVA);
break;
}
}
}
template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
- if (this->Header->sh_type == SHT_NOBITS)
+ if (this->Type == SHT_NOBITS)
+ return;
+
+ if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this)) {
+ S->writeTo(Buf + OutSecOff);
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));
+ if (this->Type == SHT_RELA) {
+ copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rela>());
return;
}
- if (this->Header->sh_type == SHT_REL) {
- copyRelocations(Buf + OutSecOff, EObj.rels(this->Header));
+ if (this->Type == SHT_REL) {
+ copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rel>());
return;
}
// Copy section contents from source object file to output file.
- ArrayRef<uint8_t> Data = this->getSectionData();
+ ArrayRef<uint8_t> Data = this->Data;
memcpy(Buf + OutSecOff, Data.data(), Data.size());
// Iterate over all relocation sections that apply to this section.
@@ -431,15 +617,9 @@ void InputSection<ELFT>::replace(InputSection<ELFT> *Other) {
}
template <class ELFT>
-SplitInputSection<ELFT>::SplitInputSection(
- elf::ObjectFile<ELFT> *File, const Elf_Shdr *Header,
- typename InputSectionBase<ELFT>::Kind SectionKind)
- : InputSectionBase<ELFT>(File, Header, SectionKind) {}
-
-template <class ELFT>
EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header)
- : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::EHFrame) {
+ const Elf_Shdr *Header, StringRef Name)
+ : InputSectionBase<ELFT>(F, Header, Name, 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.
@@ -447,18 +627,54 @@ EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F,
}
template <class ELFT>
-bool EhInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
- return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
+bool EhInputSection<ELFT>::classof(const InputSectionData *S) {
+ return S->kind() == InputSectionBase<ELFT>::EHFrame;
+}
+
+// Returns the index of the first relocation that points to a region between
+// Begin and Begin+Size.
+template <class IntTy, class RelTy>
+static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
+ unsigned &RelocI) {
+ // Start search from RelocI for fast access. That works because the
+ // relocations are sorted in .eh_frame.
+ for (unsigned N = Rels.size(); RelocI < N; ++RelocI) {
+ const RelTy &Rel = Rels[RelocI];
+ if (Rel.r_offset < Begin)
+ continue;
+
+ if (Rel.r_offset < Begin + Size)
+ return RelocI;
+ return -1;
+ }
+ return -1;
}
// .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() {
+ // Early exit if already split.
+ if (!this->Pieces.empty())
+ return;
+
+ if (this->NumRelocations) {
+ if (this->AreRelocsRela)
+ split(this->relas());
+ else
+ split(this->rels());
+ return;
+ }
+ split(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr));
+}
+
template <class ELFT>
-void EhInputSection<ELFT>::split() {
- ArrayRef<uint8_t> Data = this->getSectionData();
+template <class RelTy>
+void EhInputSection<ELFT>::split(ArrayRef<RelTy> Rels) {
+ ArrayRef<uint8_t> Data = this->Data;
+ unsigned RelI = 0;
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));
+ size_t Size = readEhRecordSize<ELFT>(this, Off);
+ this->Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI));
// The empty record is the end marker.
if (Size == 4)
break;
@@ -466,21 +682,6 @@ void EhInputSection<ELFT>::split() {
}
}
-template <class ELFT>
-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;
- const SectionPiece *Piece = this->getSectionPiece(Offset);
- if (Piece->OutputOff == size_t(-1))
- return -1; // Not in the output
-
- 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());
@@ -497,75 +698,96 @@ static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) {
// 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;
+template <class ELFT>
+void MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data,
+ size_t EntSize) {
size_t Off = 0;
+ bool IsAlloc = this->Flags & SHF_ALLOC;
while (!Data.empty()) {
size_t End = findNull(Data, EntSize);
if (End == StringRef::npos)
- fatal("string is not null terminated");
+ fatal(toString(this) + ": string is not null terminated");
size_t Size = End + EntSize;
- V.emplace_back(Off, Data.slice(0, Size));
+ Pieces.emplace_back(Off, !IsAlloc);
+ Hashes.push_back(hash_value(toStringRef(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;
+template <class ELFT>
+void MergeInputSection<ELFT>::splitNonStrings(ArrayRef<uint8_t> Data,
+ size_t EntSize) {
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;
+ bool IsAlloc = this->Flags & SHF_ALLOC;
+ for (unsigned I = 0, N = Size; I != N; I += EntSize) {
+ Hashes.push_back(hash_value(toStringRef(Data.slice(I, EntSize))));
+ Pieces.emplace_back(I, !IsAlloc);
+ }
}
template <class ELFT>
MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header)
- : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::Merge) {}
+ const Elf_Shdr *Header,
+ StringRef Name)
+ : InputSectionBase<ELFT>(F, Header, Name, InputSectionBase<ELFT>::Merge) {}
+// This function is called after we obtain a complete list of input sections
+// that need to be linked. This is responsible to split section contents
+// into small chunks for further processing.
+//
+// Note that this function is called from parallel_for_each. This must be
+// thread-safe (i.e. no memory allocation from the pools).
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);
+ ArrayRef<uint8_t> Data = this->Data;
+ uintX_t EntSize = this->Entsize;
+ if (this->Flags & SHF_STRINGS)
+ splitStrings(Data, EntSize);
else
- this->Pieces = splitNonStrings(Data, EntSize);
+ splitNonStrings(Data, EntSize);
- if (Config->GcSections)
+ if (Config->GcSections && (this->Flags & SHF_ALLOC))
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;
+bool MergeInputSection<ELFT>::classof(const InputSectionData *S) {
+ return S->kind() == InputSectionBase<ELFT>::Merge;
}
// Do binary search to get a section piece at a given input offset.
template <class ELFT>
-SectionPiece *SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) {
- auto *This = static_cast<const SplitInputSection<ELFT> *>(this);
+SectionPiece *MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) {
+ auto *This = static_cast<const MergeInputSection<ELFT> *>(this);
return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
}
+template <class It, class T, class Compare>
+static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
+ size_t Size = std::distance(First, Last);
+ assert(Size != 0);
+ while (Size != 1) {
+ size_t H = Size / 2;
+ const It MI = First + H;
+ Size -= H;
+ First = Comp(Value, *MI) ? First : First + H;
+ }
+ return Comp(Value, *First) ? First : First + 1;
+}
+
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();
+MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
+ uintX_t Size = this->Data.size();
if (Offset >= Size)
- fatal("entry is past the end of the section");
+ fatal(toString(this) + ": entry is past the end of the section");
// Find the element this offset points to.
- auto I = std::upper_bound(
+ auto I = fastUpperBound(
Pieces.begin(), Pieces.end(), Offset,
[](const uintX_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
@@ -577,84 +799,31 @@ SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
// it is not just an addition to a base output offset.
template <class ELFT>
typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+ // Initialize OffsetMap lazily.
+ std::call_once(InitOffsetMap, [&] {
+ OffsetMap.reserve(Pieces.size());
+ for (const SectionPiece &Piece : Pieces)
+ OffsetMap[Piece.InputOff] = Piece.OutputOff;
+ });
+
+ // Find a string starting at a given offset.
auto It = OffsetMap.find(Offset);
if (It != OffsetMap.end())
return It->second;
+ if (!this->Live)
+ return 0;
+
// 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);
+ if (!Piece.Live)
+ return 0;
+
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(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");
- return;
- }
- Reginfo = reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>(D.data());
-}
-
-template <class ELFT>
-bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
- return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;
-}
-
-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>;
@@ -665,11 +834,6 @@ 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>;
@@ -680,12 +844,7 @@ 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>;
+template std::string elf::toString(const InputSectionBase<ELF32LE> *);
+template std::string elf::toString(const InputSectionBase<ELF32BE> *);
+template std::string elf::toString(const InputSectionBase<ELF64LE> *);
+template std::string elf::toString(const InputSectionBase<ELF64BE> *);
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 61a89c540c5d..adbc1e1e3829 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -14,25 +14,64 @@
#include "Relocations.h"
#include "Thunks.h"
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Object/ELF.h"
+#include <mutex>
namespace lld {
namespace elf {
-template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S);
-
+class DefinedCommon;
class SymbolBody;
+struct SectionPiece;
-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;
+class OutputSectionBase;
+
+// We need non-template input section class to store symbol layout
+// in linker script parser structures, where we do not have ELFT
+// template parameter. For each scripted output section symbol we
+// store pointer to preceding InputSectionData object or nullptr,
+// if symbol should be placed at the very beginning of the output
+// section
+class InputSectionData {
+public:
+ enum Kind { Regular, EHFrame, Merge, Synthetic, };
+
+ // The garbage collector sets sections' Live bits.
+ // If GC is disabled, all sections are considered live by default.
+ InputSectionData(Kind SectionKind, StringRef Name, ArrayRef<uint8_t> Data,
+ bool Live)
+ : SectionKind(SectionKind), Live(Live), Assigned(false), Name(Name),
+ Data(Data) {}
+
+private:
+ unsigned SectionKind : 3;
+
+public:
+ Kind kind() const { return (Kind)SectionKind; }
+
+ unsigned Live : 1; // for garbage collection
+ unsigned Assigned : 1; // for linker script
+ uint32_t Alignment;
+ StringRef Name;
+ ArrayRef<uint8_t> Data;
+
+ template <typename T> llvm::ArrayRef<T> getDataAs() const {
+ size_t S = Data.size();
+ assert(S % sizeof(T) == 0);
+ return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
+ }
+
+ std::vector<Relocation> Relocations;
+};
// This corresponds to a section of an input file.
-template <class ELFT> class InputSectionBase {
+template <class ELFT> class InputSectionBase : public InputSectionData {
protected:
typedef typename ELFT::Chdr Elf_Chdr;
typedef typename ELFT::Rel Elf_Rel;
@@ -40,27 +79,46 @@ protected:
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, MipsOptions };
- Kind SectionKind;
-
- InputSectionBase() : Repl(this) {}
+ // These corresponds to the fields in Elf_Shdr.
+ uintX_t Flags;
+ uintX_t Offset = 0;
+ uintX_t Entsize;
+ uint32_t Type;
+ uint32_t Link;
+ uint32_t Info;
+
+ InputSectionBase()
+ : InputSectionData(Regular, "", ArrayRef<uint8_t>(), false), Repl(this) {
+ NumRelocations = 0;
+ AreRelocsRela = false;
+ }
InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+ StringRef Name, Kind SectionKind);
+ InputSectionBase(ObjectFile<ELFT> *File, uintX_t Flags, uint32_t Type,
+ uintX_t Entsize, uint32_t Link, uint32_t Info,
+ uintX_t Addralign, ArrayRef<uint8_t> Data, StringRef Name,
Kind SectionKind);
- OutputSectionBase<ELFT> *OutSec = nullptr;
- uint32_t Alignment;
-
- // Used for garbage collection.
- bool Live;
+ OutputSectionBase *OutSec = nullptr;
+
+ // Relocations that refer to this section.
+ const Elf_Rel *FirstRelocation = nullptr;
+ unsigned NumRelocations : 31;
+ unsigned AreRelocsRela : 1;
+ ArrayRef<Elf_Rel> rels() const {
+ assert(!AreRelocsRela);
+ return llvm::makeArrayRef(FirstRelocation, NumRelocations);
+ }
+ ArrayRef<Elf_Rela> relas() const {
+ assert(AreRelocsRela);
+ return llvm::makeArrayRef(static_cast<const Elf_Rela *>(FirstRelocation),
+ NumRelocations);
+ }
// This pointer points to the "real" instance of this instance.
// Usually Repl == this. However, if ICF merges two sections,
@@ -72,140 +130,163 @@ public:
// Returns the size of this section (even if this is a common or BSS.)
size_t getSize() const;
- static InputSectionBase<ELFT> Discarded;
-
- StringRef getSectionName() const;
- const Elf_Shdr *getSectionHdr() const { return Header; }
ObjectFile<ELFT> *getFile() const { return File; }
+ llvm::object::ELFFile<ELFT> getObj() const { return File->getObj(); }
uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
-
+ InputSectionBase *getLinkOrderDep() const;
// Translate an offset in the input section to an offset in the output
// section.
uintX_t getOffset(uintX_t Offset) const;
- ArrayRef<uint8_t> getSectionData() const;
-
+ // ELF supports ZLIB-compressed section.
+ // Returns true if the section is compressed.
+ bool isCompressed() const;
void uncompress();
+ // Returns a source location string. Used to construct an error message.
+ std::string getLocation(uintX_t Offset);
+
void relocate(uint8_t *Buf, uint8_t *BufEnd);
- std::vector<Relocation<ELFT>> Relocations;
- bool Compressed;
-};
+private:
+ std::pair<ArrayRef<uint8_t>, uint64_t>
+ getElfCompressedData(ArrayRef<uint8_t> Data);
-template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;
+ std::pair<ArrayRef<uint8_t>, uint64_t>
+ getRawCompressedData(ArrayRef<uint8_t> Data);
+};
// SectionPiece represents a piece of splittable section contents.
+// We allocate a lot of these and binary search on them. This means that they
+// have to be as compact as possible, which is why we don't store the size (can
+// be found by looking at the next one) and put the hash in a side table.
struct SectionPiece {
- SectionPiece(size_t Off, ArrayRef<uint8_t> Data)
- : InputOff(Off), Data((const uint8_t *)Data.data()), Size(Data.size()),
- Live(!Config->GcSections) {}
-
- ArrayRef<uint8_t> data() { return {Data, Size}; }
- size_t size() const { return Size; }
+ SectionPiece(size_t Off, bool Live = false)
+ : InputOff(Off), OutputOff(-1), Live(Live || !Config->GcSections) {}
size_t InputOff;
- size_t OutputOff = -1;
-
-private:
- // 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;
-
-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 ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::uint uintX_t;
-
-public:
- SplitInputSection(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
- typename InputSectionBase<ELFT>::Kind SectionKind);
-
- // Splittable sections are handled as a sequence of data
- // rather than a single large blob of data.
- std::vector<SectionPiece> Pieces;
-
- // Returns the SectionPiece at a given input section offset.
- SectionPiece *getSectionPiece(uintX_t Offset);
- const SectionPiece *getSectionPiece(uintX_t Offset) const;
+ ssize_t OutputOff : 8 * sizeof(ssize_t) - 1;
+ size_t Live : 1;
};
+static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t),
+ "SectionPiece is too big");
// This corresponds to a SHF_MERGE section of an input file.
-template <class ELFT> class MergeInputSection : public SplitInputSection<ELFT> {
+template <class ELFT> class MergeInputSection : public InputSectionBase<ELFT> {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Shdr Elf_Shdr;
public:
- MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
- static bool classof(const InputSectionBase<ELFT> *S);
+ MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header,
+ StringRef Name);
+ static bool classof(const InputSectionData *S);
void splitIntoPieces();
// Mark the piece at a given offset live. Used by GC.
- void markLiveAt(uintX_t Offset) { LiveOffsets.insert(Offset); }
+ void markLiveAt(uintX_t Offset) {
+ assert(this->Flags & llvm::ELF::SHF_ALLOC);
+ LiveOffsets.insert(Offset);
+ }
// Translate an offset in the input section to an offset
// in the output section.
uintX_t getOffset(uintX_t Offset) const;
- void finalizePieces();
+ // Splittable sections are handled as a sequence of data
+ // rather than a single large blob of data.
+ std::vector<SectionPiece> Pieces;
+
+ // Returns I'th piece's data. This function is very hot when
+ // string merging is enabled, so we want to inline.
+ LLVM_ATTRIBUTE_ALWAYS_INLINE
+ llvm::CachedHashStringRef getData(size_t I) const {
+ size_t Begin = Pieces[I].InputOff;
+ size_t End;
+ if (Pieces.size() - 1 == I)
+ End = this->Data.size();
+ else
+ End = Pieces[I + 1].InputOff;
+
+ StringRef S = {(const char *)(this->Data.data() + Begin), End - Begin};
+ return {S, Hashes[I]};
+ }
+
+ // Returns the SectionPiece at a given input section offset.
+ SectionPiece *getSectionPiece(uintX_t Offset);
+ const SectionPiece *getSectionPiece(uintX_t Offset) const;
private:
- llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
+ void splitStrings(ArrayRef<uint8_t> A, size_t Size);
+ void splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
+
+ std::vector<uint32_t> Hashes;
+
+ mutable llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
+ mutable std::once_flag InitOffsetMap;
+
llvm::DenseSet<uintX_t> LiveOffsets;
};
+struct EhSectionPiece : public SectionPiece {
+ EhSectionPiece(size_t Off, InputSectionData *ID, uint32_t Size,
+ unsigned FirstRelocation)
+ : SectionPiece(Off, false), ID(ID), Size(Size),
+ FirstRelocation(FirstRelocation) {}
+ InputSectionData *ID;
+ uint32_t Size;
+ uint32_t size() const { return Size; }
+
+ ArrayRef<uint8_t> data() { return {ID->Data.data() + this->InputOff, Size}; }
+ unsigned FirstRelocation;
+};
+
// 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 InputSectionBase<ELFT> {
public:
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);
+ EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name);
+ static bool classof(const InputSectionData *S);
void split();
+ template <class RelTy> void split(ArrayRef<RelTy> Rels);
- // Translate an offset in the input section to an offset in the output
- // section.
- uintX_t getOffset(uintX_t Offset) const;
-
- // Relocation section that refer to this one.
- const Elf_Shdr *RelocSection = nullptr;
+ // Splittable sections are handled as a sequence of data
+ // rather than a single large blob of data.
+ std::vector<EhSectionPiece> Pieces;
};
// 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 ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::uint uintX_t;
+ typedef InputSectionData::Kind Kind;
public:
- InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+ InputSection();
+ InputSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
+ ArrayRef<uint8_t> Data, StringRef Name,
+ Kind K = InputSectionData::Regular);
+ InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name);
+
+ static InputSection<ELFT> Discarded;
// Write this section to a mmap'ed file, assuming Buf is pointing to
// beginning of the output section.
void writeTo(uint8_t *Buf);
- // Relocation sections that refer to this one.
- 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);
+ // InputSection that is dependent on us (reverse dependency for GC)
+ InputSectionBase<ELFT> *DependentSection = nullptr;
+
+ static bool classof(const InputSectionData *S);
InputSectionBase<ELFT> *getRelocatedSection();
@@ -223,46 +304,22 @@ public:
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);
+ // Used by ICF.
+ uint32_t Class[2] = {0, 0};
// Called by ICF to merge two input sections.
void replace(InputSection<ELFT> *Other);
- // Used by ICF.
- uint64_t GroupId = 0;
+private:
+ template <class RelTy>
+ void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks;
};
-// MIPS .reginfo section provides information on the registers used by the code
-// in the object file. Linker should collect this information and write a single
-// .reginfo section in the output file. The output section contains a union of
-// used registers masks taken from input .reginfo sections and final value
-// of the `_gp` symbol. For details: Chapter 4 / "Register Information" at
-// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-template <class ELFT>
-class MipsReginfoInputSection : public InputSectionBase<ELFT> {
- 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 = nullptr;
-};
+template <class ELFT> InputSection<ELFT> InputSection<ELFT>::Discarded;
-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;
-};
+template <class ELFT> std::string toString(const InputSectionBase<ELFT> *);
} // namespace elf
} // namespace lld
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index 0e8006a3b32a..a3d6a141a202 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -9,31 +9,30 @@
#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/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/CommandFlags.h"
-#include "llvm/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"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
using namespace llvm;
using namespace llvm::object;
@@ -51,275 +50,110 @@ static void saveBuffer(StringRef Buffer, const Twine &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 diagnosticHandler(const DiagnosticInfo &DI) {
+ SmallString<128> ErrStorage;
+ raw_svector_ostream OS(ErrStorage);
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+ warn(ErrStorage);
}
-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());
+static void checkError(Error E) {
+ handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
+ error(EIB.message());
+ return Error::success();
+ });
+}
- // 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;
- }
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config Conf;
- if (!Config->DisableVerify)
- MPM.addPass(VerifierPass());
- MPM.run(M, MAM);
-}
+ // LLD supports the new relocations.
+ Conf.Options = InitTargetOptionsFromCodeGenFlags();
+ Conf.Options.RelaxELFRelocations = true;
-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);
-}
+ Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static;
+ Conf.DisableVerify = Config->DisableVerify;
+ Conf.DiagHandler = diagnosticHandler;
+ Conf.OptLevel = Config->LTOO;
-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);
- }
+ // Set up a custom pipeline if we've been asked to.
+ Conf.OptPipeline = Config->LTONewPmPasses;
+ Conf.AAPipeline = Config->LTOAAPipeline;
if (Config->SaveTemps)
- saveBCFile(M, Config->OutputFile + ".lto.opt.bc");
+ checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
+ /*UseInputModulePath*/ true));
+
+ lto::ThinBackend Backend;
+ if (Config->ThinLTOJobs != -1u)
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
+ Config->LTOPartitions);
}
-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() : LTOObj(createLTO()) {}
-BitcodeCompiler::BitcodeCompiler()
- : Combined(new Module("ld-temp.o", Driver->Context)) {}
+BitcodeCompiler::~BitcodeCompiler() = default;
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());
+ replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
+ STV_DEFAULT, S->body()->Type, nullptr);
}
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());
- });
+ lto::InputFile &Obj = *F.Obj;
+ unsigned SymNum = 0;
+ std::vector<Symbol *> Syms = F.getSymbols();
+ std::vector<lto::SymbolResolution> Resols(Syms.size());
+
+ // Provide a resolution to the LTO API for each symbol.
+ for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
+ Symbol *Sym = Syms[SymNum];
+ lto::SymbolResolution &R = Resols[SymNum];
+ ++SymNum;
+ SymbolBody *B = Sym->body();
+
+ // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+ // reports two symbols for module ASM defined. Without this check, lld
+ // flags an undefined in IR with a definition in ASM as prevailing.
+ // Once IRObjectFile is fixed to report only one symbol this hack can
+ // be removed.
+ R.Prevailing =
+ !(ObjSym.getFlags() & object::BasicSymbolRef::SF_Undefined) &&
+ B->File == &F;
+
+ R.VisibleToRegularObj =
+ Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
+ if (R.Prevailing)
+ undefine(Sym);
}
-}
-
-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;
+ checkError(LTOObj->add(std::move(F.Obj), Resols));
}
// 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);
+// and return the resulting ObjectFile(s).
+std::vector<InputFile *> BitcodeCompiler::compile() {
+ std::vector<InputFile *> Ret;
+ unsigned MaxTasks = LTOObj->getMaxTasks();
+ Buff.resize(MaxTasks);
+
+ checkError(LTOObj->run([&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ }));
+
+ for (unsigned I = 0; I != MaxTasks; ++I) {
+ if (Buff[I].empty())
+ continue;
+ if (Config->SaveTemps) {
+ if (MaxTasks == 1)
+ saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
+ else
+ saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
+ }
+ InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp"));
+ Ret.push_back(Obj);
}
-
- 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);
+ return Ret;
}
diff --git a/ELF/LTO.h b/ELF/LTO.h
index 81dffb6004b2..b3d734f2d381 100644
--- a/ELF/LTO.h
+++ b/ELF/LTO.h
@@ -23,9 +23,14 @@
#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"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace lto {
+class LTO;
+}
+}
namespace lld {
namespace elf {
@@ -36,17 +41,14 @@ class InputFile;
class BitcodeCompiler {
public:
BitcodeCompiler();
+ ~BitcodeCompiler();
+
void add(BitcodeFile &F);
- std::vector<std::unique_ptr<InputFile>> compile();
+ std::vector<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;
+ std::unique_ptr<llvm::lto::LTO> LTOObj;
+ std::vector<SmallString<0>> Buff;
};
}
}
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index 61abdc185e11..5057b57a4a54 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -8,8 +8,6 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
@@ -17,311 +15,971 @@
#include "Config.h"
#include "Driver.h"
#include "InputSection.h"
+#include "Memory.h"
#include "OutputSections.h"
#include "ScriptParser.h"
#include "Strings.h"
-#include "Symbols.h"
#include "SymbolTable.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
#include "Target.h"
+#include "Writer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/ELF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/StringSaver.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <vector>
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
+using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
+LinkerScriptBase *elf::ScriptBase;
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 ExprParser : public ScriptParserBase {
-public:
- ExprParser(std::vector<StringRef> &Tokens, uint64_t Dot)
- : ScriptParserBase(Tokens), Dot(Dot) {}
+template <class ELFT> static void addRegular(SymbolAssignment *Cmd) {
+ uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+ Symbol *Sym = Symtab<ELFT>::X->addRegular(Cmd->Name, Visibility, STT_NOTYPE,
+ 0, 0, STB_GLOBAL, nullptr, nullptr);
+ Cmd->Sym = Sym->body();
- uint64_t run();
+ // If we have no SECTIONS then we don't have '.' and don't call
+ // assignAddresses(). We calculate symbol value immediately in this case.
+ if (!ScriptConfig->HasSections)
+ cast<DefinedRegular<ELFT>>(Cmd->Sym)->Value = Cmd->Expression(0);
+}
-private:
- 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();
+template <class ELFT> static void addSynthetic(SymbolAssignment *Cmd) {
+ // If we have SECTIONS block then output sections haven't been created yet.
+ const OutputSectionBase *Sec =
+ ScriptConfig->HasSections ? nullptr : Cmd->Expression.Section();
+ Symbol *Sym = Symtab<ELFT>::X->addSynthetic(
+ Cmd->Name, Sec, 0, Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT);
+ Cmd->Sym = Sym->body();
- uint64_t Dot;
-};
+ // If we already know section then we can calculate symbol value immediately.
+ if (Sec)
+ cast<DefinedSynthetic>(Cmd->Sym)->Value = Cmd->Expression(0) - Sec->Addr;
}
-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);
+static bool isUnderSysroot(StringRef Path) {
+ if (Config->Sysroot == "")
+ return false;
+ for (; !Path.empty(); Path = sys::path::parent_path(Path))
+ if (sys::fs::equivalent(Config->Sysroot, Path))
+ return true;
+ return false;
}
-static uint64_t evalExpr(std::vector<StringRef> &Tokens, uint64_t Dot) {
- return ExprParser(Tokens, Dot).run();
+template <class ELFT> static void addSymbol(SymbolAssignment *Cmd) {
+ if (Cmd->Expression.IsAbsolute())
+ addRegular<ELFT>(Cmd);
+ else
+ addSynthetic<ELFT>(Cmd);
+}
+// If a symbol was in PROVIDE(), we need to define it only when
+// it is an undefined symbol.
+template <class ELFT> static bool shouldDefine(SymbolAssignment *Cmd) {
+ if (Cmd->Name == ".")
+ return false;
+ if (!Cmd->Provide)
+ return true;
+ SymbolBody *B = Symtab<ELFT>::X->find(Cmd->Name);
+ return B && B->isUndefined();
}
-uint64_t ExprParser::run() {
- uint64_t V = parseExpr();
- if (!atEOF() && !Error)
- setError("stray token: " + peek());
- return V;
+bool SymbolAssignment::classof(const BaseCommand *C) {
+ return C->Kind == AssignmentKind;
}
-// 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;
+bool OutputSectionCommand::classof(const BaseCommand *C) {
+ return C->Kind == OutputSectionKind;
}
-uint64_t ExprParser::parseTernary(uint64_t Cond) {
- next();
- uint64_t V = parseExpr();
- expect(":");
- uint64_t W = parseExpr();
- return Cond ? V : W;
+bool InputSectionDescription::classof(const BaseCommand *C) {
+ return C->Kind == InputSectionKind;
}
-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;
+bool AssertCommand::classof(const BaseCommand *C) {
+ return C->Kind == AssertKind;
+}
+
+bool BytesDataCommand::classof(const BaseCommand *C) {
+ return C->Kind == BytesDataKind;
+}
+
+template <class ELFT> LinkerScript<ELFT>::LinkerScript() = default;
+template <class ELFT> LinkerScript<ELFT>::~LinkerScript() = default;
+
+template <class ELFT> static StringRef basename(InputSectionBase<ELFT> *S) {
+ if (S->getFile())
+ return sys::path::filename(S->getFile()->getName());
+ return "";
+}
+
+template <class ELFT>
+bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
+ for (InputSectionDescription *ID : Opt.KeptSections)
+ if (ID->FilePat.match(basename(S)))
+ for (SectionPattern &P : ID->SectionPatterns)
+ if (P.SectionPat.match(S->Name))
+ return true;
+ return false;
+}
+
+static bool comparePriority(InputSectionData *A, InputSectionData *B) {
+ return getPriority(A->Name) < getPriority(B->Name);
+}
+
+static bool compareName(InputSectionData *A, InputSectionData *B) {
+ return A->Name < B->Name;
+}
+
+static bool compareAlignment(InputSectionData *A, InputSectionData *B) {
+ // ">" is not a mistake. Larger alignments are placed before smaller
+ // alignments in order to reduce the amount of padding necessary.
+ // This is compatible with GNU.
+ return A->Alignment > B->Alignment;
+}
+
+static std::function<bool(InputSectionData *, InputSectionData *)>
+getComparator(SortSectionPolicy K) {
+ switch (K) {
+ case SortSectionPolicy::Alignment:
+ return compareAlignment;
+ case SortSectionPolicy::Name:
+ return compareName;
+ case SortSectionPolicy::Priority:
+ return comparePriority;
+ default:
+ llvm_unreachable("unknown sort policy");
}
- 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");
}
-// 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();
+template <class ELFT>
+static bool matchConstraints(ArrayRef<InputSectionBase<ELFT> *> Sections,
+ ConstraintKind Kind) {
+ if (Kind == ConstraintKind::NoConstraint)
+ return true;
+ bool IsRW = llvm::any_of(Sections, [=](InputSectionData *Sec2) {
+ auto *Sec = static_cast<InputSectionBase<ELFT> *>(Sec2);
+ return Sec->Flags & SHF_WRITE;
+ });
+ return (IsRW && Kind == ConstraintKind::ReadWrite) ||
+ (!IsRW && Kind == ConstraintKind::ReadOnly);
+}
- // 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));
+static void sortSections(InputSectionData **Begin, InputSectionData **End,
+ SortSectionPolicy K) {
+ if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None)
+ std::stable_sort(Begin, End, getComparator(K));
+}
+
+// Compute and remember which sections the InputSectionDescription matches.
+template <class ELFT>
+void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
+ // Collects all sections that satisfy constraints of I
+ // and attach them to I.
+ for (SectionPattern &Pat : I->SectionPatterns) {
+ size_t SizeBefore = I->Sections.size();
+
+ for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections) {
+ if (!S->Live || S->Assigned)
+ continue;
+
+ StringRef Filename = basename(S);
+ if (!I->FilePat.match(Filename) || Pat.ExcludedFilePat.match(Filename))
+ continue;
+ if (!Pat.SectionPat.match(S->Name))
+ continue;
+ I->Sections.push_back(S);
+ S->Assigned = true;
}
- Lhs = apply(Op1, Lhs, Rhs);
+ // Sort sections as instructed by SORT-family commands and --sort-section
+ // option. Because SORT-family commands can be nested at most two depth
+ // (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command
+ // line option is respected even if a SORT command is given, the exact
+ // behavior we have here is a bit complicated. Here are the rules.
+ //
+ // 1. If two SORT commands are given, --sort-section is ignored.
+ // 2. If one SORT command is given, and if it is not SORT_NONE,
+ // --sort-section is handled as an inner SORT command.
+ // 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
+ // 4. If no SORT command is given, sort according to --sort-section.
+ InputSectionData **Begin = I->Sections.data() + SizeBefore;
+ InputSectionData **End = I->Sections.data() + I->Sections.size();
+ if (Pat.SortOuter != SortSectionPolicy::None) {
+ if (Pat.SortInner == SortSectionPolicy::Default)
+ sortSections(Begin, End, Config->SortSection);
+ else
+ sortSections(Begin, End, Pat.SortInner);
+ sortSections(Begin, End, Pat.SortOuter);
+ }
}
- 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 "";
+void LinkerScript<ELFT>::discard(ArrayRef<InputSectionBase<ELFT> *> V) {
+ for (InputSectionBase<ELFT> *S : V) {
+ S->Live = false;
+ reportDiscarded(S);
+ }
}
template <class ELFT>
-bool LinkerScript<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) {
- return getOutputSection(S) == "/DISCARD/";
+std::vector<InputSectionBase<ELFT> *>
+LinkerScript<ELFT>::createInputSectionList(OutputSectionCommand &OutCmd) {
+ std::vector<InputSectionBase<ELFT> *> Ret;
+
+ for (const std::unique_ptr<BaseCommand> &Base : OutCmd.Commands) {
+ auto *Cmd = dyn_cast<InputSectionDescription>(Base.get());
+ if (!Cmd)
+ continue;
+ computeInputSections(Cmd);
+ for (InputSectionData *S : Cmd->Sections)
+ Ret.push_back(static_cast<InputSectionBase<ELFT> *>(S));
+ }
+
+ return Ret;
}
template <class ELFT>
-bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
- for (StringRef Pat : Opt.KeptSections)
- if (globMatch(Pat, S->getSectionName()))
- return true;
- return false;
+static SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C,
+ StringRef OutsecName) {
+ // When using linker script the merge rules are different.
+ // Unfortunately, linker scripts are name based. This means that expressions
+ // like *(.foo*) can refer to multiple input sections that would normally be
+ // placed in different output sections. We cannot put them in different
+ // output sections or we would produce wrong results for
+ // start = .; *(.foo.*) end = .; *(.bar)
+ // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to
+ // another. The problem is that there is no way to layout those output
+ // sections such that the .foo sections are the only thing between the
+ // start and end symbols.
+
+ // An extra annoyance is that we cannot simply disable merging of the contents
+ // of SHF_MERGE sections, but our implementation requires one output section
+ // per "kind" (string or not, which size/aligment).
+ // Fortunately, creating symbols in the middle of a merge section is not
+ // supported by bfd or gold, so we can just create multiple section in that
+ // case.
+ typedef typename ELFT::uint uintX_t;
+ uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
+
+ uintX_t Alignment = 0;
+ if (isa<MergeInputSection<ELFT>>(C))
+ Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
+
+ return SectionKey<ELFT::Is64Bits>{OutsecName, /*Type*/ 0, Flags, Alignment};
}
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});
- }
+void LinkerScript<ELFT>::addSection(OutputSectionFactory<ELFT> &Factory,
+ InputSectionBase<ELFT> *Sec,
+ StringRef Name) {
+ OutputSectionBase *OutSec;
+ bool IsNew;
+ std::tie(OutSec, IsNew) = Factory.create(createKey(Sec, Name), Sec);
+ if (IsNew)
+ OutputSections->push_back(OutSec);
+ OutSec->addSection(Sec);
+}
- // 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;
+template <class ELFT>
+void LinkerScript<ELFT>::processCommands(OutputSectionFactory<ELFT> &Factory) {
+ for (unsigned I = 0; I < Opt.Commands.size(); ++I) {
+ auto Iter = Opt.Commands.begin() + I;
+ const std::unique_ptr<BaseCommand> &Base1 = *Iter;
- for (SectionsCommand &Cmd : Opt.Commands) {
- if (Cmd.Kind == AssignmentKind) {
- uint64_t Val = evalExpr(Cmd.Expr, Dot);
+ // Handle symbol assignments outside of any output section.
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base1.get())) {
+ if (shouldDefine<ELFT>(Cmd))
+ addSymbol<ELFT>(Cmd);
+ continue;
+ }
- if (Cmd.Name == ".") {
- Dot = Val;
- } else {
- auto *D = cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd.Name));
- D->Value = Val;
- }
+ if (auto *Cmd = dyn_cast<AssertCommand>(Base1.get())) {
+ // If we don't have SECTIONS then output sections have already been
+ // created by Writer<ELFT>. The LinkerScript<ELFT>::assignAddresses
+ // will not be called, so ASSERT should be evaluated now.
+ if (!Opt.HasSections)
+ Cmd->Expression(0);
continue;
}
- // 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)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base1.get())) {
+ std::vector<InputSectionBase<ELFT> *> V = createInputSectionList(*Cmd);
+
+ // The output section name `/DISCARD/' is special.
+ // Any input section assigned to it is discarded.
+ if (Cmd->Name == "/DISCARD/") {
+ discard(V);
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();
+ // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive
+ // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input
+ // sections satisfy a given constraint. If not, a directive is handled
+ // as if it wasn't present from the beginning.
+ //
+ // Because we'll iterate over Commands many more times, the easiest
+ // way to "make it as if it wasn't present" is to just remove it.
+ if (!matchConstraints<ELFT>(V, Cmd->Constraint)) {
+ for (InputSectionBase<ELFT> *S : V)
+ S->Assigned = false;
+ Opt.Commands.erase(Iter);
+ --I;
continue;
}
- if (Sec->getFlags() & SHF_ALLOC) {
- Dot = alignTo(Dot, Sec->getAlignment());
- Sec->setVA(Dot);
- MinVA = std::min(MinVA, Dot);
- Dot += Sec->getSize();
+ // A directive may contain symbol definitions like this:
+ // ".foo : { ...; bar = .; }". Handle them.
+ for (const std::unique_ptr<BaseCommand> &Base : Cmd->Commands)
+ if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base.get()))
+ if (shouldDefine<ELFT>(OutCmd))
+ addSymbol<ELFT>(OutCmd);
+
+ // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
+ // is given, input sections are aligned to that value, whether the
+ // given value is larger or smaller than the original section alignment.
+ if (Cmd->SubalignExpr) {
+ uint32_t Subalign = Cmd->SubalignExpr(0);
+ for (InputSectionBase<ELFT> *S : V)
+ S->Alignment = Subalign;
+ }
+
+ // Add input sections to an output section.
+ for (InputSectionBase<ELFT> *S : V)
+ addSection(Factory, S, Cmd->Name);
+ }
+ }
+}
+
+// Add sections that didn't match any sections command.
+template <class ELFT>
+void LinkerScript<ELFT>::addOrphanSections(
+ OutputSectionFactory<ELFT> &Factory) {
+ for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections)
+ if (S->Live && !S->OutSec)
+ addSection(Factory, S, getOutputSectionName(S->Name));
+}
+
+// Sets value of a section-defined symbol. Two kinds of
+// symbols are processed: synthetic symbols, whose value
+// is an offset from beginning of section and regular
+// symbols whose value is absolute.
+template <class ELFT>
+static void assignSectionSymbol(SymbolAssignment *Cmd,
+ typename ELFT::uint Value) {
+ if (!Cmd->Sym)
+ return;
+
+ if (auto *Body = dyn_cast<DefinedSynthetic>(Cmd->Sym)) {
+ Body->Section = Cmd->Expression.Section();
+ Body->Value = Cmd->Expression(Value) - Body->Section->Addr;
+ return;
+ }
+ auto *Body = cast<DefinedRegular<ELFT>>(Cmd->Sym);
+ Body->Value = Cmd->Expression(Value);
+}
+
+template <class ELFT> static bool isTbss(OutputSectionBase *Sec) {
+ return (Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS;
+}
+
+template <class ELFT> void LinkerScript<ELFT>::output(InputSection<ELFT> *S) {
+ if (!AlreadyOutputIS.insert(S).second)
+ return;
+ bool IsTbss = isTbss<ELFT>(CurOutSec);
+
+ uintX_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot;
+ Pos = alignTo(Pos, S->Alignment);
+ S->OutSecOff = Pos - CurOutSec->Addr;
+ Pos += S->getSize();
+
+ // Update output section size after adding each section. This is so that
+ // SIZEOF works correctly in the case below:
+ // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
+ CurOutSec->Size = Pos - CurOutSec->Addr;
+
+ if (IsTbss)
+ ThreadBssOffset = Pos - Dot;
+ else
+ Dot = Pos;
+}
+
+template <class ELFT> void LinkerScript<ELFT>::flush() {
+ if (!CurOutSec || !AlreadyOutputOS.insert(CurOutSec).second)
+ return;
+ if (auto *OutSec = dyn_cast<OutputSection<ELFT>>(CurOutSec)) {
+ for (InputSection<ELFT> *I : OutSec->Sections)
+ output(I);
+ } else {
+ Dot += CurOutSec->Size;
+ }
+}
+
+template <class ELFT>
+void LinkerScript<ELFT>::switchTo(OutputSectionBase *Sec) {
+ if (CurOutSec == Sec)
+ return;
+ if (AlreadyOutputOS.count(Sec))
+ return;
+
+ flush();
+ CurOutSec = Sec;
+
+ Dot = alignTo(Dot, CurOutSec->Addralign);
+ CurOutSec->Addr = isTbss<ELFT>(CurOutSec) ? Dot + ThreadBssOffset : Dot;
+
+ // If neither AT nor AT> is specified for an allocatable section, the linker
+ // will set the LMA such that the difference between VMA and LMA for the
+ // section is the same as the preceding output section in the same region
+ // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
+ CurOutSec->setLMAOffset(LMAOffset);
+}
+
+template <class ELFT> void LinkerScript<ELFT>::process(BaseCommand &Base) {
+ // This handles the assignments to symbol or to a location counter (.)
+ if (auto *AssignCmd = dyn_cast<SymbolAssignment>(&Base)) {
+ if (AssignCmd->Name == ".") {
+ // Update to location counter means update to section size.
+ uintX_t Val = AssignCmd->Expression(Dot);
+ if (Val < Dot)
+ error("unable to move location counter backward for: " +
+ CurOutSec->Name);
+ Dot = Val;
+ CurOutSec->Size = Dot - CurOutSec->Addr;
+ return;
+ }
+ assignSectionSymbol<ELFT>(AssignCmd, Dot);
+ return;
+ }
+
+ // Handle BYTE(), SHORT(), LONG(), or QUAD().
+ if (auto *DataCmd = dyn_cast<BytesDataCommand>(&Base)) {
+ DataCmd->Offset = Dot - CurOutSec->Addr;
+ Dot += DataCmd->Size;
+ CurOutSec->Size = Dot - CurOutSec->Addr;
+ return;
+ }
+
+ if (auto *AssertCmd = dyn_cast<AssertCommand>(&Base)) {
+ AssertCmd->Expression(Dot);
+ return;
+ }
+
+ // It handles single input section description command,
+ // calculates and assigns the offsets for each section and also
+ // updates the output section size.
+ auto &ICmd = cast<InputSectionDescription>(Base);
+ for (InputSectionData *ID : ICmd.Sections) {
+ // We tentatively added all synthetic sections at the beginning and removed
+ // empty ones afterwards (because there is no way to know whether they were
+ // going be empty or not other than actually running linker scripts.)
+ // We need to ignore remains of empty sections.
+ if (auto *Sec = dyn_cast<SyntheticSection<ELFT>>(ID))
+ if (Sec->empty())
continue;
+
+ auto *IB = static_cast<InputSectionBase<ELFT> *>(ID);
+ switchTo(IB->OutSec);
+ if (auto *I = dyn_cast<InputSection<ELFT>>(IB))
+ output(I);
+ else
+ flush();
+ }
+}
+
+template <class ELFT>
+static std::vector<OutputSectionBase *>
+findSections(StringRef Name, const std::vector<OutputSectionBase *> &Sections) {
+ std::vector<OutputSectionBase *> Ret;
+ for (OutputSectionBase *Sec : Sections)
+ if (Sec->getName() == Name)
+ Ret.push_back(Sec);
+ return Ret;
+}
+
+// This function assigns offsets to input sections and an output section
+// for a single sections command (e.g. ".text { *(.text); }").
+template <class ELFT>
+void LinkerScript<ELFT>::assignOffsets(OutputSectionCommand *Cmd) {
+ if (Cmd->LMAExpr)
+ LMAOffset = Cmd->LMAExpr(Dot) - Dot;
+ std::vector<OutputSectionBase *> Sections =
+ findSections<ELFT>(Cmd->Name, *OutputSections);
+ if (Sections.empty())
+ return;
+ switchTo(Sections[0]);
+
+ // Find the last section output location. We will output orphan sections
+ // there so that end symbols point to the correct location.
+ auto E = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
+ [](const std::unique_ptr<BaseCommand> &Cmd) {
+ return !isa<SymbolAssignment>(*Cmd);
+ })
+ .base();
+ for (auto I = Cmd->Commands.begin(); I != E; ++I)
+ process(**I);
+ for (OutputSectionBase *Base : Sections)
+ switchTo(Base);
+ flush();
+ std::for_each(E, Cmd->Commands.end(),
+ [this](std::unique_ptr<BaseCommand> &B) { process(*B.get()); });
+}
+
+template <class ELFT> void LinkerScript<ELFT>::removeEmptyCommands() {
+ // It is common practice to use very generic linker scripts. So for any
+ // given run some of the output sections in the script will be empty.
+ // We could create corresponding empty output sections, but that would
+ // clutter the output.
+ // We instead remove trivially empty sections. The bfd linker seems even
+ // more aggressive at removing them.
+ auto Pos = std::remove_if(
+ Opt.Commands.begin(), Opt.Commands.end(),
+ [&](const std::unique_ptr<BaseCommand> &Base) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
+ return findSections<ELFT>(Cmd->Name, *OutputSections).empty();
+ return false;
+ });
+ Opt.Commands.erase(Pos, Opt.Commands.end());
+}
+
+static bool isAllSectionDescription(const OutputSectionCommand &Cmd) {
+ for (const std::unique_ptr<BaseCommand> &I : Cmd.Commands)
+ if (!isa<InputSectionDescription>(*I))
+ return false;
+ return true;
+}
+
+template <class ELFT> void LinkerScript<ELFT>::adjustSectionsBeforeSorting() {
+ // If the output section contains only symbol assignments, create a
+ // corresponding output section. The bfd linker seems to only create them if
+ // '.' is assigned to, but creating these section should not have any bad
+ // consequeces and gives us a section to put the symbol in.
+ uintX_t Flags = SHF_ALLOC;
+ uint32_t Type = SHT_NOBITS;
+ for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+ if (!Cmd)
+ continue;
+ std::vector<OutputSectionBase *> Secs =
+ findSections<ELFT>(Cmd->Name, *OutputSections);
+ if (!Secs.empty()) {
+ Flags = Secs[0]->Flags;
+ Type = Secs[0]->Type;
+ continue;
+ }
+
+ if (isAllSectionDescription(*Cmd))
+ continue;
+
+ auto *OutSec = make<OutputSection<ELFT>>(Cmd->Name, Type, Flags);
+ OutputSections->push_back(OutSec);
+ }
+}
+
+template <class ELFT> void LinkerScript<ELFT>::adjustSectionsAfterSorting() {
+ placeOrphanSections();
+
+ // If output section command doesn't specify any segments,
+ // and we haven't previously assigned any section to segment,
+ // then we simply assign section to the very first load segment.
+ // Below is an example of such linker script:
+ // PHDRS { seg PT_LOAD; }
+ // SECTIONS { .aaa : { *(.aaa) } }
+ std::vector<StringRef> DefPhdrs;
+ auto FirstPtLoad =
+ std::find_if(Opt.PhdrsCommands.begin(), Opt.PhdrsCommands.end(),
+ [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; });
+ if (FirstPtLoad != Opt.PhdrsCommands.end())
+ DefPhdrs.push_back(FirstPtLoad->Name);
+
+ // Walk the commands and propagate the program headers to commands that don't
+ // explicitly specify them.
+ for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+ if (!Cmd)
+ continue;
+ if (Cmd->Phdrs.empty())
+ Cmd->Phdrs = DefPhdrs;
+ else
+ DefPhdrs = Cmd->Phdrs;
+ }
+
+ removeEmptyCommands();
+}
+
+// When placing orphan sections, we want to place them after symbol assignments
+// so that an orphan after
+// begin_foo = .;
+// foo : { *(foo) }
+// end_foo = .;
+// doesn't break the intended meaning of the begin/end symbols.
+// We don't want to go over sections since Writer<ELFT>::sortSections is the
+// one in charge of deciding the order of the sections.
+// We don't want to go over alignments, since doing so in
+// rx_sec : { *(rx_sec) }
+// . = ALIGN(0x1000);
+// /* The RW PT_LOAD starts here*/
+// rw_sec : { *(rw_sec) }
+// would mean that the RW PT_LOAD would become unaligned.
+static bool shouldSkip(const BaseCommand &Cmd) {
+ if (isa<OutputSectionCommand>(Cmd))
+ return false;
+ const auto *Assign = dyn_cast<SymbolAssignment>(&Cmd);
+ if (!Assign)
+ return true;
+ return Assign->Name != ".";
+}
+
+// Orphan sections are sections present in the input files which are not
+// explicitly placed into the output file by the linker script. This just
+// places them in the order already decided in OutputSections.
+template <class ELFT> void LinkerScript<ELFT>::placeOrphanSections() {
+ // The OutputSections are already in the correct order.
+ // This loops creates or moves commands as needed so that they are in the
+ // correct order.
+ int CmdIndex = 0;
+
+ // As a horrible special case, skip the first . assignment if it is before any
+ // section. We do this because it is common to set a load address by starting
+ // the script with ". = 0xabcd" and the expectation is that every section is
+ // after that.
+ auto FirstSectionOrDotAssignment =
+ std::find_if(Opt.Commands.begin(), Opt.Commands.end(),
+ [](const std::unique_ptr<BaseCommand> &Cmd) {
+ if (isa<OutputSectionCommand>(*Cmd))
+ return true;
+ const auto *Assign = dyn_cast<SymbolAssignment>(Cmd.get());
+ if (!Assign)
+ return false;
+ return Assign->Name == ".";
+ });
+ if (FirstSectionOrDotAssignment != Opt.Commands.end()) {
+ CmdIndex = FirstSectionOrDotAssignment - Opt.Commands.begin();
+ if (isa<SymbolAssignment>(**FirstSectionOrDotAssignment))
+ ++CmdIndex;
+ }
+
+ for (OutputSectionBase *Sec : *OutputSections) {
+ StringRef Name = Sec->getName();
+
+ // Find the last spot where we can insert a command and still get the
+ // correct result.
+ auto CmdIter = Opt.Commands.begin() + CmdIndex;
+ auto E = Opt.Commands.end();
+ while (CmdIter != E && shouldSkip(**CmdIter)) {
+ ++CmdIter;
+ ++CmdIndex;
+ }
+
+ auto Pos =
+ std::find_if(CmdIter, E, [&](const std::unique_ptr<BaseCommand> &Base) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+ return Cmd && Cmd->Name == Name;
+ });
+ if (Pos == E) {
+ Opt.Commands.insert(CmdIter,
+ llvm::make_unique<OutputSectionCommand>(Name));
+ ++CmdIndex;
+ continue;
+ }
+
+ // Continue from where we found it.
+ CmdIndex = (Pos - Opt.Commands.begin()) + 1;
+ }
+}
+
+template <class ELFT>
+void LinkerScript<ELFT>::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
+ // Assign addresses as instructed by linker script SECTIONS sub-commands.
+ Dot = 0;
+
+ for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get())) {
+ if (Cmd->Name == ".") {
+ Dot = Cmd->Expression(Dot);
+ } else if (Cmd->Sym) {
+ assignSectionSymbol<ELFT>(Cmd, Dot);
}
+ continue;
}
+
+ if (auto *Cmd = dyn_cast<AssertCommand>(Base.get())) {
+ Cmd->Expression(Dot);
+ continue;
+ }
+
+ auto *Cmd = cast<OutputSectionCommand>(Base.get());
+ if (Cmd->AddrExpr)
+ Dot = Cmd->AddrExpr(Dot);
+ assignOffsets(Cmd);
}
+ uintX_t MinVA = std::numeric_limits<uintX_t>::max();
+ for (OutputSectionBase *Sec : *OutputSections) {
+ if (Sec->Flags & SHF_ALLOC)
+ MinVA = std::min<uint64_t>(MinVA, Sec->Addr);
+ else
+ Sec->Addr = 0;
+ }
+
+ uintX_t HeaderSize = getHeaderSize();
+ // If the linker script doesn't have PHDRS, add ElfHeader and ProgramHeaders
+ // now that we know we have space.
+ if (HeaderSize <= MinVA && !hasPhdrsCommands())
+ allocateHeaders<ELFT>(Phdrs, *OutputSections);
+
// 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);
+ // memory. Set their addresses accordingly.
+ MinVA = alignDown(MinVA - HeaderSize, Config->MaxPageSize);
+ Out<ELFT>::ElfHeader->Addr = MinVA;
+ Out<ELFT>::ProgramHeaders->Addr = Out<ELFT>::ElfHeader->Size + MinVA;
+}
+
+// Creates program headers as instructed by PHDRS linker script command.
+template <class ELFT> std::vector<PhdrEntry> LinkerScript<ELFT>::createPhdrs() {
+ std::vector<PhdrEntry> Ret;
+
+ // Process PHDRS and FILEHDR keywords because they are not
+ // real output sections and cannot be added in the following loop.
+ for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) {
+ Ret.emplace_back(Cmd.Type, Cmd.Flags == UINT_MAX ? PF_R : Cmd.Flags);
+ PhdrEntry &Phdr = Ret.back();
+
+ if (Cmd.HasFilehdr)
+ Phdr.add(Out<ELFT>::ElfHeader);
+ if (Cmd.HasPhdrs)
+ Phdr.add(Out<ELFT>::ProgramHeaders);
+
+ if (Cmd.LMAExpr) {
+ Phdr.p_paddr = Cmd.LMAExpr(0);
+ Phdr.HasLMA = true;
+ }
+ }
+
+ // Add output sections to program headers.
+ for (OutputSectionBase *Sec : *OutputSections) {
+ if (!(Sec->Flags & SHF_ALLOC))
+ break;
+
+ // Assign headers specified by linker script
+ for (size_t Id : getPhdrIndices(Sec->getName())) {
+ Ret[Id].add(Sec);
+ if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
+ Ret[Id].p_flags |= Sec->getPhdrFlags();
+ }
+ }
+ return Ret;
+}
+
+template <class ELFT> bool LinkerScript<ELFT>::ignoreInterpSection() {
+ // Ignore .interp section in case we have PHDRS specification
+ // and PT_INTERP isn't listed.
+ return !Opt.PhdrsCommands.empty() &&
+ llvm::find_if(Opt.PhdrsCommands, [](const PhdrsCommand &Cmd) {
+ return Cmd.Type == PT_INTERP;
+ }) == Opt.PhdrsCommands.end();
+}
+
+template <class ELFT> uint32_t LinkerScript<ELFT>::getFiller(StringRef Name) {
+ for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
+ if (Cmd->Name == Name)
+ return Cmd->Filler;
+ return 0;
}
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;
+static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
+ const endianness E = ELFT::TargetEndianness;
+
+ switch (Size) {
+ case 1:
+ *Buf = (uint8_t)Data;
+ break;
+ case 2:
+ write16<E>(Buf, Data);
+ break;
+ case 4:
+ write32<E>(Buf, Data);
+ break;
+ case 8:
+ write64<E>(Buf, Data);
+ break;
+ default:
+ llvm_unreachable("unsupported Size argument");
+ }
+}
+
+template <class ELFT>
+void LinkerScript<ELFT>::writeDataBytes(StringRef Name, uint8_t *Buf) {
+ int I = getSectionIndex(Name);
+ if (I == INT_MAX)
+ return;
+
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I].get());
+ for (const std::unique_ptr<BaseCommand> &Base : Cmd->Commands)
+ if (auto *Data = dyn_cast<BytesDataCommand>(Base.get()))
+ writeInt<ELFT>(Buf + Data->Offset, Data->Expression(0), Data->Size);
+}
+
+template <class ELFT> bool LinkerScript<ELFT>::hasLMA(StringRef Name) {
+ for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
+ if (Cmd->LMAExpr && Cmd->Name == Name)
+ return true;
+ return false;
}
// 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) {
+ for (int I = 0, E = Opt.Commands.size(); I != E; ++I)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I].get()))
+ if (Cmd->Name == Name)
+ return I;
+ return INT_MAX;
+}
+
+template <class ELFT> bool LinkerScript<ELFT>::hasPhdrsCommands() {
+ return !Opt.PhdrsCommands.empty();
+}
+
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);
+const OutputSectionBase *LinkerScript<ELFT>::getOutputSection(const Twine &Loc,
+ StringRef Name) {
+ static OutputSectionBase FakeSec("", 0, 0);
+
+ for (OutputSectionBase *Sec : *OutputSections)
+ if (Sec->getName() == Name)
+ return Sec;
+
+ error(Loc + ": undefined section " + Name);
+ return &FakeSec;
+}
+
+// This function is essentially the same as getOutputSection(Name)->Size,
+// but it won't print out an error message if a given section is not found.
+//
+// Linker script does not create an output section if its content is empty.
+// We want to allow SIZEOF(.foo) where .foo is a section which happened to
+// be empty. That is why this function is different from getOutputSection().
+template <class ELFT>
+uint64_t LinkerScript<ELFT>::getOutputSectionSize(StringRef Name) {
+ for (OutputSectionBase *Sec : *OutputSections)
+ if (Sec->getName() == Name)
+ return Sec->Size;
+ return 0;
+}
+
+template <class ELFT> uint64_t LinkerScript<ELFT>::getHeaderSize() {
+ return elf::getHeaderSize<ELFT>();
}
-// 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;
+uint64_t LinkerScript<ELFT>::getSymbolValue(const Twine &Loc, StringRef S) {
+ if (SymbolBody *B = Symtab<ELFT>::X->find(S))
+ return B->getVA<ELFT>();
+ error(Loc + ": symbol not found: " + S);
+ return 0;
+}
+
+template <class ELFT> bool LinkerScript<ELFT>::isDefined(StringRef S) {
+ return Symtab<ELFT>::X->find(S) != nullptr;
+}
+
+template <class ELFT> bool LinkerScript<ELFT>::isAbsolute(StringRef S) {
+ SymbolBody *Sym = Symtab<ELFT>::X->find(S);
+ auto *DR = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym);
+ return DR && !DR->Section;
}
+// Gets section symbol belongs to. Symbol "." doesn't belong to any
+// specific section but isn't absolute at the same time, so we try
+// to find suitable section for it as well.
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);
+const OutputSectionBase *LinkerScript<ELFT>::getSymbolSection(StringRef S) {
+ SymbolBody *Sym = Symtab<ELFT>::X->find(S);
+ if (!Sym) {
+ if (OutputSections->empty())
+ return nullptr;
+ return CurOutSec ? CurOutSec : (*OutputSections)[0];
+ }
+
+ if (auto *DR = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym))
+ return DR->Section ? DR->Section->OutSec : nullptr;
+ if (auto *DS = dyn_cast_or_null<DefinedSynthetic>(Sym))
+ return DS->Section;
+
+ return nullptr;
}
-class elf::ScriptParser : public ScriptParserBase {
+// Returns indices of ELF headers containing specific section, identified
+// by Name. Each index is a zero based number of ELF header listed within
+// PHDRS {} script block.
+template <class ELFT>
+std::vector<size_t> LinkerScript<ELFT>::getPhdrIndices(StringRef SectionName) {
+ for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+ if (!Cmd || Cmd->Name != SectionName)
+ continue;
+
+ std::vector<size_t> Ret;
+ for (StringRef PhdrName : Cmd->Phdrs)
+ Ret.push_back(getPhdrIndex(Cmd->Location, PhdrName));
+ return Ret;
+ }
+ return {};
+}
+
+template <class ELFT>
+size_t LinkerScript<ELFT>::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
+ size_t I = 0;
+ for (PhdrsCommand &Cmd : Opt.PhdrsCommands) {
+ if (Cmd.Name == PhdrName)
+ return I;
+ ++I;
+ }
+ error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
+ return 0;
+}
+
+class elf::ScriptParser final : public ScriptParserBase {
typedef void (ScriptParser::*Handler)();
public:
- ScriptParser(StringRef S, bool B) : ScriptParserBase(S), IsUnderSysroot(B) {}
+ ScriptParser(MemoryBufferRef MB)
+ : ScriptParserBase(MB),
+ IsUnderSysroot(isUnderSysroot(MB.getBufferIdentifier())) {}
- void run();
+ void readLinkerScript();
+ void readVersionScript();
+ void readDynamicList();
private:
void addFile(StringRef Path);
@@ -331,53 +989,130 @@ private:
void readExtern();
void readGroup();
void readInclude();
- void readNothing() {}
void readOutput();
void readOutputArch();
void readOutputFormat();
+ void readPhdrs();
void readSearchDir();
void readSections();
+ void readVersion();
+ void readVersionScriptCommand();
- void readLocationCounterValue();
- void readOutputSectionDescription(StringRef OutSec);
- void readSymbolAssignment(StringRef Name);
- std::vector<StringRef> readSectionsCommandExpr();
+ SymbolAssignment *readAssignment(StringRef Name);
+ BytesDataCommand *readBytesDataCommand(StringRef Tok);
+ uint32_t readFill();
+ OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
+ uint32_t readOutputSectionFiller(StringRef Tok);
+ std::vector<StringRef> readOutputSectionPhdrs();
+ InputSectionDescription *readInputSectionDescription(StringRef Tok);
+ StringMatcher readFilePatterns();
+ std::vector<SectionPattern> readInputSectionsList();
+ InputSectionDescription *readInputSectionRules(StringRef FilePattern);
+ unsigned readPhdrType();
+ SortSectionPolicy readSortKind();
+ SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
+ SymbolAssignment *readProvideOrAssignment(StringRef Tok);
+ void readSort();
+ Expr readAssert();
+
+ Expr readExpr();
+ Expr readExpr1(Expr Lhs, int MinPrec);
+ StringRef readParenLiteral();
+ Expr readPrimary();
+ Expr readTernary(Expr Cond);
+ Expr readParenExpr();
+
+ // For parsing version script.
+ std::vector<SymbolVersion> readVersionExtern();
+ void readAnonymousDeclaration();
+ void readVersionDeclaration(StringRef VerStr);
+ std::vector<SymbolVersion> readSymbols();
- 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() {
+void ScriptParser::readDynamicList() {
+ expect("{");
+ readAnonymousDeclaration();
+ if (!atEOF())
+ setError("EOF expected, but got " + next());
+}
+
+void ScriptParser::readVersionScript() {
+ readVersionScriptCommand();
+ if (!atEOF())
+ setError("EOF expected, but got " + next());
+}
+
+void ScriptParser::readVersionScriptCommand() {
+ if (consume("{")) {
+ readAnonymousDeclaration();
+ return;
+ }
+
+ while (!atEOF() && !Error && peek() != "}") {
+ StringRef VerStr = next();
+ if (VerStr == "{") {
+ setError("anonymous version definition is used in "
+ "combination with other version definitions");
+ return;
+ }
+ expect("{");
+ readVersionDeclaration(VerStr);
+ }
+}
+
+void ScriptParser::readVersion() {
+ expect("{");
+ readVersionScriptCommand();
+ expect("}");
+}
+
+void ScriptParser::readLinkerScript() {
while (!atEOF()) {
StringRef Tok = next();
- if (Handler Fn = Cmd.lookup(Tok))
- (this->*Fn)();
- else
+ if (Tok == ";")
+ continue;
+
+ if (Tok == "ASSERT") {
+ Opt.Commands.emplace_back(new AssertCommand(readAssert()));
+ } else 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 == "PHDRS") {
+ readPhdrs();
+ } else if (Tok == "SEARCH_DIR") {
+ readSearchDir();
+ } else if (Tok == "SECTIONS") {
+ readSections();
+ } else if (Tok == "VERSION") {
+ readVersion();
+ } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
+ Opt.Commands.emplace_back(Cmd);
+ } else {
setError("unknown directive: " + Tok);
+ }
}
}
void ScriptParser::addFile(StringRef S) {
if (IsUnderSysroot && S.startswith("/")) {
- SmallString<128> Path;
- (Config->Sysroot + S).toStringRef(Path);
+ SmallString<128> PathData;
+ StringRef Path = (Config->Sysroot + S).toStringRef(PathData);
if (sys::fs::exists(Path)) {
- Driver->addFile(Saver.save(Path.str()));
+ Driver->addFile(Saver.save(Path));
return;
}
}
@@ -394,11 +1129,10 @@ void ScriptParser::addFile(StringRef S) {
} else if (sys::fs::exists(S)) {
Driver->addFile(S);
} else {
- std::string Path = findFromSearchPaths(S);
- if (Path.empty())
- setError("unable to find " + S);
+ if (Optional<std::string> Path = findFromSearchPaths(S))
+ Driver->addFile(Saver.save(*Path));
else
- Driver->addFile(Saver.save(Path));
+ setError("unable to find " + S);
}
}
@@ -406,12 +1140,8 @@ void ScriptParser::readAsNeeded() {
expect("(");
bool Orig = Config->AsNeeded;
Config->AsNeeded = true;
- while (!Error) {
- StringRef Tok = next();
- if (Tok == ")")
- break;
- addFile(Tok);
- }
+ while (!Error && !consume(")"))
+ addFile(unquote(next()));
Config->AsNeeded = Orig;
}
@@ -426,39 +1156,37 @@ void ScriptParser::readEntry() {
void ScriptParser::readExtern() {
expect("(");
- while (!Error) {
- StringRef Tok = next();
- if (Tok == ")")
- return;
- Config->Undefined.push_back(Tok);
- }
+ while (!Error && !consume(")"))
+ Config->Undefined.push_back(next());
}
void ScriptParser::readGroup() {
expect("(");
- while (!Error) {
+ while (!Error && !consume(")")) {
StringRef Tok = next();
- if (Tok == ")")
- return;
- if (Tok == "AS_NEEDED") {
+ if (Tok == "AS_NEEDED")
readAsNeeded();
- continue;
- }
- addFile(Tok);
+ else
+ addFile(unquote(Tok));
}
}
void ScriptParser::readInclude() {
- StringRef Tok = next();
+ StringRef Tok = unquote(next());
+ // https://sourceware.org/binutils/docs/ld/File-Commands.html:
+ // The file will be searched for in the current directory, and in any
+ // directory specified with the -L option.
auto MBOrErr = MemoryBuffer::getFile(Tok);
+ if (!MBOrErr)
+ if (Optional<std::string> Path = findFromSearchPaths(Tok))
+ MBOrErr = MemoryBuffer::getFile(*Path);
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());
+ MemoryBufferRef MBRef = (*MBOrErr)->getMemBufferRef();
+ make<std::unique_ptr<MemoryBuffer>>(std::move(*MBOrErr)); // take MB ownership
+ tokenize(MBRef);
}
void ScriptParser::readOutput() {
@@ -466,138 +1194,782 @@ void ScriptParser::readOutput() {
expect("(");
StringRef Tok = next();
if (Config->OutputFile.empty())
- Config->OutputFile = Tok;
+ Config->OutputFile = unquote(Tok);
expect(")");
}
void ScriptParser::readOutputArch() {
// Error checking only for now.
expect("(");
- next();
+ skip();
expect(")");
}
void ScriptParser::readOutputFormat() {
// Error checking only for now.
expect("(");
- next();
+ skip();
StringRef Tok = next();
if (Tok == ")")
- return;
+ return;
if (Tok != ",") {
setError("unexpected token: " + Tok);
return;
}
- next();
+ skip();
expect(",");
- next();
+ skip();
expect(")");
}
+void ScriptParser::readPhdrs() {
+ expect("{");
+ while (!Error && !consume("}")) {
+ StringRef Tok = next();
+ Opt.PhdrsCommands.push_back(
+ {Tok, PT_NULL, false, false, UINT_MAX, nullptr});
+ PhdrsCommand &PhdrCmd = Opt.PhdrsCommands.back();
+
+ PhdrCmd.Type = readPhdrType();
+ do {
+ Tok = next();
+ if (Tok == ";")
+ break;
+ if (Tok == "FILEHDR")
+ PhdrCmd.HasFilehdr = true;
+ else if (Tok == "PHDRS")
+ PhdrCmd.HasPhdrs = true;
+ else if (Tok == "AT")
+ PhdrCmd.LMAExpr = readParenExpr();
+ else if (Tok == "FLAGS") {
+ expect("(");
+ // Passing 0 for the value of dot is a bit of a hack. It means that
+ // we accept expressions like ".|1".
+ PhdrCmd.Flags = readExpr()(0);
+ expect(")");
+ } else
+ setError("unexpected header attribute: " + Tok);
+ } while (!Error);
+ }
+}
+
void ScriptParser::readSearchDir() {
expect("(");
- Config->SearchPaths.push_back(next());
+ StringRef Tok = next();
+ if (!Config->Nostdlib)
+ Config->SearchPaths.push_back(unquote(Tok));
expect(")");
}
void ScriptParser::readSections() {
- Opt.DoLayout = true;
+ Opt.HasSections = true;
+ // -no-rosegment is used to avoid placing read only non-executable sections in
+ // their own segment. We do the same if SECTIONS command is present in linker
+ // script. See comment for computeFlags().
+ Config->SingleRoRx = true;
+
expect("{");
- while (!Error && !skip("}")) {
- StringRef Tok = peek();
- if (Tok == ".") {
- readLocationCounterValue();
- continue;
+ while (!Error && !consume("}")) {
+ StringRef Tok = next();
+ BaseCommand *Cmd = readProvideOrAssignment(Tok);
+ if (!Cmd) {
+ if (Tok == "ASSERT")
+ Cmd = new AssertCommand(readAssert());
+ else
+ Cmd = readOutputSectionDescription(Tok);
}
- next();
- if (peek() == "=")
- readSymbolAssignment(Tok);
- else
- readOutputSectionDescription(Tok);
+ Opt.Commands.emplace_back(Cmd);
}
}
-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), "."});
+static int precedence(StringRef Op) {
+ return StringSwitch<int>(Op)
+ .Cases("*", "/", 5)
+ .Cases("+", "-", 4)
+ .Cases("<<", ">>", 3)
+ .Cases("<", "<=", ">", ">=", "==", "!=", 2)
+ .Cases("&", "|", 1)
+ .Default(-1);
}
-void ScriptParser::readOutputSectionDescription(StringRef OutSec) {
- Opt.Commands.push_back({SectionKind, {}, OutSec});
- expect(":");
- expect("{");
+StringMatcher ScriptParser::readFilePatterns() {
+ std::vector<StringRef> V;
+ while (!Error && !consume(")"))
+ V.push_back(next());
+ return StringMatcher(V);
+}
- while (!Error && !skip("}")) {
- StringRef Tok = next();
- if (Tok == "*") {
- expect("(");
- while (!Error && !skip(")"))
- Opt.Sections.emplace_back(OutSec, next());
- } else if (Tok == "KEEP") {
+SortSectionPolicy ScriptParser::readSortKind() {
+ if (consume("SORT") || consume("SORT_BY_NAME"))
+ return SortSectionPolicy::Name;
+ if (consume("SORT_BY_ALIGNMENT"))
+ return SortSectionPolicy::Alignment;
+ if (consume("SORT_BY_INIT_PRIORITY"))
+ return SortSectionPolicy::Priority;
+ if (consume("SORT_NONE"))
+ return SortSectionPolicy::None;
+ return SortSectionPolicy::Default;
+}
+
+// Method reads a list of sequence of excluded files and section globs given in
+// a following form: ((EXCLUDE_FILE(file_pattern+))? section_pattern+)+
+// Example: *(.foo.1 EXCLUDE_FILE (*a.o) .foo.2 EXCLUDE_FILE (*b.o) .foo.3)
+// The semantics of that is next:
+// * Include .foo.1 from every file.
+// * Include .foo.2 from every file but a.o
+// * Include .foo.3 from every file but b.o
+std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
+ std::vector<SectionPattern> Ret;
+ while (!Error && peek() != ")") {
+ StringMatcher ExcludeFilePat;
+ if (consume("EXCLUDE_FILE")) {
expect("(");
- expect("*");
+ ExcludeFilePat = readFilePatterns();
+ }
+
+ std::vector<StringRef> V;
+ while (!Error && peek() != ")" && peek() != "EXCLUDE_FILE")
+ V.push_back(next());
+
+ if (!V.empty())
+ Ret.push_back({std::move(ExcludeFilePat), StringMatcher(V)});
+ else
+ setError("section pattern is expected");
+ }
+ return Ret;
+}
+
+// Reads contents of "SECTIONS" directive. That directive contains a
+// list of glob patterns for input sections. The grammar is as follows.
+//
+// <patterns> ::= <section-list>
+// | <sort> "(" <section-list> ")"
+// | <sort> "(" <sort> "(" <section-list> ")" ")"
+//
+// <sort> ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT"
+// | "SORT_BY_INIT_PRIORITY" | "SORT_NONE"
+//
+// <section-list> is parsed by readInputSectionsList().
+InputSectionDescription *
+ScriptParser::readInputSectionRules(StringRef FilePattern) {
+ auto *Cmd = new InputSectionDescription(FilePattern);
+ expect("(");
+ while (!Error && !consume(")")) {
+ SortSectionPolicy Outer = readSortKind();
+ SortSectionPolicy Inner = SortSectionPolicy::Default;
+ std::vector<SectionPattern> V;
+ if (Outer != SortSectionPolicy::Default) {
expect("(");
- while (!Error && !skip(")")) {
- StringRef Sec = next();
- Opt.Sections.emplace_back(OutSec, Sec);
- Opt.KeptSections.push_back(Sec);
+ Inner = readSortKind();
+ if (Inner != SortSectionPolicy::Default) {
+ expect("(");
+ V = readInputSectionsList();
+ expect(")");
+ } else {
+ V = readInputSectionsList();
}
expect(")");
} else {
+ V = readInputSectionsList();
+ }
+
+ for (SectionPattern &Pat : V) {
+ Pat.SortInner = Inner;
+ Pat.SortOuter = Outer;
+ }
+
+ std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns));
+ }
+ return Cmd;
+}
+
+InputSectionDescription *
+ScriptParser::readInputSectionDescription(StringRef Tok) {
+ // Input section wildcard can be surrounded by KEEP.
+ // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
+ if (Tok == "KEEP") {
+ expect("(");
+ StringRef FilePattern = next();
+ InputSectionDescription *Cmd = readInputSectionRules(FilePattern);
+ expect(")");
+ Opt.KeptSections.push_back(Cmd);
+ return Cmd;
+ }
+ return readInputSectionRules(Tok);
+}
+
+void ScriptParser::readSort() {
+ expect("(");
+ expect("CONSTRUCTORS");
+ expect(")");
+}
+
+Expr ScriptParser::readAssert() {
+ expect("(");
+ Expr E = readExpr();
+ expect(",");
+ StringRef Msg = unquote(next());
+ expect(")");
+ return [=](uint64_t Dot) {
+ uint64_t V = E(Dot);
+ if (!V)
+ error(Msg);
+ return V;
+ };
+}
+
+// Reads a FILL(expr) command. We handle the FILL command as an
+// alias for =fillexp section attribute, which is different from
+// what GNU linkers do.
+// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
+uint32_t ScriptParser::readFill() {
+ expect("(");
+ uint32_t V = readOutputSectionFiller(next());
+ expect(")");
+ expect(";");
+ return V;
+}
+
+OutputSectionCommand *
+ScriptParser::readOutputSectionDescription(StringRef OutSec) {
+ OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec);
+ Cmd->Location = getCurrentLocation();
+
+ // Read an address expression.
+ // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html#Output-Section-Address
+ if (peek() != ":")
+ Cmd->AddrExpr = readExpr();
+
+ expect(":");
+
+ if (consume("AT"))
+ Cmd->LMAExpr = readParenExpr();
+ if (consume("ALIGN"))
+ Cmd->AlignExpr = readParenExpr();
+ if (consume("SUBALIGN"))
+ Cmd->SubalignExpr = readParenExpr();
+
+ // Parse constraints.
+ if (consume("ONLY_IF_RO"))
+ Cmd->Constraint = ConstraintKind::ReadOnly;
+ if (consume("ONLY_IF_RW"))
+ Cmd->Constraint = ConstraintKind::ReadWrite;
+ expect("{");
+
+ while (!Error && !consume("}")) {
+ StringRef Tok = next();
+ if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) {
+ Cmd->Commands.emplace_back(Assignment);
+ } else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) {
+ Cmd->Commands.emplace_back(Data);
+ } else if (Tok == "ASSERT") {
+ Cmd->Commands.emplace_back(new AssertCommand(readAssert()));
+ expect(";");
+ } else if (Tok == "FILL") {
+ Cmd->Filler = readFill();
+ } else if (Tok == "SORT") {
+ readSort();
+ } else if (peek() == "(") {
+ Cmd->Commands.emplace_back(readInputSectionDescription(Tok));
+ } else {
setError("unknown command " + Tok);
}
}
+ Cmd->Phdrs = readOutputSectionPhdrs();
- StringRef Tok = peek();
- if (Tok.startswith("=")) {
- if (!Tok.startswith("=0x")) {
- setError("filler should be a hexadecimal value");
- return;
+ if (consume("="))
+ Cmd->Filler = readOutputSectionFiller(next());
+ else if (peek().startswith("="))
+ Cmd->Filler = readOutputSectionFiller(next().drop_front());
+
+ return Cmd;
+}
+
+// Read "=<number>" where <number> is an octal/decimal/hexadecimal number.
+// https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html
+//
+// ld.gold is not fully compatible with ld.bfd. ld.bfd handles
+// hexstrings as blobs of arbitrary sizes, while ld.gold handles them
+// as 32-bit big-endian values. We will do the same as ld.gold does
+// because it's simpler than what ld.bfd does.
+uint32_t ScriptParser::readOutputSectionFiller(StringRef Tok) {
+ uint32_t V;
+ if (!Tok.getAsInteger(0, V))
+ return V;
+ setError("invalid filler expression: " + Tok);
+ return 0;
+}
+
+SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
+ expect("(");
+ SymbolAssignment *Cmd = readAssignment(next());
+ Cmd->Provide = Provide;
+ Cmd->Hidden = Hidden;
+ expect(")");
+ expect(";");
+ return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
+ SymbolAssignment *Cmd = nullptr;
+ if (peek() == "=" || peek() == "+=") {
+ Cmd = readAssignment(Tok);
+ expect(";");
+ } else if (Tok == "PROVIDE") {
+ Cmd = readProvideHidden(true, false);
+ } else if (Tok == "HIDDEN") {
+ Cmd = readProvideHidden(false, true);
+ } else if (Tok == "PROVIDE_HIDDEN") {
+ Cmd = readProvideHidden(true, true);
+ }
+ return Cmd;
+}
+
+static uint64_t getSymbolValue(const Twine &Loc, StringRef S, uint64_t Dot) {
+ if (S == ".")
+ return Dot;
+ return ScriptBase->getSymbolValue(Loc, S);
+}
+
+static bool isAbsolute(StringRef S) {
+ if (S == ".")
+ return false;
+ return ScriptBase->isAbsolute(S);
+}
+
+SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
+ StringRef Op = next();
+ Expr E;
+ assert(Op == "=" || Op == "+=");
+ if (consume("ABSOLUTE")) {
+ // The RHS may be something like "ABSOLUTE(.) & 0xff".
+ // Call readExpr1 to read the whole expression.
+ E = readExpr1(readParenExpr(), 0);
+ E.IsAbsolute = [] { return true; };
+ } else {
+ E = readExpr();
+ }
+ if (Op == "+=") {
+ std::string Loc = getCurrentLocation();
+ E = [=](uint64_t Dot) {
+ return getSymbolValue(Loc, Name, Dot) + E(Dot);
+ };
+ }
+ return new SymbolAssignment(Name, E);
+}
+
+// This is an operator-precedence parser to parse a linker
+// script expression.
+Expr ScriptParser::readExpr() { return readExpr1(readPrimary(), 0); }
+
+static Expr combine(StringRef Op, Expr L, Expr R) {
+ if (Op == "*")
+ return [=](uint64_t Dot) { return L(Dot) * R(Dot); };
+ if (Op == "/") {
+ return [=](uint64_t Dot) -> uint64_t {
+ uint64_t RHS = R(Dot);
+ if (RHS == 0) {
+ error("division by zero");
+ return 0;
+ }
+ return L(Dot) / RHS;
+ };
+ }
+ if (Op == "+")
+ return {[=](uint64_t Dot) { return L(Dot) + R(Dot); },
+ [=] { return L.IsAbsolute() && R.IsAbsolute(); },
+ [=] {
+ const OutputSectionBase *S = L.Section();
+ return S ? S : R.Section();
+ }};
+ if (Op == "-")
+ return [=](uint64_t Dot) { return L(Dot) - R(Dot); };
+ if (Op == "<<")
+ return [=](uint64_t Dot) { return L(Dot) << R(Dot); };
+ if (Op == ">>")
+ return [=](uint64_t Dot) { return L(Dot) >> R(Dot); };
+ if (Op == "<")
+ return [=](uint64_t Dot) { return L(Dot) < R(Dot); };
+ if (Op == ">")
+ return [=](uint64_t Dot) { return L(Dot) > R(Dot); };
+ if (Op == ">=")
+ return [=](uint64_t Dot) { return L(Dot) >= R(Dot); };
+ if (Op == "<=")
+ return [=](uint64_t Dot) { return L(Dot) <= R(Dot); };
+ if (Op == "==")
+ return [=](uint64_t Dot) { return L(Dot) == R(Dot); };
+ if (Op == "!=")
+ return [=](uint64_t Dot) { return L(Dot) != R(Dot); };
+ if (Op == "&")
+ return [=](uint64_t Dot) { return L(Dot) & R(Dot); };
+ if (Op == "|")
+ return [=](uint64_t Dot) { return L(Dot) | R(Dot); };
+ llvm_unreachable("invalid operator");
+}
+
+// This is a part of the operator-precedence parser. This function
+// assumes that the remaining token stream starts with an operator.
+Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) {
+ while (!atEOF() && !Error) {
+ // Read an operator and an expression.
+ if (consume("?"))
+ return readTernary(Lhs);
+ StringRef Op1 = peek();
+ if (precedence(Op1) < MinPrec)
+ break;
+ skip();
+ Expr Rhs = readPrimary();
+
+ // 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 = readExpr1(Rhs, precedence(Op2));
}
- Tok = Tok.substr(3);
- Opt.Filler[OutSec] = parseHex(Tok);
- next();
+
+ Lhs = combine(Op1, Lhs, Rhs);
}
+ return Lhs;
}
-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});
+uint64_t static getConstant(StringRef S) {
+ if (S == "COMMONPAGESIZE")
+ return Target->PageSize;
+ if (S == "MAXPAGESIZE")
+ return Config->MaxPageSize;
+ error("unknown constant: " + S);
+ return 0;
+}
+
+// Parses Tok as an integer. Returns true if successful.
+// It recognizes hexadecimal (prefixed with "0x" or suffixed with "H")
+// and decimal numbers. Decimal numbers may have "K" (kilo) or
+// "M" (mega) prefixes.
+static bool readInteger(StringRef Tok, uint64_t &Result) {
+ // Negative number
+ if (Tok.startswith("-")) {
+ if (!readInteger(Tok.substr(1), Result))
+ return false;
+ Result = -Result;
+ return true;
+ }
+
+ // Hexadecimal
+ if (Tok.startswith_lower("0x"))
+ return !Tok.substr(2).getAsInteger(16, Result);
+ if (Tok.endswith_lower("H"))
+ return !Tok.drop_back().getAsInteger(16, Result);
+
+ // Decimal
+ int Suffix = 1;
+ if (Tok.endswith_lower("K")) {
+ Suffix = 1024;
+ Tok = Tok.drop_back();
+ } else if (Tok.endswith_lower("M")) {
+ Suffix = 1024 * 1024;
+ Tok = Tok.drop_back();
+ }
+ if (Tok.getAsInteger(10, Result))
+ return false;
+ Result *= Suffix;
+ return true;
+}
+
+BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) {
+ int Size = StringSwitch<unsigned>(Tok)
+ .Case("BYTE", 1)
+ .Case("SHORT", 2)
+ .Case("LONG", 4)
+ .Case("QUAD", 8)
+ .Default(-1);
+ if (Size == -1)
+ return nullptr;
+
+ return new BytesDataCommand(readParenExpr(), Size);
+}
+
+StringRef ScriptParser::readParenLiteral() {
+ expect("(");
+ StringRef Tok = next();
+ expect(")");
+ return Tok;
+}
+
+Expr ScriptParser::readPrimary() {
+ if (peek() == "(")
+ return readParenExpr();
+
+ StringRef Tok = next();
+ std::string Location = getCurrentLocation();
+
+ if (Tok == "~") {
+ Expr E = readPrimary();
+ return [=](uint64_t Dot) { return ~E(Dot); };
+ }
+ if (Tok == "-") {
+ Expr E = readPrimary();
+ return [=](uint64_t Dot) { return -E(Dot); };
+ }
+
+ // Built-in functions are parsed here.
+ // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
+ if (Tok == "ADDR") {
+ StringRef Name = readParenLiteral();
+ return {[=](uint64_t Dot) {
+ return ScriptBase->getOutputSection(Location, Name)->Addr;
+ },
+ [=] { return false; },
+ [=] { return ScriptBase->getOutputSection(Location, Name); }};
+ }
+ if (Tok == "LOADADDR") {
+ StringRef Name = readParenLiteral();
+ return [=](uint64_t Dot) {
+ return ScriptBase->getOutputSection(Location, Name)->getLMA();
+ };
+ }
+ if (Tok == "ASSERT")
+ return readAssert();
+ if (Tok == "ALIGN") {
+ expect("(");
+ Expr E = readExpr();
+ if (consume(",")) {
+ Expr E2 = readExpr();
+ expect(")");
+ return [=](uint64_t Dot) { return alignTo(E(Dot), E2(Dot)); };
+ }
+ expect(")");
+ return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
+ }
+ if (Tok == "CONSTANT") {
+ StringRef Name = readParenLiteral();
+ return [=](uint64_t Dot) { return getConstant(Name); };
+ }
+ if (Tok == "DEFINED") {
+ StringRef Name = readParenLiteral();
+ return [=](uint64_t Dot) { return ScriptBase->isDefined(Name) ? 1 : 0; };
+ }
+ if (Tok == "SEGMENT_START") {
+ expect("(");
+ skip();
+ expect(",");
+ Expr E = readExpr();
+ expect(")");
+ return [=](uint64_t Dot) { return E(Dot); };
+ }
+ if (Tok == "DATA_SEGMENT_ALIGN") {
+ expect("(");
+ Expr E = readExpr();
+ expect(",");
+ readExpr();
+ expect(")");
+ return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
+ }
+ if (Tok == "DATA_SEGMENT_END") {
+ expect("(");
+ expect(".");
+ expect(")");
+ return [](uint64_t Dot) { return Dot; };
+ }
+ // GNU linkers implements more complicated logic to handle
+ // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and just align to
+ // the next page boundary for simplicity.
+ if (Tok == "DATA_SEGMENT_RELRO_END") {
+ expect("(");
+ readExpr();
+ expect(",");
+ readExpr();
+ expect(")");
+ return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); };
+ }
+ if (Tok == "SIZEOF") {
+ StringRef Name = readParenLiteral();
+ return [=](uint64_t Dot) { return ScriptBase->getOutputSectionSize(Name); };
+ }
+ if (Tok == "ALIGNOF") {
+ StringRef Name = readParenLiteral();
+ return [=](uint64_t Dot) {
+ return ScriptBase->getOutputSection(Location, Name)->Addralign;
+ };
+ }
+ if (Tok == "SIZEOF_HEADERS")
+ return [=](uint64_t Dot) { return ScriptBase->getHeaderSize(); };
+
+ // Tok is a literal number.
+ uint64_t V;
+ if (readInteger(Tok, V))
+ return [=](uint64_t Dot) { return V; };
+
+ // Tok is a symbol name.
+ if (Tok != "." && !isValidCIdentifier(Tok))
+ setError("malformed number: " + Tok);
+ return {[=](uint64_t Dot) { return getSymbolValue(Location, Tok, Dot); },
+ [=] { return isAbsolute(Tok); },
+ [=] { return ScriptBase->getSymbolSection(Tok); }};
}
-std::vector<StringRef> ScriptParser::readSectionsCommandExpr() {
- std::vector<StringRef> Expr;
- while (!Error) {
+Expr ScriptParser::readTernary(Expr Cond) {
+ Expr L = readExpr();
+ expect(":");
+ Expr R = readExpr();
+ return [=](uint64_t Dot) { return Cond(Dot) ? L(Dot) : R(Dot); };
+}
+
+Expr ScriptParser::readParenExpr() {
+ expect("(");
+ Expr E = readExpr();
+ expect(")");
+ return E;
+}
+
+std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() {
+ std::vector<StringRef> Phdrs;
+ while (!Error && peek().startswith(":")) {
StringRef Tok = next();
- if (Tok == ";")
+ Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1));
+ }
+ return Phdrs;
+}
+
+// Read a program header type name. The next token must be a
+// name of a program header type or a constant (e.g. "0x3").
+unsigned ScriptParser::readPhdrType() {
+ StringRef Tok = next();
+ uint64_t Val;
+ if (readInteger(Tok, Val))
+ return Val;
+
+ unsigned Ret = StringSwitch<unsigned>(Tok)
+ .Case("PT_NULL", PT_NULL)
+ .Case("PT_LOAD", PT_LOAD)
+ .Case("PT_DYNAMIC", PT_DYNAMIC)
+ .Case("PT_INTERP", PT_INTERP)
+ .Case("PT_NOTE", PT_NOTE)
+ .Case("PT_SHLIB", PT_SHLIB)
+ .Case("PT_PHDR", PT_PHDR)
+ .Case("PT_TLS", PT_TLS)
+ .Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
+ .Case("PT_GNU_STACK", PT_GNU_STACK)
+ .Case("PT_GNU_RELRO", PT_GNU_RELRO)
+ .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
+ .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
+ .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
+ .Default(-1);
+
+ if (Ret == (unsigned)-1) {
+ setError("invalid program header type: " + Tok);
+ return PT_NULL;
+ }
+ return Ret;
+}
+
+// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };".
+void ScriptParser::readAnonymousDeclaration() {
+ // Read global symbols first. "global:" is default, so if there's
+ // no label, we assume global symbols.
+ if (consume("global:") || peek() != "local:")
+ Config->VersionScriptGlobals = readSymbols();
+
+ // Next, read local symbols.
+ if (consume("local:")) {
+ if (consume("*")) {
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ expect(";");
+ } else {
+ setError("local symbol list for anonymous version is not supported");
+ }
+ }
+ expect("}");
+ expect(";");
+}
+
+// Reads a list of symbols, e.g. "VerStr { global: foo; bar; local: *; };".
+void ScriptParser::readVersionDeclaration(StringRef VerStr) {
+ // Identifiers start at 2 because 0 and 1 are reserved
+ // for VER_NDX_LOCAL and VER_NDX_GLOBAL constants.
+ uint16_t VersionId = Config->VersionDefinitions.size() + 2;
+ Config->VersionDefinitions.push_back({VerStr, VersionId});
+
+ // Read global symbols.
+ if (consume("global:") || peek() != "local:")
+ Config->VersionDefinitions.back().Globals = readSymbols();
+
+ // Read local symbols.
+ if (consume("local:")) {
+ if (consume("*")) {
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ expect(";");
+ } else {
+ for (SymbolVersion V : readSymbols())
+ Config->VersionScriptLocals.push_back(V);
+ }
+ }
+ 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 hint; the runtime doesn't care about it
+ // at all. In LLD, we simply ignore it.
+ if (peek() != ";")
+ skip();
+ expect(";");
+}
+
+// Reads a list of symbols for a versions cript.
+std::vector<SymbolVersion> ScriptParser::readSymbols() {
+ std::vector<SymbolVersion> Ret;
+ for (;;) {
+ if (consume("extern")) {
+ for (SymbolVersion V : readVersionExtern())
+ Ret.push_back(V);
+ continue;
+ }
+
+ if (peek() == "}" || peek() == "local:" || Error)
break;
- Expr.push_back(Tok);
+ StringRef Tok = next();
+ Ret.push_back({unquote(Tok), false, hasWildcard(Tok)});
+ expect(";");
}
- return Expr;
+ return Ret;
}
-static bool isUnderSysroot(StringRef Path) {
- if (Config->Sysroot == "")
- return false;
- for (; !Path.empty(); Path = sys::path::parent_path(Path))
- if (sys::fs::equivalent(Config->Sysroot, Path))
- return true;
- return false;
+// Reads an "extern C++" directive, e.g.,
+// "extern "C++" { ns::*; "f(int, double)"; };"
+std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
+ StringRef Tok = next();
+ bool IsCXX = Tok == "\"C++\"";
+ if (!IsCXX && Tok != "\"C\"")
+ setError("Unknown language");
+ expect("{");
+
+ std::vector<SymbolVersion> Ret;
+ while (!Error && peek() != "}") {
+ StringRef Tok = next();
+ bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
+ Ret.push_back({unquote(Tok), IsCXX, HasWildcard});
+ expect(";");
+ }
+
+ expect("}");
+ expect(";");
+ return Ret;
}
-// Entry point.
void elf::readLinkerScript(MemoryBufferRef MB) {
- StringRef Path = MB.getBufferIdentifier();
- ScriptParser(MB.getBuffer(), isUnderSysroot(Path)).run();
+ ScriptParser(MB).readLinkerScript();
+}
+
+void elf::readVersionScript(MemoryBufferRef MB) {
+ ScriptParser(MB).readVersionScript();
+}
+
+void elf::readDynamicList(MemoryBufferRef MB) {
+ ScriptParser(MB).readDynamicList();
}
template class elf::LinkerScript<ELF32LE>;
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index 768f78a66468..505162f0ab43 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -10,86 +10,279 @@
#ifndef LLD_ELF_LINKER_SCRIPT_H
#define LLD_ELF_LINKER_SCRIPT_H
+#include "Config.h"
+#include "Strings.h"
+#include "Writer.h"
#include "lld/Core/LLVM.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/MapVector.h"
-#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <vector>
namespace lld {
namespace elf {
+class DefinedCommon;
+class ScriptParser;
+class SymbolBody;
+template <class ELFT> class InputSectionBase;
+template <class ELFT> class InputSection;
+class OutputSectionBase;
+template <class ELFT> class OutputSectionFactory;
+class InputSectionData;
+
+// This represents an expression in the linker script.
+// ScriptParser::readExpr reads an expression and returns an Expr.
+// Later, we evaluate the expression by calling the function
+// with the value of special context variable ".".
+struct Expr {
+ std::function<uint64_t(uint64_t)> Val;
+ std::function<bool()> IsAbsolute;
+
+ // If expression is section-relative the function below is used
+ // to get the output section pointer.
+ std::function<const OutputSectionBase *()> Section;
+
+ uint64_t operator()(uint64_t Dot) const { return Val(Dot); }
+ operator bool() const { return (bool)Val; }
+
+ Expr(std::function<uint64_t(uint64_t)> Val, std::function<bool()> IsAbsolute,
+ std::function<const OutputSectionBase *()> Section)
+ : Val(Val), IsAbsolute(IsAbsolute), Section(Section) {}
+ template <typename T>
+ Expr(T V) : Expr(V, [] { return true; }, [] { return nullptr; }) {}
+ Expr() : Expr(nullptr) {}
+};
+
// Parses a linker script. Calling this function updates
// Config and ScriptConfig.
void readLinkerScript(MemoryBufferRef MB);
-class ScriptParser;
-template <class ELFT> class InputSectionBase;
-template <class ELFT> class OutputSectionBase;
+// Parses a version script.
+void readVersionScript(MemoryBufferRef MB);
+
+void readDynamicList(MemoryBufferRef MB);
+
+// This enum is used to implement linker script SECTIONS command.
+// https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
+enum SectionsCommandKind {
+ AssignmentKind, // . = expr or <sym> = expr
+ OutputSectionKind,
+ InputSectionKind,
+ AssertKind, // ASSERT(expr)
+ BytesDataKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr)
+};
+
+struct BaseCommand {
+ BaseCommand(int K) : Kind(K) {}
+
+ virtual ~BaseCommand() = default;
-// This class represents each rule in SECTIONS command.
-struct SectionRule {
- SectionRule(StringRef D, StringRef S)
- : Dest(D), SectionPattern(S) {}
+ int Kind;
+};
+
+// This represents ". = <expr>" or "<symbol> = <expr>".
+struct SymbolAssignment : BaseCommand {
+ SymbolAssignment(StringRef Name, Expr E)
+ : BaseCommand(AssignmentKind), Name(Name), Expression(E) {}
+
+ static bool classof(const BaseCommand *C);
+
+ // The LHS of an expression. Name is either a symbol name or ".".
+ StringRef Name;
+ SymbolBody *Sym = nullptr;
- StringRef Dest;
+ // The RHS of an expression.
+ Expr Expression;
- StringRef SectionPattern;
+ // Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN.
+ bool Provide = false;
+ bool Hidden = false;
};
-// 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 };
+// Linker scripts allow additional constraints to be put on ouput sections.
+// If an output section is marked as ONLY_IF_RO, the section is created
+// only if its input sections are read-only. Likewise, an output section
+// with ONLY_IF_RW is created if all input sections are RW.
+enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
+
+struct OutputSectionCommand : BaseCommand {
+ OutputSectionCommand(StringRef Name)
+ : BaseCommand(OutputSectionKind), Name(Name) {}
+
+ static bool classof(const BaseCommand *C);
-struct SectionsCommand {
- SectionsCommandKind Kind;
- std::vector<StringRef> Expr;
StringRef Name;
+ Expr AddrExpr;
+ Expr AlignExpr;
+ Expr LMAExpr;
+ Expr SubalignExpr;
+ std::vector<std::unique_ptr<BaseCommand>> Commands;
+ std::vector<StringRef> Phdrs;
+ uint32_t Filler = 0;
+ ConstraintKind Constraint = ConstraintKind::NoConstraint;
+ std::string Location;
};
-// ScriptConfiguration holds linker script parse results.
-struct ScriptConfiguration {
- // SECTIONS commands.
- std::vector<SectionRule> Sections;
+// This struct represents one section match pattern in SECTIONS() command.
+// It can optionally have negative match pattern for EXCLUDED_FILE command.
+// Also it may be surrounded with SORT() command, so contains sorting rules.
+struct SectionPattern {
+ SectionPattern(StringMatcher &&Pat1, StringMatcher &&Pat2)
+ : ExcludedFilePat(Pat1), SectionPat(Pat2) {}
+
+ StringMatcher ExcludedFilePat;
+ StringMatcher SectionPat;
+ SortSectionPolicy SortOuter;
+ SortSectionPolicy SortInner;
+};
+
+struct InputSectionDescription : BaseCommand {
+ InputSectionDescription(StringRef FilePattern)
+ : BaseCommand(InputSectionKind), FilePat(FilePattern) {}
- // Section fill attribute for each section.
- llvm::StringMap<std::vector<uint8_t>> Filler;
+ static bool classof(const BaseCommand *C);
+ StringMatcher FilePat;
+
+ // Input sections that matches at least one of SectionPatterns
+ // will be associated with this InputSectionDescription.
+ std::vector<SectionPattern> SectionPatterns;
+
+ std::vector<InputSectionData *> Sections;
+};
+
+// Represents an ASSERT().
+struct AssertCommand : BaseCommand {
+ AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {}
+
+ static bool classof(const BaseCommand *C);
+
+ Expr Expression;
+};
+
+// Represents BYTE(), SHORT(), LONG(), or QUAD().
+struct BytesDataCommand : BaseCommand {
+ BytesDataCommand(Expr E, unsigned Size)
+ : BaseCommand(BytesDataKind), Expression(E), Size(Size) {}
+
+ static bool classof(const BaseCommand *C);
+
+ Expr Expression;
+ unsigned Offset;
+ unsigned Size;
+};
+
+struct PhdrsCommand {
+ StringRef Name;
+ unsigned Type;
+ bool HasFilehdr;
+ bool HasPhdrs;
+ unsigned Flags;
+ Expr LMAExpr;
+};
+
+class LinkerScriptBase {
+protected:
+ ~LinkerScriptBase() = default;
+
+public:
+ virtual uint64_t getHeaderSize() = 0;
+ virtual uint64_t getSymbolValue(const Twine &Loc, StringRef S) = 0;
+ virtual bool isDefined(StringRef S) = 0;
+ virtual bool isAbsolute(StringRef S) = 0;
+ virtual const OutputSectionBase *getSymbolSection(StringRef S) = 0;
+ virtual const OutputSectionBase *getOutputSection(const Twine &Loc,
+ StringRef S) = 0;
+ virtual uint64_t getOutputSectionSize(StringRef S) = 0;
+};
+
+// ScriptConfiguration holds linker script parse results.
+struct ScriptConfiguration {
// Used to assign addresses to sections.
- std::vector<SectionsCommand> Commands;
+ std::vector<std::unique_ptr<BaseCommand>> Commands;
- bool DoLayout = false;
+ // Used to assign sections to headers.
+ std::vector<PhdrsCommand> PhdrsCommands;
- llvm::BumpPtrAllocator Alloc;
+ bool HasSections = false;
// 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;
+ std::vector<InputSectionDescription *> KeptSections;
};
extern ScriptConfiguration *ScriptConfig;
// This is a runner of the linker script.
-template <class ELFT> class LinkerScript {
+template <class ELFT> class LinkerScript final : public LinkerScriptBase {
typedef typename ELFT::uint uintX_t;
public:
- StringRef getOutputSection(InputSectionBase<ELFT> *S);
- ArrayRef<uint8_t> getFiller(StringRef Name);
- bool isDiscarded(InputSectionBase<ELFT> *S);
+ LinkerScript();
+ ~LinkerScript();
+
+ void processCommands(OutputSectionFactory<ELFT> &Factory);
+ void addOrphanSections(OutputSectionFactory<ELFT> &Factory);
+ void removeEmptyCommands();
+ void adjustSectionsBeforeSorting();
+ void adjustSectionsAfterSorting();
+
+ std::vector<PhdrEntry> createPhdrs();
+ bool ignoreInterpSection();
+
+ uint32_t getFiller(StringRef Name);
+ void writeDataBytes(StringRef Name, uint8_t *Buf);
+ bool hasLMA(StringRef Name);
bool shouldKeep(InputSectionBase<ELFT> *S);
- void assignAddresses(ArrayRef<OutputSectionBase<ELFT> *> S);
- int compareSections(StringRef A, StringRef B);
- void addScriptedSymbols();
+ void assignOffsets(OutputSectionCommand *Cmd);
+ void placeOrphanSections();
+ void assignAddresses(std::vector<PhdrEntry> &Phdrs);
+ bool hasPhdrsCommands();
+ uint64_t getHeaderSize() override;
+ uint64_t getSymbolValue(const Twine &Loc, StringRef S) override;
+ bool isDefined(StringRef S) override;
+ bool isAbsolute(StringRef S) override;
+ const OutputSectionBase *getSymbolSection(StringRef S) override;
+ const OutputSectionBase *getOutputSection(const Twine &Loc,
+ StringRef S) override;
+ uint64_t getOutputSectionSize(StringRef S) override;
+
+ std::vector<OutputSectionBase *> *OutputSections;
+
+ int getSectionIndex(StringRef Name);
private:
+ void computeInputSections(InputSectionDescription *);
+
+ void addSection(OutputSectionFactory<ELFT> &Factory,
+ InputSectionBase<ELFT> *Sec, StringRef Name);
+ void discard(ArrayRef<InputSectionBase<ELFT> *> V);
+
+ std::vector<InputSectionBase<ELFT> *>
+ createInputSectionList(OutputSectionCommand &Cmd);
+
// "ScriptConfig" is a bit too long, so define a short name for it.
ScriptConfiguration &Opt = *ScriptConfig;
- int getSectionIndex(StringRef Name);
+ std::vector<size_t> getPhdrIndices(StringRef SectionName);
+ size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
uintX_t Dot;
+ uintX_t LMAOffset = 0;
+ OutputSectionBase *CurOutSec = nullptr;
+ uintX_t ThreadBssOffset = 0;
+ void switchTo(OutputSectionBase *Sec);
+ void flush();
+ void output(InputSection<ELFT> *Sec);
+ void process(BaseCommand &Base);
+ llvm::DenseSet<OutputSectionBase *> AlreadyOutputOS;
+ llvm::DenseSet<InputSectionData *> AlreadyOutputIS;
};
// Variable template is a C++14 feature, so we can't template
@@ -97,7 +290,9 @@ private:
template <class ELFT> struct Script { static LinkerScript<ELFT> *X; };
template <class ELFT> LinkerScript<ELFT> *Script<ELFT>::X;
-} // namespace elf
-} // namespace lld
+extern LinkerScriptBase *ScriptBase;
+
+} // end namespace elf
+} // end namespace lld
-#endif
+#endif // LLD_ELF_LINKER_SCRIPT_H
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index 41e30ce599d2..8d129fc3ff13 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -36,22 +36,24 @@
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
+using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
+namespace {
// A resolved relocation. The Sec and Offset fields are set if the relocation
// was resolved to an offset within a section.
-template <class ELFT>
-struct ResolvedReloc {
+template <class ELFT> struct ResolvedReloc {
InputSectionBase<ELFT> *Sec;
typename ELFT::uint Offset;
};
+} // end anonymous namespace
template <class ELFT>
static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
const typename ELFT::Rel &Rel) {
- return Target->getImplicitAddend(Sec.getSectionData().begin(),
+ return Target->getImplicitAddend(Sec.Data.begin() + Rel.r_offset,
Rel.getType(Config->Mips64EL));
}
@@ -74,56 +76,103 @@ static ResolvedReloc<ELFT> resolveReloc(InputSectionBase<ELFT> &Sec,
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);
+ if (Sec.AreRelocsRela) {
+ for (const typename ELFT::Rela &Rel : Sec.relas())
+ Fn(resolveReloc(Sec, Rel));
+ } else {
+ for (const typename ELFT::Rel &Rel : Sec.rels())
+ Fn(resolveReloc(Sec, Rel));
+ }
+ if (Sec.DependentSection)
+ Fn({Sec.DependentSection, 0});
+}
+
+// The .eh_frame section is an unfortunate special case.
+// The section is divided in CIEs and FDEs and the relocations it can have are
+// * CIEs can refer to a personality function.
+// * FDEs can refer to a LSDA
+// * FDEs refer to the function they contain information about
+// The last kind of relocation cannot keep the referred section alive, or they
+// would keep everything alive in a common object file. In fact, each FDE is
+// alive if the section it refers to is alive.
+// To keep things simple, in here we just ignore the last relocation kind. The
+// other two keep the referred section alive.
+//
+// A possible improvement would be to fully process .eh_frame in the middle of
+// the gc pass. With that we would be able to also gc some sections holding
+// LSDAs and personality functions if we found that they were unused.
+template <class ELFT, class RelTy>
+static void
+scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
+ std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+ const endianness E = ELFT::TargetEndianness;
+ for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
+ EhSectionPiece &Piece = EH.Pieces[I];
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI == (unsigned)-1)
+ continue;
+ if (read32<E>(Piece.data().data() + 4) == 0) {
+ // This is a CIE, we only need to worry about the first relocation. It is
+ // known to point to the personality function.
+ Enqueue(resolveReloc(EH, Rels[FirstRelI]));
+ continue;
+ }
+ // This is a FDE. The relocations point to the described function or to
+ // a LSDA. We only need to keep the LSDA alive, so ignore anything that
+ // points to executable sections.
+ typename ELFT::uint PieceEnd = Piece.InputOff + Piece.size();
+ for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) {
+ const RelTy &Rel = Rels[I2];
+ if (Rel.r_offset >= PieceEnd)
+ break;
+ ResolvedReloc<ELFT> R = resolveReloc(EH, Rels[I2]);
+ if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+ continue;
+ if (R.Sec->Flags & SHF_EXECINSTR)
+ continue;
+ Enqueue({R.Sec, 0});
+ }
+ }
}
template <class ELFT>
-static void scanEhFrameSection(EhInputSection<ELFT> &EH,
- std::function<void(ResolvedReloc<ELFT>)> Fn) {
- if (!EH.RelocSection)
+static void
+scanEhFrameSection(EhInputSection<ELFT> &EH,
+ std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+ if (!EH.NumRelocations)
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});
- });
+
+ // Unfortunately we need to split .eh_frame early since some relocations in
+ // .eh_frame keep other section alive and some don't.
+ EH.split();
+
+ if (EH.AreRelocsRela)
+ scanEhFrameSection(EH, EH.relas(), Enqueue);
+ else
+ scanEhFrameSection(EH, EH.rels(), Enqueue);
}
-// 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.
+// We do not garbage-collect two types of sections:
+// 1) Sections used by the loader (.init, .fini, .ctors, .dtors or .jcr)
+// 2) Non-allocatable sections which typically contain debugging information
template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
- switch (Sec->getSectionHdr()->sh_type) {
+ switch (Sec->Type) {
case SHT_FINI_ARRAY:
case SHT_INIT_ARRAY:
case SHT_NOTE:
case SHT_PREINIT_ARRAY:
return true;
default:
- StringRef S = Sec->getSectionName();
+ if (!(Sec->Flags & SHF_ALLOC))
+ return true;
// We do not want to reclaim sections if they can be referred
// by __start_* and __stop_* symbols.
+ StringRef S = Sec->Name;
if (isValidCIdentifier(S))
return true;
@@ -140,7 +189,15 @@ template <class ELFT> void elf::markLive() {
SmallVector<InputSection<ELFT> *, 256> Q;
auto Enqueue = [&](ResolvedReloc<ELFT> R) {
- if (!R.Sec)
+ // Skip over discarded sections. This in theory shouldn't happen, because
+ // the ELF spec doesn't allow a relocation to point to a deduplicated
+ // COMDAT section directly. Unfortunately this happens in practice (e.g.
+ // .eh_frame) so we need to add a check.
+ if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+ return;
+
+ // We don't gc non alloc sections.
+ if (!(R.Sec->Flags & SHF_ALLOC))
return;
// Usually, a whole section is marked as live or dead, but in mergeable
@@ -152,6 +209,7 @@ template <class ELFT> void elf::markLive() {
if (R.Sec->Live)
return;
R.Sec->Live = true;
+ // Add input section to the queue.
if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(R.Sec))
Q.push_back(S);
};
@@ -162,8 +220,7 @@ template <class ELFT> void elf::markLive() {
};
// Add GC root symbols.
- if (Config->EntrySym)
- MarkSymbol(Config->EntrySym->body());
+ MarkSymbol(Symtab<ELFT>::X->find(Config->Entry));
MarkSymbol(Symtab<ELFT>::X->find(Config->Init));
MarkSymbol(Symtab<ELFT>::X->find(Config->Fini));
for (StringRef S : Config->Undefined)
@@ -177,18 +234,15 @@ template <class ELFT> void elf::markLive() {
// 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) {
- // .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});
- }
+ for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
+ // .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())
diff --git a/ELF/Memory.h b/ELF/Memory.h
new file mode 100644
index 000000000000..e5a04ed1e5a8
--- /dev/null
+++ b/ELF/Memory.h
@@ -0,0 +1,67 @@
+//===- Memory.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines arena allocators.
+//
+// Almost all large objects, such as files, sections or symbols, are
+// used for the entire lifetime of the linker once they are created.
+// This usage characteristic makes arena allocator an attractive choice
+// where the entire linker is one arena. With an arena, newly created
+// objects belong to the arena and freed all at once when everything is done.
+// Arena allocators are efficient and easy to understand.
+// Most objects are allocated using the arena allocators defined by this file.
+//
+// If you edit this file, please edit COFF/Memory.h too.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_MEMORY_H
+#define LLD_ELF_MEMORY_H
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/StringSaver.h"
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+// Use this arena if your object doesn't have a destructor.
+extern llvm::BumpPtrAllocator BAlloc;
+extern llvm::StringSaver Saver;
+
+// These two classes are hack to keep track of all
+// SpecificBumpPtrAllocator instances.
+struct SpecificAllocBase {
+ SpecificAllocBase() { Instances.push_back(this); }
+ virtual ~SpecificAllocBase() = default;
+ virtual void reset() = 0;
+ static std::vector<SpecificAllocBase *> Instances;
+};
+
+template <class T> struct SpecificAlloc : public SpecificAllocBase {
+ void reset() override { Alloc.DestroyAll(); }
+ llvm::SpecificBumpPtrAllocator<T> Alloc;
+};
+
+// Use this arena if your object has a destructor.
+// Your destructor will be invoked from freeArena().
+template <typename T, typename... U> T *make(U &&... Args) {
+ static SpecificAlloc<T> Alloc;
+ return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...);
+}
+
+inline void freeArena() {
+ for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances)
+ Alloc->reset();
+ BAlloc.Reset();
+}
+}
+}
+
+#endif
diff --git a/ELF/Mips.cpp b/ELF/Mips.cpp
new file mode 100644
index 000000000000..ac65672b70fc
--- /dev/null
+++ b/ELF/Mips.cpp
@@ -0,0 +1,369 @@
+//===- Mips.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file contains a helper function for the Writer.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Writer.h"
+
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/MipsABIFlags.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+struct ArchTreeEdge {
+ uint32_t Child;
+ uint32_t Parent;
+};
+
+struct FileFlags {
+ StringRef Filename;
+ uint32_t Flags;
+};
+}
+
+static StringRef getAbiName(uint32_t Flags) {
+ switch (Flags) {
+ case 0:
+ return "n64";
+ case EF_MIPS_ABI2:
+ return "n32";
+ case EF_MIPS_ABI_O32:
+ return "o32";
+ case EF_MIPS_ABI_O64:
+ return "o64";
+ case EF_MIPS_ABI_EABI32:
+ return "eabi32";
+ case EF_MIPS_ABI_EABI64:
+ return "eabi64";
+ default:
+ return "unknown";
+ }
+}
+
+static StringRef getNanName(bool IsNan2008) {
+ return IsNan2008 ? "2008" : "legacy";
+}
+
+static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; }
+
+static void checkFlags(ArrayRef<FileFlags> Files) {
+ uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
+ bool Nan = Files[0].Flags & EF_MIPS_NAN2008;
+ bool Fp = Files[0].Flags & EF_MIPS_FP64;
+
+ for (const FileFlags &F : Files.slice(1)) {
+ uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
+ if (ABI != ABI2)
+ error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" +
+ getAbiName(ABI2) + "': " + F.Filename);
+
+ bool Nan2 = F.Flags & EF_MIPS_NAN2008;
+ if (Nan != Nan2)
+ error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" +
+ getNanName(Nan2) + ": " + F.Filename);
+
+ bool Fp2 = F.Flags & EF_MIPS_FP64;
+ if (Fp != Fp2)
+ error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" +
+ getFpName(Fp2) + ": " + F.Filename);
+ }
+}
+
+static uint32_t getMiscFlags(ArrayRef<FileFlags> Files) {
+ uint32_t Ret = 0;
+ for (const FileFlags &F : Files)
+ Ret |= F.Flags &
+ (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER |
+ EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE);
+ return Ret;
+}
+
+static uint32_t getPicFlags(ArrayRef<FileFlags> Files) {
+ // Check PIC/non-PIC compatibility.
+ bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+ for (const FileFlags &F : Files.slice(1)) {
+ bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+ if (IsPic && !IsPic2)
+ warn("linking abicalls code with non-abicalls file: " + F.Filename);
+ if (!IsPic && IsPic2)
+ warn("linking non-abicalls code with abicalls file: " + F.Filename);
+ }
+
+ // Compute the result PIC/non-PIC flag.
+ uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+ for (const FileFlags &F : Files.slice(1))
+ Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
+
+ // PIC code is inherently CPIC and may not set CPIC flag explicitly.
+ if (Ret & EF_MIPS_PIC)
+ Ret |= EF_MIPS_CPIC;
+ return Ret;
+}
+
+static ArchTreeEdge ArchTree[] = {
+ // MIPS32R6 and MIPS64R6 are not compatible with other extensions
+ // MIPS64R2 extensions.
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2},
+ // MIPS64 extensions.
+ {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64},
+ {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64},
+ {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
+ // MIPS V extensions.
+ {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
+ // R5000 extensions.
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400},
+ // MIPS IV extensions.
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4},
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4},
+ {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
+ // VR4100 extensions.
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
+ // MIPS III extensions.
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3},
+ {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
+ // MIPS32 extensions.
+ {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
+ // MIPS II extensions.
+ {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
+ {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
+ // MIPS I extensions.
+ {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1},
+ {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
+};
+
+static bool isArchMatched(uint32_t New, uint32_t Res) {
+ if (New == Res)
+ return true;
+ if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res))
+ return true;
+ if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res))
+ return true;
+ for (const auto &Edge : ArchTree) {
+ if (Res == Edge.Child) {
+ Res = Edge.Parent;
+ if (Res == New)
+ return true;
+ }
+ }
+ return false;
+}
+
+static StringRef getMachName(uint32_t Flags) {
+ switch (Flags & EF_MIPS_MACH) {
+ case EF_MIPS_MACH_NONE:
+ return "";
+ case EF_MIPS_MACH_3900:
+ return "r3900";
+ case EF_MIPS_MACH_4010:
+ return "r4010";
+ case EF_MIPS_MACH_4100:
+ return "r4100";
+ case EF_MIPS_MACH_4650:
+ return "r4650";
+ case EF_MIPS_MACH_4120:
+ return "r4120";
+ case EF_MIPS_MACH_4111:
+ return "r4111";
+ case EF_MIPS_MACH_5400:
+ return "vr5400";
+ case EF_MIPS_MACH_5900:
+ return "vr5900";
+ case EF_MIPS_MACH_5500:
+ return "vr5500";
+ case EF_MIPS_MACH_9000:
+ return "rm9000";
+ case EF_MIPS_MACH_LS2E:
+ return "loongson2e";
+ case EF_MIPS_MACH_LS2F:
+ return "loongson2f";
+ case EF_MIPS_MACH_LS3A:
+ return "loongson3a";
+ case EF_MIPS_MACH_OCTEON:
+ return "octeon";
+ case EF_MIPS_MACH_OCTEON2:
+ return "octeon2";
+ case EF_MIPS_MACH_OCTEON3:
+ return "octeon3";
+ case EF_MIPS_MACH_SB1:
+ return "sb1";
+ case EF_MIPS_MACH_XLR:
+ return "xlr";
+ default:
+ return "unknown machine";
+ }
+}
+
+static StringRef getArchName(uint32_t Flags) {
+ StringRef S = getMachName(Flags);
+ if (!S.empty())
+ return S;
+
+ switch (Flags & EF_MIPS_ARCH) {
+ case EF_MIPS_ARCH_1:
+ return "mips1";
+ case EF_MIPS_ARCH_2:
+ return "mips2";
+ case EF_MIPS_ARCH_3:
+ return "mips3";
+ case EF_MIPS_ARCH_4:
+ return "mips4";
+ case EF_MIPS_ARCH_5:
+ return "mips5";
+ case EF_MIPS_ARCH_32:
+ return "mips32";
+ case EF_MIPS_ARCH_64:
+ return "mips64";
+ case EF_MIPS_ARCH_32R2:
+ return "mips32r2";
+ case EF_MIPS_ARCH_64R2:
+ return "mips64r2";
+ case EF_MIPS_ARCH_32R6:
+ return "mips32r6";
+ case EF_MIPS_ARCH_64R6:
+ return "mips64r6";
+ default:
+ return "unknown arch";
+ }
+}
+
+// There are (arguably too) many MIPS ISAs out there. Their relationships
+// can be represented as a forest. If all input files have ISAs which
+// reachable by repeated proceeding from the single child to the parent,
+// these input files are compatible. In that case we need to return "highest"
+// ISA. If there are incompatible input files, we show an error.
+// For example, mips1 is a "parent" of mips2 and such files are compatible.
+// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32
+// are incompatible because nor mips3 is a parent for misp32, nor mips32
+// is a parent for mips3.
+static uint32_t getArchFlags(ArrayRef<FileFlags> Files) {
+ uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
+
+ for (const FileFlags &F : Files.slice(1)) {
+ uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
+
+ // Check ISA compatibility.
+ if (isArchMatched(New, Ret))
+ continue;
+ if (!isArchMatched(Ret, New)) {
+ error("target ISA '" + getArchName(Ret) + "' is incompatible with '" +
+ getArchName(New) + "': " + F.Filename);
+ return 0;
+ }
+ Ret = New;
+ }
+ return Ret;
+}
+
+template <class ELFT> uint32_t elf::getMipsEFlags() {
+ std::vector<FileFlags> V;
+ for (elf::ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles())
+ V.push_back({F->getName(), F->getObj().getHeader()->e_flags});
+ if (V.empty())
+ return 0;
+ checkFlags(V);
+ return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V);
+}
+
+static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) {
+ if (FpA == FpB)
+ return 0;
+ if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY)
+ return 1;
+ if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A &&
+ FpA == Mips::Val_GNU_MIPS_ABI_FP_64)
+ return 1;
+ if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX)
+ return -1;
+ if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
+ FpA == Mips::Val_GNU_MIPS_ABI_FP_64 ||
+ FpA == Mips::Val_GNU_MIPS_ABI_FP_64A)
+ return 1;
+ return -1;
+}
+
+static StringRef getMipsFpAbiName(uint8_t FpAbi) {
+ switch (FpAbi) {
+ case Mips::Val_GNU_MIPS_ABI_FP_ANY:
+ return "any";
+ case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
+ return "-mdouble-float";
+ case Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
+ return "-msingle-float";
+ case Mips::Val_GNU_MIPS_ABI_FP_SOFT:
+ return "-msoft-float";
+ case Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
+ return "-mips32r2 -mfp64 (old)";
+ case Mips::Val_GNU_MIPS_ABI_FP_XX:
+ return "-mfpxx";
+ case Mips::Val_GNU_MIPS_ABI_FP_64:
+ return "-mgp32 -mfp64";
+ case Mips::Val_GNU_MIPS_ABI_FP_64A:
+ return "-mgp32 -mfp64 -mno-odd-spreg";
+ default:
+ return "unknown";
+ }
+}
+
+uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
+ StringRef FileName) {
+ if (compareMipsFpAbi(NewFlag, OldFlag) >= 0)
+ return NewFlag;
+ if (compareMipsFpAbi(OldFlag, NewFlag) < 0)
+ error("target floating point ABI '" + getMipsFpAbiName(OldFlag) +
+ "' is incompatible with '" + getMipsFpAbiName(NewFlag) + "': " +
+ FileName);
+ return OldFlag;
+}
+
+template <class ELFT> static bool isN32Abi(const InputFile *F) {
+ if (auto *EF = dyn_cast<ELFFileBase<ELFT>>(F))
+ return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2;
+ return false;
+}
+
+bool elf::isMipsN32Abi(const InputFile *F) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return isN32Abi<ELF32LE>(F);
+ case ELF32BEKind:
+ return isN32Abi<ELF32BE>(F);
+ case ELF64LEKind:
+ return isN32Abi<ELF64LE>(F);
+ case ELF64BEKind:
+ return isN32Abi<ELF64BE>(F);
+ default:
+ llvm_unreachable("unknown Config->EKind");
+ }
+}
+
+template uint32_t elf::getMipsEFlags<ELF32LE>();
+template uint32_t elf::getMipsEFlags<ELF32BE>();
+template uint32_t elf::getMipsEFlags<ELF64LE>();
+template uint32_t elf::getMipsEFlags<ELF64BE>();
diff --git a/ELF/Options.td b/ELF/Options.td
index 010f37687f03..d436f056d013 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -7,6 +7,8 @@ class J<string name>: Joined<["--", "-"], name>;
class S<string name>: Separate<["--", "-"], name>;
class JS<string name>: JoinedOrSeparate<["--", "-"], name>;
+def auxiliary: S<"auxiliary">, HelpText<"Set DT_AUXILIARY field to the specified name">;
+
def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">;
def Bsymbolic_functions: F<"Bsymbolic-functions">,
@@ -25,12 +27,24 @@ def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
def O: Joined<["-"], "O">, HelpText<"Optimize output file size">;
+def Tbss: S<"Tbss">, HelpText<"Same as --section-start with .bss as the sectionname">;
+
+def Tdata: S<"Tdata">, HelpText<"Same as --section-start with .data as the sectionname">;
+
+def Ttext: S<"Ttext">, HelpText<"Same as --section-start with .text as the sectionname">;
+
def allow_multiple_definition: F<"allow-multiple-definition">,
HelpText<"Allow multiple definitions">;
def as_needed: F<"as-needed">,
HelpText<"Only set DT_NEEDED for shared libraries if used">;
+def color_diagnostics: F<"color-diagnostics">,
+ HelpText<"Use colors in diagnostics">;
+
+def color_diagnostics_eq: J<"color-diagnostics=">,
+ HelpText<"Use colors in diagnostics">;
+
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@@ -60,6 +74,9 @@ def end_lib: F<"end-lib">,
def entry: S<"entry">, MetaVarName<"<entry>">,
HelpText<"Name of entry point symbol">;
+def error_limit: S<"error-limit">,
+ HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+
def export_dynamic: F<"export-dynamic">,
HelpText<"Put symbols in the dynamic symbol table">;
@@ -72,6 +89,18 @@ def fatal_warnings: F<"fatal-warnings">,
def fini: S<"fini">, MetaVarName<"<symbol>">,
HelpText<"Specify a finalizer function">;
+def full_shutdown : F<"full-shutdown">,
+ HelpText<"Perform a full shutdown instead of calling _exit">;
+
+def format: J<"format=">, MetaVarName<"<input-format>">,
+ HelpText<"Change the input format of the inputs following this option">;
+
+def gc_sections: F<"gc-sections">,
+ HelpText<"Enable garbage collection of unused sections">;
+
+def gdb_index: F<"gdb-index">,
+ HelpText<"Generate .gdb_index section">;
+
def hash_style: S<"hash-style">,
HelpText<"Specify hash style (sysv, gnu or both)">;
@@ -81,9 +110,6 @@ 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: S<"init">, MetaVarName<"<symbol>">,
HelpText<"Specify an initializer function">;
@@ -95,21 +121,37 @@ def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+def nostdlib: F<"nostdlib">,
+ HelpText<"Only search directories specified on the command line">;
+
def no_as_needed: F<"no-as-needed">,
HelpText<"Always DT_NEEDED for shared libraries">;
+def no_color_diagnostics: F<"no-color-diagnostics">,
+ HelpText<"Do not use colors in diagnostics">;
+
def no_demangle: F<"no-demangle">,
HelpText<"Do not demangle symbol names">;
+def no_gc_sections: F<"no-gc-sections">,
+ HelpText<"Disable garbage collection of unused sections">;
+
def no_gnu_unique: F<"no-gnu-unique">,
HelpText<"Disable STB_GNU_UNIQUE symbol binding">;
+def no_threads: F<"no-threads">,
+ HelpText<"Do not run the linker multi-threaded">;
+
def no_whole_archive: F<"no-whole-archive">,
HelpText<"Restores the default behavior of loading archive members">;
def noinhibit_exec: F<"noinhibit-exec">,
HelpText<"Retain the executable output file whenever it is still usable">;
+def nopie: F<"nopie">, HelpText<"Do not create a position independent executable">;
+
+def no_rosegment: F<"no-rosegment">, HelpText<"Do not put read-only non-executable sections in their own segment">;
+
def no_undefined: F<"no-undefined">,
HelpText<"Report unresolved symbols even if the linker is creating a shared library">;
@@ -119,6 +161,12 @@ def no_undefined_version: F<"no-undefined-version">,
def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">;
+def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
+ HelpText<"Specify the binary format for the output object file">;
+
+def omagic: F<"omagic">, MetaVarName<"<magic>">,
+ HelpText<"Set the text and data sections to be readable and writable">;
+
def pie: F<"pie">, HelpText<"Create a position independent executable">;
def print_gc_sections: F<"print-gc-sections">,
@@ -131,12 +179,20 @@ def rpath: S<"rpath">, HelpText<"Add a DT_RUNPATH to the output">;
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
+def retain_symbols_file: J<"retain-symbols-file=">, MetaVarName<"<file>">,
+ HelpText<"Retain only the symbols listed in the file">;
+
def script: S<"script">, HelpText<"Read linker script">;
+def section_start: S<"section-start">, MetaVarName<"<address>">,
+ HelpText<"Set address of section">;
+
def shared: F<"shared">, HelpText<"Build a shared object">;
def soname: J<"soname=">, HelpText<"Set DT_SONAME">;
+def sort_section: S<"sort-section">, HelpText<"Specifies sections sorting rule when linkerscript is used">;
+
def start_lib: F<"start-lib">,
HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
@@ -144,15 +200,24 @@ def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
+def symbol_ordering_file: S<"symbol-ordering-file">,
+ HelpText<"Layout sections in the order specified by symbol file">;
+
def sysroot: J<"sysroot=">, HelpText<"Set the system root">;
-def threads: F<"threads">, HelpText<"Enable use of threads">;
+def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">;
+
+def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">;
+
+def target2: J<"target2=">, MetaVarName<"<type>">, HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">;
+
+def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">;
-def undefined: J<"undefined=">,
+def undefined: S<"undefined">,
HelpText<"Force undefined symbol during linking">;
def unresolved_symbols: J<"unresolved-symbols=">,
@@ -161,9 +226,11 @@ def unresolved_symbols: J<"unresolved-symbols=">,
def rsp_quoting: J<"rsp-quoting=">,
HelpText<"Quoting style for response files. Values supported: windows|posix">;
+def v: Flag<["-"], "v">, HelpText<"Display the version number">;
+
def verbose: F<"verbose">, HelpText<"Verbose mode">;
-def version: F<"version">, HelpText<"Display the version number">;
+def version: F<"version">, HelpText<"Display the version number and exit">;
def version_script: S<"version-script">,
HelpText<"Read a version script">;
@@ -181,6 +248,7 @@ def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
HelpText<"Linker option extensions">;
// Aliases
+def alias_auxiliary: Separate<["-"], "f">, Alias<auxiliary>;
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>;
@@ -192,29 +260,41 @@ def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
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_error_limit: J<"error-limit=">, Alias<error_limit>;
def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">,
Alias<export_dynamic_symbol>;
def alias_fini_fini: J<"fini=">, Alias<fini>;
+def alias_format_b: S<"b">, Alias<format>;
def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>;
def alias_init_init: J<"init=">, Alias<init>;
def alias_l__library: J<"library=">, Alias<l>;
+def alias_omagic: Flag<["-"], "N">, Alias<omagic>;
def alias_o_output: Joined<["--"], "output=">, Alias<o>;
+def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
-def alias_rpath_R: Joined<["-"], "R">, Alias<rpath>;
+def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>;
+def alias_rpath_R: JoinedOrSeparate<["-"], "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_sort_section: J<"sort-section=">, Alias<sort_section>;
+def alias_script: J<"script=">, Alias<script>;
def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>;
def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
+def alias_Tbss: J<"Tbss=">, Alias<Tbss>;
+def alias_Tdata: J<"Tdata=">, Alias<Tdata>;
def alias_trace: Flag<["-"], "t">, Alias<trace>;
def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
+def alias_Ttext: J<"Ttext=">, Alias<Ttext>;
+def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>;
+def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias<Ttext>;
+def alias_undefined_eq: J<"undefined=">, Alias<undefined>;
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
@@ -239,9 +319,13 @@ def plugin_opt_eq: J<"plugin-opt=">;
// Options listed below are silently ignored for now for compatibility.
def allow_shlib_undefined: F<"allow-shlib-undefined">;
+def cref: Flag<["--"], "cref">;
def define_common: F<"define-common">;
def demangle: F<"demangle">;
def detect_odr_violations: F<"detect-odr-violations">;
+def g: Flag<["-"], "g">;
+def M: Flag<["-"], "M">;
+def Map: JS<"Map">;
def no_add_needed: F<"no-add-needed">;
def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">,
@@ -254,23 +338,30 @@ 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 stats: F<"stats">;
def warn_execstack: F<"warn-execstack">;
def warn_shared_textrel: F<"warn-shared-textrel">;
-def G: Separate<["-"], "G">;
+def EB : F<"EB">;
+def EL : F<"EL">;
+def G: JoinedOrSeparate<["-"], "G">;
+def Qy : F<"Qy">;
// Aliases for ignored options
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_Map_eq: J<"Map=">, Alias<Map>;
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 lto_partitions: J<"lto-partitions=">,
+ HelpText<"Number of LTO codegen partitions">;
def disable_verify: F<"disable-verify">;
def mllvm: S<"mllvm">;
def save_temps: F<"save-temps">;
+def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 50b94015f229..bf7f9c29a29a 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -11,15 +11,16 @@
#include "Config.h"
#include "EhFrame.h"
#include "LinkerScript.h"
+#include "Memory.h"
#include "Strings.h"
#include "SymbolTable.h"
+#include "SyntheticSections.h"
#include "Target.h"
-#include "lld/Core/Parallel.h"
+#include "Threads.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;
@@ -30,855 +31,152 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-template <class ELFT>
-OutputSectionBase<ELFT>::OutputSectionBase(StringRef Name, uint32_t Type,
- uintX_t Flags)
+OutputSectionBase::OutputSectionBase(StringRef Name, uint32_t Type,
+ uint64_t Flags)
: Name(Name) {
- memset(&Header, 0, sizeof(Elf_Shdr));
- Header.sh_type = Type;
- Header.sh_flags = Flags;
- Header.sh_addralign = 1;
+ this->Type = Type;
+ this->Flags = Flags;
+ this->Addralign = 1;
}
-template <class ELFT>
-void OutputSectionBase<ELFT>::writeHeaderTo(Elf_Shdr *Shdr) {
- *Shdr = Header;
+uint32_t OutputSectionBase::getPhdrFlags() const {
+ uint32_t Ret = PF_R;
+ if (Flags & SHF_WRITE)
+ Ret |= PF_W;
+ if (Flags & SHF_EXECINSTR)
+ Ret |= PF_X;
+ return Ret;
}
template <class ELFT>
-GotPltSection<ELFT>::GotPltSection()
- : OutputSectionBase<ELFT>(".got.plt", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
- this->Header.sh_addralign = Target->GotPltEntrySize;
-}
-
-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> void GotPltSection<ELFT>::finalize() {
- this->Header.sh_size = (Target->GotPltHeaderEntriesNum + Entries.size()) *
- Target->GotPltEntrySize;
-}
-
-template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
- Target->writeGotPltHeader(Buf);
- Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
- for (const SymbolBody *B : Entries) {
- Target->writeGotPlt(Buf, *B);
- Buf += sizeof(uintX_t);
+void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
+ Shdr->sh_entsize = Entsize;
+ Shdr->sh_addralign = Addralign;
+ Shdr->sh_type = Type;
+ Shdr->sh_offset = Offset;
+ Shdr->sh_flags = Flags;
+ Shdr->sh_info = Info;
+ Shdr->sh_link = Link;
+ Shdr->sh_addr = Addr;
+ Shdr->sh_size = Size;
+ Shdr->sh_name = ShName;
+}
+
+template <class ELFT> static uint64_t getEntsize(uint32_t Type) {
+ switch (Type) {
+ case SHT_RELA:
+ return sizeof(typename ELFT::Rela);
+ case SHT_REL:
+ return sizeof(typename ELFT::Rel);
+ case SHT_MIPS_REGINFO:
+ return sizeof(Elf_Mips_RegInfo<ELFT>);
+ case SHT_MIPS_OPTIONS:
+ return sizeof(Elf_Mips_Options<ELFT>) + sizeof(Elf_Mips_RegInfo<ELFT>);
+ case SHT_MIPS_ABIFLAGS:
+ return sizeof(Elf_Mips_ABIFlags<ELFT>);
+ default:
+ return 0;
}
}
template <class ELFT>
-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 = Target->GotEntrySize;
-}
-
-template <class ELFT>
-void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
- Sym.GotIndex = Entries.size();
- Entries.push_back(&Sym);
-}
-
-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 = Entries.size();
- // Global Dynamic TLS entries take two GOT slots.
- Entries.push_back(nullptr);
- Entries.push_back(&Sym);
- return true;
+OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
+ : OutputSectionBase(Name, Type, Flags) {
+ this->Entsize = getEntsize<ELFT>(Type);
}
-// 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))
+template <typename ELFT>
+static bool compareByFilePosition(InputSection<ELFT> *A,
+ InputSection<ELFT> *B) {
+ // Synthetic doesn't have link order dependecy, stable_sort will keep it last
+ if (A->kind() == InputSectionData::Synthetic ||
+ B->kind() == InputSectionData::Synthetic)
return false;
- TlsIndexOff = Entries.size() * sizeof(uintX_t);
- Entries.push_back(nullptr);
- Entries.push_back(nullptr);
- return true;
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::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>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
- return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
-}
-
-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 MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
-}
-
-template <class ELFT>
-unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
- return MipsPageEntries + MipsLocal.size();
+ auto *LA = cast<InputSection<ELFT>>(A->getLinkOrderDep());
+ auto *LB = cast<InputSection<ELFT>>(B->getLinkOrderDep());
+ OutputSectionBase *AOut = LA->OutSec;
+ OutputSectionBase *BOut = LB->OutSec;
+ if (AOut != BOut)
+ return AOut->SectionIndex < BOut->SectionIndex;
+ return LA->OutSecOff < LB->OutSecOff;
}
-template <class ELFT> void GotSection<ELFT>::finalize() {
- 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) {
- if (Config->EMachine == EM_MIPS)
- writeMipsGot(Buf);
- for (const SymbolBody *B : Entries) {
- uint8_t *Entry = Buf;
- Buf += sizeof(uintX_t);
- if (!B)
- continue;
- if (B->isPreemptible())
- continue; // The dynamic linker will take care of it.
- uintX_t VA = B->getVA<ELFT>();
- write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
- }
-}
-
-template <class ELFT>
-PltSection<ELFT>::PltSection()
- : OutputSectionBase<ELFT>(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) {
- this->Header.sh_addralign = 16;
-}
-
-template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
- // 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 *B = I.first;
- unsigned RelOff = I.second;
- uint64_t Got = B->getGotPltVA<ELFT>();
- uint64_t Plt = this->getVA() + Off;
- 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 = Out<ELFT>::RelaPlt->getRelocOffset();
- Entries.push_back(std::make_pair(&Sym, RelOff));
-}
-
-template <class ELFT> void PltSection<ELFT>::finalize() {
- this->Header.sh_size =
- Target->PltHeaderSize + Entries.size() * Target->PltEntrySize;
-}
-
-template <class ELFT>
-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);
-}
-
-template <class ELFT>
-void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
- Relocs.push_back(Reloc);
-}
-
-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_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);
- }
-
- if (Sort) {
- if (Config->Rela)
- std::stable_sort((Elf_Rela *)BufBegin,
- (Elf_Rela *)BufBegin + Relocs.size(),
- compRelocations<ELFT, Elf_Rela>);
- else
- std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(),
- compRelocations<ELFT, Elf_Rel>);
- }
-}
-
-template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
- return this->Header.sh_entsize * Relocs.size();
-}
-
-template <class ELFT> void RelocationSection<ELFT>::finalize() {
- this->Header.sh_link = Static ? Out<ELFT>::SymTab->SectionIndex
- : Out<ELFT>::DynSymTab->SectionIndex;
- this->Header.sh_size = Relocs.size() * this->Header.sh_entsize;
-}
-
-template <class ELFT>
-InterpSection<ELFT>::InterpSection()
- : OutputSectionBase<ELFT>(".interp", SHT_PROGBITS, SHF_ALLOC) {
- this->Header.sh_size = Config->DynamicLinker.size() + 1;
-}
-
-template <class ELFT> void InterpSection<ELFT>::writeTo(uint8_t *Buf) {
- StringRef S = Config->DynamicLinker;
- memcpy(Buf, S.data(), S.size());
-}
-
-template <class ELFT>
-HashTableSection<ELFT>::HashTableSection()
- : OutputSectionBase<ELFT>(".hash", SHT_HASH, SHF_ALLOC) {
- this->Header.sh_entsize = sizeof(Elf_Word);
- this->Header.sh_addralign = sizeof(Elf_Word);
-}
-
-static uint32_t hashSysv(StringRef Name) {
- uint32_t H = 0;
- for (char C : Name) {
- H = (H << 4) + C;
- uint32_t G = H & 0xf0000000;
- if (G)
- H ^= G >> 24;
- H &= ~G;
- }
- return H;
-}
-
-template <class ELFT> void HashTableSection<ELFT>::finalize() {
- this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
-
- unsigned NumEntries = 2; // nbucket and nchain.
- NumEntries += Out<ELFT>::DynSymTab->getNumSymbols(); // The chain entries.
-
- // Create as many buckets as there are symbols.
- // FIXME: This is simplistic. We can try to optimize it, but implementing
- // support for SHT_GNU_HASH is probably even more profitable.
- NumEntries += Out<ELFT>::DynSymTab->getNumSymbols();
- this->Header.sh_size = NumEntries * sizeof(Elf_Word);
-}
-
-template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
- unsigned NumSymbols = Out<ELFT>::DynSymTab->getNumSymbols();
- auto *P = reinterpret_cast<Elf_Word *>(Buf);
- *P++ = NumSymbols; // nbucket
- *P++ = NumSymbols; // nchain
-
- Elf_Word *Buckets = P;
- Elf_Word *Chains = P + NumSymbols;
-
- for (const std::pair<SymbolBody *, unsigned> &P :
- Out<ELFT>::DynSymTab->getSymbols()) {
- SymbolBody *Body = P.first;
- StringRef Name = Body->getName();
- unsigned I = Body->DynsymIndex;
- uint32_t Hash = hashSysv(Name) % NumSymbols;
- Chains[I] = Buckets[Hash];
- Buckets[Hash] = I;
- }
-}
-
-static uint32_t hashGnu(StringRef Name) {
- uint32_t H = 5381;
- for (uint8_t C : Name)
- H = (H << 5) + H + C;
- return H;
-}
-
-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 = sizeof(uintX_t);
-}
-
-template <class ELFT>
-unsigned GnuHashTableSection<ELFT>::calcNBuckets(unsigned NumHashed) {
- if (!NumHashed)
- return 0;
-
- // These values are prime numbers which are not greater than 2^(N-1) + 1.
- // In result, for any particular NumHashed we return a prime number
- // which is not greater than NumHashed.
- static const unsigned Primes[] = {
- 1, 1, 3, 3, 7, 13, 31, 61, 127, 251,
- 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071};
-
- return Primes[std::min<unsigned>(Log2_32_Ceil(NumHashed),
- array_lengthof(Primes) - 1)];
-}
-
-// Bloom filter estimation: at least 8 bits for each hashed symbol.
-// GNU Hash table requirement: it should be a power of 2,
-// the minimum value is 1, even for an empty table.
-// Expected results for a 32-bit target:
-// calcMaskWords(0..4) = 1
-// calcMaskWords(5..8) = 2
-// calcMaskWords(9..16) = 4
-// For a 64-bit target:
-// calcMaskWords(0..8) = 1
-// calcMaskWords(9..16) = 2
-// calcMaskWords(17..32) = 4
-template <class ELFT>
-unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) {
- if (!NumHashed)
- return 1;
- return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off));
-}
-
-template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
- unsigned NumHashed = Symbols.size();
- NBuckets = calcNBuckets(NumHashed);
- MaskWords = calcMaskWords(NumHashed);
- // Second hash shift estimation: just predefined values.
- Shift2 = ELFT::Is64Bits ? 6 : 5;
-
- this->Header.sh_link = Out<ELFT>::DynSymTab->SectionIndex;
- this->Header.sh_size = sizeof(Elf_Word) * 4 // Header
- + sizeof(Elf_Off) * MaskWords // Bloom Filter
- + sizeof(Elf_Word) * NBuckets // Hash Buckets
- + sizeof(Elf_Word) * NumHashed; // Hash Values
-}
-
-template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
- writeHeader(Buf);
- if (Symbols.empty())
- return;
- writeBloomFilter(Buf);
- writeHashTable(Buf);
-}
-
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) {
- auto *P = reinterpret_cast<Elf_Word *>(Buf);
- *P++ = NBuckets;
- *P++ = Out<ELFT>::DynSymTab->getNumSymbols() - Symbols.size();
- *P++ = MaskWords;
- *P++ = Shift2;
- Buf = reinterpret_cast<uint8_t *>(P);
-}
-
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) {
- unsigned C = sizeof(Elf_Off) * 8;
-
- auto *Masks = reinterpret_cast<Elf_Off *>(Buf);
- 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;
-}
+template <class ELFT> void OutputSection<ELFT>::finalize() {
+ if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
+ std::sort(Sections.begin(), Sections.end(), compareByFilePosition<ELFT>);
+ Size = 0;
+ assignOffsets();
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
- Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf);
- Elf_Word *Values = Buckets + NBuckets;
-
- int PrevBucket = -1;
- int I = 0;
- for (const SymbolData &Sym : Symbols) {
- int Bucket = Sym.Hash % NBuckets;
- assert(PrevBucket <= Bucket);
- if (Bucket != PrevBucket) {
- Buckets[Bucket] = Sym.Body->DynsymIndex;
- PrevBucket = Bucket;
- if (I > 0)
- Values[I - 1] |= 1;
- }
- Values[I] = Sym.Hash & ~1;
- ++I;
+ // We must preserve the link order dependency of sections with the
+ // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
+ // need to translate the InputSection sh_link to the OutputSection sh_link,
+ // all InputSections in the OutputSection have the same dependency.
+ if (auto *D = this->Sections.front()->getLinkOrderDep())
+ this->Link = D->OutSec->SectionIndex;
}
- if (I > 0)
- Values[I - 1] |= 1;
-}
-// 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<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())
+ uint32_t Type = this->Type;
+ if (!Config->Relocatable || (Type != SHT_RELA && Type != SHT_REL))
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(Symbols.size());
- std::stable_sort(Symbols.begin(), Symbols.end(),
- [&](const SymbolData &L, const SymbolData &R) {
- return L.Hash % NBuckets < R.Hash % NBuckets;
- });
-
- 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()
- : OutputSectionBase<ELFT>(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE) {
- Elf_Shdr &Header = this->Header;
- Header.sh_addralign = sizeof(uintX_t);
- Header.sh_entsize = ELFT::Is64Bits ? 16 : 8;
-
- // .dynamic section is not writable on MIPS.
- // See "Special Section" in Chapter 4 in the following document:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (Config->EMachine == EM_MIPS)
- Header.sh_flags = SHF_ALLOC;
-}
-
-template <class ELFT> void DynamicSection<ELFT>::finalize() {
- if (this->Header.sh_size)
- return; // Already finalized.
-
- Elf_Shdr &Header = this->Header;
- Header.sh_link = Out<ELFT>::DynStrTab->SectionIndex;
-
- 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()) {
- 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()) {
- 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)});
- }
- 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)
- Add({DT_GNU_HASH, Out<ELFT>::GnuHashTab});
- if (Out<ELFT>::HashTab)
- Add({DT_HASH, Out<ELFT>::HashTab});
-
- if (PreInitArraySec) {
- Add({DT_PREINIT_ARRAY, PreInitArraySec});
- Add({DT_PREINIT_ARRAYSZ, PreInitArraySec->getSize()});
- }
- if (InitArraySec) {
- Add({DT_INIT_ARRAY, InitArraySec});
- Add({DT_INIT_ARRAYSZ, (uintX_t)InitArraySec->getSize()});
- }
- if (FiniArraySec) {
- Add({DT_FINI_ARRAY, FiniArraySec});
- Add({DT_FINI_ARRAYSZ, (uintX_t)FiniArraySec->getSize()});
- }
-
- 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)
- DtFlags1 |= DF_1_NODELETE;
- if (Config->ZNow) {
- DtFlags |= DF_BIND_NOW;
- DtFlags1 |= DF_1_NOW;
- }
- if (Config->ZOrigin) {
- DtFlags |= DF_ORIGIN;
- DtFlags1 |= DF_1_ORIGIN;
- }
-
- if (DtFlags)
- Add({DT_FLAGS, DtFlags});
- if (DtFlags1)
- Add({DT_FLAGS_1, DtFlags1});
-
- if (!Config->Entry.empty())
- 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) {
- 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)
- Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap});
- }
-
- // +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);
-
- 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;
- }
-}
-
-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;
-
- // 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;
-}
-
-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) {
- 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;
+ this->Link = In<ELFT>::SymTab->OutSec->SectionIndex;
// sh_info for SHT_REL[A] sections should contain the section header index of
// the section to which the relocation applies.
InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection();
- this->Header.sh_info = S->OutSec->SectionIndex;
+ this->Info = S->OutSec->SectionIndex;
}
template <class ELFT>
-void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+void OutputSection<ELFT>::addSection(InputSectionData *C) {
assert(C->Live);
auto *S = cast<InputSection<ELFT>>(C);
Sections.push_back(S);
S->OutSec = this;
this->updateAlignment(S->Alignment);
-}
-
-// 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;
+ // Keep sh_entsize value of the input section to be able to perform merging
+ // later during a final linking using the generated relocatable object.
+ if (Config->Relocatable && (S->Flags & SHF_MERGE))
+ this->Entsize = S->Entsize;
}
// 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;
+ uintX_t Off = this->Size;
for (InputSection<ELFT> *S : Sections) {
Off = alignTo(Off, S->Alignment);
S->OutSecOff = Off;
Off += S->getSize();
}
- this->Header.sh_size = Off;
+ this->Size = Off;
}
-// 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;
+template <class ELFT>
+void OutputSection<ELFT>::sort(
+ std::function<int(InputSection<ELFT> *S)> Order) {
+ typedef std::pair<unsigned, 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});
+ V.push_back({Order(S), S});
std::stable_sort(V.begin(), V.end(), Comp);
Sections.clear();
for (Pair &P : V)
Sections.push_back(P.second);
}
+// 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.
+ sort([](InputSection<ELFT> *S) { return getPriority(S->Name); });
+}
+
// Returns true if S matches /Filename.?\.o$/.
static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
if (!S.endswith(".o"))
@@ -921,8 +219,8 @@ static bool compCtors(const InputSection<ELFT> *A,
bool EndB = isCrtend(B->getFile()->getName());
if (EndA != EndB)
return EndB;
- StringRef X = A->getSectionName();
- StringRef Y = B->getSectionName();
+ StringRef X = A->Name;
+ StringRef Y = B->Name;
assert(X.startswith(".ctors") || X.startswith(".dtors"));
assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
X = X.substr(6);
@@ -939,65 +237,50 @@ template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
}
-static void fill(uint8_t *Buf, size_t Size, ArrayRef<uint8_t> A) {
+// Fill [Buf, Buf + Size) with Filler. Filler is written in big
+// endian order. This is used for linker script "=fillexp" command.
+void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
+ uint8_t V[4];
+ write32be(V, Filler);
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);
+ for (; I + 4 < Size; I += 4)
+ memcpy(Buf + I, V, 4);
+ memcpy(Buf + I, V, Size - I);
}
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);
- }
+ Loc = Buf;
+ if (uint32_t Filler = Script<ELFT>::X->getFiller(this->Name))
+ fill(Buf, this->Size, Filler);
+
+ auto Fn = [=](InputSection<ELFT> *IS) { IS->writeTo(Buf); };
+ forEach(Sections.begin(), Sections.end(), Fn);
+
+ // Linker scripts may have BYTE()-family commands with which you
+ // can write arbitrary bytes to the output. Process them if any.
+ Script<ELFT>::X->writeDataBytes(this->Name, Buf);
}
template <class ELFT>
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;
-}
+ : OutputSectionBase(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
// Search for an existing CIE record or create a new one.
// CIE records from input object files are uniquified by their contents
// and where their relocations point to.
template <class ELFT>
template <class RelTy>
-CieRecord *EhOutputSection<ELFT>::addCie(SectionPiece &Piece,
- EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> &Rels) {
+CieRecord *EhOutputSection<ELFT>::addCie(EhSectionPiece &Piece,
+ ArrayRef<RelTy> Rels) {
+ auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
const endianness E = ELFT::TargetEndianness;
if (read32<E>(Piece.data().data() + 4) != 0)
- fatal("CIE expected at beginning of .eh_frame: " + Sec->getSectionName());
+ fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
SymbolBody *Personality = nullptr;
- if (const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels))
- Personality = &Sec->getFile()->getRelocTargetSym(*Rel);
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI != (unsigned)-1)
+ Personality = &Sec->getFile()->getRelocTargetSym(Rels[FirstRelI]);
// Search for an existing CIE by CIE contents/relocation target pair.
CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
@@ -1014,13 +297,14 @@ CieRecord *EhOutputSection<ELFT>::addCie(SectionPiece &Piece,
// 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);
+bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
+ ArrayRef<RelTy> Rels) {
+ auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI == (unsigned)-1)
+ fatal(toString(Sec) + ": FDE doesn't reference another section");
+ const RelTy &Rel = Rels[FirstRelI];
+ SymbolBody &B = Sec->getFile()->getRelocTargetSym(Rel);
auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
if (!D || !D->Section)
return false;
@@ -1039,7 +323,7 @@ void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
const endianness E = ELFT::TargetEndianness;
DenseMap<size_t, CieRecord *> OffsetToCie;
- for (SectionPiece &Piece : Sec->Pieces) {
+ for (EhSectionPiece &Piece : Sec->Pieces) {
// The empty record is the end marker.
if (Piece.size() == 4)
return;
@@ -1047,16 +331,16 @@ void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
size_t Offset = Piece.InputOff;
uint32_t ID = read32<E>(Piece.data().data() + 4);
if (ID == 0) {
- OffsetToCie[Offset] = addCie(Piece, Sec, Rels);
+ OffsetToCie[Offset] = addCie(Piece, Rels);
continue;
}
uint32_t CieOffset = Offset + 4 - ID;
CieRecord *Cie = OffsetToCie[CieOffset];
if (!Cie)
- fatal("invalid CIE reference");
+ fatal(toString(Sec) + ": invalid CIE reference");
- if (!isFdeLive(Piece, Sec, Rels))
+ if (!isFdeLive(Piece, Rels))
continue;
Cie->FdePieces.push_back(&Piece);
NumFdes++;
@@ -1064,7 +348,7 @@ void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
}
template <class ELFT>
-void EhOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+void EhOutputSection<ELFT>::addSection(InputSectionData *C) {
auto *Sec = cast<EhInputSection<ELFT>>(C);
Sec->OutSec = this;
this->updateAlignment(Sec->Alignment);
@@ -1077,12 +361,11 @@ void EhOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
if (Sec->Pieces.empty())
return;
- if (const Elf_Shdr *RelSec = Sec->RelocSection) {
- ELFFile<ELFT> &Obj = Sec->getFile()->getObj();
- if (RelSec->sh_type == SHT_RELA)
- addSectionAux(Sec, Obj.relas(RelSec));
+ if (Sec->NumRelocations) {
+ if (Sec->AreRelocsRela)
+ addSectionAux(Sec, Sec->relas());
else
- addSectionAux(Sec, Obj.rels(RelSec));
+ addSectionAux(Sec, Sec->rels());
return;
}
addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
@@ -1098,7 +381,7 @@ static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
}
template <class ELFT> void EhOutputSection<ELFT>::finalize() {
- if (this->Header.sh_size)
+ if (this->Size)
return; // Already finalized.
size_t Off = 0;
@@ -1106,12 +389,12 @@ template <class ELFT> void EhOutputSection<ELFT>::finalize() {
Cie->Piece->OutputOff = Off;
Off += alignTo(Cie->Piece->size(), sizeof(uintX_t));
- for (SectionPiece *Fde : Cie->FdePieces) {
+ for (EhSectionPiece *Fde : Cie->FdePieces) {
Fde->OutputOff = Off;
Off += alignTo(Fde->size(), sizeof(uintX_t));
}
}
- this->Header.sh_size = Off;
+ this->Size = Off;
}
template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
@@ -1143,7 +426,7 @@ typename ELFT::uint EhOutputSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
if ((Enc & 0x70) == DW_EH_PE_absptr)
return Addr;
if ((Enc & 0x70) == DW_EH_PE_pcrel)
- return Addr + this->getVA() + Off;
+ return Addr + this->Addr + Off;
fatal("unknown FDE size relative encoding");
}
@@ -1153,7 +436,7 @@ template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
size_t CieOffset = Cie->Piece->OutputOff;
writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
- for (SectionPiece *Fde : Cie->FdePieces) {
+ for (EhSectionPiece *Fde : Cie->FdePieces) {
size_t Off = Fde->OutputOff;
writeCieFde<ELFT>(Buf + Off, Fde->data());
@@ -1169,13 +452,13 @@ template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
// 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) {
+ if (In<ELFT>::EhFrameHdr) {
for (CieRecord *Cie : Cies) {
- uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece->data());
+ uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
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);
+ uintX_t FdeVA = this->Addr + Fde->OutputOff;
+ In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
}
}
}
@@ -1184,620 +467,127 @@ template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
template <class ELFT>
MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
uintX_t Flags, uintX_t Alignment)
- : OutputSectionBase<ELFT>(Name, Type, Flags),
+ : OutputSectionBase(Name, Type, Flags),
Builder(StringTableBuilder::RAW, Alignment) {}
template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- if (shouldTailMerge()) {
- StringRef Data = Builder.data();
- memcpy(Buf, Data.data(), Data.size());
- return;
- }
- 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 StringRef toStringRef(ArrayRef<uint8_t> A) {
- return {(const char *)A.data(), A.size()};
+ Builder.write(Buf);
}
template <class ELFT>
-void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
+void MergeOutputSection<ELFT>::addSection(InputSectionData *C) {
auto *Sec = cast<MergeInputSection<ELFT>>(C);
Sec->OutSec = this;
this->updateAlignment(Sec->Alignment);
- this->Header.sh_entsize = Sec->getSectionHdr()->sh_entsize;
+ this->Entsize = Sec->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;
- }
-}
-
-template <class ELFT>
-unsigned MergeOutputSection<ELFT>::getOffset(StringRef Val) {
- return Builder.getOffset(Val);
}
template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
- return Config->Optimize >= 2 && this->Header.sh_flags & SHF_STRINGS;
+ return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
}
-template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
- if (shouldTailMerge())
- Builder.finalize();
- this->Header.sh_size = Builder.getSize();
-}
-
-template <class ELFT> void MergeOutputSection<ELFT>::finalizePieces() {
+template <class ELFT> void MergeOutputSection<ELFT>::finalizeTailMerge() {
+ // Add all string pieces to the string table builder to create section
+ // contents.
for (MergeInputSection<ELFT> *Sec : Sections)
- 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) {}
-
-// 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);
- return Ret;
-}
-
-template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) {
- // ELF string tables start with NUL byte, so advance the pointer by one.
- ++Buf;
- for (StringRef S : Strings) {
- memcpy(Buf, S.data(), S.size());
- Buf += S.size() + 1;
- }
-}
-
-template <class ELFT>
-typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
- if (OutputSec)
- return OutputSec->getVA() + OffsetInSec;
- return InputSec->OutSec->getVA() + InputSec->getOffset(OffsetInSec);
-}
-
-template <class ELFT>
-typename ELFT::uint DynamicReloc<ELFT>::getAddend() const {
- if (UseSymVA)
- return Sym->getVA<ELFT>(Addend);
- return Addend;
-}
-
-template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const {
- if (Sym && !UseSymVA)
- return Sym->DynsymIndex;
- return 0;
-}
-
-template <class ELFT>
-SymbolTableSection<ELFT>::SymbolTableSection(
- StringTableSection<ELFT> &StrTabSec)
- : OutputSectionBase<ELFT>(StrTabSec.isDynamic() ? ".dynsym" : ".symtab",
- StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
- StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0),
- StrTabSec(StrTabSec) {
- this->Header.sh_entsize = sizeof(Elf_Sym);
- this->Header.sh_addralign = sizeof(uintX_t);
-}
-
-// Orders symbols according to their positions in the GOT,
-// in compliance with MIPS ABI rules.
-// 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(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() {
- if (this->Header.sh_size)
- return; // Already finalized.
-
- this->Header.sh_size = getNumSymbols() * sizeof(Elf_Sym);
- 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(),
- [](const std::pair<SymbolBody *, unsigned> &L,
- const std::pair<SymbolBody *, unsigned> &R) {
- return getSymbolBinding(L.first) == STB_LOCAL &&
- getSymbolBinding(R.first) != STB_LOCAL;
- });
- return;
- }
- if (Out<ELFT>::GnuHashTab)
- // NB: It also sorts Symbols to meet the GNU hash table requirements.
- Out<ELFT>::GnuHashTab->addSymbols(Symbols);
- else if (Config->EMachine == EM_MIPS)
- std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
- size_t I = 0;
- for (const std::pair<SymbolBody *, size_t> &P : Symbols)
- P.first->DynsymIndex = ++I;
-}
-
-template <class ELFT>
-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) {
- Buf += sizeof(Elf_Sym);
-
- // All symbols with STB_LOCAL binding precede the weak and global symbols.
- // .dynsym only contains global symbols.
- if (!Config->DiscardAll && !StrTabSec.isDynamic())
- writeLocalSymbols(Buf);
-
- writeGlobalSymbols(Buf);
-}
-
-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 :
- 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);
-
- if (!Section) {
- ESym->st_shndx = SHN_ABS;
- ESym->st_value = Body.Value;
- } else {
- const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
- ESym->st_shndx = OutSec->SectionIndex;
- ESym->st_value = OutSec->getVA() + Section->getOffset(Body);
- }
- ESym->st_name = P.second;
- ESym->st_size = Body.template getSize<ELFT>();
- ESym->setBindingAndType(STB_LOCAL, Body.Type);
- Buf += sizeof(*ESym);
- }
- }
-}
-
-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 (const std::pair<SymbolBody *, size_t> &P : Symbols) {
- SymbolBody *Body = P.first;
- size_t StrOff = P.second;
-
- uint8_t Type = Body->Type;
- uintX_t Size = Body->getSize<ELFT>();
-
- ESym->setBindingAndType(getSymbolBinding(Body), Type);
- ESym->st_size = Size;
- ESym->st_name = StrOff;
- ESym->setVisibility(Body->symbol()->Visibility);
- ESym->st_value = Body->getVA<ELFT>();
-
- 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>
-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;
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Builder.add(Sec->getData(I));
- // 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);
-}
+ // Fix the string table content. After this, the contents will never change.
+ Builder.finalize();
+ this->Size = Builder.getSize();
-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);
+ // finalize() fixed tail-optimized strings, so we can now get
+ // offsets of strings. Get an offset for each string and save it
+ // to a corresponding StringPiece for easy access.
+ for (MergeInputSection<ELFT> *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
}
-template <class ELFT>
-BuildIdHexstring<ELFT>::BuildIdHexstring()
- : BuildIdSection<ELFT>(Config->BuildIdVector.size()) {}
+template <class ELFT> void MergeOutputSection<ELFT>::finalizeNoTailMerge() {
+ // Add all string pieces to the string table builder to create section
+ // contents. Because we are not tail-optimizing, offsets of strings are
+ // fixed when they are added to the builder (string table builder contains
+ // a hash table from strings to offsets).
+ for (MergeInputSection<ELFT> *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
-template <class ELFT>
-void BuildIdHexstring<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
- memcpy(this->HashBuf, Config->BuildIdVector.data(),
- Config->BuildIdVector.size());
+ Builder.finalizeInOrder();
+ this->Size = Builder.getSize();
}
-template <class ELFT>
-MipsReginfoOutputSection<ELFT>::MipsReginfoOutputSection()
- : OutputSectionBase<ELFT>(".reginfo", SHT_MIPS_REGINFO, SHF_ALLOC) {
- this->Header.sh_addralign = 4;
- this->Header.sh_entsize = sizeof(Elf_Mips_RegInfo);
- this->Header.sh_size = sizeof(Elf_Mips_RegInfo);
+template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
+ if (shouldTailMerge())
+ finalizeTailMerge();
+ else
+ finalizeNoTailMerge();
}
template <class ELFT>
-void MipsReginfoOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- auto *R = reinterpret_cast<Elf_Mips_RegInfo *>(Buf);
- R->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset;
- R->ri_gprmask = GprMask;
+static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
+ return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
}
template <class ELFT>
-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;
-}
+static SectionKey<ELFT::Is64Bits> createKey(InputSectionBase<ELFT> *C,
+ StringRef OutsecName) {
+ typedef typename ELFT::uint uintX_t;
+ uintX_t Flags = getOutFlags(C);
-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);
-}
+ // 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.
+ // In case of relocatable object generation we do not try to perform merging
+ // and treat SHF_MERGE sections as regular ones, but also create different
+ // output sections for them to allow merging at final linking stage.
+ uintX_t Alignment = 0;
+ if (isa<MergeInputSection<ELFT>>(C) ||
+ (Config->Relocatable && (C->Flags & SHF_MERGE)))
+ Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
-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;
+ return SectionKey<ELFT::Is64Bits>{OutsecName, C->Type, Flags, Alignment};
}
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>
+std::pair<OutputSectionBase *, bool>
OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
StringRef OutsecName) {
SectionKey<ELFT::Is64Bits> Key = createKey(C, OutsecName);
- OutputSectionBase<ELFT> *&Sec = Map[Key];
- if (Sec)
+ return create(Key, C);
+}
+
+template <class ELFT>
+std::pair<OutputSectionBase *, bool>
+OutputSectionFactory<ELFT>::create(const SectionKey<ELFT::Is64Bits> &Key,
+ InputSectionBase<ELFT> *C) {
+ uintX_t Flags = getOutFlags(C);
+ OutputSectionBase *&Sec = Map[Key];
+ if (Sec) {
+ Sec->Flags |= Flags;
return {Sec, false};
+ }
- switch (C->SectionKind) {
+ uint32_t Type = C->Type;
+ switch (C->kind()) {
case InputSectionBase<ELFT>::Regular:
- Sec = new OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ case InputSectionBase<ELFT>::Synthetic:
+ Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
break;
case InputSectionBase<ELFT>::EHFrame:
return {Out<ELFT>::EhFrame, false};
case InputSectionBase<ELFT>::Merge:
- Sec = 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>();
+ Sec = make<MergeOutputSection<ELFT>>(Key.Name, Type, Flags, Key.Alignment);
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() {
@@ -1832,55 +622,11 @@ template struct DenseMapInfo<SectionKey<false>>;
namespace lld {
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>;
-template class GotPltSection<ELF64BE>;
-
-template class GotSection<ELF32LE>;
-template class GotSection<ELF32BE>;
-template class GotSection<ELF64LE>;
-template class GotSection<ELF64BE>;
-
-template class PltSection<ELF32LE>;
-template class PltSection<ELF32BE>;
-template class PltSection<ELF64LE>;
-template class PltSection<ELF64BE>;
-
-template class RelocationSection<ELF32LE>;
-template class RelocationSection<ELF32BE>;
-template class RelocationSection<ELF64LE>;
-template class RelocationSection<ELF64BE>;
-
-template class InterpSection<ELF32LE>;
-template class InterpSection<ELF32BE>;
-template class InterpSection<ELF64LE>;
-template class InterpSection<ELF64BE>;
-
-template class GnuHashTableSection<ELF32LE>;
-template class GnuHashTableSection<ELF32BE>;
-template class GnuHashTableSection<ELF64LE>;
-template class GnuHashTableSection<ELF64BE>;
-
-template class HashTableSection<ELF32LE>;
-template class HashTableSection<ELF32BE>;
-template class HashTableSection<ELF64LE>;
-template class HashTableSection<ELF64BE>;
-
-template class DynamicSection<ELF32LE>;
-template class DynamicSection<ELF32BE>;
-template class DynamicSection<ELF64LE>;
-template class DynamicSection<ELF64BE>;
+
+template void OutputSectionBase::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
+template void OutputSectionBase::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
+template void OutputSectionBase::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
+template void OutputSectionBase::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
template class OutputSection<ELF32LE>;
template class OutputSection<ELF32BE>;
@@ -1892,71 +638,11 @@ 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>;
template class MergeOutputSection<ELF64BE>;
-template class StringTableSection<ELF32LE>;
-template class StringTableSection<ELF32BE>;
-template class StringTableSection<ELF64LE>;
-template class StringTableSection<ELF64BE>;
-
-template class SymbolTableSection<ELF32LE>;
-template class SymbolTableSection<ELF32BE>;
-template class SymbolTableSection<ELF64LE>;
-template class SymbolTableSection<ELF64BE>;
-
-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>;
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 5fdf8de4cb46..978b1f8191ef 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -14,25 +14,19 @@
#include "Relocations.h"
#include "lld/Core/LLVM.h"
-#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/MD5.h"
-#include "llvm/Support/SHA1.h"
namespace lld {
namespace elf {
+struct PhdrEntry;
class SymbolBody;
-struct SectionPiece;
-template <class ELFT> class SymbolTable;
-template <class ELFT> class SymbolTableSection;
-template <class ELFT> class StringTableSection;
+struct EhSectionPiece;
template <class ELFT> class EhInputSection;
template <class ELFT> class InputSection;
template <class ELFT> class InputSectionBase;
template <class ELFT> class MergeInputSection;
-template <class ELFT> class MipsReginfoInputSection;
template <class ELFT> class OutputSection;
template <class ELFT> class ObjectFile;
template <class ELFT> class SharedFile;
@@ -44,341 +38,126 @@ template <class ELFT> class DefinedRegular;
// input sections, others are created by the linker.
// The writer creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
-template <class ELFT> class OutputSectionBase {
+class OutputSectionBase {
public:
- typedef typename ELFT::uint uintX_t;
- typedef typename ELFT::Shdr Elf_Shdr;
+ enum Kind {
+ Base,
+ EHFrame,
+ Merge,
+ Regular,
+ };
- 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; }
+ OutputSectionBase(StringRef Name, uint32_t Type, uint64_t Flags);
+ void setLMAOffset(uint64_t LMAOff) { LMAOffset = LMAOff; }
+ uint64_t getLMA() const { return Addr + LMAOffset; }
+ template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
+ StringRef getName() const { return Name; }
- virtual void addSection(InputSectionBase<ELFT> *C) {}
+ virtual void addSection(InputSectionData *C) {}
+ virtual Kind getKind() const { return Base; }
+ static bool classof(const OutputSectionBase *B) {
+ return B->getKind() == Base;
+ }
unsigned SectionIndex;
- // 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() 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;
+ uint32_t getPhdrFlags() const;
+
+ void updateAlignment(uint64_t Alignment) {
+ if (Alignment > Addralign)
+ 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;
+ // Pointer to the first section in PT_LOAD segment, which this section
+ // also resides in. This field is used to correctly compute file offset
+ // of a section. When two sections share the same load segment, difference
+ // between their file offsets should be equal to difference between their
+ // virtual addresses. To compute some section offset we use the following
+ // formula: Off = Off_first + VA - VA_first.
+ OutputSectionBase *FirstInPtLoad = nullptr;
+
virtual void finalize() {}
- virtual void finalizePieces() {}
virtual void assignOffsets() {}
virtual void writeTo(uint8_t *Buf) {}
virtual ~OutputSectionBase() = default;
-protected:
StringRef Name;
- Elf_Shdr Header;
-};
-template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> {
- typedef OutputSectionBase<ELFT> Base;
- typedef typename ELFT::uint uintX_t;
-
-public:
- GotSection();
- void finalize() override;
- void writeTo(uint8_t *Buf) override;
- 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
- // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
- // table properties.
- // Returns nullptr if the global part is empty.
- const SymbolBody *getMipsFirstGlobalEntry() const;
-
- // Returns the number of entries in the local part of GOT including
- // the number of reserved entries. This method is MIPS-specific.
- unsigned getMipsLocalEntriesNum() const;
-
- // 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 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);
+ // The following fields correspond to Elf_Shdr members.
+ uint64_t Size = 0;
+ uint64_t Entsize = 0;
+ uint64_t Addralign = 0;
+ uint64_t Offset = 0;
+ uint64_t Flags = 0;
+ uint64_t LMAOffset = 0;
+ uint64_t Addr = 0;
+ uint32_t ShName = 0;
+ uint32_t Type = 0;
+ uint32_t Info = 0;
+ uint32_t Link = 0;
};
-template <class ELFT>
-class GotPltSection final : public OutputSectionBase<ELFT> {
- typedef typename ELFT::uint uintX_t;
+template <class ELFT> class OutputSection final : public OutputSectionBase {
public:
- GotPltSection();
- void finalize() override;
- void writeTo(uint8_t *Buf) override;
- void addEntry(SymbolBody &Sym);
- bool empty() const;
-
-private:
- std::vector<const SymbolBody *> Entries;
-};
-
-template <class ELFT> class PltSection final : public OutputSectionBase<ELFT> {
- typedef OutputSectionBase<ELFT> Base;
- typedef typename ELFT::uint uintX_t;
-
-public:
- PltSection();
- void finalize() override;
- void writeTo(uint8_t *Buf) override;
- void addEntry(SymbolBody &Sym);
- bool empty() const { return Entries.empty(); }
-
-private:
- std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
-};
-
-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 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 addSymbol(SymbolBody *Body);
- StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
- unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; }
-
- 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);
-
- const OutputSectionBase<ELFT> *getOutputSection(SymbolBody *Sym);
-
- // 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 ELFT::Rel Elf_Rel;
- typedef typename ELFT::Rela Elf_Rela;
- typedef typename ELFT::uint uintX_t;
-
-public:
- RelocationSection(StringRef Name, bool Sort);
- void addReloc(const DynamicReloc<ELFT> &Reloc);
- unsigned getRelocOffset();
- void finalize() override;
- void writeTo(uint8_t *Buf) override;
- bool hasRelocs() const { return !Relocs.empty(); }
-
- bool Static = false;
-
-private:
- bool Sort;
- std::vector<DynamicReloc<ELFT>> Relocs;
-};
-
-template <class ELFT>
-class OutputSection final : public OutputSectionBase<ELFT> {
-public:
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::uint uintX_t;
OutputSection(StringRef Name, uint32_t Type, uintX_t Flags);
- void addSection(InputSectionBase<ELFT> *C) override;
+ void addSection(InputSectionData *C) override;
+ void sort(std::function<int(InputSection<ELFT> *S)> Order);
void sortInitFini();
void sortCtorsDtors();
void writeTo(uint8_t *Buf) override;
void finalize() override;
void assignOffsets() override;
+ Kind getKind() const override { return Regular; }
+ static bool classof(const OutputSectionBase *B) {
+ return B->getKind() == Regular;
+ }
std::vector<InputSection<ELFT> *> Sections;
+
+ // Location in the output buffer.
+ uint8_t *Loc = nullptr;
};
template <class ELFT>
-class MergeOutputSection final : public OutputSectionBase<ELFT> {
+class MergeOutputSection final : public OutputSectionBase {
typedef typename ELFT::uint uintX_t;
public:
MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
uintX_t Alignment);
- void addSection(InputSectionBase<ELFT> *S) override;
+ void addSection(InputSectionData *S) override;
void writeTo(uint8_t *Buf) override;
- unsigned getOffset(StringRef Val);
void finalize() override;
- void finalizePieces() override;
bool shouldTailMerge() const;
+ Kind getKind() const override { return Merge; }
+ static bool classof(const OutputSectionBase *B) {
+ return B->getKind() == Merge;
+ }
private:
+ void finalizeTailMerge();
+ void finalizeNoTailMerge();
+
llvm::StringTableBuilder Builder;
std::vector<MergeInputSection<ELFT> *> Sections;
};
struct CieRecord {
- SectionPiece *Piece = nullptr;
- std::vector<SectionPiece *> FdePieces;
+ EhSectionPiece *Piece = nullptr;
+ std::vector<EhSectionPiece *> FdePieces;
};
// Output section for .eh_frame.
-template <class ELFT>
-class EhOutputSection final : public OutputSectionBase<ELFT> {
+template <class ELFT> class EhOutputSection final : public OutputSectionBase {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Rel Elf_Rel;
@@ -390,7 +169,11 @@ public:
void finalize() override;
bool empty() const { return Sections.empty(); }
- void addSection(InputSectionBase<ELFT> *S) override;
+ void addSection(InputSectionData *S) override;
+ Kind getKind() const override { return EHFrame; }
+ static bool classof(const OutputSectionBase *B) {
+ return B->getKind() == EHFrame;
+ }
size_t NumFdes = 0;
@@ -399,12 +182,10 @@ private:
void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
template <class RelTy>
- CieRecord *addCie(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> &Rels);
+ CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
template <class RelTy>
- bool isFdeLive(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> &Rels);
+ bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
@@ -415,247 +196,25 @@ private:
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
};
-template <class ELFT>
-class InterpSection final : public OutputSectionBase<ELFT> {
-public:
- InterpSection();
- void writeTo(uint8_t *Buf) override;
-};
-
-template <class ELFT>
-class StringTableSection final : public OutputSectionBase<ELFT> {
-public:
- typedef typename ELFT::uint uintX_t;
- StringTableSection(StringRef Name, bool Dynamic);
- unsigned addString(StringRef S, bool HashIt = true);
- void writeTo(uint8_t *Buf) override;
- 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;
- unsigned Size = 1; // ELF string tables start with a NUL byte, so 1.
-};
-
-template <class ELFT>
-class HashTableSection final : public OutputSectionBase<ELFT> {
- typedef typename ELFT::Word Elf_Word;
-
-public:
- HashTableSection();
- void finalize() override;
- void writeTo(uint8_t *Buf) override;
-};
-
-// Outputs GNU Hash section. For detailed explanation see:
-// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
-template <class ELFT>
-class GnuHashTableSection final : public OutputSectionBase<ELFT> {
- typedef typename ELFT::Off Elf_Off;
- typedef typename ELFT::Word Elf_Word;
- typedef typename ELFT::uint uintX_t;
-
-public:
- GnuHashTableSection();
- void finalize() override;
- void writeTo(uint8_t *Buf) override;
-
- // Adds symbols to the hash table.
- // Sorts the input to satisfy GNU hash section requirements.
- void addSymbols(std::vector<std::pair<SymbolBody *, size_t>> &Symbols);
-
-private:
- static unsigned calcNBuckets(unsigned NumHashed);
- static unsigned calcMaskWords(unsigned NumHashed);
-
- void writeHeader(uint8_t *&Buf);
- void writeBloomFilter(uint8_t *&Buf);
- void writeHashTable(uint8_t *Buf);
-
- struct SymbolData {
- SymbolBody *Body;
- size_t STName;
- uint32_t Hash;
- };
-
- std::vector<SymbolData> Symbols;
-
- unsigned MaskWords;
- unsigned NBuckets;
- unsigned Shift2;
-};
-
-template <class ELFT>
-class DynamicSection final : public OutputSectionBase<ELFT> {
- typedef OutputSectionBase<ELFT> Base;
- 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:
- explicit DynamicSection();
- void finalize() override;
- void writeTo(uint8_t *Buf) override;
-
- OutputSectionBase<ELFT> *PreInitArraySec = nullptr;
- OutputSectionBase<ELFT> *InitArraySec = nullptr;
- OutputSectionBase<ELFT> *FiniArraySec = nullptr;
-};
-
-template <class ELFT>
-class MipsReginfoOutputSection final : public OutputSectionBase<ELFT> {
- typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
-
-public:
- MipsReginfoOutputSection();
- void writeTo(uint8_t *Buf) override;
- void addSection(InputSectionBase<ELFT> *S) override;
-
-private:
- uint32_t GprMask = 0;
-};
-
-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 ELFT::uint uintX_t;
typedef typename ELFT::Phdr Elf_Phdr;
- static BuildIdSection<ELFT> *BuildId;
- static DynamicSection<ELFT> *Dynamic;
- static EhFrameHeader<ELFT> *EhFrameHdr;
+
+ static uint8_t First;
static EhOutputSection<ELFT> *EhFrame;
- static GnuHashTableSection<ELFT> *GnuHashTab;
- static GotPltSection<ELFT> *GotPlt;
- static GotSection<ELFT> *Got;
- static HashTableSection<ELFT> *HashTab;
- static InterpSection<ELFT> *Interp;
static OutputSection<ELFT> *Bss;
- static OutputSection<ELFT> *MipsRldMap;
- static OutputSectionBase<ELFT> *Opd;
+ static OutputSectionBase *Opd;
static uint8_t *OpdBuf;
- static PltSection<ELFT> *Plt;
- static RelocationSection<ELFT> *RelaDyn;
- static RelocationSection<ELFT> *RelaPlt;
- static StringTableSection<ELFT> *DynStrTab;
- static StringTableSection<ELFT> *ShStrTab;
- 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;
+ static PhdrEntry *TlsPhdr;
+ static OutputSectionBase *DebugInfo;
+ static OutputSectionBase *ElfHeader;
+ static OutputSectionBase *ProgramHeaders;
+ static OutputSectionBase *PreinitArray;
+ static OutputSectionBase *InitArray;
+ static OutputSectionBase *FiniArray;
};
template <bool Is64Bits> struct SectionKey {
@@ -676,45 +235,33 @@ template <class ELFT> class OutputSectionFactory {
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);
+ std::pair<OutputSectionBase *, bool> create(InputSectionBase<ELFT> *C,
+ StringRef OutsecName);
+ std::pair<OutputSectionBase *, bool>
+ create(const SectionKey<ELFT::Is64Bits> &Key, InputSectionBase<ELFT> *C);
private:
- Key createKey(InputSectionBase<ELFT> *C, StringRef OutsecName);
-
- llvm::SmallDenseMap<Key, OutputSectionBase<ELFT> *> Map;
+ llvm::SmallDenseMap<Key, OutputSectionBase *> 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> uint64_t getHeaderSize() {
+ if (Config->OFormatBinary)
+ return 0;
+ return Out<ELFT>::ElfHeader->Size + Out<ELFT>::ProgramHeaders->Size;
+}
+
+template <class ELFT> uint8_t Out<ELFT>::First;
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;
-template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab;
-template <class ELFT> InterpSection<ELFT> *Out<ELFT>::Interp;
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
-template <class ELFT> OutputSection<ELFT> *Out<ELFT>::MipsRldMap;
-template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::Opd;
+template <class ELFT> OutputSectionBase *Out<ELFT>::Opd;
template <class ELFT> uint8_t *Out<ELFT>::OpdBuf;
-template <class ELFT> PltSection<ELFT> *Out<ELFT>::Plt;
-template <class ELFT> RelocationSection<ELFT> *Out<ELFT>::RelaDyn;
-template <class ELFT> RelocationSection<ELFT> *Out<ELFT>::RelaPlt;
-template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::DynStrTab;
-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> 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;
-
+template <class ELFT> PhdrEntry *Out<ELFT>::TlsPhdr;
+template <class ELFT> OutputSectionBase *Out<ELFT>::DebugInfo;
+template <class ELFT> OutputSectionBase *Out<ELFT>::ElfHeader;
+template <class ELFT> OutputSectionBase *Out<ELFT>::ProgramHeaders;
+template <class ELFT> OutputSectionBase *Out<ELFT>::PreinitArray;
+template <class ELFT> OutputSectionBase *Out<ELFT>::InitArray;
+template <class ELFT> OutputSectionBase *Out<ELFT>::FiniArray;
} // namespace elf
} // namespace lld
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index c09cf6b2b1ef..f7dcc5d24e93 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -44,7 +44,9 @@
#include "Relocations.h"
#include "Config.h"
#include "OutputSections.h"
+#include "Strings.h"
#include "SymbolTable.h"
+#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
@@ -60,11 +62,10 @@ 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;
+ return isRelExprOneOf<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
+ R_MIPS_GOT_OFF32, R_MIPS_TLSGD, R_MIPS_TLSLD,
+ R_GOT_PAGE_PC, R_GOT_PC, R_GOT_FROM_END, R_TLSGD,
+ R_TLSGD_PC, R_TLSDESC, R_TLSDESC_PAGE>(Expr);
}
static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
@@ -83,34 +84,46 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
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});
+// This function is similar to the `handleTlsRelocation`. ARM and MIPS do not
+// support any relaxations for TLS relocations so by factoring out ARM and MIPS
+// handling in to the separate function we can simplify the code and do not
+// pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements.
+template <class ELFT, class GOT>
+static unsigned handleNoRelaxTlsRelocation(
+ GOT *Got, uint32_t Type, SymbolBody &Body, InputSectionBase<ELFT> &C,
+ typename ELFT::uint Offset, typename ELFT::uint Addend, RelExpr Expr) {
+ typedef typename ELFT::uint uintX_t;
+ auto addModuleReloc = [](SymbolBody &Body, GOT *Got, uintX_t Off, bool LD) {
+ // The Dynamic TLS Module Index Relocation can be statically resolved to 1
+ // if we know that we are linking an executable. For ARM we resolve the
+ // relocation when writing the Got. MIPS has a custom Got implementation
+ // that writes the Module index in directly.
+ if (!Body.isPreemptible() && !Config->Pic && Config->EMachine == EM_ARM)
+ Got->Relocations.push_back(
+ {R_ABS, Target->TlsModuleIndexRel, Off, 0, &Body});
+ else {
+ SymbolBody *Dest = LD ? nullptr : &Body;
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->TlsModuleIndexRel, Got, Off, false, Dest, 0});
+ }
+ };
+ if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) {
+ if (Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM))
+ addModuleReloc(Body, Got, Got->getTlsIndexOff(), true);
+ C.Relocations.push_back({Expr, Type, 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});
+ if (Got->addDynTlsEntry(Body) &&
+ (Body.isPreemptible() || Config->EMachine == EM_ARM)) {
+ uintX_t Off = Got->getGlobalDynOffset(Body);
+ addModuleReloc(Body, Got, Off, false);
+ if (Body.isPreemptible())
+ In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Got,
+ Off + (uintX_t)sizeof(uintX_t), false,
+ &Body, 0});
}
- C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
return 0;
@@ -122,7 +135,7 @@ 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))
+ if (!(C.Flags & SHF_ALLOC))
return 0;
if (!Body.isTls())
@@ -130,18 +143,23 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
typedef typename ELFT::uint uintX_t;
+ if (Config->EMachine == EM_ARM)
+ return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::Got, Type, Body, C,
+ Offset, Addend, Expr);
if (Config->EMachine == EM_MIPS)
- return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
+ return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::MipsGot, Type, Body, C,
+ Offset, Addend, Expr);
- if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) &&
+ bool IsPreemptible = isPreemptible(Body, Type);
+ if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC_CALL) &&
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 (In<ELFT>::Got->addDynTlsEntry(Body)) {
+ uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
+ In<ELFT>::RelaDyn->addReloc({Target->TlsDescRel, In<ELFT>::Got, Off,
+ !IsPreemptible, &Body, 0});
}
- if (Expr != R_HINT)
- C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ if (Expr != R_TLSDESC_CALL)
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
@@ -149,69 +167,71 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
// 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});
+ {R_RELAX_TLS_LD_TO_LE, Type, 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});
+ if (In<ELFT>::Got->addTlsIndex())
+ In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::Got,
+ In<ELFT>::Got->getTlsIndexOff(), false,
+ nullptr, 0});
+ C.Relocations.push_back({Expr, Type, 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});
+ {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
return 1;
}
- if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_HINT ||
+ if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_TLSDESC_CALL ||
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 (In<ELFT>::Got->addDynTlsEntry(Body)) {
+ uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->TlsModuleIndexRel, In<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});
+ uintX_t OffsetOff = Off + (uintX_t)sizeof(uintX_t);
+ if (IsPreemptible)
+ In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::Got,
+ OffsetOff, false, &Body, 0});
+ else
+ In<ELFT>::Got->Relocations.push_back(
+ {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Body});
}
- C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
+ C.Relocations.push_back({Expr, Type, 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)) {
+ if (IsPreemptible) {
C.Relocations.push_back(
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
- &C, Offset, Addend, &Body});
+ 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});
+ In<ELFT>::Got->addEntry(Body);
+ In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, In<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,
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type,
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)) {
+ if (Target->isTlsInitialExecRel(Type) && !Config->Shared && !IsPreemptible) {
C.Relocations.push_back(
- {R_RELAX_TLS_IE_TO_LE, Type, &C, Offset, Addend, &Body});
+ {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
return 1;
}
return 0;
@@ -260,8 +280,8 @@ static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc,
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)));
+ warn("can't find matching " + toString(Type) + " relocation for " +
+ toString(Rel->getType(Config->Mips64EL)));
return 0;
}
@@ -275,27 +295,34 @@ template <class ELFT> static bool isAbsolute(const SymbolBody &Body) {
return false;
}
+template <class ELFT> static bool isAbsoluteValue(const SymbolBody &Body) {
+ return isAbsolute<ELFT>(Body) || Body.isTls();
+}
+
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;
+ return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC,
+ R_THUNK_PLT_PC>(Expr);
}
// 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;
+ return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
+ R_PAGE_PC, R_RELAX_GOT_PC, R_THUNK_PC, R_THUNK_PLT_PC>(
+ Expr);
}
template <class ELFT>
static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
- const SymbolBody &Body) {
+ const SymbolBody &Body,
+ InputSectionBase<ELFT> &S,
+ typename ELFT::uint RelOff) {
// 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)
+ if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_TLSGD,
+ R_GOT_PAGE_PC, R_GOT_PC, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
+ R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
+ R_THUNK_PC, R_THUNK_PLT_PC>(E))
return true;
// These never do, except if the entire file is position dependent or if
@@ -309,7 +336,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
if (!Config->Pic)
return true;
- bool AbsVal = isAbsolute<ELFT>(Body) || Body.isTls();
+ bool AbsVal = isAbsoluteValue<ELFT>(Body);
bool RelE = isRelExpr(E);
if (AbsVal && !RelE)
return true;
@@ -321,11 +348,17 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
// 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.
+ // Another special case is MIPS _gp_disp symbol which represents offset
+ // between start of a function and '_gp' value and defined as absolute just
+ // to simplify the code.
if (AbsVal && RelE) {
if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
return true;
- error("relocation " + getRelName(Type) +
- " cannot refer to absolute symbol " + Body.getName());
+ if (&Body == ElfSym<ELFT>::MipsGpDisp)
+ return true;
+ error(S.getLocation(RelOff) + ": relocation " + toString(Type) +
+ " cannot refer to absolute symbol '" + toString(Body) +
+ "' defined in " + toString(Body.File));
return true;
}
@@ -374,18 +407,18 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) {
// 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());
+ fatal("cannot create a copy relocation for symbol " + toString(*SS));
uintX_t Alignment = getAlignment(SS);
- uintX_t Off = alignTo(Out<ELFT>::Bss->getSize(), Alignment);
- Out<ELFT>::Bss->setSize(Off + SymSize);
+ uintX_t Off = alignTo(Out<ELFT>::Bss->Size, Alignment);
+ Out<ELFT>::Bss->Size = 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)) {
+ for (const Elf_Sym &S : SS->file()->getGlobalSymbols()) {
if (S.st_shndx != Shndx || S.st_value != Value)
continue;
auto *Alias = dyn_cast_or_null<SharedSymbol<ELFT>>(
@@ -396,38 +429,43 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) {
Alias->NeedsCopyOrPltAddr = true;
Alias->symbol()->IsUsedInRegularObj = true;
}
- Out<ELFT>::RelaDyn->addReloc(
+ In<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) {
+ const uint8_t *Data, InputSectionBase<ELFT> &S,
+ typename ELFT::uint RelOff) {
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)
+ if (Expr == R_GOT_PC && !isAbsoluteValue<ELFT>(Body))
Expr = Target->adjustRelaxExpr(Type, Data, Expr);
}
Expr = Target->getThunkExpr(Expr, Type, File, Body);
- if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body))
+ if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff))
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");
+ error(S.getLocation(RelOff) + ": can't create dynamic relocation " +
+ toString(Type) + " against " +
+ (Body.getName().empty() ? "local symbol in readonly segment"
+ : "symbol '" + toString(Body) + "'") +
+ " defined in " + toString(Body.File));
return Expr;
}
if (Body.getVisibility() != STV_DEFAULT) {
- error("cannot preempt symbol");
+ error(S.getLocation(RelOff) + ": cannot preempt symbol '" + toString(Body) +
+ "' defined in " + toString(Body.File));
return Expr;
}
if (Body.isObject()) {
@@ -461,7 +499,8 @@ static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
Body.NeedsCopyOrPltAddr = true;
return toPlt(Expr);
}
- error("symbol is missing type");
+ error("symbol '" + toString(Body) + "' defined in " + toString(Body.File) +
+ " is missing type");
return Expr;
}
@@ -487,17 +526,49 @@ static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File,
// 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 (Expr == R_MIPS_GOTREL && Body.isLocal())
+ Addend += File.MipsGp0;
}
if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC)
Addend += getPPC64TocBase();
return Addend;
}
+template <class ELFT>
+static void reportUndefined(SymbolBody &Sym, InputSectionBase<ELFT> &S,
+ typename ELFT::uint Offset) {
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
+ return;
+
+ if (Config->Shared && Sym.symbol()->Visibility == STV_DEFAULT &&
+ Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef)
+ return;
+
+ std::string Msg =
+ S.getLocation(Offset) + ": undefined symbol '" + toString(Sym) + "'";
+
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn)
+ warn(Msg);
+ else
+ error(Msg);
+}
+
+template <class RelTy>
+static std::pair<uint32_t, uint32_t>
+mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) {
+ // MIPS N32 ABI treats series of successive relocations with the same offset
+ // as a single relocation. The similar approach used by N64 ABI, but this ABI
+ // packs all relocations into the single relocation record. Here we emulate
+ // this for the N32 ABI. Iterate over relocation with the same offset and put
+ // theirs types into the single bit-set.
+ uint32_t Processed = 0;
+ for (; I != E && Offset == I->r_offset; ++I) {
+ ++Processed;
+ Type |= I->getType(Config->Mips64EL) << (8 * Processed);
+ }
+ return std::make_pair(Type, Processed);
+}
+
// 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.
@@ -515,53 +586,90 @@ 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;
+ bool IsWrite = C.Flags & SHF_WRITE;
auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) {
- Out<ELFT>::RelaDyn->addReloc(Reloc);
+ In<ELFT>::RelaDyn->addReloc(Reloc);
};
- const elf::ObjectFile<ELFT> &File = *C.getFile();
- ArrayRef<uint8_t> SectionData = C.getSectionData();
+ const elf::ObjectFile<ELFT> *File = C.getFile();
+ ArrayRef<uint8_t> SectionData = C.Data;
const uint8_t *Buf = SectionData.begin();
+
+ ArrayRef<EhSectionPiece> Pieces;
+ if (auto *Eh = dyn_cast<EhInputSection<ELFT>>(&C))
+ Pieces = Eh->Pieces;
+
+ ArrayRef<EhSectionPiece>::iterator PieceI = Pieces.begin();
+ ArrayRef<EhSectionPiece>::iterator PieceE = Pieces.end();
+
for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
const RelTy &RI = *I;
- SymbolBody &Body = File.getRelocTargetSym(RI);
+ SymbolBody &Body = File->getRelocTargetSym(RI);
uint32_t Type = RI.getType(Config->Mips64EL);
+ if (Config->MipsN32Abi) {
+ uint32_t Processed;
+ std::tie(Type, Processed) =
+ mergeMipsN32RelTypes(Type, RI.r_offset, I + 1, E);
+ I += Processed;
+ }
+
+ // We only report undefined symbols if they are referenced somewhere in the
+ // code.
+ if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak())
+ reportUndefined(Body, C, RI.r_offset);
+
RelExpr Expr = Target->getRelExpr(Type, Body);
bool Preemptible = isPreemptible(Body, Type);
- Expr = adjustExpr(File, Body, IsWrite, Expr, Type, Buf + RI.r_offset);
- if (HasError)
+ Expr = adjustExpr(*File, Body, IsWrite, Expr, Type, Buf + RI.r_offset, C,
+ RI.r_offset);
+ if (ErrorCount)
continue;
// Skip a relocation that points to a dead piece
- // in a mergeable section.
- if (C.getOffset(RI.r_offset) == (uintX_t)-1)
- continue;
+ // in a eh_frame section.
+ while (PieceI != PieceE &&
+ (PieceI->InputOff + PieceI->size() <= RI.r_offset))
+ ++PieceI;
+
+ // Compute the offset of this section in the output section. We do it here
+ // to try to compute it only once.
+ uintX_t Offset;
+ if (PieceI != PieceE) {
+ assert(PieceI->InputOff <= RI.r_offset && "Relocation not in any piece");
+ if (PieceI->OutputOff == -1)
+ continue;
+ Offset = PieceI->OutputOff + RI.r_offset - PieceI->InputOff;
+ } else {
+ Offset = RI.r_offset;
+ }
// 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;
+ if (Expr == R_GOTONLY_PC || Expr == R_GOTONLY_PC_FROM_END ||
+ Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || Expr == R_PPC_TOC)
+ In<ELFT>::Got->HasGotOffRel = true;
- uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body);
+ uintX_t Addend = computeAddend(*File, Buf, E, RI, Expr, Body);
- if (unsigned Processed = handleTlsRelocation<ELFT>(
- Type, Body, C, RI.r_offset, Addend, Expr)) {
+ if (unsigned Processed =
+ handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
I += (Processed - 1);
continue;
}
- // Ignore "hint" relocation because it is for optional code optimization.
- if (Expr == R_HINT)
+ // Ignore "hint" and TLS Descriptor call relocation because they are
+ // only markers for relaxation.
+ if (isRelExprOneOf<R_HINT, R_TLSDESC_CALL>(Expr))
continue;
- if (needsPlt(Expr) || Expr == R_THUNK_ABS || Expr == R_THUNK_PC ||
- Expr == R_THUNK_PLT_PC || refersToGotEntry(Expr) ||
- !isPreemptible(Body, Type)) {
+ if (needsPlt(Expr) ||
+ isRelExprOneOf<R_THUNK_ABS, R_THUNK_PC, R_THUNK_PLT_PC>(Expr) ||
+ 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);
+ bool Constant =
+ isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, C, RI.r_offset);
// 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
@@ -569,17 +677,21 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
// 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});
+ AddDyn({Target->RelativeRel, &C, 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});
+ C.Relocations.push_back({Expr, Type, 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});
+ if (!Target->isPicRel(Type))
+ error(C.getLocation(Offset) + ": relocation " + toString(Type) +
+ " cannot be used against shared object; recompile with -fPIC.");
+ AddDyn({Target->getDynRel(Type), &C, 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
@@ -596,18 +708,10 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
// 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);
+ In<ELFT>::MipsGot->addEntry(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.
@@ -615,90 +719,107 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
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});
+ if (Body.isGnuIFunc() && !Preemptible) {
+ In<ELFT>::Iplt->addEntry(Body);
+ In<ELFT>::IgotPlt->addEntry(Body);
+ In<ELFT>::RelaIplt->addReloc({Target->IRelativeRel, In<ELFT>::IgotPlt,
+ Body.getGotPltOffset<ELFT>(),
+ !Preemptible, &Body, 0});
+ } else {
+ In<ELFT>::Plt->addEntry(Body);
+ In<ELFT>::GotPlt->addEntry(Body);
+ In<ELFT>::RelaPlt->addReloc({Target->PltRel, In<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.
+ // MIPS ABI has special rules to process GOT entries and doesn't
+ // require relocation entries for them. A special case is TLS
+ // relocations. In that case dynamic loader applies dynamic
+ // relocations to initialize TLS 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
- Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
- if (Body.isTls())
- AddDyn({Target->TlsGotRel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
- !Preemptible, &Body, 0});
+ In<ELFT>::MipsGot->addEntry(Body, Addend, Expr);
+ if (Body.isTls() && Body.isPreemptible())
+ AddDyn({Target->TlsGotRel, In<ELFT>::MipsGot,
+ Body.getGotOffset<ELFT>(), false, &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});
- }
+ In<ELFT>::Got->addEntry(Body);
+ uintX_t Off = Body.getGotOffset<ELFT>();
+ uint32_t DynType;
+ RelExpr GotRE = R_ABS;
+ if (Body.isTls()) {
+ DynType = Target->TlsGotRel;
+ GotRE = R_TLS;
+ } else if (!Preemptible && Config->Pic && !isAbsolute<ELFT>(Body))
+ DynType = Target->RelativeRel;
+ else
+ DynType = Target->GotRel;
+
+ // FIXME: this logic is almost duplicated above.
+ bool Constant = !Preemptible && !(Config->Pic && !isAbsolute<ELFT>(Body));
+ if (!Constant)
+ AddDyn({DynType, In<ELFT>::Got, Off, !Preemptible, &Body, 0});
+ if (Constant || (!RelTy::IsRela && !Preemptible))
+ In<ELFT>::Got->Relocations.push_back({GotRE, DynType, Off, 0, &Body});
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) {
+ if (S.AreRelocsRela)
+ scanRelocs(S, S.relas());
+ else
+ scanRelocs(S, S.rels());
}
-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));
+template <class ELFT, class RelTy>
+static void createThunks(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
+ const elf::ObjectFile<ELFT> *File = C.getFile();
+ for (const RelTy &Rel : Rels) {
+ SymbolBody &Body = File->getRelocTargetSym(Rel);
+ uint32_t Type = Rel.getType(Config->Mips64EL);
+ RelExpr Expr = Target->getRelExpr(Type, Body);
+ if (!isPreemptible(Body, Type) && needsPlt(Expr))
+ Expr = fromPlt(Expr);
+ Expr = Target->getThunkExpr(Expr, Type, *File, Body);
+ // 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);
+ }
+ }
+}
+
+template <class ELFT> void createThunks(InputSectionBase<ELFT> &S) {
+ if (S.AreRelocsRela)
+ createThunks(S, S.relas());
else
- scanRelocs(S, EObj.rels(&RelSec));
+ createThunks(S, S.rels());
}
-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 &);
+template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &);
+template void scanRelocations<ELF32BE>(InputSectionBase<ELF32BE> &);
+template void scanRelocations<ELF64LE>(InputSectionBase<ELF64LE> &);
+template void scanRelocations<ELF64BE>(InputSectionBase<ELF64BE> &);
+
+template void createThunks<ELF32LE>(InputSectionBase<ELF32LE> &);
+template void createThunks<ELF32BE>(InputSectionBase<ELF32BE> &);
+template void createThunks<ELF64LE>(InputSectionBase<ELF64LE> &);
+template void createThunks<ELF64BE>(InputSectionBase<ELF64BE> &);
}
}
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index 4c1c74efb0da..b5825bdd5e59 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -15,14 +15,20 @@
namespace lld {
namespace elf {
class SymbolBody;
+class InputSectionData;
template <class ELFT> class InputSection;
template <class ELFT> class InputSectionBase;
+// List of target-independent relocation types. Relocations read
+// from files are converted to these types so that the main code
+// doesn't have to know about architecture-specific details.
enum RelExpr {
R_ABS,
R_GOT,
R_GOTONLY_PC,
+ R_GOTONLY_PC_FROM_END,
R_GOTREL,
+ R_GOTREL_FROM_END,
R_GOT_FROM_END,
R_GOT_OFF,
R_GOT_PAGE_PC,
@@ -30,6 +36,8 @@ enum RelExpr {
R_HINT,
R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOT_OFF,
+ R_MIPS_GOT_OFF32,
+ R_MIPS_GOTREL,
R_MIPS_TLSGD,
R_MIPS_TLSLD,
R_NEG_TLS,
@@ -58,25 +66,54 @@ enum RelExpr {
R_TLS,
R_TLSDESC,
R_TLSDESC_PAGE,
+ R_TLSDESC_CALL,
R_TLSGD,
R_TLSGD_PC,
R_TLSLD,
- R_TLSLD_PC
+ R_TLSLD_PC,
};
-template <class ELFT> struct Relocation {
+// Build a bitmask with one bit set for each RelExpr.
+//
+// Constexpr function arguments can't be used in static asserts, so we
+// use template arguments to build the mask.
+// But function template partial specializations don't exist (needed
+// for base case of the recursion), so we need a dummy struct.
+template <RelExpr... Exprs> struct RelExprMaskBuilder {
+ static inline uint64_t build() { return 0; }
+};
+
+// Specialization for recursive case.
+template <RelExpr Head, RelExpr... Tail>
+struct RelExprMaskBuilder<Head, Tail...> {
+ static inline uint64_t build() {
+ static_assert(0 <= Head && Head < 64,
+ "RelExpr is too large for 64-bit mask!");
+ return (uint64_t(1) << Head) | RelExprMaskBuilder<Tail...>::build();
+ }
+};
+
+// Return true if `Expr` is one of `Exprs`.
+// There are fewer than 64 RelExpr's, so we can represent any set of
+// RelExpr's as a constant bit mask and test for membership with a
+// couple cheap bitwise operations.
+template <RelExpr... Exprs> bool isRelExprOneOf(RelExpr Expr) {
+ assert(0 <= Expr && (int)Expr < 64 && "RelExpr is too large for 64-bit mask!");
+ return (uint64_t(1) << Expr) & RelExprMaskBuilder<Exprs...>::build();
+}
+
+// Architecture-neutral representation of relocation.
+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> &);
-template <class ELFT>
-void scanRelocations(InputSectionBase<ELFT> &, const typename ELFT::Shdr &);
+template <class ELFT> void createThunks(InputSectionBase<ELFT> &);
template <class ELFT>
static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) {
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index 559ec1be0e39..c740685a15a1 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -20,69 +20,101 @@ 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();
+// Returns a whole line containing the current token.
+StringRef ScriptParserBase::getLine() {
+ StringRef S = getCurrentMB().getBuffer();
+ StringRef Tok = Tokens[Pos - 1];
+
+ size_t Pos = S.rfind('\n', Tok.data() - S.data());
+ if (Pos != StringRef::npos)
+ S = S.substr(Pos + 1);
+ return S.substr(0, S.find_first_of("\r\n"));
+}
+
+// Returns 1-based line number of the current token.
+size_t ScriptParserBase::getLineNumber() {
+ StringRef S = getCurrentMB().getBuffer();
+ StringRef Tok = Tokens[Pos - 1];
+ return S.substr(0, Tok.data() - S.data()).count('\n') + 1;
}
-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, ' ') + "^");
+// Returns 0-based column number of the current token.
+size_t ScriptParserBase::getColumnNumber() {
+ StringRef Tok = Tokens[Pos - 1];
+ return Tok.data() - getLine().data();
}
+std::string ScriptParserBase::getCurrentLocation() {
+ std::string Filename = getCurrentMB().getBufferIdentifier();
+ if (!Pos)
+ return Filename;
+ return (Filename + ":" + Twine(getLineNumber())).str();
+}
+
+ScriptParserBase::ScriptParserBase(MemoryBufferRef MB) { tokenize(MB); }
+
// 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;
+
+ if (!Pos) {
+ error(getCurrentLocation() + ": " + Msg);
+ return;
+ }
+
+ std::string S = getCurrentLocation() + ": ";
+ error(S + Msg);
+ error(S + getLine());
+ error(S + std::string(getColumnNumber(), ' ') + "^");
}
// Split S into linker script tokens.
-std::vector<StringRef> ScriptParserBase::tokenize(StringRef S) {
- std::vector<StringRef> Ret;
+void ScriptParserBase::tokenize(MemoryBufferRef MB) {
+ std::vector<StringRef> Vec;
+ MBs.push_back(MB);
+ StringRef S = MB.getBuffer();
+ StringRef Begin = S;
+
for (;;) {
S = skipSpace(S);
if (S.empty())
- return Ret;
+ break;
- // Quoted token
+ // Quoted token. Note that double-quote characters are parts of a token
+ // because, in a glob match context, only unquoted tokens are interpreted
+ // as glob patterns. Double-quoted tokens are literal patterns in that
+ // context.
if (S.startswith("\"")) {
size_t E = S.find("\"", 1);
if (E == StringRef::npos) {
- error("unclosed quote");
- return {};
+ StringRef Filename = MB.getBufferIdentifier();
+ size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n');
+ error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote");
+ return;
}
- Ret.push_back(S.substr(1, E - 1));
+
+ Vec.push_back(S.take_front(E + 1));
S = S.substr(E + 1);
continue;
}
- // Unquoted token
+ // Unquoted token. This is more relaxed than tokens in C-like language,
+ // so that you can write "file-name.cpp" as one bare token, for example.
size_t Pos = S.find_first_not_of(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789_.$/\\~=+[]*?-:!<>");
+ "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));
+ Vec.push_back(S.substr(0, Pos));
S = S.substr(Pos);
}
+
+ Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end());
}
// Skip leading whitespace characters or comments.
@@ -132,19 +164,16 @@ StringRef ScriptParserBase::peek() {
return Tok;
}
-bool ScriptParserBase::skip(StringRef Tok) {
- if (Error)
- return false;
- if (atEOF()) {
- setError("unexpected EOF");
- return false;
+bool ScriptParserBase::consume(StringRef Tok) {
+ if (peek() == Tok) {
+ skip();
+ return true;
}
- if (Tokens[Pos] != Tok)
- return false;
- ++Pos;
- return true;
+ return false;
}
+void ScriptParserBase::skip() { (void)next(); }
+
void ScriptParserBase::expect(StringRef Expect) {
if (Error)
return;
@@ -153,11 +182,19 @@ void ScriptParserBase::expect(StringRef 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;
+// Returns true if S encloses T.
+static bool encloses(StringRef S, StringRef T) {
+ return S.bytes_begin() <= T.bytes_begin() && T.bytes_end() <= S.bytes_end();
+}
+
+MemoryBufferRef ScriptParserBase::getCurrentMB() {
+ // Find input buffer containing the current token.
+ assert(!MBs.empty());
+ if (!Pos)
+ return MBs[0];
+
+ for (MemoryBufferRef MB : MBs)
+ if (encloses(MB.getBuffer(), Tokens[Pos - 1]))
+ return MB;
+ llvm_unreachable("getCurrentMB: failed to find a token");
}
diff --git a/ELF/ScriptParser.h b/ELF/ScriptParser.h
index 20735f78da81..264c49792337 100644
--- a/ELF/ScriptParser.h
+++ b/ELF/ScriptParser.h
@@ -12,6 +12,7 @@
#include "lld/Core/LLVM.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
#include <utility>
#include <vector>
@@ -20,27 +21,30 @@ 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)) {}
+ explicit ScriptParserBase(MemoryBufferRef MB);
-protected:
void setError(const Twine &Msg);
- static std::vector<StringRef> tokenize(StringRef S);
+ void tokenize(MemoryBufferRef MB);
static StringRef skipSpace(StringRef S);
bool atEOF();
StringRef next();
StringRef peek();
- bool skip(StringRef Tok);
+ void skip();
+ bool consume(StringRef Tok);
void expect(StringRef Expect);
+ std::string getCurrentLocation();
- size_t getPos();
- void printErrorPos();
-
- StringRef Input;
+ std::vector<MemoryBufferRef> MBs;
std::vector<StringRef> Tokens;
size_t Pos = 0;
bool Error = false;
+
+private:
+ StringRef getLine();
+ size_t getLineNumber();
+ size_t getColumnNumber();
+
+ MemoryBufferRef getCurrentMB();
};
} // namespace elf
diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp
index 0c21e8819d6c..ec3d1f1b2b51 100644
--- a/ELF/Strings.cpp
+++ b/ELF/Strings.cpp
@@ -8,44 +8,59 @@
//===----------------------------------------------------------------------===//
#include "Strings.h"
+#include "Config.h"
#include "Error.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Config/config.h"
+#include "llvm/Demangle/Demangle.h"
#include <algorithm>
-
-#ifdef HAVE_CXXABI_H
-#include <cxxabi.h>
-#endif
+#include <cstring>
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);
+StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
+ for (StringRef S : Pat) {
+ Expected<GlobPattern> Pat = GlobPattern::create(S);
+ if (!Pat)
+ error(toString(Pat.takeError()));
+ else
+ Patterns.push_back(*Pat);
}
}
+bool StringMatcher::match(StringRef S) const {
+ for (const GlobPattern &Pat : Patterns)
+ if (Pat.match(S))
+ return true;
+ return false;
+}
+
+// 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.
+int elf::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;
+}
+
+bool elf::hasWildcard(StringRef S) {
+ return S.find_first_of("?*[") != StringRef::npos;
+}
+
+StringRef elf::unquote(StringRef S) {
+ if (!S.startswith("\""))
+ return S;
+ return S.substr(1, S.size() - 2);
+}
+
// Converts a hex string (e.g. "deadbeef") to a vector.
std::vector<uint8_t> elf::parseHex(StringRef S) {
std::vector<uint8_t> Hex;
@@ -75,24 +90,19 @@ bool elf::isValidCIdentifier(StringRef S) {
}
// Returns the demangled C++ symbol name for Name.
-std::string elf::demangle(StringRef Name) {
-#if !defined(HAVE_CXXABI_H)
- return Name;
-#else
+Optional<std::string> elf::demangle(StringRef Name) {
// __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;
+ return None;
- char *Buf =
- abi::__cxa_demangle(Name.str().c_str(), nullptr, nullptr, nullptr);
+ char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
if (!Buf)
- return Name;
+ return None;
std::string S(Buf);
free(Buf);
return S;
-#endif
}
diff --git a/ELF/Strings.h b/ELF/Strings.h
index 4948e9dbd56b..934b6427105f 100644
--- a/ELF/Strings.h
+++ b/ELF/Strings.h
@@ -7,22 +7,75 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLD_COFF_STRINGS_H
-#define LLD_COFF_STRINGS_H
+#ifndef LLD_ELF_STRINGS_H
+#define LLD_ELF_STRINGS_H
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/GlobPattern.h"
#include <vector>
namespace lld {
namespace elf {
-bool globMatch(StringRef S, StringRef T);
+
+int getPriority(StringRef S);
+bool hasWildcard(StringRef S);
std::vector<uint8_t> parseHex(StringRef S);
bool isValidCIdentifier(StringRef S);
+StringRef unquote(StringRef S);
+
+// This is a lazy version of StringRef. String size is computed lazily
+// when it is needed. It is more efficient than StringRef to instantiate
+// if you have a string whose size is unknown.
+//
+// ELF string tables contain a lot of null-terminated strings.
+// Most of them are not necessary for the linker because they are names
+// of local symbols and the linker doesn't use local symbol names for
+// name resolution. So, we use this class to represents strings read
+// from string tables.
+class StringRefZ {
+public:
+ StringRefZ() : Start(nullptr), Size(0) {}
+ StringRefZ(const char *S, size_t Size) : Start(S), Size(Size) {}
+
+ /*implicit*/ StringRefZ(const char *S) : Start(S), Size(-1) {}
+
+ /*implicit*/ StringRefZ(llvm::StringRef S)
+ : Start(S.data()), Size(S.size()) {}
+
+ operator llvm::StringRef() const {
+ if (Size == (size_t)-1)
+ Size = strlen(Start);
+ return {Start, Size};
+ }
+
+private:
+ const char *Start;
+ mutable size_t Size;
+};
+
+// This class represents multiple glob patterns.
+class StringMatcher {
+public:
+ StringMatcher() = default;
+ explicit StringMatcher(ArrayRef<StringRef> Pat);
+
+ bool match(StringRef S) const;
+
+private:
+ std::vector<llvm::GlobPattern> Patterns;
+};
// 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);
+// name, it returns Optional::None.
+llvm::Optional<std::string> demangle(StringRef Name);
+
+inline StringRef toStringRef(ArrayRef<uint8_t> Arr) {
+ return {(const char *)Arr.data(), Arr.size()};
+}
}
}
diff --git a/ELF/SymbolListFile.cpp b/ELF/SymbolListFile.cpp
deleted file mode 100644
index 9e088025c1b7..000000000000
--- a/ELF/SymbolListFile.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-//===- 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
deleted file mode 100644
index cf3c4c639ea4..000000000000
--- a/ELF/SymbolListFile.h
+++ /dev/null
@@ -1,27 +0,0 @@
-//===- 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 78c1298df427..79097e176e68 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -18,11 +18,9 @@
#include "Config.h"
#include "Error.h"
#include "LinkerScript.h"
-#include "Strings.h"
-#include "SymbolListFile.h"
+#include "Memory.h"
#include "Symbols.h"
-#include "llvm/Bitcode/ReaderWriter.h"
-#include "llvm/Support/StringSaver.h"
+#include "llvm/ADT/STLExtras.h"
using namespace llvm;
using namespace llvm::object;
@@ -37,62 +35,69 @@ using namespace lld::elf;
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);
+
+ if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) {
+ if (Config->EMachine != EM_MIPS)
+ return true;
+ if (isMipsN32Abi(F) == Config->MipsN32Abi)
+ return true;
+ }
+
+ if (!Config->Emulation.empty())
+ error(toString(F) + " is incompatible with " + Config->Emulation);
+ else
+ error(toString(F) + " is incompatible with " + toString(Config->FirstElf));
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();
- if (!isCompatible<ELFT>(FileP))
+template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
+ if (!isCompatible<ELFT>(File))
+ return;
+
+ // Binary file
+ if (auto *F = dyn_cast<BinaryFile>(File)) {
+ BinaryFiles.push_back(F);
+ F->parse<ELFT>();
return;
+ }
// .a file
- if (auto *F = dyn_cast<ArchiveFile>(FileP)) {
- ArchiveFiles.emplace_back(cast<ArchiveFile>(File.release()));
+ if (auto *F = dyn_cast<ArchiveFile>(File)) {
F->parse<ELFT>();
return;
}
// Lazy object file
- if (auto *F = dyn_cast<LazyObjectFile>(FileP)) {
- LazyObjectFiles.emplace_back(cast<LazyObjectFile>(File.release()));
+ if (auto *F = dyn_cast<LazyObjectFile>(File)) {
F->parse<ELFT>();
return;
}
if (Config->Trace)
- outs() << getFilename(FileP) << "\n";
+ outs() << toString(File) << "\n";
// .so file
- if (auto *F = dyn_cast<SharedFile<ELFT>>(FileP)) {
+ if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
// DSOs are uniquified not by filename but by soname.
F->parseSoName();
- if (!SoNames.insert(F->getSoName()).second)
+ if (ErrorCount || !SoNames.insert(F->getSoName()).second)
return;
-
- SharedFiles.emplace_back(cast<SharedFile<ELFT>>(File.release()));
+ SharedFiles.push_back(F);
F->parseRest();
return;
}
// LLVM bitcode file
- if (auto *F = dyn_cast<BitcodeFile>(FileP)) {
- BitcodeFiles.emplace_back(cast<BitcodeFile>(File.release()));
+ if (auto *F = dyn_cast<BitcodeFile>(File)) {
+ BitcodeFiles.push_back(F);
F->parse<ELFT>(ComdatGroups);
return;
}
// Regular object file
- auto *F = cast<ObjectFile<ELFT>>(FileP);
- ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
+ auto *F = cast<ObjectFile<ELFT>>(File);
+ ObjectFiles.push_back(F);
F->parse(ComdatGroups);
}
@@ -103,31 +108,30 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
// 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() {
+template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
if (BitcodeFiles.empty())
return;
- // 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();
+ // Compile bitcode files and replace bitcode symbols.
+ LTO.reset(new BitcodeCompiler);
+ for (BitcodeFile *F : BitcodeFiles)
+ LTO->add(*F);
- // Replace bitcode symbols.
- for (auto &IF : IFs) {
- ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(IF.release());
-
- DenseSet<StringRef> DummyGroups;
+ for (InputFile *File : LTO->compile()) {
+ ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File);
+ DenseSet<CachedHashStringRef> DummyGroups;
Obj->parse(DummyGroups);
- ObjectFiles.emplace_back(Obj);
+ ObjectFiles.push_back(Obj);
}
}
template <class ELFT>
DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name,
- uint8_t Visibility) {
- return cast<DefinedRegular<ELFT>>(
- addRegular(Name, STB_GLOBAL, Visibility)->body());
+ uint8_t Visibility,
+ uint8_t Binding) {
+ Symbol *Sym =
+ addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr);
+ return cast<DefinedRegular<ELFT>>(Sym->body());
}
// Add Name as an "ignored" symbol. An ignored symbol is a regular
@@ -135,7 +139,8 @@ DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name,
template <class ELFT>
DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name,
uint8_t Visibility) {
- if (!find(Name))
+ SymbolBody *S = find(Name);
+ if (!S || !S->isUndefined())
return nullptr;
return addAbsolute(Name, Visibility);
}
@@ -143,7 +148,7 @@ DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name,
// 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}});
+ Symtab.insert({CachedHashStringRef(Name), {-1, true}});
}
// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
@@ -152,10 +157,10 @@ template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
SymbolBody *B = find(Name);
if (!B)
return;
- StringSaver Saver(Alloc);
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.
@@ -174,24 +179,26 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
// Find an existing symbol or create and insert a new one.
template <class ELFT>
std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
- auto P = Symtab.insert({Name, {(int)SymVector.size(), false}});
+ auto P = Symtab.insert(
+ {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)});
SymIndex &V = P.first->second;
bool IsNew = P.second;
if (V.Idx == -1) {
IsNew = true;
- V = {(int)SymVector.size(), true};
+ V = SymIndex((int)SymVector.size(), true);
}
Symbol *Sym;
if (IsNew) {
- Sym = new (Alloc) Symbol;
+ Sym = new (BAlloc) Symbol;
+ Sym->InVersionScript = false;
Sym->Binding = STB_WEAK;
Sym->Visibility = STV_DEFAULT;
Sym->IsUsedInRegularObj = false;
Sym->ExportDynamic = false;
- Sym->VersionId = Config->DefaultSymbolVersion;
Sym->Traced = V.Traced;
+ Sym->VersionId = Config->DefaultSymbolVersion;
SymVector.push_back(Sym);
} else {
Sym = SymVector[V.Idx];
@@ -199,13 +206,20 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
return {Sym, IsNew};
}
+// Construct a string in the form of "Sym in File1 and File2".
+// Used to construct an error message.
+static std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile) {
+ return "'" + toString(*Existing) + "' in " + toString(Existing->File) +
+ " and " + toString(NewFile);
+}
+
// Find an existing symbol or create and insert a new one, then apply the given
// attributes.
template <class ELFT>
std::pair<Symbol *, bool>
SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
- bool CanOmitFromDynSym, bool IsUsedInRegularObj,
- InputFile *File) {
+ bool CanOmitFromDynSym, InputFile *File) {
+ bool IsUsedInRegularObj = !File || File->kind() == InputFile::ObjectKind;
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
@@ -218,42 +232,31 @@ SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
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));
+ 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 <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);
-}
-
template <class ELFT> Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name) {
- return addUndefined(Name, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0,
+ return addUndefined(Name, /*IsLocal=*/false, STB_GLOBAL, STV_DEFAULT,
+ /*Type*/ 0,
/*CanOmitFromDynSym*/ false, /*File*/ nullptr);
}
+static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; }
+
template <class ELFT>
-Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, uint8_t Binding,
- uint8_t StOther, uint8_t Type,
- bool CanOmitFromDynSym,
+Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
+ 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);
+ insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File);
if (WasInserted) {
S->Binding = Binding;
- replaceBody<Undefined>(S, Name, StOther, Type, File);
+ replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File);
return S;
}
if (Binding != STB_WEAK) {
@@ -267,8 +270,8 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, uint8_t Binding,
// its type. See also comment in addLazyArchive.
if (S->isWeak())
L->Type = Type;
- else if (auto F = L->fetch())
- addFile(std::move(F));
+ else if (InputFile *F = L->fetch())
+ addFile(F);
}
return S;
}
@@ -292,17 +295,24 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
// 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) {
+template <typename ELFT>
+static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
+ bool IsAbsolute, typename ELFT::uint Value) {
if (int Cmp = compareDefined(S, WasInserted, Binding)) {
if (Cmp > 0)
S->Binding = Binding;
return Cmp;
}
- if (isa<DefinedCommon>(S->body())) {
+ SymbolBody *B = S->body();
+ if (isa<DefinedCommon>(B)) {
// Non-common symbols take precedence over common symbols.
if (Config->WarnCommon)
- warning("common " + S->body()->getName() + " is overridden");
+ warn("common " + S->body()->getName() + " is overridden");
return 1;
+ } else if (auto *R = dyn_cast<DefinedRegular<ELFT>>(B)) {
+ if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute &&
+ R->Value == Value)
+ return -1;
}
return 0;
}
@@ -314,9 +324,8 @@ Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
InputFile *File) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) =
- insert(N, Type, StOther & 3, /*CanOmitFromDynSym*/ false,
- /*IsUsedInRegularObj*/ true, File);
+ std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
+ /*CanOmitFromDynSym*/ false, File);
int Cmp = compareDefined(S, WasInserted, Binding);
if (Cmp > 0) {
S->Binding = Binding;
@@ -326,74 +335,80 @@ Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
if (!C) {
// Non-common symbols take precedence over common symbols.
if (Config->WarnCommon)
- warning("common " + S->body()->getName() + " is overridden");
+ warn("common " + S->body()->getName() + " is overridden");
return S;
}
if (Config->WarnCommon)
- warning("multiple common of " + S->body()->getName());
+ warn("multiple common of " + S->body()->getName());
- C->Size = std::max(C->Size, Size);
- C->Alignment = std::max(C->Alignment, Alignment);
+ Alignment = C->Alignment = std::max(C->Alignment, Alignment);
+ if (Size > C->Size)
+ replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File);
}
return S;
}
-template <class ELFT>
-void SymbolTable<ELFT>::reportDuplicate(SymbolBody *Existing,
- InputFile *NewFile) {
- std::string Msg = "duplicate symbol: " + conflictMsg(Existing, NewFile);
+static void print(const Twine &Msg) {
if (Config->AllowMultipleDefinition)
- warning(Msg);
+ warn(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;
+static void reportDuplicate(SymbolBody *Existing, InputFile *NewFile) {
+ print("duplicate symbol " + conflictMsg(Existing, NewFile));
+}
+
+template <class ELFT>
+static void reportDuplicate(SymbolBody *Existing,
+ InputSectionBase<ELFT> *ErrSec,
+ typename ELFT::uint ErrOffset) {
+ DefinedRegular<ELFT> *D = dyn_cast<DefinedRegular<ELFT>>(Existing);
+ if (!D || !D->Section || !ErrSec) {
+ reportDuplicate(Existing, ErrSec ? ErrSec->getFile() : nullptr);
+ return;
+ }
+
+ std::string OldLoc = D->Section->getLocation(D->Value);
+ std::string NewLoc = ErrSec->getLocation(ErrOffset);
+
+ print(NewLoc + ": duplicate symbol '" + toString(*Existing) + "'");
+ print(OldLoc + ": previous definition was here");
}
template <typename ELFT>
-Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t Binding,
- uint8_t StOther) {
+Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t StOther,
+ uint8_t Type, uintX_t Value, uintX_t Size,
+ uint8_t Binding,
+ InputSectionBase<ELFT> *Section,
+ InputFile *File) {
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);
+ std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther),
+ /*CanOmitFromDynSym*/ false, File);
+ int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
+ Section == nullptr, Value);
if (Cmp > 0)
- replaceBody<DefinedRegular<ELFT>>(S, Name, StOther);
+ replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type,
+ Value, Size, Section, File);
else if (Cmp == 0)
- reportDuplicate(S->body(), nullptr);
+ reportDuplicate(S->body(), Section, Value);
return S;
}
template <typename ELFT>
Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N,
- OutputSectionBase<ELFT> *Section,
- uintX_t Value) {
+ const OutputSectionBase *Section,
+ uintX_t Value, uint8_t StOther) {
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);
+ std::tie(S, WasInserted) = insert(N, STT_NOTYPE, getVisibility(StOther),
+ /*CanOmitFromDynSym*/ false, nullptr);
+ int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, STB_GLOBAL,
+ /*IsAbsolute*/ false, /*Value*/ 0);
if (Cmp > 0)
- replaceBody<DefinedSynthetic<ELFT>>(S, N, Value, Section);
+ replaceBody<DefinedSynthetic>(S, N, Value, Section);
else if (Cmp == 0)
reportDuplicate(S->body(), nullptr);
return S;
@@ -409,11 +424,14 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) =
- insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true,
- /*IsUsedInRegularObj*/ false, F);
+ insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, F);
// Make sure we preempt DSO symbols with default visibility.
- if (Sym.getVisibility() == STV_DEFAULT)
+ if (Sym.getVisibility() == STV_DEFAULT) {
S->ExportDynamic = true;
+ // Exporting preempting symbols takes precedence over linker scripts.
+ if (S->VersionId == VER_NDX_LOCAL)
+ S->VersionId = VER_NDX_GLOBAL;
+ }
if (WasInserted || isa<Undefined>(S->body())) {
replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
if (!S->isWeak())
@@ -422,24 +440,25 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
}
template <class ELFT>
-Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, bool IsWeak,
+Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, uint8_t Binding,
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);
+ std::tie(S, WasInserted) =
+ insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F);
+ int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
+ /*IsAbs*/ false, /*Value*/ 0);
if (Cmp > 0)
- replaceBody<DefinedBitcode>(S, Name, StOther, Type, F);
+ replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type,
+ 0, 0, nullptr, 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);
+ auto It = Symtab.find(CachedHashStringRef(Name));
if (It == Symtab.end())
return nullptr;
SymIndex V = It->second;
@@ -448,24 +467,13 @@ template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
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>::addLazyArchive(ArchiveFile *F,
const object::Archive::Symbol Sym) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Sym.getName());
+ StringRef Name = Sym.getName();
+ std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType);
return;
@@ -484,9 +492,9 @@ void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
return;
}
- MemoryBufferRef MBRef = F->getMember(&Sym);
- if (!MBRef.getBuffer().empty())
- addFile(createObjectFile(MBRef, F->getName()));
+ std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym);
+ if (!MBInfo.first.getBuffer().empty())
+ addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second));
}
template <class ELFT>
@@ -515,8 +523,8 @@ void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) {
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));
+ if (InputFile *File = L->fetch())
+ addFile(File);
}
// This function takes care of the case in which shared libraries depend on
@@ -527,184 +535,173 @@ template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() {
// shared libraries can find them.
// Except this, we ignore undefined symbols in DSOs.
template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
- for (std::unique_ptr<SharedFile<ELFT>> &File : SharedFiles)
+ for (SharedFile<ELFT> *File : SharedFiles)
for (StringRef U : File->getUndefinedSymbols())
if (SymbolBody *Sym = find(U))
if (Sym->isDefined())
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;
+// Initialize DemangledSyms with a map from demangled symbols to symbol
+// objects. Used to handle "extern C++" directive in version scripts.
+//
+// The map will contain all demangled symbols. That can be very large,
+// and in LLD we generally want to avoid do anything for each symbol.
+// Then, why are we doing this? Here's why.
+//
+// Users can use "extern C++ {}" directive to match against demangled
+// C++ symbols. For example, you can write a pattern such as
+// "llvm::*::foo(int, ?)". Obviously, there's no way to handle this
+// other than trying to match a pattern against all demangled symbols.
+// So, if "extern C++" feature is used, we need to demangle all known
+// symbols.
+template <class ELFT>
+StringMap<std::vector<SymbolBody *>> &SymbolTable<ELFT>::getDemangledSyms() {
+ if (!DemangledSyms) {
+ DemangledSyms.emplace();
+ for (Symbol *Sym : SymVector) {
+ SymbolBody *B = Sym->body();
+ if (B->isUndefined())
+ continue;
+ if (Optional<std::string> S = demangle(B->getName()))
+ (*DemangledSyms)[*S].push_back(B);
+ else
+ (*DemangledSyms)[B->getName()].push_back(B);
+ }
+ }
+ return *DemangledSyms;
}
-static bool hasWildcard(StringRef S) {
- return S.find_first_of("?*") != StringRef::npos;
+template <class ELFT>
+std::vector<SymbolBody *> SymbolTable<ELFT>::findByVersion(SymbolVersion Ver) {
+ if (Ver.IsExternCpp)
+ return getDemangledSyms().lookup(Ver.Name);
+ if (SymbolBody *B = find(Ver.Name))
+ if (!B->isUndefined())
+ return {B};
+ return {};
}
-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;
- }
+template <class ELFT>
+std::vector<SymbolBody *>
+SymbolTable<ELFT>::findAllByVersion(SymbolVersion Ver) {
+ std::vector<SymbolBody *> Res;
+ StringMatcher M(Ver.Name);
- Symbol *Sym = Body->symbol();
- if (Sym->VersionId != Config->DefaultSymbolVersion)
- warning("duplicate symbol " + Name + " in version script");
- Sym->VersionId = Version;
-}
+ if (Ver.IsExternCpp) {
+ for (auto &P : getDemangledSyms())
+ if (M.match(P.first()))
+ Res.insert(Res.end(), P.second.begin(), P.second.end());
+ return Res;
+ }
-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;
+ if (!B->isUndefined() && M.match(B->getName()))
+ Res.push_back(B);
}
- return Result;
-}
-
-static bool hasExternCpp() {
- for (VersionDefinition &V : Config->VersionDefinitions)
- for (SymbolVersion Sym : V.Globals)
- if (Sym.IsExternCpp)
- return true;
- return false;
+ return Res;
}
-// 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))
+// If there's only one anonymous version definition in a version
+// script file, the script does not actually define any symbol version,
+// but just specifies symbols visibilities. We assume that the script was
+// in the form of { global: foo; bar; local *; }. So, local is default.
+// In this function, we make specified symbols global.
+template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() {
+ for (SymbolVersion &Ver : Config->VersionScriptGlobals) {
+ if (Ver.HasWildcard) {
+ for (SymbolBody *B : findAllByVersion(Ver))
B->symbol()->VersionId = VER_NDX_GLOBAL;
- return;
+ continue;
+ }
+ for (SymbolBody *B : findByVersion(Ver))
+ B->symbol()->VersionId = VER_NDX_GLOBAL;
}
+}
- if (Config->VersionDefinitions.empty())
+// Set symbol versions to symbols. This function handles patterns
+// containing no wildcard characters.
+template <class ELFT>
+void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
+ StringRef VersionName) {
+ if (Ver.HasWildcard)
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);
- }
+ // Get a list of symbols which we need to assign the version to.
+ std::vector<SymbolBody *> Syms = findByVersion(Ver);
+ if (Syms.empty()) {
+ if (Config->NoUndefinedVersion)
+ error("version script assignment of '" + VersionName + "' to symbol '" +
+ Ver.Name + "' failed: symbol not defined");
+ return;
}
- // 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;
+ // Assign the version.
+ for (SymbolBody *B : Syms) {
+ Symbol *Sym = B->symbol();
+ if (Sym->InVersionScript)
+ warn("duplicate symbol '" + Ver.Name + "' in version script");
+ Sym->VersionId = VersionId;
+ Sym->InVersionScript = true;
}
}
-// 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)};
- }
+template <class ELFT>
+void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
+ uint16_t VersionId) {
+ if (!Ver.HasWildcard)
+ return;
+ std::vector<SymbolBody *> Syms = findAllByVersion(Ver);
- // It is an error if the specified version was not defined.
- error("symbol " + S + " has undefined version " + Verstr);
- return {"", 0};
+ // Exact matching takes precendence over fuzzy matching,
+ // so we set a version to a symbol only if no version has been assigned
+ // to the symbol. This behavior is compatible with GNU.
+ for (SymbolBody *B : Syms)
+ if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
+ B->symbol()->VersionId = VersionId;
}
-// 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())
+// This function processes version scripts by updating VersionId
+// member of symbols.
+template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
+ // Symbol themselves might know their versions because symbols
+ // can contain versions in the form of <name>@<version>.
+ // Let them parse their names.
+ if (!Config->VersionDefinitions.empty())
+ for (Symbol *Sym : SymVector)
+ Sym->body()->parseSymbolVersion();
+
+ // Handle edge cases first.
+ if (!Config->VersionScriptGlobals.empty()) {
+ handleAnonymousVersion();
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;
+ if (Config->VersionDefinitions.empty())
+ return;
- // Look for '@' in the symbol name.
- StringRef Name;
- uint16_t Version;
- std::tie(Name, Version) = getSymbolVersion(B, MaxVersionLen);
- if (Name.empty())
- continue;
+ // Now we have version definitions, so we need to set version ids to symbols.
+ // Each version definition has a glob pattern, and all symbols that match
+ // with the pattern get that version.
- B->setName(Name);
- Sym->VersionId = Version;
- }
+ // First, we assign versions to exact matching symbols,
+ // i.e. version definitions not containing any glob meta-characters.
+ for (SymbolVersion &Ver : Config->VersionScriptLocals)
+ assignExactVersion(Ver, VER_NDX_LOCAL, "local");
+ for (VersionDefinition &V : Config->VersionDefinitions)
+ for (SymbolVersion &Ver : V.Globals)
+ assignExactVersion(Ver, V.Id, V.Name);
+
+ // Next, we assign versions to fuzzy matching symbols,
+ // i.e. version definitions containing glob meta-characters.
+ // Note that because the last match takes precedence over previous matches,
+ // we iterate over the definitions in the reverse order.
+ for (SymbolVersion &Ver : Config->VersionScriptLocals)
+ assignWildcardVersion(Ver, VER_NDX_LOCAL);
+ for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions))
+ for (SymbolVersion &Ver : V.Globals)
+ assignWildcardVersion(Ver, V.Id);
}
template class elf::SymbolTable<ELF32LE>;
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
index 40415b645a44..1e5a335acc16 100644
--- a/ELF/SymbolTable.h
+++ b/ELF/SymbolTable.h
@@ -12,16 +12,16 @@
#include "InputFiles.h"
#include "LTO.h"
+#include "Strings.h"
+#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
namespace lld {
namespace elf {
class Lazy;
-template <class ELFT> class OutputSectionBase;
+class OutputSectionBase;
struct Symbol;
-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
// files whose archive members are not yet loaded).
@@ -39,40 +39,39 @@ template <class ELFT> class SymbolTable {
typedef typename ELFT::uint uintX_t;
public:
- void addFile(std::unique_ptr<InputFile> File);
- void addCombinedLtoObject();
-
- llvm::ArrayRef<Symbol *> getSymbols() const { return SymVector; }
+ void addFile(InputFile *File);
+ void addCombinedLTOObject();
- const std::vector<std::unique_ptr<ObjectFile<ELFT>>> &getObjectFiles() const {
- return ObjectFiles;
- }
-
- const std::vector<std::unique_ptr<SharedFile<ELFT>>> &getSharedFiles() const {
- return SharedFiles;
- }
+ ArrayRef<Symbol *> getSymbols() const { return SymVector; }
+ ArrayRef<ObjectFile<ELFT> *> getObjectFiles() const { return ObjectFiles; }
+ ArrayRef<BinaryFile *> getBinaryFiles() const { return BinaryFiles; }
+ ArrayRef<SharedFile<ELFT> *> getSharedFiles() const { return SharedFiles; }
DefinedRegular<ELFT> *addAbsolute(StringRef Name,
- uint8_t Visibility = llvm::ELF::STV_HIDDEN);
+ uint8_t Visibility = llvm::ELF::STV_HIDDEN,
+ uint8_t Binding = llvm::ELF::STB_GLOBAL);
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);
+ Symbol *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding,
+ uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym,
+ InputFile *File);
+
+ Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
+ uintX_t Value, uintX_t Size, uint8_t Binding,
+ InputSectionBase<ELFT> *Section, InputFile *File);
+
+ Symbol *addSynthetic(StringRef N, const OutputSectionBase *Section,
+ uintX_t Value, uint8_t StOther);
+
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 *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
+ uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File);
Symbol *addCommon(StringRef N, uint64_t Size, uint64_t Alignment,
uint8_t Binding, uint8_t StOther, uint8_t Type,
@@ -80,28 +79,32 @@ public:
void scanUndefinedFlags();
void scanShlibUndefined();
- void scanDynamicList();
void scanVersionScript();
- void scanSymbolVersions();
SymbolBody *find(StringRef Name);
void trace(StringRef Name);
void wrap(StringRef Name);
+ std::vector<InputSectionBase<ELFT> *> Sections;
+
private:
- 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);
+ InputFile *File);
- std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile);
- void reportDuplicate(SymbolBody *Existing, InputFile *NewFile);
+ std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);
+ std::vector<SymbolBody *> findAllByVersion(SymbolVersion Ver);
- std::map<std::string, SymbolBody *> getDemangledSyms();
+ llvm::StringMap<std::vector<SymbolBody *>> &getDemangledSyms();
+ void handleAnonymousVersion();
+ void assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
+ StringRef VersionName);
+ void assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId);
struct SymIndex {
+ SymIndex(int Idx, bool Traced) : Idx(Idx), Traced(Traced) {}
int Idx : 31;
unsigned Traced : 1;
};
@@ -113,26 +116,30 @@ private:
// but a bit inefficient.
// FIXME: Experiment with passing in a custom hashing or sorting the symbols
// once symbol resolution is finished.
- llvm::DenseMap<SymName, SymIndex> Symtab;
+ llvm::DenseMap<llvm::CachedHashStringRef, SymIndex> Symtab;
std::vector<Symbol *> SymVector;
- llvm::BumpPtrAllocator Alloc;
// Comdat groups define "link once" sections. If two comdat groups have the
// same name, only one of them is linked, and the other is ignored. This set
// is used to uniquify them.
- llvm::DenseSet<StringRef> ComdatGroups;
+ llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups;
- // 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;
+ std::vector<ObjectFile<ELFT> *> ObjectFiles;
+ std::vector<SharedFile<ELFT> *> SharedFiles;
+ std::vector<BitcodeFile *> BitcodeFiles;
+ std::vector<BinaryFile *> BinaryFiles;
// Set of .so files to not link the same shared object file more than once.
llvm::DenseSet<StringRef> SoNames;
- std::unique_ptr<BitcodeCompiler> Lto;
+ // A map from demangled symbol names to their symbol objects.
+ // This mapping is 1:N because two symbols with different versions
+ // can have the same name. We use this map to handle "extern C++ {}"
+ // directive in version scripts.
+ llvm::Optional<llvm::StringMap<std::vector<SymbolBody *>>> DemangledSyms;
+
+ // For LTO.
+ std::unique_ptr<BitcodeCompiler> LTO;
};
template <class ELFT> struct Symtab { static SymbolTable<ELFT> *X; };
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index d6a605d11183..a2133f411c20 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -12,9 +12,14 @@
#include "InputFiles.h"
#include "InputSection.h"
#include "OutputSections.h"
+#include "Strings.h"
+#include "SyntheticSections.h"
#include "Target.h"
+#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Path.h"
+#include <cstring>
using namespace llvm;
using namespace llvm::object;
@@ -30,27 +35,27 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
switch (Body.kind()) {
case SymbolBody::DefinedSyntheticKind: {
- auto &D = cast<DefinedSynthetic<ELFT>>(Body);
- const OutputSectionBase<ELFT> *Sec = D.Section;
+ auto &D = cast<DefinedSynthetic>(Body);
+ const OutputSectionBase *Sec = D.Section;
if (!Sec)
return D.Value;
- if (D.Value == DefinedSynthetic<ELFT>::SectionEnd)
- return Sec->getVA() + Sec->getSize();
- return Sec->getVA() + D.Value;
+ if (D.Value == uintX_t(-1))
+ return Sec->Addr + Sec->Size;
+ return Sec->Addr + D.Value;
}
case SymbolBody::DefinedRegularKind: {
auto &D = cast<DefinedRegular<ELFT>>(Body);
- InputSectionBase<ELFT> *SC = D.Section;
+ InputSectionBase<ELFT> *IS = 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)
+ if (IS == &InputSection<ELFT>::Discarded)
return 0;
// This is an absolute symbol.
- if (!SC)
+ if (!IS)
return D.Value;
uintX_t Offset = D.Value;
@@ -58,20 +63,25 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
Offset += Addend;
Addend = 0;
}
- uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset);
- if (D.isTls())
+ uintX_t VA = (IS->OutSec ? IS->OutSec->Addr : 0) + IS->getOffset(Offset);
+ if (D.isTls() && !Config->Relocatable) {
+ if (!Out<ELFT>::TlsPhdr)
+ fatal(toString(D.File) +
+ " has a STT_TLS symbol but doesn't have a PT_TLS section");
return VA - Out<ELFT>::TlsPhdr->p_vaddr;
+ }
return VA;
}
case SymbolBody::DefinedCommonKind:
- return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(Body).OffsetInBss;
+ return In<ELFT>::Common->OutSec->Addr + In<ELFT>::Common->OutSecOff +
+ cast<DefinedCommon>(Body).Offset;
case SymbolBody::SharedKind: {
auto &SS = cast<SharedSymbol<ELFT>>(Body);
if (!SS.NeedsCopyOrPltAddr)
return 0;
if (SS.isFunc())
return Body.getPltVA<ELFT>();
- return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
+ return Out<ELFT>::Bss->Addr + SS.OffsetInBss;
}
case SymbolBody::UndefinedKind:
return 0;
@@ -79,32 +89,15 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
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");
}
-SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
+SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, 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()}) {}
-
-StringRef SymbolBody::getName() const {
- assert(!isLocal());
- return StringRef(Name.S, Name.Len);
-}
-
-void SymbolBody::setName(StringRef S) {
- Name.S = S.data();
- Name.Len = S.size();
-}
+ : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal),
+ IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
+ IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {}
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
@@ -151,7 +144,7 @@ typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
- return Out<ELFT>::Got->getVA() + getGotOffset<ELFT>();
+ return In<ELFT>::Got->getVA() + getGotOffset<ELFT>();
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
@@ -159,7 +152,9 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
- return Out<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
+ if (this->IsInIgot)
+ return In<ELFT>::IgotPlt->getVA() + getGotPltOffset<ELFT>();
+ return In<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
@@ -167,7 +162,9 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
}
template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
- return Out<ELFT>::Plt->getVA() + Target->PltHeaderSize +
+ if (this->IsInIplt)
+ return In<ELFT>::Iplt->getVA() + PltIndex * Target->PltEntrySize;
+ return In<ELFT>::Plt->getVA() + Target->PltHeaderSize +
PltIndex * Target->PltEntrySize;
}
@@ -189,48 +186,67 @@ template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
return 0;
}
-Defined::Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
- : SymbolBody(K, Name, StOther, Type) {}
-
-Defined::Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type)
- : SymbolBody(K, NameOffset, StOther, Type) {}
+// If a symbol name contains '@', the characters after that is
+// a symbol version name. This function parses that.
+void SymbolBody::parseSymbolVersion() {
+ StringRef S = getName();
+ size_t Pos = S.find('@');
+ if (Pos == 0 || Pos == StringRef::npos)
+ return;
+ StringRef Verstr = S.substr(Pos + 1);
+ if (Verstr.empty())
+ return;
+
+ // Truncate the symbol name so that it doesn't include the version string.
+ Name = {S.data(), Pos};
+
+ // '@@' 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 &Ver : Config->VersionDefinitions) {
+ if (Ver.Name != Verstr)
+ continue;
+
+ if (IsDefault)
+ symbol()->VersionId = Ver.Id;
+ else
+ symbol()->VersionId = Ver.Id | VERSYM_HIDDEN;
+ return;
+ }
-DefinedBitcode::DefinedBitcode(StringRef Name, uint8_t StOther, uint8_t Type,
- BitcodeFile *F)
- : Defined(DefinedBitcodeKind, Name, StOther, Type) {
- this->File = F;
+ // It is an error if the specified version is not defined.
+ error(toString(File) + ": symbol " + S + " has undefined version " + Verstr);
}
-bool DefinedBitcode::classof(const SymbolBody *S) {
- return S->kind() == DefinedBitcodeKind;
-}
+Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
+ uint8_t Type)
+ : SymbolBody(K, Name, IsLocal, StOther, Type) {}
-Undefined::Undefined(StringRef Name, uint8_t StOther, uint8_t Type,
- InputFile *File)
- : SymbolBody(SymbolBody::UndefinedKind, Name, StOther, Type) {
- this->File = File;
+template <class ELFT> bool DefinedRegular<ELFT>::isMipsPIC() const {
+ if (!Section || !isFunc())
+ return false;
+ return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
+ (Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC);
}
-Undefined::Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type,
- InputFile *File)
- : SymbolBody(SymbolBody::UndefinedKind, NameOffset, StOther, Type) {
+Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
+ uint8_t Type, InputFile *File)
+ : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
this->File = File;
}
-template <typename ELFT>
-DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value,
- 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,
+DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment,
uint8_t StOther, uint8_t Type, InputFile *File)
- : Defined(SymbolBody::DefinedCommonKind, N, StOther, Type),
+ : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther,
+ Type),
Alignment(Alignment), Size(Size) {
this->File = File;
}
-std::unique_ptr<InputFile> Lazy::fetch() {
+InputFile *Lazy::fetch() {
if (auto *S = dyn_cast<LazyArchive>(this))
return S->fetch();
return cast<LazyObject>(this)->fetch();
@@ -247,20 +263,20 @@ LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type)
this->File = &File;
}
-std::unique_ptr<InputFile> LazyArchive::fetch() {
- MemoryBufferRef MBRef = file()->getMember(&Sym);
+InputFile *LazyArchive::fetch() {
+ std::pair<MemoryBufferRef, uint64_t> MBInfo = 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());
+ if (MBInfo.first.getBuffer().empty())
+ return nullptr;
+ return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second);
}
-std::unique_ptr<InputFile> LazyObject::fetch() {
+InputFile *LazyObject::fetch() {
MemoryBufferRef MBRef = file()->getBuffer();
if (MBRef.getBuffer().empty())
- return std::unique_ptr<InputFile>(nullptr);
+ return nullptr;
return createObjectFile(MBRef);
}
@@ -274,7 +290,7 @@ bool Symbol::includeInDynsym() const {
// Print out a log message for --trace-symbol.
void elf::printTraceSymbol(Symbol *Sym) {
SymbolBody *B = Sym->body();
- outs() << getFilename(B->File);
+ outs() << toString(B->File);
if (B->isUndefined())
outs() << ": reference to ";
@@ -285,6 +301,14 @@ void elf::printTraceSymbol(Symbol *Sym) {
outs() << B->getName() << "\n";
}
+// Returns a symbol for an error message.
+std::string elf::toString(const SymbolBody &B) {
+ if (Config->Demangle)
+ if (Optional<std::string> S = demangle(B.getName()))
+ return *S;
+ return B.getName();
+}
+
template bool SymbolBody::hasThunk<ELF32LE>() const;
template bool SymbolBody::hasThunk<ELF32BE>() const;
template bool SymbolBody::hasThunk<ELF64LE>() const;
@@ -330,7 +354,7 @@ template uint32_t SymbolBody::template getSize<ELF32BE>() const;
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
template uint64_t SymbolBody::template getSize<ELF64BE>() const;
-template class elf::DefinedSynthetic<ELF32LE>;
-template class elf::DefinedSynthetic<ELF32BE>;
-template class elf::DefinedSynthetic<ELF64LE>;
-template class elf::DefinedSynthetic<ELF64BE>;
+template class elf::DefinedRegular<ELF32LE>;
+template class elf::DefinedRegular<ELF32BE>;
+template class elf::DefinedRegular<ELF64LE>;
+template class elf::DefinedRegular<ELF64BE>;
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index aa9a87d3b4f7..c95241a5293e 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -16,11 +16,11 @@
#define LLD_ELF_SYMBOLS_H
#include "InputSection.h"
+#include "Strings.h"
#include "lld/Core/LLVM.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/AlignOf.h"
namespace lld {
namespace elf {
@@ -29,10 +29,9 @@ 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;
+class OutputSectionBase;
template <class ELFT> class SharedFile;
struct Symbol;
@@ -45,7 +44,6 @@ public:
DefinedRegularKind = DefinedFirst,
SharedKind,
DefinedCommonKind,
- DefinedBitcodeKind,
DefinedSyntheticKind,
DefinedLast = DefinedSyntheticKind,
UndefinedKind,
@@ -71,22 +69,10 @@ public:
bool isShared() const { return SymbolKind == SharedKind; }
bool isLocal() const { return IsLocal; }
bool isPreemptible() const;
-
- StringRef getName() const;
- void setName(StringRef S);
-
- uint32_t getNameOffset() const {
- assert(isLocal());
- return NameOffset;
- }
-
+ StringRef getName() const { return Name; }
uint8_t getVisibility() const { return StOther & 0x3; }
+ void parseSymbolVersion();
- unsigned DynsymIndex = 0;
- uint32_t GotIndex = -1;
- uint32_t GotPltIndex = -1;
- uint32_t PltIndex = -1;
- uint32_t GlobalDynIndex = -1;
bool isInGot() const { return GotIndex != -1U; }
bool isInPlt() const { return PltIndex != -1U; }
template <class ELFT> bool hasThunk() const;
@@ -105,10 +91,15 @@ public:
// The file from which this symbol was created.
InputFile *File = nullptr;
-protected:
- SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type);
+ uint32_t DynsymIndex = 0;
+ uint32_t GotIndex = -1;
+ uint32_t GotPltIndex = -1;
+ uint32_t PltIndex = -1;
+ uint32_t GlobalDynIndex = -1;
- SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
+protected:
+ SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
+ uint8_t Type);
const unsigned SymbolKind : 8;
@@ -123,6 +114,15 @@ public:
// True if this symbol has an entry in the global part of MIPS GOT.
unsigned IsInGlobalMipsGot : 1;
+ // True if this symbol is referenced by 32-bit GOT relocations.
+ unsigned Is32BitMipsGot : 1;
+
+ // True if this symbol is in the Iplt sub-section of the Plt.
+ unsigned IsInIplt : 1;
+
+ // True if this symbol is in the Igot sub-section of the .got.plt or .got.
+ unsigned IsInIgot : 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
@@ -142,32 +142,16 @@ public:
bool isFile() const { return Type == llvm::ELF::STT_FILE; }
protected:
- struct Str {
- const char *S;
- size_t Len;
- };
- union {
- Str Name;
- uint32_t NameOffset;
- };
+ StringRefZ Name;
};
// The base class for any defined symbols.
class Defined : public SymbolBody {
public:
- Defined(Kind K, StringRef Name, uint8_t StOther, uint8_t Type);
- Defined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
+ Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type);
static bool classof(const SymbolBody *S) { return S->isDefined(); }
};
-// The defined symbol in LLVM bitcode files.
-class DefinedBitcode : public Defined {
-public:
- 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, uint8_t StOther,
@@ -179,7 +163,7 @@ public:
// The output offset of this common symbol in the output bss. Computed by the
// writer.
- uint64_t OffsetInBss;
+ uint64_t Offset;
// The maximum alignment we have seen for this symbol.
uint64_t Alignment;
@@ -193,30 +177,17 @@ template <class ELFT> class DefinedRegular : public Defined {
typedef typename ELFT::uint uintX_t;
public:
- DefinedRegular(StringRef Name, const Elf_Sym &Sym,
- InputSectionBase<ELFT> *Section)
- : Defined(SymbolBody::DefinedRegularKind, Name, Sym.st_other,
- Sym.getType()),
- Value(Sym.st_value), Size(Sym.st_size),
+ DefinedRegular(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
+ uintX_t Value, uintX_t Size, InputSectionBase<ELFT> *Section,
+ InputFile *File)
+ : Defined(SymbolBody::DefinedRegularKind, Name, IsLocal, StOther, Type),
+ Value(Value), Size(Size),
Section(Section ? Section->Repl : NullInputSection) {
- if (Section)
- this->File = Section->getFile();
+ this->File = File;
}
- 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) {}
+ // Return true if the symbol is a PIC function.
+ bool isMipsPIC() const;
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedRegularKind;
@@ -249,28 +220,26 @@ InputSectionBase<ELFT> *DefinedRegular<ELFT>::NullInputSection;
// 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 {
+class DefinedSynthetic : public Defined {
public:
- typedef typename ELFT::uint uintX_t;
- DefinedSynthetic(StringRef N, uintX_t Value,
- OutputSectionBase<ELFT> *Section);
+ DefinedSynthetic(StringRef Name, uint64_t Value,
+ const OutputSectionBase *Section)
+ : Defined(SymbolBody::DefinedSyntheticKind, Name, /*IsLocal=*/false,
+ llvm::ELF::STV_HIDDEN, 0 /* Type */),
+ Value(Value), Section(Section) {}
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedSyntheticKind;
}
- // 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;
+ uint64_t Value;
+ const OutputSectionBase *Section;
};
class Undefined : public SymbolBody {
public:
- Undefined(StringRef Name, uint8_t StOther, uint8_t Type, InputFile *F);
- Undefined(uint32_t NameOffset, uint8_t StOther, uint8_t Type, InputFile *F);
+ Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
+ InputFile *F);
static bool classof(const SymbolBody *S) {
return S->kind() == UndefinedKind;
@@ -291,7 +260,8 @@ public:
SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
const Elf_Verdef *Verdef)
- : Defined(SymbolBody::SharedKind, Name, Sym.st_other, Sym.getType()),
+ : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, Sym.st_other,
+ Sym.getType()),
Sym(Sym), Verdef(Verdef) {
// IFuncs defined in DSOs are treated as functions by the static linker.
if (isGnuIFunc())
@@ -326,11 +296,11 @@ public:
// Returns an object file for this symbol, or a nullptr if the file
// was already returned.
- std::unique_ptr<InputFile> fetch();
+ InputFile *fetch();
protected:
Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type)
- : SymbolBody(K, Name, llvm::ELF::STV_DEFAULT, Type) {}
+ : SymbolBody(K, Name, /*IsLocal=*/false, llvm::ELF::STV_DEFAULT, Type) {}
};
// LazyArchive symbols represents symbols in archive files.
@@ -344,7 +314,7 @@ public:
}
ArchiveFile *file() { return (ArchiveFile *)this->File; }
- std::unique_ptr<InputFile> fetch();
+ InputFile *fetch();
private:
const llvm::object::Archive::Symbol Sym;
@@ -361,12 +331,15 @@ public:
}
LazyObjectFile *file() { return (LazyObjectFile *)this->File; }
- std::unique_ptr<InputFile> fetch();
+ InputFile *fetch();
};
// Some linker-generated symbols need to be created as
// DefinedRegular symbols.
template <class ELFT> struct ElfSym {
+ // The content for __ehdr_start symbol.
+ static DefinedRegular<ELFT> *EhdrStart;
+
// The content for _etext and etext symbols.
static DefinedRegular<ELFT> *Etext;
static DefinedRegular<ELFT> *Etext2;
@@ -379,17 +352,22 @@ template <class ELFT> struct ElfSym {
static DefinedRegular<ELFT> *End;
static DefinedRegular<ELFT> *End2;
- // The content for _gp_disp symbol for MIPS target.
- static SymbolBody *MipsGpDisp;
+ // The content for _gp_disp/__gnu_local_gp symbols for MIPS target.
+ static DefinedRegular<ELFT> *MipsGpDisp;
+ static DefinedRegular<ELFT> *MipsLocalGp;
+ static DefinedRegular<ELFT> *MipsGp;
};
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::EhdrStart;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext2;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End;
template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2;
-template <class ELFT> SymbolBody *ElfSym<ELFT>::MipsGpDisp;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGpDisp;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsLocalGp;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGp;
// A real symbol object, SymbolBody, is usually stored within a Symbol. There's
// always one Symbol for each symbol name. The resolver updates the SymbolBody
@@ -425,6 +403,9 @@ struct Symbol {
// True if this symbol is specified by --trace-symbol option.
unsigned Traced : 1;
+ // This symbol version was found in a version script.
+ unsigned InVersionScript : 1;
+
bool includeInDynsym() const;
bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
@@ -434,9 +415,8 @@ struct Symbol {
// 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>
+ DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic,
+ Undefined, SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject>
Body;
SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
@@ -448,8 +428,7 @@ 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,
+ static_assert(alignof(T) <= alignof(decltype(S->Body)),
"Body not aligned enough");
assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a SymbolBody");
@@ -468,6 +447,8 @@ inline Symbol *SymbolBody::symbol() {
offsetof(Symbol, Body));
}
+std::string toString(const SymbolBody &B);
+
} // namespace elf
} // namespace lld
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
new file mode 100644
index 000000000000..3c8a439ba308
--- /dev/null
+++ b/ELF/SyntheticSections.cpp
@@ -0,0 +1,1990 @@
+//===- SyntheticSections.cpp ----------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains linker-synthesized sections. Currently,
+// synthetic sections are created either output sections or input sections,
+// but we are rewriting code so that all synthetic sections are created as
+// input sections.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SyntheticSections.h"
+#include "Config.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "Target.h"
+#include "Threads.h"
+#include "Writer.h"
+#include "lld/Config/Version.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Support/SHA1.h"
+#include "llvm/Support/xxhash.h"
+#include <cstdlib>
+
+using namespace llvm;
+using namespace llvm::dwarf;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+
+using namespace lld;
+using namespace lld::elf;
+
+template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() {
+ std::vector<DefinedCommon *> V;
+ for (Symbol *S : Symtab<ELFT>::X->getSymbols())
+ if (auto *B = dyn_cast<DefinedCommon>(S->body()))
+ V.push_back(B);
+ return V;
+}
+
+// Find all common symbols and allocate space for them.
+template <class ELFT> InputSection<ELFT> *elf::createCommonSection() {
+ auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 1,
+ ArrayRef<uint8_t>(), "COMMON");
+ Ret->Live = true;
+
+ // Sort the common symbols by alignment as an heuristic to pack them better.
+ std::vector<DefinedCommon *> Syms = getCommonSymbols<ELFT>();
+ std::stable_sort(Syms.begin(), Syms.end(),
+ [](const DefinedCommon *A, const DefinedCommon *B) {
+ return A->Alignment > B->Alignment;
+ });
+
+ // Assign offsets to symbols.
+ size_t Size = 0;
+ size_t Alignment = 1;
+ for (DefinedCommon *Sym : Syms) {
+ Alignment = std::max<size_t>(Alignment, Sym->Alignment);
+ Size = alignTo(Size, Sym->Alignment);
+
+ // Compute symbol offset relative to beginning of input section.
+ Sym->Offset = Size;
+ Size += Sym->Size;
+ }
+ Ret->Alignment = Alignment;
+ Ret->Data = makeArrayRef<uint8_t>(nullptr, Size);
+ return Ret;
+}
+
+// Returns an LLD version string.
+static ArrayRef<uint8_t> getVersion() {
+ // Check LLD_VERSION first for ease of testing.
+ // You can get consitent output by using the environment variable.
+ // This is only for testing.
+ StringRef S = getenv("LLD_VERSION");
+ if (S.empty())
+ S = Saver.save(Twine("Linker: ") + getLLDVersion());
+
+ // +1 to include the terminating '\0'.
+ return {(const uint8_t *)S.data(), S.size() + 1};
+}
+
+// Creates a .comment section containing LLD version info.
+// With this feature, you can identify LLD-generated binaries easily
+// by "objdump -s -j .comment <file>".
+// The returned object is a mergeable string section.
+template <class ELFT> MergeInputSection<ELFT> *elf::createCommentSection() {
+ typename ELFT::Shdr Hdr = {};
+ Hdr.sh_flags = SHF_MERGE | SHF_STRINGS;
+ Hdr.sh_type = SHT_PROGBITS;
+ Hdr.sh_entsize = 1;
+ Hdr.sh_addralign = 1;
+
+ auto *Ret = make<MergeInputSection<ELFT>>(/*file=*/nullptr, &Hdr, ".comment");
+ Ret->Data = getVersion();
+ Ret->splitIntoPieces();
+ return Ret;
+}
+
+// .MIPS.abiflags section.
+template <class ELFT>
+MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags)
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"),
+ Flags(Flags) {}
+
+template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *Buf) {
+ memcpy(Buf, &Flags, sizeof(Flags));
+}
+
+template <class ELFT>
+MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
+ Elf_Mips_ABIFlags Flags = {};
+ bool Create = false;
+
+ for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
+ if (!Sec->Live || Sec->Type != SHT_MIPS_ABIFLAGS)
+ continue;
+ Sec->Live = false;
+ Create = true;
+
+ std::string Filename = toString(Sec->getFile());
+ const size_t Size = Sec->Data.size();
+ // Older version of BFD (such as the default FreeBSD linker) concatenate
+ // .MIPS.abiflags instead of merging. To allow for this case (or potential
+ // zero padding) we ignore everything after the first Elf_Mips_ABIFlags
+ if (Size < sizeof(Elf_Mips_ABIFlags)) {
+ error(Filename + ": invalid size of .MIPS.abiflags section: got " +
+ Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags)));
+ return nullptr;
+ }
+ auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->Data.data());
+ if (S->version != 0) {
+ error(Filename + ": unexpected .MIPS.abiflags version " +
+ Twine(S->version));
+ return nullptr;
+ }
+
+ // LLD checks ISA compatibility in getMipsEFlags(). Here we just
+ // select the highest number of ISA/Rev/Ext.
+ Flags.isa_level = std::max(Flags.isa_level, S->isa_level);
+ Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev);
+ Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext);
+ Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size);
+ Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size);
+ Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size);
+ Flags.ases |= S->ases;
+ Flags.flags1 |= S->flags1;
+ Flags.flags2 |= S->flags2;
+ Flags.fp_abi = elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, Filename);
+ };
+
+ if (Create)
+ return make<MipsAbiFlagsSection<ELFT>>(Flags);
+ return nullptr;
+}
+
+// .MIPS.options section.
+template <class ELFT>
+MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo)
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"),
+ Reginfo(Reginfo) {}
+
+template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
+ auto *Options = reinterpret_cast<Elf_Mips_Options *>(Buf);
+ Options->kind = ODK_REGINFO;
+ Options->size = getSize();
+
+ if (!Config->Relocatable)
+ Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
+ memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
+}
+
+template <class ELFT>
+MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
+ // N64 ABI only.
+ if (!ELFT::Is64Bits)
+ return nullptr;
+
+ Elf_Mips_RegInfo Reginfo = {};
+ bool Create = false;
+
+ for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
+ if (!Sec->Live || Sec->Type != SHT_MIPS_OPTIONS)
+ continue;
+ Sec->Live = false;
+ Create = true;
+
+ std::string Filename = toString(Sec->getFile());
+ ArrayRef<uint8_t> D = Sec->Data;
+
+ while (!D.empty()) {
+ if (D.size() < sizeof(Elf_Mips_Options)) {
+ error(Filename + ": invalid size of .MIPS.options section");
+ break;
+ }
+
+ auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data());
+ if (Opt->kind == ODK_REGINFO) {
+ if (Config->Relocatable && Opt->getRegInfo().ri_gp_value)
+ error(Filename + ": unsupported non-zero ri_gp_value");
+ Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
+ Sec->getFile()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
+ break;
+ }
+
+ if (!Opt->size)
+ fatal(Filename + ": zero option descriptor size");
+ D = D.slice(Opt->size);
+ }
+ };
+
+ if (Create)
+ return make<MipsOptionsSection<ELFT>>(Reginfo);
+ return nullptr;
+}
+
+// MIPS .reginfo section.
+template <class ELFT>
+MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"),
+ Reginfo(Reginfo) {}
+
+template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
+ if (!Config->Relocatable)
+ Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
+ memcpy(Buf, &Reginfo, sizeof(Reginfo));
+}
+
+template <class ELFT>
+MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
+ // Section should be alive for O32 and N32 ABIs only.
+ if (ELFT::Is64Bits)
+ return nullptr;
+
+ Elf_Mips_RegInfo Reginfo = {};
+ bool Create = false;
+
+ for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
+ if (!Sec->Live || Sec->Type != SHT_MIPS_REGINFO)
+ continue;
+ Sec->Live = false;
+ Create = true;
+
+ if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) {
+ error(toString(Sec->getFile()) + ": invalid size of .reginfo section");
+ return nullptr;
+ }
+ auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
+ if (Config->Relocatable && R->ri_gp_value)
+ error(toString(Sec->getFile()) + ": unsupported non-zero ri_gp_value");
+
+ Reginfo.ri_gprmask |= R->ri_gprmask;
+ Sec->getFile()->MipsGp0 = R->ri_gp_value;
+ };
+
+ if (Create)
+ return make<MipsReginfoSection<ELFT>>(Reginfo);
+ return nullptr;
+}
+
+template <class ELFT> InputSection<ELFT> *elf::createInterpSection() {
+ auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC, SHT_PROGBITS, 1,
+ ArrayRef<uint8_t>(), ".interp");
+ Ret->Live = true;
+
+ // StringSaver guarantees that the returned string ends with '\0'.
+ StringRef S = Saver.save(Config->DynamicLinker);
+ Ret->Data = {(const uint8_t *)S.data(), S.size() + 1};
+ return Ret;
+}
+
+static size_t getHashSize() {
+ switch (Config->BuildId) {
+ case BuildIdKind::Fast:
+ return 8;
+ case BuildIdKind::Md5:
+ case BuildIdKind::Uuid:
+ return 16;
+ case BuildIdKind::Sha1:
+ return 20;
+ case BuildIdKind::Hexstring:
+ return Config->BuildIdVector.size();
+ default:
+ llvm_unreachable("unknown BuildIdKind");
+ }
+}
+
+template <class ELFT>
+BuildIdSection<ELFT>::BuildIdSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"),
+ HashSize(getHashSize()) {}
+
+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;
+}
+
+// Split one uint8 array into small pieces of uint8 arrays.
+static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr,
+ size_t ChunkSize) {
+ std::vector<ArrayRef<uint8_t>> Ret;
+ while (Arr.size() > ChunkSize) {
+ Ret.push_back(Arr.take_front(ChunkSize));
+ Arr = Arr.drop_front(ChunkSize);
+ }
+ if (!Arr.empty())
+ Ret.push_back(Arr);
+ return Ret;
+}
+
+// Computes a hash value of Data using a given hash function.
+// In order to utilize multiple cores, we first split data into 1MB
+// chunks, compute a hash for each chunk, and then compute a hash value
+// of the hash values.
+template <class ELFT>
+void BuildIdSection<ELFT>::computeHash(
+ llvm::ArrayRef<uint8_t> Data,
+ std::function<void(uint8_t *Dest, ArrayRef<uint8_t> Arr)> HashFn) {
+ std::vector<ArrayRef<uint8_t>> Chunks = split(Data, 1024 * 1024);
+ std::vector<uint8_t> Hashes(Chunks.size() * HashSize);
+
+ // Compute hash values.
+ forLoop(0, Chunks.size(),
+ [&](size_t I) { HashFn(Hashes.data() + I * HashSize, Chunks[I]); });
+
+ // Write to the final output buffer.
+ HashFn(HashBuf, Hashes);
+}
+
+template <class ELFT>
+void BuildIdSection<ELFT>::writeBuildId(ArrayRef<uint8_t> Buf) {
+ switch (Config->BuildId) {
+ case BuildIdKind::Fast:
+ computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
+ write64le(Dest, xxHash64(toStringRef(Arr)));
+ });
+ break;
+ case BuildIdKind::Md5:
+ computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
+ memcpy(Dest, MD5::hash(Arr).data(), 16);
+ });
+ break;
+ case BuildIdKind::Sha1:
+ computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
+ memcpy(Dest, SHA1::hash(Arr).data(), 20);
+ });
+ break;
+ case BuildIdKind::Uuid:
+ if (getRandomBytes(HashBuf, HashSize))
+ error("entropy source failure");
+ break;
+ case BuildIdKind::Hexstring:
+ memcpy(HashBuf, Config->BuildIdVector.data(), Config->BuildIdVector.size());
+ break;
+ default:
+ llvm_unreachable("unknown BuildIdKind");
+ }
+}
+
+template <class ELFT>
+GotSection<ELFT>::GotSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotEntrySize, ".got") {}
+
+template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
+ Sym.GotIndex = NumEntries;
+ ++NumEntries;
+}
+
+template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+ if (Sym.GlobalDynIndex != -1U)
+ return false;
+ Sym.GlobalDynIndex = NumEntries;
+ // Global Dynamic TLS entries take two GOT slots.
+ NumEntries += 2;
+ return true;
+}
+
+// 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 = NumEntries * sizeof(uintX_t);
+ NumEntries += 2;
+ return true;
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
+ return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
+ return B.GlobalDynIndex * sizeof(uintX_t);
+}
+
+template <class ELFT> void GotSection<ELFT>::finalize() {
+ Size = NumEntries * sizeof(uintX_t);
+}
+
+template <class ELFT> bool GotSection<ELFT>::empty() const {
+ // If we have a relocation that is relative to GOT (such as GOTOFFREL),
+ // we need to emit a GOT even if it's empty.
+ return NumEntries == 0 && !HasGotOffRel;
+}
+
+template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
+ this->relocate(Buf, Buf + Size);
+}
+
+template <class ELFT>
+MipsGotSection<ELFT>::MipsGotSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL,
+ SHT_PROGBITS, Target->GotEntrySize, ".got") {}
+
+template <class ELFT>
+void MipsGotSection<ELFT>::addEntry(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.
+ PageIndexMap.insert({cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec, 0});
+ 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 = TlsEntries.size();
+ TlsEntries.push_back(&Sym);
+ return;
+ }
+ auto AddEntry = [&](SymbolBody &S, uintX_t A, GotEntries &Items) {
+ if (S.isInGot() && !A)
+ return;
+ size_t NewIndex = Items.size();
+ if (!EntryIndexMap.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, GlobalEntries);
+ Sym.IsInGlobalMipsGot = true;
+ } else if (Expr == R_MIPS_GOT_OFF32) {
+ AddEntry(Sym, Addend, LocalEntries32);
+ Sym.Is32BitMipsGot = true;
+ } else {
+ // Hold local GOT entries accessed via a 16-bit index separately.
+ // That allows to write them in the beginning of the GOT and keep
+ // their indexes as less as possible to escape relocation's overflow.
+ AddEntry(Sym, Addend, LocalEntries);
+ }
+}
+
+template <class ELFT>
+bool MipsGotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+ if (Sym.GlobalDynIndex != -1U)
+ return false;
+ Sym.GlobalDynIndex = TlsEntries.size();
+ // Global Dynamic TLS entries take two GOT slots.
+ TlsEntries.push_back(nullptr);
+ TlsEntries.push_back(&Sym);
+ return true;
+}
+
+// Reserves TLS entries for a TLS module ID and a TLS block offset.
+// In total it takes two GOT slots.
+template <class ELFT> bool MipsGotSection<ELFT>::addTlsIndex() {
+ if (TlsIndexOff != uint32_t(-1))
+ return false;
+ TlsIndexOff = TlsEntries.size() * sizeof(uintX_t);
+ TlsEntries.push_back(nullptr);
+ TlsEntries.push_back(nullptr);
+ return true;
+}
+
+static uint64_t getMipsPageAddr(uint64_t Addr) {
+ return (Addr + 0x8000) & ~0xffff;
+}
+
+static uint64_t getMipsPageCount(uint64_t Size) {
+ return (Size + 0xfffe) / 0xffff + 1;
+}
+
+template <class ELFT>
+typename MipsGotSection<ELFT>::uintX_t
+MipsGotSection<ELFT>::getPageEntryOffset(const SymbolBody &B,
+ uintX_t Addend) const {
+ const OutputSectionBase *OutSec =
+ cast<DefinedRegular<ELFT>>(&B)->Section->OutSec;
+ uintX_t SecAddr = getMipsPageAddr(OutSec->Addr);
+ uintX_t SymAddr = getMipsPageAddr(B.getVA<ELFT>(Addend));
+ uintX_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
+ assert(Index < PageEntriesNum);
+ return (HeaderEntriesNum + Index) * sizeof(uintX_t);
+}
+
+template <class ELFT>
+typename MipsGotSection<ELFT>::uintX_t
+MipsGotSection<ELFT>::getBodyEntryOffset(const SymbolBody &B,
+ uintX_t Addend) const {
+ // Calculate offset of the GOT entries block: TLS, global, local.
+ uintX_t Index = HeaderEntriesNum + PageEntriesNum;
+ if (B.isTls())
+ Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size();
+ else if (B.IsInGlobalMipsGot)
+ Index += LocalEntries.size() + LocalEntries32.size();
+ else if (B.Is32BitMipsGot)
+ Index += LocalEntries.size();
+ // Calculate offset of the GOT entry in the block.
+ if (B.isInGot())
+ Index += B.GotIndex;
+ else {
+ auto It = EntryIndexMap.find({&B, Addend});
+ assert(It != EntryIndexMap.end());
+ Index += It->second;
+ }
+ return Index * sizeof(uintX_t);
+}
+
+template <class ELFT>
+typename MipsGotSection<ELFT>::uintX_t
+MipsGotSection<ELFT>::getTlsOffset() const {
+ return (getLocalEntriesNum() + GlobalEntries.size()) * sizeof(uintX_t);
+}
+
+template <class ELFT>
+typename MipsGotSection<ELFT>::uintX_t
+MipsGotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
+ return B.GlobalDynIndex * sizeof(uintX_t);
+}
+
+template <class ELFT>
+const SymbolBody *MipsGotSection<ELFT>::getFirstGlobalEntry() const {
+ return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first;
+}
+
+template <class ELFT>
+unsigned MipsGotSection<ELFT>::getLocalEntriesNum() const {
+ return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() +
+ LocalEntries32.size();
+}
+
+template <class ELFT> void MipsGotSection<ELFT>::finalize() {
+ PageEntriesNum = 0;
+ for (std::pair<const OutputSectionBase *, size_t> &P : PageIndexMap) {
+ // For each output section referenced by GOT page relocations calculate
+ // and save into PageIndexMap 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. And take in account the case when the section intersects
+ // page boundaries.
+ P.second = PageEntriesNum;
+ PageEntriesNum += getMipsPageCount(P.first->Size);
+ }
+ Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
+ sizeof(uintX_t);
+}
+
+template <class ELFT> bool MipsGotSection<ELFT>::empty() const {
+ // We add the .got section to the result for dynamic MIPS target because
+ // its address and properties are mentioned in the .dynamic section.
+ return Config->Relocatable;
+}
+
+template <class ELFT>
+typename MipsGotSection<ELFT>::uintX_t MipsGotSection<ELFT>::getGp() const {
+ return ElfSym<ELFT>::MipsGp->template getVA<ELFT>(0);
+}
+
+template <class ELFT>
+static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
+ typedef typename ELFT::uint uintX_t;
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val);
+}
+
+template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) {
+ // Set the MSB of the second GOT slot. This is not required by any
+ // MIPS ABI documentation, though.
+ //
+ // There i