summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lld/ELF
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2017-04-02 17:24:58 +0000
committerdim <dim@FreeBSD.org>2017-04-02 17:24:58 +0000
commit60b571e49a90d38697b3aca23020d9da42fc7d7f (patch)
tree99351324c24d6cb146b6285b6caffa4d26fce188 /contrib/llvm/tools/lld/ELF
parentbea1b22c7a9bce1dfdd73e6e5b65bc4752215180 (diff)
downloadFreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.zip
FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.tar.gz
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release:
MFC r309142 (by emaste): Add WITH_LLD_AS_LD build knob If set it installs LLD as /usr/bin/ld. LLD (as of version 3.9) is not capable of linking the world and kernel, but can self-host and link many substantial applications. GNU ld continues to be used for the world and kernel build, regardless of how this knob is set. It is on by default for arm64, and off for all other CPU architectures. Sponsored by: The FreeBSD Foundation MFC r310840: Reapply 310775, now it also builds correctly if lldb is disabled: Move llvm-objdump from CLANG_EXTRAS to installed by default We currently install three tools from binutils 2.17.50: as, ld, and objdump. Work is underway to migrate to a permissively-licensed tool-chain, with one goal being the retirement of binutils 2.17.50. LLVM's llvm-objdump is intended to be compatible with GNU objdump although it is currently missing some options and may have formatting differences. Enable it by default for testing and further investigation. It may later be changed to install as /usr/bin/objdump, it becomes a fully viable replacement. Reviewed by: emaste Differential Revision: https://reviews.freebsd.org/D8879 MFC r312855 (by emaste): Rename LLD_AS_LD to LLD_IS_LD, for consistency with CLANG_IS_CC Reported by: Dan McGregor <dan.mcgregor usask.ca> MFC r313559 | glebius | 2017-02-10 18:34:48 +0100 (Fri, 10 Feb 2017) | 5 lines Don't check struct rtentry on FreeBSD, it is an internal kernel structure. On other systems it may be API structure for SIOCADDRT/SIOCDELRT. Reviewed by: emaste, dim MFC r314152 (by jkim): Remove an assembler flag, which is redundant since r309124. The upstream took care of it by introducing a macro NO_EXEC_STACK_DIRECTIVE. http://llvm.org/viewvc/llvm-project?rev=273500&view=rev Reviewed by: dim MFC r314564: Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 (branches/release_40 296509). The release will follow soon. Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11 support to build; see UPDATING for more information. Also note that as of 4.0.0, lld should be able to link the base system on amd64 and aarch64. See the WITH_LLD_IS_LLD setting in src.conf(5). Though please be aware that this is work in progress. Release notes for llvm, clang and lld will be available here: <http://releases.llvm.org/4.0.0/docs/ReleaseNotes.html> <http://releases.llvm.org/4.0.0/tools/clang/docs/ReleaseNotes.html> <http://releases.llvm.org/4.0.0/tools/lld/docs/ReleaseNotes.html> Thanks to Ed Maste, Jan Beich, Antoine Brodin and Eric Fiselier for their help. Relnotes: yes Exp-run: antoine PR: 215969, 216008 MFC r314708: For now, revert r287232 from upstream llvm trunk (by Daniil Fukalov): [SCEV] limit recursion depth of CompareSCEVComplexity Summary: CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled loop) and runs almost infinite time. Added cache of "equal" SCEV pairs to earlier cutoff of further estimation. Recursion depth limit was also introduced as a parameter. Reviewers: sanjoy Subscribers: mzolotukhin, tstellarAMD, llvm-commits Differential Revision: https://reviews.llvm.org/D26389 This commit is the cause of excessive compile times on skein_block.c (and possibly other files) during kernel builds on amd64. We never saw the problematic behavior described in this upstream commit, so for now it is better to revert it. An upstream bug has been filed here: https://bugs.llvm.org/show_bug.cgi?id=32142 Reported by: mjg MFC r314795: Reapply r287232 from upstream llvm trunk (by Daniil Fukalov): [SCEV] limit recursion depth of CompareSCEVComplexity Summary: CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled loop) and runs almost infinite time. Added cache of "equal" SCEV pairs to earlier cutoff of further estimation. Recursion depth limit was also introduced as a parameter. Reviewers: sanjoy Subscribers: mzolotukhin, tstellarAMD, llvm-commits Differential Revision: https://reviews.llvm.org/D26389 Pull in r296992 from upstream llvm trunk (by Sanjoy Das): [SCEV] Decrease the recursion threshold for CompareValueComplexity Fixes PR32142. r287232 accidentally increased the recursion threshold for CompareValueComplexity from 2 to 32. This change reverses that change by introducing a separate flag for CompareValueComplexity's threshold. The latter revision fixes the excessive compile times for skein_block.c. MFC r314907 | mmel | 2017-03-08 12:40:27 +0100 (Wed, 08 Mar 2017) | 7 lines Unbreak ARMv6 world. The new compiler_rt library imported with clang 4.0.0 have several fatal issues (non-functional __udivsi3 for example) with ARM specific instrict functions. As temporary workaround, until upstream solve these problems, disable all thumb[1][2] related feature. MFC r315016: Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release. We were already very close to the last release candidate, so this is a pretty minor update. Relnotes: yes MFC r316005: Revert r314907, and pull in r298713 from upstream compiler-rt trunk (by Weiming Zhao): builtins: Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA. Summary: Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation mode (-mthumb, -marm), it reflect's capability of given CPU. Due to this: - use __tbumb__ and __thumb2__ insteand of __ARM_ARCH_ISA_THUMB - use '.thumb' directive consistently in all affected files - decorate all thumb functions using DEFINE_COMPILERRT_THUMB_FUNCTION() --------- Note: This patch doesn't fix broken Thumb1 variant of __udivsi3 ! Reviewers: weimingz, rengolin, compnerd Subscribers: aemerson, dim Differential Revision: https://reviews.llvm.org/D30938 Discussed with: mmel
Diffstat (limited to 'contrib/llvm/tools/lld/ELF')
-rw-r--r--contrib/llvm/tools/lld/ELF/CMakeLists.txt17
-rw-r--r--contrib/llvm/tools/lld/ELF/Config.h68
-rw-r--r--contrib/llvm/tools/lld/ELF/Driver.cpp573
-rw-r--r--contrib/llvm/tools/lld/ELF/Driver.h53
-rw-r--r--contrib/llvm/tools/lld/ELF/DriverUtils.cpp224
-rw-r--r--contrib/llvm/tools/lld/ELF/EhFrame.cpp146
-rw-r--r--contrib/llvm/tools/lld/ELF/EhFrame.h8
-rw-r--r--contrib/llvm/tools/lld/ELF/Error.cpp93
-rw-r--r--contrib/llvm/tools/lld/ELF/Error.h41
-rw-r--r--contrib/llvm/tools/lld/ELF/GdbIndex.cpp205
-rw-r--r--contrib/llvm/tools/lld/ELF/GdbIndex.h99
-rw-r--r--contrib/llvm/tools/lld/ELF/ICF.cpp508
-rw-r--r--contrib/llvm/tools/lld/ELF/InputFiles.cpp781
-rw-r--r--contrib/llvm/tools/lld/ELF/InputFiles.h144
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.cpp641
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.h290
-rw-r--r--contrib/llvm/tools/lld/ELF/LTO.cpp383
-rw-r--r--contrib/llvm/tools/lld/ELF/LTO.h26
-rw-r--r--contrib/llvm/tools/lld/ELF/LinkerScript.cpp2046
-rw-r--r--contrib/llvm/tools/lld/ELF/LinkerScript.h275
-rw-r--r--contrib/llvm/tools/lld/ELF/MarkLive.cpp150
-rw-r--r--contrib/llvm/tools/lld/ELF/Memory.h67
-rw-r--r--contrib/llvm/tools/lld/ELF/Mips.cpp369
-rw-r--r--contrib/llvm/tools/lld/ELF/Options.td124
-rw-r--r--contrib/llvm/tools/lld/ELF/OutputSections.cpp1873
-rw-r--r--contrib/llvm/tools/lld/ELF/OutputSections.h682
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.cpp529
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.h49
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptParser.cpp133
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptParser.h24
-rw-r--r--contrib/llvm/tools/lld/ELF/Strings.cpp80
-rw-r--r--contrib/llvm/tools/lld/ELF/Strings.h65
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolListFile.cpp168
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolListFile.h27
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolTable.cpp571
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolTable.h92
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.cpp215
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.h176
-rw-r--r--contrib/llvm/tools/lld/ELF/SyntheticSections.cpp2004
-rw-r--r--contrib/llvm/tools/lld/ELF/SyntheticSections.h750
-rw-r--r--contrib/llvm/tools/lld/ELF/Target.cpp633
-rw-r--r--contrib/llvm/tools/lld/ELF/Target.h21
-rw-r--r--contrib/llvm/tools/lld/ELF/Threads.h90
-rw-r--r--contrib/llvm/tools/lld/ELF/Thunks.cpp39
-rw-r--r--contrib/llvm/tools/lld/ELF/Writer.cpp1800
-rw-r--r--contrib/llvm/tools/lld/ELF/Writer.h48
46 files changed, 11182 insertions, 6218 deletions
diff --git a/contrib/llvm/tools/lld/ELF/CMakeLists.txt b/contrib/llvm/tools/lld/ELF/CMakeLists.txt
index a1b65ad..2e9d2b9 100644
--- a/contrib/llvm/tools/lld/ELF/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/Config.h b/contrib/llvm/tools/lld/ELF/Config.h
index 2ccd95e..b770620 100644
--- a/contrib/llvm/tools/lld/ELF/Config.h
+++ b/contrib/llvm/tools/lld/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,93 @@ 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 DefineCommon;
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/contrib/llvm/tools/lld/ELF/Driver.cpp b/contrib/llvm/tools/lld/ELF/Driver.cpp
index c6ca263..50b7011 100644
--- a/contrib/llvm/tools/lld/ELF/Driver.cpp
+++ b/contrib/llvm/tools/lld/ELF/Driver.cpp
@@ -14,14 +14,20 @@
#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/Object/Decompressor.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
@@ -38,48 +44,60 @@ 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];
+ Tar = nullptr;
- 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 +105,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 +135,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,35 +167,18 @@ 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) {
- auto MBOrErr = MemoryBuffer::getFile(Path);
- if (auto EC = MBOrErr.getError()) {
- error(EC, "cannot open " + Path);
- return None;
- }
- std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
- MemoryBufferRef MBRef = MB->getMemBufferRef();
- OwningMBs.push_back(std::move(MB)); // take MB ownership
-
- if (Cpio)
- Cpio->append(relativeToRoot(Path), MBRef.getBuffer());
-
- return MBRef;
-}
-
// Add a given library by searching it from input search paths.
void LinkerDriver::addLibrary(StringRef Name) {
- std::string Path = searchLibrary(Name);
- if (Path.empty())
- error("unable to find library -l" + Name);
+ 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 +191,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 +207,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 +222,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 +252,67 @@ 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) {
- Cpio->append("response.txt", createResponseFile(Args));
- Cpio->append("version.txt", getVersionString());
+ Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
+ TarWriter::create(Path, path::stem(Path));
+ if (ErrOrWriter) {
+ Tar = ErrOrWriter->get();
+ Tar->append("response.txt", createResponseFile(Args));
+ Tar->append("version.txt", getLLDVersion() + "\n");
+ make<std::unique_ptr<TarWriter>>(std::move(*ErrOrWriter));
+ } else {
+ error(Twine("--reproduce: failed to open ") + Path + ": " +
+ toString(ErrOrWriter.takeError()));
}
}
readConfigs(Args);
initLLVM(Args);
createFiles(Args);
+ inferMachineType();
checkOptions(Args);
- if (HasError)
+ if (ErrorCount)
return;
switch (Config->EKind) {
@@ -297,7 +329,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 +346,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: " + toString(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 +471,39 @@ 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->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
+ !Config->Relocatable);
+ Config->Discard = getDiscardOption(Args);
Config->SaveTemps = Args.hasArg(OPT_save_temps);
+ Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
Config->Shared = Args.hasArg(OPT_shared);
- Config->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 +512,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 +570,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 +589,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 +649,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 +673,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 +687,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 +743,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 +814,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 (Decompressor::isCompressedELFSection(S->Flags, S->Name))
+ 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/contrib/llvm/tools/lld/ELF/Driver.h b/contrib/llvm/tools/lld/ELF/Driver.h
index dc20961..b600fae 100644
--- a/contrib/llvm/tools/lld/ELF/Driver.h
+++ b/contrib/llvm/tools/lld/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,32 +24,29 @@ 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:
std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB);
- 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 +54,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 +64,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/contrib/llvm/tools/lld/ELF/DriverUtils.cpp b/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
index 274c08b..ae76958 100644
--- a/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
+++ b/contrib/llvm/tools/lld/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 "ELF/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,51 +142,49 @@ 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";
+ OS << toString(Arg) << "\n";
}
}
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/contrib/llvm/tools/lld/ELF/EhFrame.cpp b/contrib/llvm/tools/lld/ELF/EhFrame.cpp
index 1f3d928..2428473 100644
--- a/contrib/llvm/tools/lld/ELF/EhFrame.cpp
+++ b/contrib/llvm/tools/lld/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,78 +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();
- // Skip code alignment factor.
- skipLeb128(D);
-
- // 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/contrib/llvm/tools/lld/ELF/EhFrame.h b/contrib/llvm/tools/lld/ELF/EhFrame.h
index 0d5a2ff..cadc93d 100644
--- a/contrib/llvm/tools/lld/ELF/EhFrame.h
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/Error.cpp b/contrib/llvm/tools/lld/ELF/Error.cpp
index 59a49c1..d9b41f9 100644
--- a/contrib/llvm/tools/lld/ELF/Error.cpp
+++ b/contrib/llvm/tools/lld/ELF/Error.cpp
@@ -12,54 +12,99 @@
#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();
+
+ outs().flush();
+ errs().flush();
+ _exit(Val);
}
-void fatal(const Twine &Msg, const Twine &Prefix) {
- fatal(Prefix + ": " + Msg);
+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(std::error_code EC) {
- if (EC)
- fatal(EC.message());
+void elf::fatal(std::error_code EC, const Twine &Prefix) {
+ fatal(Prefix + ": " + EC.message());
}
-void check(Error Err) {
- check(errorToErrorCode(std::move(Err)));
+void elf::fatal(Error &E, const Twine &Prefix) {
+ fatal(Prefix + ": " + llvm::toString(std::move(E)));
}
-} // namespace elf
} // namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/Error.h b/contrib/llvm/tools/lld/ELF/Error.h
index 552f504..f18cf45 100644
--- a/contrib/llvm/tools/lld/ELF/Error.h
+++ b/contrib/llvm/tools/lld/ELF/Error.h
@@ -6,31 +6,48 @@
// 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);
+LLVM_ATTRIBUTE_NORETURN void fatal(Error &E, 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 +56,19 @@ template <class T> T check(ErrorOr<T> E) {
template <class T> T check(Expected<T> E) {
if (!E)
- fatal(errorToErrorCode(E.takeError()).message());
+ fatal(llvm::toString(E.takeError()));
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/contrib/llvm/tools/lld/ELF/GdbIndex.cpp b/contrib/llvm/tools/lld/ELF/GdbIndex.cpp
new file mode 100644
index 0000000..762144d
--- /dev/null
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/GdbIndex.h b/contrib/llvm/tools/lld/ELF/GdbIndex.h
new file mode 100644
index 0000000..c761ea1
--- /dev/null
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/ICF.cpp b/contrib/llvm/tools/lld/ELF/ICF.cpp
index 10a2603..32cd0f8 100644
--- a/contrib/llvm/tools/lld/ELF/ICF.cpp
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/InputFiles.cpp b/contrib/llvm/tools/lld/ELF/InputFiles.cpp
index 426d9c3..f3afb1c 100644
--- a/contrib/llvm/tools/lld/ELF/InputFiles.cpp
+++ b/contrib/llvm/tools/lld/ELF/InputFiles.cpp
@@ -8,17 +8,24 @@
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
-#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/TarWriter.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -29,8 +36,87 @@ using namespace llvm::sys::fs;
using namespace lld;
using namespace lld::elf;
+TarWriter *elf::Tar;
+
+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>();
+ }
+};
+}
+
+Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
+ if (Config->Verbose)
+ outs() << Path << "\n";
+
+ auto MBOrErr = MemoryBuffer::getFile(Path);
+ if (auto EC = MBOrErr.getError()) {
+ error(EC, "cannot open " + Path);
+ return None;
+ }
+ std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
+ MemoryBufferRef MBRef = MB->getMemBufferRef();
+ make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
+
+ if (Tar)
+ Tar->append(relativeToRoot(Path), MBRef.getBuffer());
+ return MBRef;
+}
+
+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 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 lld::toString(const InputFile *F) {
if (!F)
return "(internal)";
if (!F->ArchiveName.empty())
@@ -38,15 +124,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 +131,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 +164,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 +192,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 +221,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 +269,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 +333,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 +343,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 +415,31 @@ 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 linkonce feature is a sort of proto-comdat. Some glibc i386 object
+ // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce
+ // sections. Drop those sections to avoid duplicate symbol errors.
+ // FIXME: This is glibc PR20543, we should remove this hack once that has been
+ // fixed for a while.
+ if (Name.startswith(".gnu.linkonce."))
+ return &InputSection<ELFT>::Discarded;
// 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 +447,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 +472,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<ELFT>(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 +499,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,24 +538,25 @@ 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(),
"could not get the buffer for the member defining symbol " +
Sym->getName());
- if (C.getParent()->isThin() && Driver->Cpio)
- Driver->Cpio->append(relativeToRoot(check(C.getFullName())),
- Ret.getBuffer());
-
- return Ret;
+ if (C.getParent()->isThin() && Tar)
+ Tar->append(relativeToRoot(check(C.getFullName())), Ret.getBuffer());
+ if (C.getParent()->isThin())
+ return {Ret, 0};
+ return {Ret, C.getChildOffset()};
}
template <class ELFT>
@@ -423,32 +566,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 +599,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 +639,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 +652,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,13 +671,15 @@ 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) {
VersymIndex = Versym->vs_index;
++Versym;
}
+ bool Hidden = VersymIndex & VERSYM_HIDDEN;
+ VersymIndex = VersymIndex & ~VERSYM_HIDDEN;
StringRef Name = check(Sym.getName(this->StringTable));
if (Sym.isUndefined()) {
@@ -540,30 +687,36 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
continue;
}
- if (Versym) {
- // Ignore local symbols and non-default versions.
- if (VersymIndex == VER_NDX_LOCAL || (VersymIndex & VERSYM_HIDDEN))
- continue;
- }
+ // Ignore local symbols.
+ if (Versym && VersymIndex == VER_NDX_LOCAL)
+ continue;
const Elf_Verdef *V =
VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex];
- elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
+
+ if (!Hidden)
+ elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
+
+ // Also add the symbol with the versioned name to handle undefined symbols
+ // with explicit versions.
+ if (V) {
+ StringRef VerName = this->StringTable.data() + V->getAux()->vda_name;
+ Name = Saver.save(Twine(Name) + "@" + VerName);
+ elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
+ }
}
}
-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 +731,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 +758,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;
+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);
- if (GV)
- if (const Comdat *C = GV->getComdat())
- if (!KeptComdats.count(C))
- return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
- CanOmitFromDynSym, this);
-
- const Module &M = Obj.getModule();
if (Flags & BasicSymbolRef::SF_Undefined)
- return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
- CanOmitFromDynSym, this);
- if (Flags & BasicSymbolRef::SF_Common) {
- // FIXME: Set SF_Common flag correctly for module asm symbols, and expose
- // size and alignment.
- assert(GV);
- const DataLayout &DL = M.getDataLayout();
- uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
- return Symtab<ELFT>::X->addCommon(NameRef, Size, GV->getAlignment(),
- Binding, Visibility, STT_OBJECT, this);
- }
- return Symtab<ELFT>::X->addBitcode(NameRef, IsWeak, Visibility, Type,
- CanOmitFromDynSym, this);
-}
+ return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
+ Visibility, Type, CanOmitFromDynSym,
+ F);
-bool BitcodeFile::shouldSkip(uint32_t Flags) {
- return !(Flags & BasicSymbolRef::SF_Global) ||
- (Flags & BasicSymbolRef::SF_FormatSpecific);
+ if (Flags & BasicSymbolRef::SF_Common)
+ return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(),
+ ObjSym.getCommonAlignment(), Binding,
+ Visibility, STT_OBJECT, F);
+
+ 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 | SHF_WRITE, 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 +896,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 +906,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 +924,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 +955,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 +979,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/contrib/llvm/tools/lld/ELF/InputFiles.h b/contrib/llvm/tools/lld/ELF/InputFiles.h
index 79cb751..9588806 100644
--- a/contrib/llvm/tools/lld/ELF/InputFiles.h
+++ b/contrib/llvm/tools/lld/ELF/InputFiles.h
@@ -16,25 +16,47 @@
#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;
+class TarWriter;
+namespace lto {
+class InputFile;
+}
+}
+
namespace lld {
namespace elf {
+class InputFile;
+}
+
+// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
+std::string toString(const elf::InputFile *F);
+
+namespace elf {
using llvm::object::Archive;
-class InputFile;
class Lazy;
class SymbolBody;
+// If -reproduce option is given, all input files are written
+// to this tar archive.
+extern llvm::TarWriter *Tar;
+
+// Opens a given file.
+llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
+
// The root class of input files.
class InputFile {
public:
@@ -44,6 +66,7 @@ public:
LazyObjectKind,
ArchiveKind,
BitcodeKind,
+ BinaryKind,
};
Kind kind() const { return FileKind; }
@@ -56,10 +79,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) {}
@@ -68,9 +98,6 @@ private:
const Kind FileKind;
};
-// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
-std::string getFilename(const InputFile *F);
-
template <typename ELFT> class ELFFileBase : public InputFile {
public:
typedef typename ELFT::Shdr Elf_Shdr;
@@ -84,37 +111,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 +154,45 @@ 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 +203,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 +233,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 +243,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 +259,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 +317,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/contrib/llvm/tools/lld/ELF/InputSection.cpp b/contrib/llvm/tools/lld/ELF/InputSection.cpp
index 6564e79..6b1e928 100644
--- a/contrib/llvm/tools/lld/ELF/InputSection.cpp
+++ b/contrib/llvm/tools/lld/ELF/InputSection.cpp
@@ -13,103 +13,138 @@
#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/Object/Decompressor.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 lld::toString(const InputSectionBase<ELFT> *Sec) {
+ // File can be absent if section is synthetic.
+ std::string FileName =
+ Sec->getFile() ? Sec->getFile()->getName() : "<internal>";
+ return (FileName + ":(" + 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));
-}
-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));
+ return Data.size();
}
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");
}
+// 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("build lld with zlib to enable compressed sections support");
-
- // A compressed section consists of a header of Elf_Chdr type
- // followed by compressed data.
- ArrayRef<uint8_t> Data =
- check(this->File->getObj().getSectionContents(this->Header));
- if (Data.size() < sizeof(Elf_Chdr))
- fatal("corrupt compressed section");
-
- auto *Hdr = reinterpret_cast<const Elf_Chdr *>(Data.data());
- Data = Data.slice(sizeof(Elf_Chdr));
-
- if (Hdr->ch_type != ELFCOMPRESS_ZLIB)
- fatal("unsupported compression type");
+ Decompressor Decompressor = check(Decompressor::create(
+ Name, toStringRef(Data), ELFT::TargetEndianness == llvm::support::little,
+ ELFT::Is64Bits));
+
+ size_t Size = Decompressor.getDecompressedSize();
+ char *OutputBuf;
+ {
+ static std::mutex Mu;
+ std::lock_guard<std::mutex> Lock(Mu);
+ OutputBuf = BAlloc.Allocate<char>(Size);
+ }
- StringRef Buf((const char *)Data.data(), Data.size());
- if (zlib::uncompress(Buf, Uncompressed, Hdr->ch_size) != zlib::StatusOK)
- fatal("error uncompressing section");
+ if (Error E = Decompressor.decompress({OutputBuf, Size}))
+ fatal(E, toString(this));
+ Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size);
}
template <class ELFT>
@@ -119,29 +154,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 +240,63 @@ 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);
+ P->setSymbolAndType(In<ELFT>::SymTab->getSymbolIndex(&Body), 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 +305,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 +322,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 +339,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 +370,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 +400,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 +409,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 +438,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 +448,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 +467,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;
- ELFFile<ELFT> &EObj = this->File->getObj();
+
+ if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this)) {
+ S->writeTo(Buf + OutSecOff);
+ return;
+ }
// 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 +569,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 +579,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 +634,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 +650,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 +751,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 +786,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 +796,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 lld::toString(const InputSectionBase<ELF32LE> *);
+template std::string lld::toString(const InputSectionBase<ELF32BE> *);
+template std::string lld::toString(const InputSectionBase<ELF64LE> *);
+template std::string lld::toString(const InputSectionBase<ELF64BE> *);
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.h b/contrib/llvm/tools/lld/ELF/InputSection.h
index 61a89c54..3f3a055 100644
--- a/contrib/llvm/tools/lld/ELF/InputSection.h
+++ b/contrib/llvm/tools/lld/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,153 @@ 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;
-
void uncompress();
- void relocate(uint8_t *Buf, uint8_t *BufEnd);
- std::vector<Relocation<ELFT>> Relocations;
+ // Returns a source location string. Used to construct an error message.
+ std::string getLocation(uintX_t Offset);
- bool Compressed;
+ void relocate(uint8_t *Buf, uint8_t *BufEnd);
};
-template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;
-
// 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,48 +294,23 @@ 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>
-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> InputSection<ELFT> InputSection<ELFT>::Discarded;
} // namespace elf
+
+template <class ELFT> std::string toString(const elf::InputSectionBase<ELFT> *);
} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/LTO.cpp b/contrib/llvm/tools/lld/ELF/LTO.cpp
index 0e8006a..b342b61 100644
--- a/contrib/llvm/tools/lld/ELF/LTO.cpp
+++ b/contrib/llvm/tools/lld/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,115 @@ 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);
+static void checkError(Error E) {
+ handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
+ error(EIB.message());
+ return Error::success();
+ });
+}
- ModulePassManager MPM;
- if (!Config->DisableVerify)
- MPM.addPass(VerifierPass());
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config Conf;
- // 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;
- }
+ // LLD supports the new relocations.
+ Conf.Options = InitTargetOptionsFromCodeGenFlags();
+ Conf.Options.RelaxELFRelocations = true;
- if (!Config->DisableVerify)
- MPM.addPass(VerifierPass());
- MPM.run(M, MAM);
-}
+ Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static;
+ Conf.DisableVerify = Config->DisableVerify;
+ Conf.DiagHandler = diagnosticHandler;
+ Conf.OptLevel = Config->LTOO;
-static void runOldLtoPasses(Module &M, TargetMachine &TM) {
- // Note that the gold plugin has a similar piece of code, so
- // it is probably better to move this code to a common place.
- legacy::PassManager LtoPasses;
- LtoPasses.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
- PassManagerBuilder PMB;
- PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple()));
- PMB.Inliner = createFunctionInliningPass();
- PMB.VerifyInput = PMB.VerifyOutput = !Config->DisableVerify;
- PMB.LoopVectorize = true;
- PMB.SLPVectorize = true;
- PMB.OptLevel = Config->LtoO;
- PMB.populateLTOPassManager(LtoPasses);
- LtoPasses.run(M);
-}
-
-static void runLTOPasses(Module &M, TargetMachine &TM) {
- if (!Config->LtoNewPmPasses.empty()) {
- // The user explicitly asked for a set of passes to be run.
- // This needs the new PM to work as there's no clean way to
- // pass a set of passes to run in the legacy PM.
- runNewCustomLtoPasses(M, TM);
- if (HasError)
- return;
- } else {
- // Run the 'default' set of LTO passes. This code still uses
- // the legacy PM as the new one is not the default.
- runOldLtoPasses(M, TM);
- }
+ // 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");
-}
-
-static bool shouldInternalize(const SmallPtrSet<GlobalValue *, 8> &Used,
- Symbol *S, GlobalValue *GV) {
- if (S->IsUsedInRegularObj || Used.count(GV))
- return false;
- return !S->includeInDynsym();
+ 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);
}
-BitcodeCompiler::BitcodeCompiler()
- : Combined(new Module("ld-temp.o", Driver->Context)) {}
+BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
-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;
+BitcodeCompiler::~BitcodeCompiler() = default;
- // 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());
+template <class ELFT> static void undefine(Symbol *S) {
+ replaceBody<Undefined<ELFT>>(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());
- });
+template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
+ 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<ELFT>(Sym);
}
+ checkError(LTOObj->add(std::move(F.Obj), Resols));
}
-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");
+// Merge all the bitcode files we have seen, codegen the result
+// 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);
}
-
- return ObjFiles;
+ return Ret;
}
-// Merge all the bitcode files we have seen, codegen the result
-// and return the resulting ObjectFile.
-std::vector<std::unique_ptr<InputFile>> BitcodeCompiler::compile() {
- for (const auto &Name : InternalizedSyms) {
- GlobalValue *GV = Combined->getNamedValue(Name.first());
- assert(GV);
- internalize(*GV);
- }
-
- std::string TheTriple = Combined->getTargetTriple();
- std::string Msg;
- const Target *T = TargetRegistry::lookupTarget(TheTriple, Msg);
- if (!T)
- fatal("target not found: " + Msg);
-
- // LLD supports the new relocations.
- TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
- Options.RelaxELFRelocations = true;
-
- auto CreateTargetMachine = [&]() {
- return std::unique_ptr<TargetMachine>(T->createTargetMachine(
- TheTriple, "", "", Options, Config->Pic ? Reloc::PIC_ : Reloc::Static));
- };
-
- std::unique_ptr<TargetMachine> TM = CreateTargetMachine();
-
- // Update llvm.compiler.used so that optimizations won't strip
- // off AsmUndefinedReferences.
- updateCompilerUsed(*Combined, *TM, AsmUndefinedRefs);
-
- if (Config->SaveTemps)
- saveBCFile(*Combined, Config->OutputFile + ".lto.bc");
-
- runLTOPasses(*Combined, *TM);
- if (HasError)
- return {};
-
- return runSplitCodegen(CreateTargetMachine);
-}
+template void BitcodeCompiler::template add<ELF32LE>(BitcodeFile &);
+template void BitcodeCompiler::template add<ELF32BE>(BitcodeFile &);
+template void BitcodeCompiler::template add<ELF64LE>(BitcodeFile &);
+template void BitcodeCompiler::template add<ELF64BE>(BitcodeFile &);
diff --git a/contrib/llvm/tools/lld/ELF/LTO.h b/contrib/llvm/tools/lld/ELF/LTO.h
index 81dffb6..3cb7636 100644
--- a/contrib/llvm/tools/lld/ELF/LTO.h
+++ b/contrib/llvm/tools/lld/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();
- void add(BitcodeFile &F);
- std::vector<std::unique_ptr<InputFile>> compile();
+ ~BitcodeCompiler();
-private:
- std::vector<std::unique_ptr<InputFile>> runSplitCodegen(
- const std::function<std::unique_ptr<llvm::TargetMachine>()> &TMFactory);
+ template <class ELFT> void add(BitcodeFile &F);
+ std::vector<InputFile *> compile();
- std::unique_ptr<llvm::Module> Combined;
- std::vector<SmallString<0>> OwningData;
- llvm::StringSet<> InternalizedSyms;
- llvm::StringSet<> AsmUndefinedRefs;
+private:
+ std::unique_ptr<llvm::lto::LTO> LTOObj;
+ std::vector<SmallString<0>> Buff;
};
}
}
diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
index 61abdc1..3cc2353 100644
--- a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
+++ b/contrib/llvm/tools/lld/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,953 @@
#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 SymbolBody *addRegular(SymbolAssignment *Cmd) {
+ uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+ Symbol *Sym = Symtab<ELFT>::X->addUndefined(
+ Cmd->Name, /*IsLocal=*/false, STB_GLOBAL, Visibility,
+ /*Type*/ 0,
+ /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
- uint64_t run();
+ replaceBody<DefinedRegular<ELFT>>(Sym, Cmd->Name, /*IsLocal=*/false,
+ Visibility, STT_NOTYPE, 0, 0, nullptr,
+ nullptr);
+ return Sym->body();
+}
-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 SymbolBody *addSynthetic(SymbolAssignment *Cmd) {
+ uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+ const OutputSectionBase *Sec =
+ ScriptConfig->HasSections ? nullptr : Cmd->Expression.Section();
+ Symbol *Sym = Symtab<ELFT>::X->addUndefined(
+ Cmd->Name, /*IsLocal=*/false, STB_GLOBAL, Visibility,
+ /*Type*/ 0,
+ /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
- uint64_t Dot;
-};
+ replaceBody<DefinedSynthetic>(Sym, Cmd->Name, 0, Sec);
+ return Sym->body();
}
-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 assignSymbol(SymbolAssignment *Cmd) {
+ // If there are sections, then let the value be assigned later in
+ // `assignAddresses`.
+ if (ScriptConfig->HasSections)
+ return;
+
+ uint64_t Value = Cmd->Expression(0);
+ if (Cmd->Expression.IsAbsolute()) {
+ cast<DefinedRegular<ELFT>>(Cmd->Sym)->Value = Value;
+ } else {
+ const OutputSectionBase *Sec = Cmd->Expression.Section();
+ if (Sec)
+ cast<DefinedSynthetic>(Cmd->Sym)->Value = Value - Sec->Addr;
+ }
}
-uint64_t ExprParser::run() {
- uint64_t V = parseExpr();
- if (!atEOF() && !Error)
- setError("stray token: " + peek());
- return V;
+template <class ELFT> static void addSymbol(SymbolAssignment *Cmd) {
+ if (Cmd->Name == ".")
+ return;
+
+ // If a symbol was in PROVIDE(), we need to define it only when
+ // it is a referenced undefined symbol.
+ SymbolBody *B = Symtab<ELFT>::X->find(Cmd->Name);
+ if (Cmd->Provide && (!B || B->isDefined()))
+ return;
+
+ // Otherwise, create a new symbol if one does not exist or an
+ // undefined one does exist.
+ if (Cmd->Expression.IsAbsolute())
+ Cmd->Sym = addRegular<ELFT>(Cmd);
+ else
+ Cmd->Sym = addSynthetic<ELFT>(Cmd);
+ assignSymbol<ELFT>(Cmd);
}
-// 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);
+bool SymbolAssignment::classof(const BaseCommand *C) {
+ return C->Kind == AssignmentKind;
+}
+
+bool OutputSectionCommand::classof(const BaseCommand *C) {
+ return C->Kind == OutputSectionKind;
+}
+
+bool InputSectionDescription::classof(const BaseCommand *C) {
+ return C->Kind == InputSectionKind;
+}
+
+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");
}
- uint64_t V = 0;
- if (Tok.getAsInteger(0, V))
- setError("malformed number: " + Tok);
- return V;
}
-uint64_t ExprParser::parseTernary(uint64_t Cond) {
- next();
- uint64_t V = parseExpr();
- expect(":");
- uint64_t W = parseExpr();
- return Cond ? V : W;
+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);
}
-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;
+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;
+ }
+
+ // 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 L / R;
}
- if (Op == "+")
- return L + R;
- if (Op == "-")
- return L - R;
- if (Op == "<")
- return L < R;
- if (Op == ">")
- return L > R;
- if (Op == ">=")
- return L >= R;
- if (Op == "<=")
- return L <= R;
- if (Op == "==")
- return L == R;
- if (Op == "!=")
- return L != R;
- if (Op == "&")
- return L & R;
- llvm_unreachable("invalid operator");
}
-// 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>
+void LinkerScript<ELFT>::discard(ArrayRef<InputSectionBase<ELFT> *> V) {
+ for (InputSectionBase<ELFT> *S : V) {
+ S->Live = false;
+ reportDiscarded(S);
+ }
+}
- // 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));
+template <class ELFT>
+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>
+void LinkerScript<ELFT>::addSection(OutputSectionFactory<ELFT> &Factory,
+ InputSectionBase<ELFT> *Sec,
+ StringRef Name) {
+ OutputSectionBase *OutSec;
+ bool IsNew;
+ std::tie(OutSec, IsNew) = Factory.create(Sec, Name);
+ if (IsNew)
+ OutputSections->push_back(OutSec);
+ OutSec->addSection(Sec);
+}
+
+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;
+
+ // Handle symbol assignments outside of any output section.
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base1.get())) {
+ addSymbol<ELFT>(Cmd);
+ continue;
}
- Lhs = apply(Op1, Lhs, Rhs);
+ 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;
+ }
+
+ 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;
+ }
+
+ // 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;
+ }
+
+ // 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()))
+ 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);
+ }
}
- return Lhs;
}
-// Reads and evaluates an arithmetic expression.
-uint64_t ExprParser::parseExpr() { return parseExpr1(parsePrimary(), 0); }
+// 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>
-StringRef LinkerScript<ELFT>::getOutputSection(InputSectionBase<ELFT> *S) {
- for (SectionRule &R : Opt.Sections)
- if (globMatch(R.SectionPattern, S->getSectionName()))
- return R.Dest;
- return "";
+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>
-bool LinkerScript<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) {
- return getOutputSection(S) == "/DISCARD/";
+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>
-bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
- for (StringRef Pat : Opt.KeptSections)
- if (globMatch(Pat, S->getSectionName()))
- return true;
- return false;
+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>::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>::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);
}
+}
- // 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>::adjustSectionsAfterSorting() {
+ placeOrphanSections();
- for (SectionsCommand &Cmd : Opt.Commands) {
- if (Cmd.Kind == AssignmentKind) {
- uint64_t Val = evalExpr(Cmd.Expr, Dot);
+ // 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);
- if (Cmd.Name == ".") {
- Dot = Val;
- } else {
- auto *D = cast<DefinedRegular<ELFT>>(Symtab<ELFT>::X->find(Cmd.Name));
- D->Value = Val;
- }
+ // 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;
}
- // Find all the sections with required name. There can be more than
- // ont section with such name, if the alignment, flags or type
- // attribute differs.
- assert(Cmd.Kind == SectionKind);
- for (OutputSectionBase<ELFT> *Sec : Sections) {
- if (Sec->getName() != Cmd.Name)
- continue;
+ 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;
+ }
- if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) {
- uintX_t TVA = Dot + ThreadBssOffset;
- TVA = alignTo(TVA, Sec->getAlignment());
- Sec->setVA(TVA);
- ThreadBssOffset = TVA - Dot + Sec->getSize();
- continue;
- }
+ // Continue from where we found it.
+ CmdIndex = (Pos - Opt.Commands.begin()) + 1;
+ }
+}
- if (Sec->getFlags() & SHF_ALLOC) {
- Dot = alignTo(Dot, Sec->getAlignment());
- Sec->setVA(Dot);
- MinVA = std::min(MinVA, Dot);
- Dot += Sec->getSize();
- continue;
+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;
}
-// A compartor to sort output sections. Returns -1 or 1 if
-// A or B are mentioned in linker script. Otherwise, returns 0.
+// 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>
-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>::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>();
+}
+
+template <class ELFT>
+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];
+ }
+
+ return SymbolTableSection<ELFT>::getOutputSection(Sym);
+}
+
+// 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 {};
}
-class elf::ScriptParser : public ScriptParserBase {
+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 +971,131 @@ 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();
+
+ 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();
- void readLocationCounterValue();
- void readOutputSectionDescription(StringRef OutSec);
- void readSymbolAssignment(StringRef Name);
- std::vector<StringRef> readSectionsCommandExpr();
+ 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();
+ void readLocals();
- 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 +1112,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 +1123,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 +1139,38 @@ 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();
- auto MBOrErr = MemoryBuffer::getFile(Tok);
- if (!MBOrErr) {
- setError("cannot open " + Tok);
+ 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.
+ if (sys::fs::exists(Tok)) {
+ if (Optional<MemoryBufferRef> MB = readFile(Tok))
+ tokenize(*MB);
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());
+ if (Optional<std::string> Path = findFromSearchPaths(Tok)) {
+ if (Optional<MemoryBufferRef> MB = readFile(*Path))
+ tokenize(*MB);
+ return;
+ }
+ setError("cannot open " + Tok);
}
void ScriptParser::readOutput() {
@@ -466,138 +1178,778 @@ 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;
}
-std::vector<StringRef> ScriptParser::readSectionsCommandExpr() {
- std::vector<StringRef> Expr;
- while (!Error) {
+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); }};
+}
+
+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();
+
+ readLocals();
+ expect("}");
+ expect(";");
+}
+
+void ScriptParser::readLocals() {
+ if (!consume("local:"))
+ return;
+ std::vector<SymbolVersion> Locals = readSymbols();
+ for (SymbolVersion V : Locals) {
+ if (V.Name == "*") {
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ continue;
+ }
+ Config->VersionScriptLocals.push_back(V);
+ }
+}
+
+// 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();
+
+ readLocals();
+ 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/contrib/llvm/tools/lld/ELF/LinkerScript.h b/contrib/llvm/tools/lld/ELF/LinkerScript.h
index 768f78a..505162f 100644
--- a/contrib/llvm/tools/lld/ELF/LinkerScript.h
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/MarkLive.cpp b/contrib/llvm/tools/lld/ELF/MarkLive.cpp
index 41e30ce..8d129fc 100644
--- a/contrib/llvm/tools/lld/ELF/MarkLive.cpp
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/Memory.h b/contrib/llvm/tools/lld/ELF/Memory.h
new file mode 100644
index 0000000..e5a04ed
--- /dev/null
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/Mips.cpp b/contrib/llvm/tools/lld/ELF/Mips.cpp
new file mode 100644
index 0000000..ac65672
--- /dev/null
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/Options.td b/contrib/llvm/tools/lld/ELF/Options.td
index 010f376..77ed4c7 100644
--- a/contrib/llvm/tools/lld/ELF/Options.td
+++ b/contrib/llvm/tools/lld/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,27 @@ 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 define_common: F<"define-common">,
+ HelpText<"Assign space to common symbols">;
+
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@@ -60,6 +77,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 +92,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 +113,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 +124,40 @@ 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_define_common: F<"no-define-common">,
+ HelpText<"Do not assign space to common symbols">;
+
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 +167,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 +185,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 +206,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 +232,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,40 +254,56 @@ 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>;
def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>;
def alias_Bstatic_static: F<"static">, Alias<Bstatic>;
def alias_L__library_path: J<"library-path=">, Alias<L>;
+def alias_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_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
def alias_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 +328,12 @@ def plugin_opt_eq: J<"plugin-opt=">;
// Options listed below are silently ignored for now for compatibility.
def allow_shlib_undefined: F<"allow-shlib-undefined">;
-def define_common: F<"define-common">;
+def cref: Flag<["--"], "cref">;
def demangle: F<"demangle">;
def detect_odr_violations: F<"detect-odr-violations">;
+def g: Flag<["-"], "g">;
+def M: Flag<["-"], "M">;
+def Map: JS<"Map">;
def no_add_needed: F<"no-add-needed">;
def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">,
@@ -254,23 +346,27 @@ 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/contrib/llvm/tools/lld/ELF/OutputSections.cpp b/contrib/llvm/tools/lld/ELF/OutputSections.cpp
index 50b9401..7c708ce 100644
--- a/contrib/llvm/tools/lld/ELF/OutputSections.cpp
+++ b/contrib/llvm/tools/lld/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();
-}
-
-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);
+ 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>::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 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>::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;
+ // 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;
}
- Buf += sizeof(Elf_Off) * MaskWords;
-}
-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;
- }
- 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,703 +467,227 @@ 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;
-}
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Builder.add(Sec->getData(I));
-template <class ELFT>
-VersionTableSection<ELFT>::VersionTableSection()
- : OutputSectionBase<ELFT>(".gnu.version", SHT_GNU_versym, SHF_ALLOC) {
- this->Header.sh_addralign = sizeof(uint16_t);
-}
+ // Fix the string table content. After this, the contents will never change.
+ Builder.finalize();
+ this->Size = Builder.getSize();
-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;
+ // finalize() fixed tail-optimized strings, so we can now get
+ // offsets of strings. Get an offset for each string and save it
+ // to a corresponding StringPiece for easy access.
+ for (MergeInputSection<ELFT> *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
}
-template <class ELFT>
-void BuildIdFnv1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
- const endianness E = ELFT::TargetEndianness;
-
- // 64-bit FNV-1 hash
- uint64_t Hash = 0xcbf29ce484222325;
- for (ArrayRef<uint8_t> Buf : Bufs) {
- for (uint8_t B : Buf) {
- Hash *= 0x100000001b3;
- Hash ^= B;
- }
- }
- write64<E>(this->HashBuf, Hash);
-}
+template <class ELFT> void 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 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);
+ Builder.finalizeInOrder();
+ this->Size = Builder.getSize();
}
-template <class ELFT>
-void BuildIdSha1<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
- SHA1 Hash;
- for (ArrayRef<uint8_t> Buf : Bufs)
- Hash.update(Buf);
- memcpy(this->HashBuf, Hash.final().data(), 20);
+template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
+ if (shouldTailMerge())
+ finalizeTailMerge();
+ else
+ finalizeNoTailMerge();
}
template <class ELFT>
-BuildIdHexstring<ELFT>::BuildIdHexstring()
- : BuildIdSection<ELFT>(Config->BuildIdVector.size()) {}
-
-template <class ELFT>
-void BuildIdHexstring<ELFT>::writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) {
- memcpy(this->HashBuf, Config->BuildIdVector.data(),
- Config->BuildIdVector.size());
+static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
+ return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
}
-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);
-}
+namespace llvm {
+template <> struct DenseMapInfo<lld::elf::SectionKey> {
+ static lld::elf::SectionKey getEmptyKey();
+ static lld::elf::SectionKey getTombstoneKey();
+ static unsigned getHashValue(const lld::elf::SectionKey &Val);
+ static bool isEqual(const lld::elf::SectionKey &LHS,
+ const lld::elf::SectionKey &RHS);
+};
+}
+
+template <class ELFT>
+static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
+ // The ELF spec just says
+ // ----------------------------------------------------------------
+ // In the first phase, input sections that match in name, type and
+ // attribute flags should be concatenated into single sections.
+ // ----------------------------------------------------------------
+ //
+ // However, it is clear that at least some flags have to be ignored for
+ // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be
+ // ignored. We should not have two output .text sections just because one was
+ // in a group and another was not for example.
+ //
+ // It also seems that that wording was a late addition and didn't get the
+ // necessary scrutiny.
+ //
+ // Merging sections with different flags is expected by some users. One
+ // reason is that if one file has
+ //
+ // int *const bar __attribute__((section(".foo"))) = (int *)0;
+ //
+ // gcc with -fPIC will produce a read only .foo section. But if another
+ // file has
+ //
+ // int zed;
+ // int *const bar __attribute__((section(".foo"))) = (int *)&zed;
+ //
+ // gcc with -fPIC will produce a read write section.
+ //
+ // Last but not least, when using linker script the merge rules are forced by
+ // the script. Unfortunately, linker scripts are name based. This means that
+ // expressions like *(.foo*) can refer to multiple input sections with
+ // different flags. 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.
+ //
+ // Given the above issues, we instead merge sections by name and error on
+ // incompatible types and flags.
+ //
+ // The exception being SHF_MERGE, where we create different output sections
+ // for each alignment. This makes each output section simple. In case of
+ // relocatable object generation we do not try to perform merging and treat
+ // SHF_MERGE sections as regular ones, but also create different output
+ // sections for them to allow merging at final linking stage.
+ //
+ // Fortunately, creating symbols in the middle of a merge section is not
+ // supported by bfd or gold, so the SHF_MERGE exception should not cause
+ // problems with most linker scripts.
-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;
-}
+ typedef typename ELFT::uint uintX_t;
+ uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
-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;
-}
+ 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>
-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);
+ return SectionKey{OutsecName, Flags, Alignment};
}
-template <class ELFT>
-void MipsOptionsOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- auto *Opt = reinterpret_cast<Elf_Mips_Options *>(Buf);
- Opt->kind = ODK_REGINFO;
- Opt->size = this->Header.sh_size;
- Opt->section = 0;
- Opt->info = 0;
- auto *Reg = reinterpret_cast<Elf_Mips_RegInfo *>(Buf + sizeof(*Opt));
- Reg->ri_gp_value = Out<ELFT>::Got->getVA() + MipsGPOffset;
- Reg->ri_gprmask = GprMask;
-}
+template <class ELFT> OutputSectionFactory<ELFT>::OutputSectionFactory() {}
-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> OutputSectionFactory<ELFT>::~OutputSectionFactory() {}
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)
+ SectionKey Key = createKey(C, OutsecName);
+ return create(Key, C);
+}
+
+static uint64_t getIncompatibleFlags(uint64_t Flags) {
+ return Flags & (SHF_ALLOC | SHF_TLS);
+}
+
+template <class ELFT>
+std::pair<OutputSectionBase *, bool>
+OutputSectionFactory<ELFT>::create(const SectionKey &Key,
+ InputSectionBase<ELFT> *C) {
+ uintX_t Flags = getOutFlags(C);
+ OutputSectionBase *&Sec = Map[Key];
+ if (Sec) {
+ if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(C->Flags))
+ error("Section has flags incompatible with others with the same name " +
+ toString(C));
+ // Convert notbits to progbits if they are mixed. This happens is some
+ // linker scripts.
+ if (Sec->Type == SHT_NOBITS && C->Type == SHT_PROGBITS)
+ Sec->Type = SHT_PROGBITS;
+ if (Sec->Type != C->Type &&
+ !(Sec->Type == SHT_PROGBITS && C->Type == SHT_NOBITS))
+ error("Section has different type from others with the same name " +
+ toString(C));
+ Sec->Flags |= Flags;
return {Sec, false};
+ }
- 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});
+SectionKey DenseMapInfo<SectionKey>::getEmptyKey() {
+ return SectionKey{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
}
-template <class ELFT>
-SectionKey<ELFT::Is64Bits>
-OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C,
- StringRef OutsecName) {
- const Elf_Shdr *H = C->getSectionHdr();
- uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED;
-
- // For SHF_MERGE we create different output sections for each alignment.
- // This makes each output section simple and keeps a single level mapping from
- // input to output.
- uintX_t Alignment = 0;
- if (isa<MergeInputSection<ELFT>>(C))
- Alignment = std::max(H->sh_addralign, H->sh_entsize);
-
- uint32_t Type = H->sh_type;
- return SectionKey<ELFT::Is64Bits>{OutsecName, Type, Flags, Alignment};
-}
-
-template <bool Is64Bits>
-typename lld::elf::SectionKey<Is64Bits>
-DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getEmptyKey() {
- return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0, 0};
+SectionKey DenseMapInfo<SectionKey>::getTombstoneKey() {
+ return SectionKey{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0};
}
-template <bool Is64Bits>
-typename lld::elf::SectionKey<Is64Bits>
-DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getTombstoneKey() {
- return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0,
- 0};
+unsigned DenseMapInfo<SectionKey>::getHashValue(const SectionKey &Val) {
+ return hash_combine(Val.Name, Val.Flags, Val.Alignment);
}
-template <bool Is64Bits>
-unsigned
-DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::getHashValue(const Key &Val) {
- return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment);
-}
-
-template <bool Is64Bits>
-bool DenseMapInfo<lld::elf::SectionKey<Is64Bits>>::isEqual(const Key &LHS,
- const Key &RHS) {
+bool DenseMapInfo<SectionKey>::isEqual(const SectionKey &LHS,
+ const SectionKey &RHS) {
return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
- LHS.Type == RHS.Type && LHS.Flags == RHS.Flags &&
- LHS.Alignment == RHS.Alignment;
-}
-
-namespace llvm {
-template struct DenseMapInfo<SectionKey<true>>;
-template struct DenseMapInfo<SectionKey<false>>;
+ LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment;
}
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 +699,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/contrib/llvm/tools/lld/ELF/OutputSections.h b/contrib/llvm/tools/lld/ELF/OutputSections.h
index 5fdf8de..5c494bb 100644
--- a/contrib/llvm/tools/lld/ELF/OutputSections.h
+++ b/contrib/llvm/tools/lld/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);
-};
-
-template <class ELFT>
-class GotPltSection final : public OutputSectionBase<ELFT> {
- typedef typename ELFT::uint uintX_t;
-
-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;
+ // 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 DynamicReloc {
- typedef typename ELFT::uint uintX_t;
+template <class ELFT> class OutputSection final : public OutputSectionBase {
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,255 +196,32 @@ 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 OutputSection<ELFT> *BssRelRo;
+ 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 {
- typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
+struct SectionKey {
StringRef Name;
- uint32_t Type;
- uintX_t Flags;
- uintX_t Alignment;
+ uint64_t Flags;
+ uint64_t Alignment;
};
// This class knows how to create an output section for a given
@@ -673,60 +231,40 @@ template <bool Is64Bits> struct SectionKey {
template <class ELFT> class OutputSectionFactory {
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::uint uintX_t;
- typedef typename elf::SectionKey<ELFT::Is64Bits> Key;
public:
- std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C,
- StringRef OutsecName);
-
- OutputSectionBase<ELFT> *lookup(StringRef Name, uint32_t Type, uintX_t Flags);
+ OutputSectionFactory();
+ ~OutputSectionFactory();
+ std::pair<OutputSectionBase *, bool> create(InputSectionBase<ELFT> *C,
+ StringRef OutsecName);
+ std::pair<OutputSectionBase *, bool> create(const SectionKey &Key,
+ InputSectionBase<ELFT> *C);
private:
- Key createKey(InputSectionBase<ELFT> *C, StringRef OutsecName);
-
- llvm::SmallDenseMap<Key, OutputSectionBase<ELFT> *> Map;
+ llvm::SmallDenseMap<SectionKey, 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> OutputSection<ELFT> *Out<ELFT>::BssRelRo;
+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
-namespace llvm {
-template <bool Is64Bits> struct DenseMapInfo<lld::elf::SectionKey<Is64Bits>> {
- typedef typename lld::elf::SectionKey<Is64Bits> Key;
-
- static Key getEmptyKey();
- static Key getTombstoneKey();
- static unsigned getHashValue(const Key &Val);
- static bool isEqual(const Key &LHS, const Key &RHS);
-};
-}
#endif
diff --git a/contrib/llvm/tools/lld/ELF/Relocations.cpp b/contrib/llvm/tools/lld/ELF/Relocations.cpp
index c09cf6b..cecd11e 100644
--- a/contrib/llvm/tools/lld/ELF/Relocations.cpp
+++ b/contrib/llvm/tools/lld/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;
}
@@ -366,7 +399,21 @@ template <class ELFT> static uint32_t getAlignment(SharedSymbol<ELFT> *SS) {
return 1 << TrailingZeros;
}
-// Reserve space in .bss for copy relocation.
+template <class ELFT> static bool isReadOnly(SharedSymbol<ELFT> *SS) {
+ typedef typename ELFT::uint uintX_t;
+ typedef typename ELFT::Phdr Elf_Phdr;
+
+ // Determine if the symbol is read-only by scanning the DSO's program headers.
+ uintX_t Value = SS->Sym.st_value;
+ for (const Elf_Phdr &Phdr : check(SS->file()->getObj().program_headers()))
+ if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
+ !(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr &&
+ Value < Phdr.p_vaddr + Phdr.p_memsz)
+ return true;
+ return false;
+}
+
+// Reserve space in .bss or .bss.rel.ro for copy relocation.
template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Sym Elf_Sym;
@@ -374,60 +421,71 @@ 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));
+
+ // See if this symbol is in a read-only segment. If so, preserve the symbol's
+ // memory protection by reserving space in the .bss.rel.ro section.
+ bool IsReadOnly = isReadOnly(SS);
+ OutputSection<ELFT> *CopySec =
+ IsReadOnly ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss;
uintX_t Alignment = getAlignment(SS);
- uintX_t Off = alignTo(Out<ELFT>::Bss->getSize(), Alignment);
- Out<ELFT>::Bss->setSize(Off + SymSize);
- Out<ELFT>::Bss->updateAlignment(Alignment);
+ uintX_t Off = alignTo(CopySec->Size, Alignment);
+ CopySec->Size = Off + SymSize;
+ CopySec->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>>(
Symtab<ELFT>::X->find(check(S.getName(SS->file()->getStringTable()))));
if (!Alias)
continue;
- Alias->OffsetInBss = Off;
+ Alias->CopyIsInBssRelRo = IsReadOnly;
+ Alias->CopyOffset = Off;
Alias->NeedsCopyOrPltAddr = true;
Alias->symbol()->IsUsedInRegularObj = true;
}
- Out<ELFT>::RelaDyn->addReloc(
- {Target->CopyRel, Out<ELFT>::Bss, SS->OffsetInBss, false, SS, 0});
+ In<ELFT>::RelaDyn->addReloc({Target->CopyRel, CopySec, Off, 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 +519,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 +546,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 +606,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 +697,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 +728,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 +739,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/contrib/llvm/tools/lld/ELF/Relocations.h b/contrib/llvm/tools/lld/ELF/Relocations.h
index 4c1c74e..b5825bd 100644
--- a/contrib/llvm/tools/lld/ELF/Relocations.h
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/ScriptParser.cpp b/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
index 559ec1b..c740685 100644
--- a/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/ScriptParser.h b/contrib/llvm/tools/lld/ELF/ScriptParser.h
index 20735f7..264c497 100644
--- a/contrib/llvm/tools/lld/ELF/ScriptParser.h
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/Strings.cpp b/contrib/llvm/tools/lld/ELF/Strings.cpp
index 0c21e88..ec3d1f1 100644
--- a/contrib/llvm/tools/lld/ELF/Strings.cpp
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/Strings.h b/contrib/llvm/tools/lld/ELF/Strings.h
index 4948e9d..934b642 100644
--- a/contrib/llvm/tools/lld/ELF/Strings.h
+++ b/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/SymbolListFile.cpp b/contrib/llvm/tools/lld/ELF/SymbolListFile.cpp
deleted file mode 100644
index 9e08802..0000000
--- a/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/SymbolListFile.h b/contrib/llvm/tools/lld/ELF/SymbolListFile.h
deleted file mode 100644
index cf3c4c6..0000000
--- a/contrib/llvm/tools/lld/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/contrib/llvm/tools/lld/ELF/SymbolTable.cpp b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
index 78c1298..ce25793 100644
--- a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
+++ b/contrib/llvm/tools/lld/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();
-
- // Replace bitcode symbols.
- for (auto &IF : IFs) {
- ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(IF.release());
+ // Compile bitcode files and replace bitcode symbols.
+ LTO.reset(new BitcodeCompiler);
+ for (BitcodeFile *F : BitcodeFiles)
+ LTO->add<ELFT>(*F);
- 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->isInCurrentDSO())
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<ELFT>>(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;
}
@@ -280,7 +283,7 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
if (WasInserted)
return 1;
SymbolBody *Body = S->body();
- if (Body->isLazy() || Body->isUndefined() || Body->isShared())
+ if (Body->isLazy() || !Body->isInCurrentDSO())
return 1;
if (Binding == STB_WEAK)
return -1;
@@ -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,12 +424,11 @@ 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)
S->ExportDynamic = true;
- if (WasInserted || isa<Undefined>(S->body())) {
+ if (WasInserted || isa<Undefined<ELFT>>(S->body())) {
replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
if (!S->isWeak())
F->IsUsed = true;
@@ -422,24 +436,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,16 +463,12 @@ 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;
+SymbolBody *SymbolTable<ELFT>::findInCurrentDSO(StringRef Name) {
+ if (SymbolBody *S = find(Name))
+ if (S->isInCurrentDSO())
+ return S;
+ return nullptr;
}
template <class ELFT>
@@ -465,7 +476,8 @@ 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 +496,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 +527,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 +539,163 @@ 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;
+ return Res;
}
-static bool hasExternCpp() {
- for (VersionDefinition &V : Config->VersionDefinitions)
- for (SymbolVersion Sym : V.Globals)
- if (Sym.IsExternCpp)
- return true;
- return false;
+// 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.
+template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() {
+ for (SymbolVersion &Ver : Config->VersionScriptGlobals)
+ assignExactVersion(Ver, VER_NDX_GLOBAL, "global");
+ for (SymbolVersion &Ver : Config->VersionScriptGlobals)
+ assignWildcardVersion(Ver, VER_NDX_GLOBAL);
+ for (SymbolVersion &Ver : Config->VersionScriptLocals)
+ assignExactVersion(Ver, VER_NDX_LOCAL, "local");
+ for (SymbolVersion &Ver : Config->VersionScriptLocals)
+ assignWildcardVersion(Ver, VER_NDX_LOCAL);
}
-// This function processes the --version-script option by marking all global
-// symbols with the VersionScriptGlobal flag, which acts as a filter on the
-// dynamic symbol table.
-template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
- // If version script does not contain versions declarations,
- // we just should mark global symbols.
- if (!Config->VersionScriptGlobals.empty()) {
- for (SymbolVersion &Sym : Config->VersionScriptGlobals)
- if (SymbolBody *B = find(Sym.Name))
- B->symbol()->VersionId = VER_NDX_GLOBAL;
+// 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 (Config->VersionDefinitions.empty())
+ // 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;
-
- // If we have symbols version declarations, we should
- // assign version references for each symbol.
- // Current rules are:
- // * If there is an exact match for the mangled name or we have extern C++
- // exact match, then we use it.
- // * Otherwise, we look through the wildcard patterns. We look through the
- // version tags in reverse order. We use the first match we find (the last
- // matching version tag in the file).
- // Handle exact matches and build a map of demangled externs for
- // quick search during next step.
- std::map<std::string, SymbolBody *> Demangled;
- if (hasExternCpp())
- Demangled = getDemangledSyms();
-
- for (VersionDefinition &V : Config->VersionDefinitions) {
- for (SymbolVersion Sym : V.Globals) {
- if (hasWildcard(Sym.Name))
- continue;
- SymbolBody *B = Sym.IsExternCpp ? Demangled[Sym.Name] : find(Sym.Name);
- setVersionId(B, V.Name, Sym.Name, V.Id);
- }
}
- // Handle wildcards.
- for (size_t I = Config->VersionDefinitions.size() - 1; I != (size_t)-1; --I) {
- VersionDefinition &V = Config->VersionDefinitions[I];
- for (SymbolVersion &Sym : V.Globals)
- if (hasWildcard(Sym.Name))
- for (SymbolBody *B : findAll(Sym.Name))
- if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
- B->symbol()->VersionId = V.Id;
+ // 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() {
+// 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.
+ handleAnonymousVersion();
+
if (Config->VersionDefinitions.empty())
return;
- int MaxVersionLen = getMaxVersionLen();
+ // 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.
- // Unfortunately there's no way other than iterating over all
- // symbols to look for '@' characters in symbol names.
- // So this is inherently slow. A good news is that we do this
- // only when versions have been defined.
- for (Symbol *Sym : SymVector) {
- // Symbol versions for exported symbols are by nature
- // only for defined global symbols.
- SymbolBody *B = Sym->body();
- if (!B->isDefined())
- continue;
- uint8_t Visibility = B->getVisibility();
- if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
- continue;
-
- // Look for '@' in the symbol name.
- StringRef Name;
- uint16_t Version;
- std::tie(Name, Version) = getSymbolVersion(B, MaxVersionLen);
- if (Name.empty())
- continue;
-
- B->setName(Name);
- Sym->VersionId = Version;
- }
+ // First, we assign versions to exact matching symbols,
+ // i.e. version definitions not containing any glob meta-characters.
+ 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 (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions))
+ for (SymbolVersion &Ver : V.Globals)
+ assignWildcardVersion(Ver, V.Id);
}
template class elf::SymbolTable<ELF32LE>;
diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.h b/contrib/llvm/tools/lld/ELF/SymbolTable.h
index 40415b6..f39dbd1 100644
--- a/contrib/llvm/tools/lld/ELF/SymbolTable.h
+++ b/contrib/llvm/tools/lld/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,33 @@ public:
void scanUndefinedFlags();
void scanShlibUndefined();
- void scanDynamicList();
void scanVersionScript();
- void scanSymbolVersions();
SymbolBody *find(StringRef Name);
+ SymbolBody *findInCurrentDSO(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 +117,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/contrib/llvm/tools/lld/ELF/Symbols.cpp b/contrib/llvm/tools/lld/ELF/Symbols.cpp
index d6a605d..43af44e 100644
--- a/contrib/llvm/tools/lld/ELF/Symbols.cpp
+++ b/contrib/llvm/tools/lld/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,27 @@ 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;
+ if (!Config->DefineCommon)
+ return 0;
+ 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 SS.getBssSectionForCopy()->Addr + SS.CopyOffset;
}
case SymbolBody::UndefinedKind:
return 0;
@@ -79,32 +91,16 @@ 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), CopyIsInBssRelRo(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 +147,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 +155,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 +165,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;
}
@@ -176,6 +176,8 @@ template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
return DR->ThunkData->getVA();
if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
return S->ThunkData->getVA();
+ if (const auto *S = dyn_cast<Undefined<ELFT>>(this))
+ return S->ThunkData->getVA();
fatal("getThunkVA() not supported for Symbol class\n");
}
@@ -189,48 +191,78 @@ 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};
+
+ // If this is not in this DSO, it is not a definition.
+ if (!isInCurrentDSO())
+ return;
+
+ // '@@' 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) {
+template <typename ELFT>
+Undefined<ELFT>::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) {}
+OutputSection<ELFT> *SharedSymbol<ELFT>::getBssSectionForCopy() const {
+ assert(needsCopy());
+ return CopyIsInBssRelRo ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss;
+}
-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,34 +279,47 @@ 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);
}
-bool Symbol::includeInDynsym() const {
+uint8_t Symbol::computeBinding() const {
+ if (Config->Relocatable)
+ return Binding;
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
+ return STB_LOCAL;
+ const SymbolBody *Body = body();
+ if (VersionId == VER_NDX_LOCAL && Body->isInCurrentDSO())
+ return STB_LOCAL;
+ if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
+ return STB_GLOBAL;
+ return Binding;
+}
+
+bool Symbol::includeInDynsym() const {
+ if (computeBinding() == STB_LOCAL)
return false;
- return (ExportDynamic && VersionId != VER_NDX_LOCAL) || body()->isShared() ||
+ return ExportDynamic || body()->isShared() ||
(body()->isUndefined() && Config->Shared);
}
// 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 +330,14 @@ void elf::printTraceSymbol(Symbol *Sym) {
outs() << B->getName() << "\n";
}
+// Returns a symbol for an error message.
+std::string lld::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 +383,17 @@ 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::Undefined<ELF32LE>;
+template class elf::Undefined<ELF32BE>;
+template class elf::Undefined<ELF64LE>;
+template class elf::Undefined<ELF64BE>;
+
+template class elf::SharedSymbol<ELF32LE>;
+template class elf::SharedSymbol<ELF32BE>;
+template class elf::SharedSymbol<ELF64LE>;
+template class elf::SharedSymbol<ELF64BE>;
+
+template class elf::DefinedRegular<ELF32LE>;
+template class elf::DefinedRegular<ELF32BE>;
+template class elf::DefinedRegular<ELF64LE>;
+template class elf::DefinedRegular<ELF64BE>;
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.h b/contrib/llvm/tools/lld/ELF/Symbols.h
index aa9a87d..7acb89a 100644
--- a/contrib/llvm/tools/lld/ELF/Symbols.h
+++ b/contrib/llvm/tools/lld/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,
@@ -69,24 +67,13 @@ public:
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
}
bool isShared() const { return SymbolKind == SharedKind; }
+ bool isInCurrentDSO() const { return !isUndefined() && !isShared(); }
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 +92,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 +115,20 @@ 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;
+
+ // True if this is a shared symbol in a read-only segment which requires a
+ // copy relocation. This causes space for the symbol to be allocated in the
+ // .bss.rel.ro section.
+ unsigned CopyIsInBssRelRo : 1;
+
// The following fields have the same meaning as the ELF symbol attributes.
uint8_t Type; // symbol type
uint8_t StOther; // st_other field value
@@ -142,32 +148,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 +169,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 +183,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),
- Section(Section ? Section->Repl : NullInputSection) {
- if (Section)
- this->File = Section->getFile();
- }
-
- DefinedRegular(const Elf_Sym &Sym, InputSectionBase<ELFT> *Section)
- : Defined(SymbolBody::DefinedRegularKind, Sym.st_name, Sym.st_other,
- Sym.getType()),
- Value(Sym.st_value), Size(Sym.st_size),
+ 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) {
- assert(isLocal());
- if (Section)
- this->File = Section->getFile();
+ this->File = File;
}
- 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,33 +226,37 @@ 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 {
+template <class ELFT> 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;
}
+ // If non-null the symbol has a Thunk that may be used as an alternative
+ // destination for callers of this Symbol. When linking a DSO undefined
+ // symbols are implicitly imported, the symbol lookup will be performed by
+ // the dynamic loader. A call to an undefined symbol will be given a PLT
+ // entry and on ARM this may need a Thunk if the caller is in Thumb state.
+ Thunk<ELFT> *ThunkData = nullptr;
InputFile *file() { return this->File; }
};
@@ -291,7 +272,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())
@@ -306,13 +288,15 @@ public:
// This field is a pointer to the symbol's version definition.
const Elf_Verdef *Verdef;
- // OffsetInBss is significant only when needsCopy() is true.
- uintX_t OffsetInBss = 0;
+ // CopyOffset is significant only when needsCopy() is true.
+ uintX_t CopyOffset = 0;
// If non-null the symbol has a Thunk that may be used as an alternative
// destination for callers of this Symbol.
Thunk<ELFT> *ThunkData = nullptr;
bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); }
+
+ OutputSection<ELFT> *getBssSectionForCopy() const;
};
// This class represents a symbol defined in an archive file. It is
@@ -326,11 +310,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 +328,7 @@ public:
}
ArchiveFile *file() { return (ArchiveFile *)this->File; }
- std::unique_ptr<InputFile> fetch();
+ InputFile *fetch();
private:
const llvm::object::Archive::Symbol Sym;
@@ -361,12 +345,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 +366,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,7 +417,11 @@ 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;
+ uint8_t computeBinding() const;
bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
// This field is used to store the Symbol's SymbolBody. This instantiation of
@@ -434,9 +430,9 @@ 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<llvm::object::ELF64LE>, SharedSymbol<llvm::object::ELF64LE>,
+ LazyArchive, LazyObject>
Body;
SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
@@ -448,8 +444,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");
@@ -467,8 +462,9 @@ inline Symbol *SymbolBody::symbol() {
return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) -
offsetof(Symbol, Body));
}
-
} // namespace elf
+
+std::string toString(const elf::SymbolBody &B);
} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
new file mode 100644
index 0000000..b673a4e
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
@@ -0,0 +1,2004 @@
+//===- 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;
+
+ if (!Config->DefineCommon)
+ return Ret;
+
+ // 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, 16, ".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 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);
+ Buf += HeaderEntriesNum * sizeof(uintX_t);
+ // Write 'page address' entries to the local part of the GOT.
+ for (std::pair<const OutputSectionBase *, size_t> &L : PageIndexMap) {
+ size_t PageCount = getMipsPageCount(L.first->Size);
+ uintX_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+ for (size_t PI = 0; PI < PageCount; ++PI) {
+ uint8_t *Entry = Buf + (L.second + PI) * sizeof(uintX_t);
+ writeUint<ELFT>(Entry, FirstPageAddr + PI * 0x10000);
+ }
+ }
+ Buf += PageEntriesNum * sizeof(uintX_t);
+ auto AddEntry = [&](const GotEntry &SA) {
+ uint8_t *Entry = Buf;
+ Buf += sizeof(uintX_t);
+ const SymbolBody *Body = SA.first;
+ uintX_t VA = Body->template getVA<ELFT>(SA.second);
+ writeUint<ELFT>(Entry, VA);
+ };
+ std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry);
+ std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry);
+ std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry);
+ // Initialize TLS-related GOT entries. If the entry has a corresponding
+ // dynamic relocations, leave it initialized by zero. Write down adjusted
+ // TLS symbol's values otherwise. To calculate the adjustments use offsets
+ // for thread-local storage.
+ // https://www.linux-mips.org/wiki/NPTL
+ if (TlsIndexOff != -1U && !Config->Pic)
+ writeUint<ELFT>(Buf + TlsIndexOff, 1);
+ for (const SymbolBody *B : TlsEntries) {
+ if (!B || B->isPreemptible())
+ continue;
+ uintX_t VA = B->getVA<ELFT>();
+ if (B->GotIndex != -1U) {
+ uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
+ writeUint<ELFT>(Entry, VA - 0x7000);
+ }
+ if (B->GlobalDynIndex != -1U) {
+ uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
+ writeUint<ELFT>(Entry, 1);
+ Entry += sizeof(uintX_t);
+ writeUint<ELFT>(Entry, VA - 0x8000);
+ }
+ }
+}
+
+template <class ELFT>
+GotPltSection<ELFT>::GotPltSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotPltEntrySize, ".got.plt") {}
+
+template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
+ Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
+ Entries.push_back(&Sym);
+}
+
+template <class ELFT> size_t GotPltSection<ELFT>::getSize() const {
+ return (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);
+ }
+}
+
+// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
+// part of the .got.plt
+template <class ELFT>
+IgotPltSection<ELFT>::IgotPltSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotPltEntrySize,
+ Config->EMachine == EM_ARM ? ".got" : ".got.plt") {
+}
+
+template <class ELFT> void IgotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
+ Sym.IsInIgot = true;
+ Sym.GotPltIndex = Entries.size();
+ Entries.push_back(&Sym);
+}
+
+template <class ELFT> size_t IgotPltSection<ELFT>::getSize() const {
+ return Entries.size() * Target->GotPltEntrySize;
+}
+
+template <class ELFT> void IgotPltSection<ELFT>::writeTo(uint8_t *Buf) {
+ for (const SymbolBody *B : Entries) {
+ Target->writeIgotPlt(Buf, *B);
+ Buf += sizeof(uintX_t);
+ }
+}
+
+template <class ELFT>
+StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic)
+ : SyntheticSection<ELFT>(Dynamic ? (uintX_t)SHF_ALLOC : 0, SHT_STRTAB, 1,
+ Name),
+ 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, this->Size));
+ if (!R.second)
+ return R.first->second;
+ }
+ unsigned Ret = this->Size;
+ this->Size = this->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;
+ }
+}
+
+// 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()
+ : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC,
+ sizeof(uintX_t), ".dynamic") {
+ this->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)
+ this->Flags = SHF_ALLOC;
+
+ addEntries();
+}
+
+// There are some dynamic entries that don't depend on other sections.
+// Such entries can be set early.
+template <class ELFT> void DynamicSection<ELFT>::addEntries() {
+ // Add strings to .dynstr early so that .dynstr's size will be
+ // fixed early.
+ for (StringRef S : Config->AuxiliaryList)
+ add({DT_AUXILIARY, In<ELFT>::DynStrTab->addString(S)});
+ if (!Config->RPath.empty())
+ add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
+ In<ELFT>::DynStrTab->addString(Config->RPath)});
+ for (SharedFile<ELFT> *F : Symtab<ELFT>::X->getSharedFiles())
+ if (F->isNeeded())
+ add({DT_NEEDED, In<ELFT>::DynStrTab->addString(F->getSoName())});
+ if (!Config->SoName.empty())
+ add({DT_SONAME, In<ELFT>::DynStrTab->addString(Config->SoName)});
+
+ // Set DT_FLAGS and DT_FLAGS_1.
+ 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->Shared && !Config->Relocatable)
+ add({DT_DEBUG, (uint64_t)0});
+}
+
+// Add remaining entries to complete .dynamic contents.
+template <class ELFT> void DynamicSection<ELFT>::finalize() {
+ if (this->Size)
+ return; // Already finalized.
+
+ this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
+ if (In<ELFT>::RelaDyn->OutSec->Size > 0) {
+ bool IsRela = Config->Rela;
+ add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
+ add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->OutSec->Size});
+ add({IsRela ? DT_RELAENT : DT_RELENT,
+ uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
+
+ // MIPS dynamic loader does not support RELCOUNT tag.
+ // The problem is in the tight relation between dynamic
+ // relocations and GOT. So do not emit this tag on MIPS.
+ if (Config->EMachine != EM_MIPS) {
+ size_t NumRelativeRels = In<ELFT>::RelaDyn->getRelativeRelocCount();
+ if (Config->ZCombreloc && NumRelativeRels)
+ add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels});
+ }
+ }
+ if (In<ELFT>::RelaPlt->OutSec->Size > 0) {
+ add({DT_JMPREL, In<ELFT>::RelaPlt});
+ add({DT_PLTRELSZ, In<ELFT>::RelaPlt->OutSec->Size});
+ add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
+ In<ELFT>::GotPlt});
+ add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)});
+ }
+
+ add({DT_SYMTAB, In<ELFT>::DynSymTab});
+ add({DT_SYMENT, sizeof(Elf_Sym)});
+ add({DT_STRTAB, In<ELFT>::DynStrTab});
+ add({DT_STRSZ, In<ELFT>::DynStrTab->getSize()});
+ if (In<ELFT>::GnuHashTab)
+ add({DT_GNU_HASH, In<ELFT>::GnuHashTab});
+ if (In<ELFT>::HashTab)
+ add({DT_HASH, In<ELFT>::HashTab});
+
+ if (Out<ELFT>::PreinitArray) {
+ add({DT_PREINIT_ARRAY, Out<ELFT>::PreinitArray});
+ add({DT_PREINIT_ARRAYSZ, Out<ELFT>::PreinitArray, Entry::SecSize});
+ }
+ if (Out<ELFT>::InitArray) {
+ add({DT_INIT_ARRAY, Out<ELFT>::InitArray});
+ add({DT_INIT_ARRAYSZ, Out<ELFT>::InitArray, Entry::SecSize});
+ }
+ if (Out<ELFT>::FiniArray) {
+ add({DT_FINI_ARRAY, Out<ELFT>::FiniArray});
+ add({DT_FINI_ARRAYSZ, Out<ELFT>::FiniArray, Entry::SecSize});
+ }
+
+ if (SymbolBody *B = Symtab<ELFT>::X->findInCurrentDSO(Config->Init))
+ add({DT_INIT, B});
+ if (SymbolBody *B = Symtab<ELFT>::X->findInCurrentDSO(Config->Fini))
+ add({DT_FINI, B});
+
+ bool HasVerNeed = In<ELFT>::VerNeed->getNeedNum() != 0;
+ if (HasVerNeed || In<ELFT>::VerDef)
+ add({DT_VERSYM, In<ELFT>::VerSym});
+ if (In<ELFT>::VerDef) {
+ add({DT_VERDEF, In<ELFT>::VerDef});
+ add({DT_VERDEFNUM, getVerDefNum()});
+ }
+ if (HasVerNeed) {
+ add({DT_VERNEED, In<ELFT>::VerNeed});
+ add({DT_VERNEEDNUM, In<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, In<ELFT>::DynSymTab->getNumSymbols()});
+ add({DT_MIPS_LOCAL_GOTNO, In<ELFT>::MipsGot->getLocalEntriesNum()});
+ if (const SymbolBody *B = In<ELFT>::MipsGot->getFirstGlobalEntry())
+ add({DT_MIPS_GOTSYM, B->DynsymIndex});
+ else
+ add({DT_MIPS_GOTSYM, In<ELFT>::DynSymTab->getNumSymbols()});
+ add({DT_PLTGOT, In<ELFT>::MipsGot});
+ if (In<ELFT>::MipsRldMap)
+ add({DT_MIPS_RLD_MAP, In<ELFT>::MipsRldMap});
+ }
+
+ this->OutSec->Entsize = this->Entsize;
+ this->OutSec->Link = this->Link;
+
+ // +1 for DT_NULL
+ this->Size = (Entries.size() + 1) * this->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->Addr;
+ break;
+ case Entry::InSecAddr:
+ P->d_un.d_ptr = E.InSec->OutSec->Addr + E.InSec->OutSecOff;
+ break;
+ case Entry::SecSize:
+ P->d_un.d_val = E.OutSec->Size;
+ 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>
+typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
+ if (OutputSec)
+ return OutputSec->Addr + OffsetInSec;
+ return InputSec->OutSec->Addr + 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>
+RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
+ : SyntheticSection<ELFT>(SHF_ALLOC, Config->Rela ? SHT_RELA : SHT_REL,
+ sizeof(uintX_t), Name),
+ Sort(Sort) {
+ this->Entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+}
+
+template <class ELFT>
+void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
+ if (Reloc.Type == Target->RelativeRel)
+ ++NumRelativeRelocs;
+ Relocs.push_back(Reloc);
+}
+
+template <class ELFT, class RelTy>
+static bool compRelocations(const RelTy &A, const RelTy &B) {
+ bool AIsRel = A.getType(Config->Mips64EL) == Target->RelativeRel;
+ bool BIsRel = B.getType(Config->Mips64EL) == Target->RelativeRel;
+ if (AIsRel != BIsRel)
+ return AIsRel;
+
+ 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.getInputSec() == In<ELFT>::MipsGot)
+ // 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 += In<ELFT>::MipsGot->getTlsOffset();
+ 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->Entsize * Relocs.size();
+}
+
+template <class ELFT> void RelocationSection<ELFT>::finalize() {
+ this->Link = In<ELFT>::DynSymTab ? In<ELFT>::DynSymTab->OutSec->SectionIndex
+ : In<ELFT>::SymTab->OutSec->SectionIndex;
+
+ // Set required output section properties.
+ this->OutSec->Link = this->Link;
+ this->OutSec->Entsize = this->Entsize;
+}
+
+template <class ELFT>
+SymbolTableSection<ELFT>::SymbolTableSection(
+ StringTableSection<ELFT> &StrTabSec)
+ : SyntheticSection<ELFT>(StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0,
+ StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
+ sizeof(uintX_t),
+ StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
+ StrTabSec(StrTabSec) {
+ this->Entsize = sizeof(Elf_Sym);
+}
+
+// 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 SymbolBody *L, const SymbolBody *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->IsInGlobalMipsGot;
+ bool RIsInLocalGot = !R->IsInGlobalMipsGot;
+ if (LIsInLocalGot || RIsInLocalGot)
+ return !RIsInLocalGot;
+ return L->GotIndex < R->GotIndex;
+}
+
+template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
+ this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex;
+ this->OutSec->Info = this->Info = NumLocals + 1;
+ this->OutSec->Entsize = this->Entsize;
+
+ if (Config->Relocatable)
+ return;
+
+ if (!StrTabSec.isDynamic()) {
+ auto GlobBegin = Symbols.begin() + NumLocals;
+ auto It = std::stable_partition(
+ GlobBegin, Symbols.end(), [](const SymbolTableEntry &S) {
+ return S.Symbol->symbol()->computeBinding() == STB_LOCAL;
+ });
+ // update sh_info with number of Global symbols output with computed
+ // binding of STB_LOCAL
+ this->OutSec->Info = this->Info = 1 + It - Symbols.begin();
+ return;
+ }
+
+ if (In<ELFT>::GnuHashTab)
+ // NB: It also sorts Symbols to meet the GNU hash table requirements.
+ In<ELFT>::GnuHashTab->addSymbols(Symbols);
+ else if (Config->EMachine == EM_MIPS)
+ std::stable_sort(Symbols.begin(), Symbols.end(),
+ [](const SymbolTableEntry &L, const SymbolTableEntry &R) {
+ return sortMipsSymbols(L.Symbol, R.Symbol);
+ });
+ size_t I = 0;
+ for (const SymbolTableEntry &S : Symbols)
+ S.Symbol->DynsymIndex = ++I;
+}
+
+template <class ELFT> void SymbolTableSection<ELFT>::addGlobal(SymbolBody *B) {
+ Symbols.push_back({B, StrTabSec.addString(B->getName(), false)});
+}
+
+template <class ELFT> void SymbolTableSection<ELFT>::addLocal(SymbolBody *B) {
+ assert(!StrTabSec.isDynamic());
+ ++NumLocals;
+ Symbols.push_back({B, StrTabSec.addString(B->getName())});
+}
+
+template <class ELFT>
+size_t SymbolTableSection<ELFT>::getSymbolIndex(SymbolBody *Body) {
+ auto I = llvm::find_if(
+ Symbols, [&](const SymbolTableEntry &E) { return E.Symbol == Body; });
+ if (I == Symbols.end())
+ return 0;
+ return I - Symbols.begin() + 1;
+}
+
+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->Discard != DiscardPolicy::All && !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 (auto I = Symbols.begin(); I != Symbols.begin() + NumLocals; ++I) {
+ const DefinedRegular<ELFT> &Body = *cast<DefinedRegular<ELFT>>(I->Symbol);
+ 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 *OutSec = Section->OutSec;
+ ESym->st_shndx = OutSec->SectionIndex;
+ ESym->st_value = OutSec->Addr + Section->getOffset(Body);
+ }
+ ESym->st_name = I->StrTabOffset;
+ 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 (auto I = Symbols.begin() + NumLocals; I != Symbols.end(); ++I) {
+ const SymbolTableEntry &S = *I;
+ SymbolBody *Body = S.Symbol;
+ size_t StrOff = S.StrTabOffset;
+
+ uint8_t Type = Body->Type;
+ uintX_t Size = Body->getSize<ELFT>();
+
+ ESym->setBindingAndType(Body->symbol()->computeBinding(), Type);
+ ESym->st_size = Size;
+ ESym->st_name = StrOff;
+ ESym->setVisibility(Body->symbol()->Visibility);
+ ESym->st_value = Body->getVA<ELFT>();
+
+ if (const OutputSectionBase *OutSec = getOutputSection(Body)) {
+ ESym->st_shndx = OutSec->SectionIndex;
+ } else if (isa<DefinedRegular<ELFT>>(Body)) {
+ ESym->st_shndx = SHN_ABS;
+ } else if (isa<DefinedCommon>(Body)) {
+ ESym->st_shndx = SHN_COMMON;
+ ESym->st_value = cast<DefinedCommon>(Body)->Alignment;
+ }
+
+ if (Config->EMachine == EM_MIPS) {
+ // 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 (Body->isInPlt() && Body->NeedsCopyOrPltAddr)
+ ESym->st_other |= STO_MIPS_PLT;
+ if (Config->Relocatable) {
+ auto *D = dyn_cast<DefinedRegular<ELFT>>(Body);
+ if (D && D->isMipsPIC())
+ ESym->st_other |= STO_MIPS_PIC;
+ }
+ }
+ ++ESym;
+ }
+}
+
+template <class ELFT>
+const OutputSectionBase *
+SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
+ switch (Sym->kind()) {
+ case SymbolBody::DefinedSyntheticKind:
+ return cast<DefinedSynthetic>(Sym)->Section;
+ case SymbolBody::DefinedRegularKind: {
+ auto &D = cast<DefinedRegular<ELFT>>(*Sym);
+ if (D.Section)
+ return D.Section->OutSec;
+ break;
+ }
+ case SymbolBody::DefinedCommonKind:
+ if (!Config->DefineCommon)
+ return nullptr;
+ return In<ELFT>::Common->OutSec;
+ case SymbolBody::SharedKind: {
+ auto &SS = cast<SharedSymbol<ELFT>>(*Sym);
+ if (SS.needsCopy())
+ return SS.getBssSectionForCopy();
+ break;
+ }
+ case SymbolBody::UndefinedKind:
+ case SymbolBody::LazyArchiveKind:
+ case SymbolBody::LazyObjectKind:
+ break;
+ }
+ return nullptr;
+}
+
+template <class ELFT>
+GnuHashTableSection<ELFT>::GnuHashTableSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_HASH, sizeof(uintX_t),
+ ".gnu.hash") {
+ this->Entsize = ELFT::Is64Bits ? 0 : 4;
+}
+
+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->OutSec->Entsize = this->Entsize;
+ this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
+ this->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++ = In<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 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;
+ }
+ if (I > 0)
+ Values[I - 1] |= 1;
+}
+
+static uint32_t hashGnu(StringRef Name) {
+ uint32_t H = 5381;
+ for (uint8_t C : Name)
+ H = (H << 5) + H + C;
+ return H;
+}
+
+// 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<SymbolTableEntry> &V) {
+ // Ideally this will just be 'auto' but GCC 6.1 is not able
+ // to deduce it correctly.
+ std::vector<SymbolTableEntry>::iterator Mid =
+ std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
+ return S.Symbol->isUndefined();
+ });
+ if (Mid == V.end())
+ return;
+ for (auto I = Mid, E = V.end(); I != E; ++I) {
+ SymbolBody *B = I->Symbol;
+ size_t StrOff = I->StrTabOffset;
+ 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});
+}
+
+template <class ELFT>
+HashTableSection<ELFT>::HashTableSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_HASH, sizeof(Elf_Word), ".hash") {
+ this->Entsize = sizeof(Elf_Word);
+}
+
+template <class ELFT> void HashTableSection<ELFT>::finalize() {
+ this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
+ this->OutSec->Entsize = this->Entsize;
+
+ unsigned NumEntries = 2; // nbucket and nchain.
+ NumEntries += In<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 += In<ELFT>::DynSymTab->getNumSymbols();
+ this->Size = NumEntries * sizeof(Elf_Word);
+}
+
+template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
+ unsigned NumSymbols = In<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 SymbolTableEntry &S : In<ELFT>::DynSymTab->getSymbols()) {
+ SymbolBody *Body = S.Symbol;
+ StringRef Name = Body->getName();
+ unsigned I = Body->DynsymIndex;
+ uint32_t Hash = hashSysV(Name) % NumSymbols;
+ Chains[I] = Buckets[Hash];
+ Buckets[Hash] = I;
+ }
+}
+
+template <class ELFT>
+PltSection<ELFT>::PltSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
+ ".plt") {}
+
+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 = In<ELFT>::RelaPlt->getRelocOffset();
+ Entries.push_back(std::make_pair(&Sym, RelOff));
+}
+
+template <class ELFT> size_t PltSection<ELFT>::getSize() const {
+ return Target->PltHeaderSize + Entries.size() * Target->PltEntrySize;
+}
+
+template <class ELFT>
+IpltSection<ELFT>::IpltSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
+ ".plt") {}
+
+template <class ELFT> void IpltSection<ELFT>::writeTo(uint8_t *Buf) {
+ // The IRelative relocations do not support lazy binding so no header is
+ // needed
+ size_t Off = 0;
+ for (auto &I : Entries) {
+ const SymbolBody *B = I.first;
+ unsigned RelOff = I.second + In<ELFT>::Plt->getSize();
+ 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 IpltSection<ELFT>::addEntry(SymbolBody &Sym) {
+ Sym.PltIndex = Entries.size();
+ Sym.IsInIplt = true;
+ unsigned RelOff = In<ELFT>::RelaIplt->getRelocOffset();
+ Entries.push_back(std::make_pair(&Sym, RelOff));
+}
+
+template <class ELFT> size_t IpltSection<ELFT>::getSize() const {
+ return Entries.size() * Target->PltEntrySize;
+}
+
+template <class ELFT>
+GdbIndexSection<ELFT>::GdbIndexSection()
+ : SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index"),
+ StringPool(llvm::StringTableBuilder::ELF) {}
+
+template <class ELFT> void GdbIndexSection<ELFT>::parseDebugSections() {
+ for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections)
+ if (InputSection<ELFT> *IS = dyn_cast<InputSection<ELFT>>(S))
+ if (IS->OutSec && IS->Name == ".debug_info")
+ readDwarf(IS);
+}
+
+// Iterative hash function for symbol's name is described in .gdb_index format
+// specification. Note that we use one for version 5 to 7 here, it is different
+// for version 4.
+static uint32_t hash(StringRef Str) {
+ uint32_t R = 0;
+ for (uint8_t C : Str)
+ R = R * 67 + tolower(C) - 113;
+ return R;
+}
+
+template <class ELFT>
+void GdbIndexSection<ELFT>::readDwarf(InputSection<ELFT> *I) {
+ GdbIndexBuilder<ELFT> Builder(I);
+ if (ErrorCount)
+ return;
+
+ size_t CuId = CompilationUnits.size();
+ std::vector<std::pair<uintX_t, uintX_t>> CuList = Builder.readCUList();
+ CompilationUnits.insert(CompilationUnits.end(), CuList.begin(), CuList.end());
+
+ std::vector<AddressEntry<ELFT>> AddrArea = Builder.readAddressArea(CuId);
+ AddressArea.insert(AddressArea.end(), AddrArea.begin(), AddrArea.end());
+
+ std::vector<std::pair<StringRef, uint8_t>> NamesAndTypes =
+ Builder.readPubNamesAndTypes();
+
+ for (std::pair<StringRef, uint8_t> &Pair : NamesAndTypes) {
+ uint32_t Hash = hash(Pair.first);
+ size_t Offset = StringPool.add(Pair.first);
+
+ bool IsNew;
+ GdbSymbol *Sym;
+ std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
+ if (IsNew) {
+ Sym->CuVectorIndex = CuVectors.size();
+ CuVectors.push_back({{CuId, Pair.second}});
+ continue;
+ }
+
+ std::vector<std::pair<uint32_t, uint8_t>> &CuVec =
+ CuVectors[Sym->CuVectorIndex];
+ CuVec.push_back({CuId, Pair.second});
+ }
+}
+
+template <class ELFT> void GdbIndexSection<ELFT>::finalize() {
+ if (Finalized)
+ return;
+ Finalized = true;
+
+ parseDebugSections();
+
+ // GdbIndex header consist from version fields
+ // and 5 more fields with different kinds of offsets.
+ CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize;
+ SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize;
+
+ ConstantPoolOffset =
+ SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize;
+
+ for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
+ CuVectorsOffset.push_back(CuVectorsSize);
+ CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1);
+ }
+ StringPoolOffset = ConstantPoolOffset + CuVectorsSize;
+
+ StringPool.finalizeInOrder();
+}
+
+template <class ELFT> size_t GdbIndexSection<ELFT>::getSize() const {
+ const_cast<GdbIndexSection<ELFT> *>(this)->finalize();
+ return StringPoolOffset + StringPool.getSize();
+}
+
+template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
+ write32le(Buf, 7); // Write version.
+ write32le(Buf + 4, CuListOffset); // CU list offset.
+ write32le(Buf + 8, CuTypesOffset); // Types CU list offset.
+ write32le(Buf + 12, CuTypesOffset); // Address area offset.
+ write32le(Buf + 16, SymTabOffset); // Symbol table offset.
+ write32le(Buf + 20, ConstantPoolOffset); // Constant pool offset.
+ Buf += 24;
+
+ // Write the CU list.
+ for (std::pair<uintX_t, uintX_t> CU : CompilationUnits) {
+ write64le(Buf, CU.first);
+ write64le(Buf + 8, CU.second);
+ Buf += 16;
+ }
+
+ // Write the address area.
+ for (AddressEntry<ELFT> &E : AddressArea) {
+ uintX_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0);
+ write64le(Buf, BaseAddr + E.LowAddress);
+ write64le(Buf + 8, BaseAddr + E.HighAddress);
+ write32le(Buf + 16, E.CuIndex);
+ Buf += 20;
+ }
+
+ // Write the symbol table.
+ for (size_t I = 0; I < SymbolTable.getCapacity(); ++I) {
+ GdbSymbol *Sym = SymbolTable.getSymbol(I);
+ if (Sym) {
+ size_t NameOffset =
+ Sym->NameOffset + StringPoolOffset - ConstantPoolOffset;
+ size_t CuVectorOffset = CuVectorsOffset[Sym->CuVectorIndex];
+ write32le(Buf, NameOffset);
+ write32le(Buf + 4, CuVectorOffset);
+ }
+ Buf += 8;
+ }
+
+ // Write the CU vectors into the constant pool.
+ for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
+ write32le(Buf, CuVec.size());
+ Buf += 4;
+ for (std::pair<uint32_t, uint8_t> &P : CuVec) {
+ uint32_t Index = P.first;
+ uint8_t Flags = P.second;
+ Index |= Flags << 24;
+ write32le(Buf, Index);
+ Buf += 4;
+ }
+ }
+
+ StringPool.write(Buf);
+}
+
+template <class ELFT> bool GdbIndexSection<ELFT>::empty() const {
+ return !Out<ELFT>::DebugInfo;
+}
+
+template <class ELFT>
+EhFrameHeader<ELFT>::EhFrameHeader()
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {}
+
+// .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->Addr - 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> size_t EhFrameHeader<ELFT>::getSize() const {
+ // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
+ return 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> bool EhFrameHeader<ELFT>::empty() const {
+ return Out<ELFT>::EhFrame->empty();
+}
+
+template <class ELFT>
+VersionDefinitionSection<ELFT>::VersionDefinitionSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
+ ".gnu.version_d") {}
+
+static StringRef getFileDefName() {
+ if (!Config->SoName.empty())
+ return Config->SoName;
+ return Config->OutputFile;
+}
+
+template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() {
+ FileDefNameOff = In<ELFT>::DynStrTab->addString(getFileDefName());
+ for (VersionDefinition &V : Config->VersionDefinitions)
+ V.NameOff = In<ELFT>::DynStrTab->addString(V.Name);
+
+ this->OutSec->Link = this->Link = In<ELFT>::DynStrTab->OutSec->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->OutSec->Info = this->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> size_t VersionDefinitionSection<ELFT>::getSize() const {
+ return (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum();
+}
+
+template <class ELFT>
+VersionTableSection<ELFT>::VersionTableSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
+ ".gnu.version") {}
+
+template <class ELFT> void VersionTableSection<ELFT>::finalize() {
+ this->OutSec->Entsize = this->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->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
+}
+
+template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
+ return sizeof(Elf_Versym) * (In<ELFT>::DynSymTab->getSymbols().size() + 1);
+}
+
+template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
+ auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
+ for (const SymbolTableEntry &S : In<ELFT>::DynSymTab->getSymbols()) {
+ OutVersym->vs_index = S.Symbol->symbol()->VersionId;
+ ++OutVersym;
+ }
+}
+
+template <class ELFT> bool VersionTableSection<ELFT>::empty() const {
+ return !In<ELFT>::VerDef && In<ELFT>::VerNeed->empty();
+}
+
+template <class ELFT>
+VersionNeedSection<ELFT>::VersionNeedSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t),
+ ".gnu.version_r") {
+ // 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, In<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 = In<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->OutSec->Link = this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
+ this->OutSec->Info = this->Info = Needed.size();
+}
+
+template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const {
+ unsigned Size = Needed.size() * sizeof(Elf_Verneed);
+ for (const std::pair<SharedFile<ELFT> *, size_t> &P : Needed)
+ Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux);
+ return Size;
+}
+
+template <class ELFT> bool VersionNeedSection<ELFT>::empty() const {
+ return getNeedNum() == 0;
+}
+
+template <class ELFT>
+MipsRldMapSection<ELFT>::MipsRldMapSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ sizeof(typename ELFT::uint), ".rld_map") {}
+
+template <class ELFT> void MipsRldMapSection<ELFT>::writeTo(uint8_t *Buf) {
+ // Apply filler from linker script.
+ uint64_t Filler = Script<ELFT>::X->getFiller(this->Name);
+ Filler = (Filler << 32) | Filler;
+ memcpy(Buf, &Filler, getSize());
+}
+
+template <class ELFT>
+ARMExidxSentinelSection<ELFT>::ARMExidxSentinelSection()
+ : SyntheticSection<ELFT>(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
+ sizeof(typename ELFT::uint), ".ARM.exidx") {}
+
+// Write a terminating sentinel entry to the end of the .ARM.exidx table.
+// This section will have been sorted last in the .ARM.exidx table.
+// This table entry will have the form:
+// | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND |
+template <class ELFT>
+void ARMExidxSentinelSection<ELFT>::writeTo(uint8_t *Buf) {
+ // Get the InputSection before us, we are by definition last
+ auto RI = cast<OutputSection<ELFT>>(this->OutSec)->Sections.rbegin();
+ InputSection<ELFT> *LE = *(++RI);
+ InputSection<ELFT> *LC = cast<InputSection<ELFT>>(LE->getLinkOrderDep());
+ uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize());
+ uint64_t P = this->getVA();
+ Target->relocateOne(Buf, R_ARM_PREL31, S - P);
+ write32le(Buf + 4, 0x1);
+}
+
+template InputSection<ELF32LE> *elf::createCommonSection();
+template InputSection<ELF32BE> *elf::createCommonSection();
+template InputSection<ELF64LE> *elf::createCommonSection();
+template InputSection<ELF64BE> *elf::createCommonSection();
+
+template InputSection<ELF32LE> *elf::createInterpSection();
+template InputSection<ELF32BE> *elf::createInterpSection();
+template InputSection<ELF64LE> *elf::createInterpSection();
+template InputSection<ELF64BE> *elf::createInterpSection();
+
+template MergeInputSection<ELF32LE> *elf::createCommentSection();
+template MergeInputSection<ELF32BE> *elf::createCommentSection();
+template MergeInputSection<ELF64LE> *elf::createCommentSection();
+template MergeInputSection<ELF64BE> *elf::createCommentSection();
+
+template class elf::MipsAbiFlagsSection<ELF32LE>;
+template class elf::MipsAbiFlagsSection<ELF32BE>;
+template class elf::MipsAbiFlagsSection<ELF64LE>;
+template class elf::MipsAbiFlagsSection<ELF64BE>;
+
+template class elf::MipsOptionsSection<ELF32LE>;
+template class elf::MipsOptionsSection<ELF32BE>;
+template class elf::MipsOptionsSection<ELF64LE>;
+template class elf::MipsOptionsSection<ELF64BE>;
+
+template class elf::MipsReginfoSection<ELF32LE>;
+template class elf::MipsReginfoSection<ELF32BE>;
+template class elf::MipsReginfoSection<ELF64LE>;
+template class elf::MipsReginfoSection<ELF64BE>;
+
+template class elf::BuildIdSection<ELF32LE>;
+template class elf::BuildIdSection<ELF32BE>;
+template class elf::BuildIdSection<ELF64LE>;
+template class elf::BuildIdSection<ELF64BE>;
+
+template class elf::GotSection<ELF32LE>;
+template class elf::GotSection<ELF32BE>;
+template class elf::GotSection<ELF64LE>;
+template class elf::GotSection<ELF64BE>;
+
+template class elf::MipsGotSection<ELF32LE>;
+template class elf::MipsGotSection<ELF32BE>;
+template class elf::MipsGotSection<ELF64LE>;
+template class elf::MipsGotSection<ELF64BE>;
+
+template class elf::GotPltSection<ELF32LE>;
+template class elf::GotPltSection<ELF32BE>;
+template class elf::GotPltSection<ELF64LE>;
+template class elf::GotPltSection<ELF64BE>;
+
+template class elf::IgotPltSection<ELF32LE>;
+template class elf::IgotPltSection<ELF32BE>;
+template class elf::IgotPltSection<ELF64LE>;
+template class elf::IgotPltSection<ELF64BE>;
+
+template class elf::StringTableSection<ELF32LE>;
+template class elf::StringTableSection<ELF32BE>;
+template class elf::StringTableSection<ELF64LE>;
+template class elf::StringTableSection<ELF64BE>;
+
+template class elf::DynamicSection<ELF32LE>;
+template class elf::DynamicSection<ELF32BE>;
+template class elf::DynamicSection<ELF64LE>;
+template class elf::DynamicSection<ELF64BE>;
+
+template class elf::RelocationSection<ELF32LE>;
+template class elf::RelocationSection<ELF32BE>;
+template class elf::RelocationSection<ELF64LE>;
+template class elf::RelocationSection<ELF64BE>;
+
+template class elf::SymbolTableSection<ELF32LE>;
+template class elf::SymbolTableSection<ELF32BE>;
+template class elf::SymbolTableSection<ELF64LE>;
+template class elf::SymbolTableSection<ELF64BE>;
+
+template class elf::GnuHashTableSection<ELF32LE>;
+template class elf::GnuHashTableSection<ELF32BE>;
+template class elf::GnuHashTableSection<ELF64LE>;
+template class elf::GnuHashTableSection<ELF64BE>;
+
+template class elf::HashTableSection<ELF32LE>;
+template class elf::HashTableSection<ELF32BE>;
+template class elf::HashTableSection<ELF64LE>;
+template class elf::HashTableSection<ELF64BE>;
+
+template class elf::PltSection<ELF32LE>;
+template class elf::PltSection<ELF32BE>;
+template class elf::PltSection<ELF64LE>;
+template class elf::PltSection<ELF64BE>;
+
+template class elf::IpltSection<ELF32LE>;
+template class elf::IpltSection<ELF32BE>;
+template class elf::IpltSection<ELF64LE>;
+template class elf::IpltSection<ELF64BE>;
+
+template class elf::GdbIndexSection<ELF32LE>;
+template class elf::GdbIndexSection<ELF32BE>;
+template class elf::GdbIndexSection<ELF64LE>;
+template class elf::GdbIndexSection<ELF64BE>;
+
+template class elf::EhFrameHeader<ELF32LE>;
+template class elf::EhFrameHeader<ELF32BE>;
+template class elf::EhFrameHeader<ELF64LE>;
+template class elf::EhFrameHeader<ELF64BE>;
+
+template class elf::VersionTableSection<ELF32LE>;
+template class elf::VersionTableSection<ELF32BE>;
+template class elf::VersionTableSection<ELF64LE>;
+template class elf::VersionTableSection<ELF64BE>;
+
+template class elf::VersionNeedSection<ELF32LE>;
+template class elf::VersionNeedSection<ELF32BE>;
+template class elf::VersionNeedSection<ELF64LE>;
+template class elf::VersionNeedSection<ELF64BE>;
+
+template class elf::VersionDefinitionSection<ELF32LE>;
+template class elf::VersionDefinitionSection<ELF32BE>;
+template class elf::VersionDefinitionSection<ELF64LE>;
+template class elf::VersionDefinitionSection<ELF64BE>;
+
+template class elf::MipsRldMapSection<ELF32LE>;
+template class elf::MipsRldMapSection<ELF32BE>;
+template class elf::MipsRldMapSection<ELF64LE>;
+template class elf::MipsRldMapSection<ELF64BE>;
+
+template class elf::ARMExidxSentinelSection<ELF32LE>;
+template class elf::ARMExidxSentinelSection<ELF32BE>;
+template class elf::ARMExidxSentinelSection<ELF64LE>;
+template class elf::ARMExidxSentinelSection<ELF64BE>;
diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.h b/contrib/llvm/tools/lld/ELF/SyntheticSections.h
new file mode 100644
index 0000000..df67e07
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.h
@@ -0,0 +1,750 @@
+//===- SyntheticSection.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_SYNTHETIC_SECTION_H
+#define LLD_ELF_SYNTHETIC_SECTION_H
+
+#include "GdbIndex.h"
+#include "InputSection.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/MC/StringTableBuilder.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> class SyntheticSection : public InputSection<ELFT> {
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ SyntheticSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
+ StringRef Name)
+ : InputSection<ELFT>(Flags, Type, Addralign, ArrayRef<uint8_t>(), Name,
+ InputSectionData::Synthetic) {
+ this->Live = true;
+ }
+
+ virtual ~SyntheticSection() = default;
+ virtual void writeTo(uint8_t *Buf) = 0;
+ virtual size_t getSize() const = 0;
+ virtual void finalize() {}
+ virtual bool empty() const { return false; }
+
+ uintX_t getVA() const {
+ return this->OutSec ? this->OutSec->Addr + this->OutSecOff : 0;
+ }
+
+ static bool classof(const InputSectionData *D) {
+ return D->kind() == InputSectionData::Synthetic;
+ }
+};
+
+template <class ELFT> class GotSection final : public SyntheticSection<ELFT> {
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ GotSection();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Size; }
+ void finalize() override;
+ bool empty() const override;
+
+ void addEntry(SymbolBody &Sym);
+ bool addDynTlsEntry(SymbolBody &Sym);
+ bool addTlsIndex();
+ uintX_t getGlobalDynAddr(const SymbolBody &B) const;
+ uintX_t getGlobalDynOffset(const SymbolBody &B) const;
+
+ uintX_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; }
+ uint32_t getTlsIndexOff() const { return TlsIndexOff; }
+
+ // Flag to force GOT to be in output if we have relocations
+ // that relies on its address.
+ bool HasGotOffRel = false;
+
+private:
+ size_t NumEntries = 0;
+ uint32_t TlsIndexOff = -1;
+ uintX_t Size = 0;
+};
+
+// .note.gnu.build-id section.
+template <class ELFT> class BuildIdSection : public SyntheticSection<ELFT> {
+ // First 16 bytes are a header.
+ static const unsigned HeaderSize = 16;
+
+public:
+ BuildIdSection();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return HeaderSize + HashSize; }
+ void writeBuildId(llvm::ArrayRef<uint8_t> Buf);
+
+private:
+ void computeHash(llvm::ArrayRef<uint8_t> Buf,
+ std::function<void(uint8_t *, ArrayRef<uint8_t>)> Hash);
+
+ size_t HashSize;
+ uint8_t *HashBuf;
+};
+
+template <class ELFT>
+class MipsGotSection final : public SyntheticSection<ELFT> {
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ MipsGotSection();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Size; }
+ void finalize() override;
+ bool empty() const override;
+ void addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
+ bool addDynTlsEntry(SymbolBody &Sym);
+ bool addTlsIndex();
+ uintX_t getPageEntryOffset(const SymbolBody &B, uintX_t Addend) const;
+ uintX_t getBodyEntryOffset(const SymbolBody &B, uintX_t Addend) const;
+ uintX_t getGlobalDynOffset(const SymbolBody &B) const;
+
+ // 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 *getFirstGlobalEntry() const;
+
+ // Returns the number of entries in the local part of GOT including
+ // the number of reserved entries.
+ unsigned getLocalEntriesNum() const;
+
+ // Returns offset of TLS part of the MIPS GOT table. This part goes
+ // after 'local' and 'global' entries.
+ uintX_t getTlsOffset() const;
+
+ uint32_t getTlsIndexOff() const { return TlsIndexOff; }
+
+ uintX_t getGp() const;
+
+private:
+ // MIPS GOT consists of three parts: local, global and tls. Each part
+ // contains different types of entries. Here is a layout of GOT:
+ // - Header entries |
+ // - Page entries | Local part
+ // - Local entries (16-bit access) |
+ // - Local entries (32-bit access) |
+ // - Normal global entries || Global part
+ // - Reloc-only global entries ||
+ // - TLS entries ||| TLS part
+ //
+ // Header:
+ // Two entries hold predefined value 0x0 and 0x80000000.
+ // Page entries:
+ // These entries created by R_MIPS_GOT_PAGE relocation and R_MIPS_GOT16
+ // relocation against local symbols. They are initialized by higher 16-bit
+ // of the corresponding symbol's value. So each 64kb of address space
+ // requires a single GOT entry.
+ // Local entries (16-bit access):
+ // These entries created by GOT relocations against global non-preemptible
+ // symbols so dynamic linker is not necessary to resolve the symbol's
+ // values. "16-bit access" means that corresponding relocations address
+ // GOT using 16-bit index. Each unique Symbol-Addend pair has its own
+ // GOT entry.
+ // Local entries (32-bit access):
+ // These entries are the same as above but created by relocations which
+ // address GOT using 32-bit index (R_MIPS_GOT_HI16/LO16 etc).
+ // Normal global entries:
+ // These entries created by GOT relocations against preemptible global
+ // symbols. They need to be initialized by dynamic linker and they ordered
+ // exactly as the corresponding entries in the dynamic symbols table.
+ // Reloc-only global entries:
+ // These entries created for symbols that are referenced by dynamic
+ // relocations R_MIPS_REL32. These entries are not accessed with gp-relative
+ // addressing, but MIPS ABI requires that these entries be present in GOT.
+ // TLS entries:
+ // Entries created by TLS relocations.
+
+ // Number of "Header" entries.
+ static const unsigned HeaderEntriesNum = 2;
+ // Number of allocated "Page" entries.
+ uint32_t PageEntriesNum = 0;
+ // Map output sections referenced by MIPS GOT relocations
+ // to the first index of "Page" entries allocated for this section.
+ llvm::SmallMapVector<const OutputSectionBase *, size_t, 16> PageIndexMap;
+
+ typedef std::pair<const SymbolBody *, uintX_t> GotEntry;
+ typedef std::vector<GotEntry> GotEntries;
+ // Map from Symbol-Addend pair to the GOT index.
+ llvm::DenseMap<GotEntry, size_t> EntryIndexMap;
+ // Local entries (16-bit access).
+ GotEntries LocalEntries;
+ // Local entries (32-bit access).
+ GotEntries LocalEntries32;
+
+ // Normal and reloc-only global entries.
+ GotEntries GlobalEntries;
+
+ // TLS entries.
+ std::vector<const SymbolBody *> TlsEntries;
+
+ uint32_t TlsIndexOff = -1;
+ uintX_t Size = 0;
+};
+
+template <class ELFT>
+class GotPltSection final : public SyntheticSection<ELFT> {
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ GotPltSection();
+ void addEntry(SymbolBody &Sym);
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const override { return Entries.empty(); }
+
+private:
+ std::vector<const SymbolBody *> Entries;
+};
+
+// The IgotPltSection is a Got associated with the IpltSection for GNU Ifunc
+// Symbols that will be relocated by Target->IRelativeRel.
+// On most Targets the IgotPltSection will immediately follow the GotPltSection
+// on ARM the IgotPltSection will immediately follow the GotSection.
+template <class ELFT>
+class IgotPltSection final : public SyntheticSection<ELFT> {
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ IgotPltSection();
+ void addEntry(SymbolBody &Sym);
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const override { return Entries.empty(); }
+
+private:
+ std::vector<const SymbolBody *> Entries;
+};
+
+template <class ELFT>
+class StringTableSection final : public SyntheticSection<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;
+ size_t getSize() const override { return Size; }
+ bool isDynamic() const { return Dynamic; }
+
+private:
+ const bool Dynamic;
+
+ // ELF string tables start with a NUL byte, so 1.
+ uintX_t Size = 1;
+
+ llvm::DenseMap<StringRef, unsigned> StringMap;
+ std::vector<StringRef> Strings;
+};
+
+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 *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 *getOutputSec() const { return OutputSec; }
+ const InputSectionBase<ELFT> *getInputSec() const { return InputSec; }
+
+ uint32_t Type;
+
+private:
+ SymbolBody *Sym;
+ const InputSectionBase<ELFT> *InputSec = nullptr;
+ const OutputSectionBase *OutputSec = nullptr;
+ uintX_t OffsetInSec;
+ bool UseSymVA;
+ uintX_t Addend;
+};
+
+template <class ELFT>
+class DynamicSection final : public SyntheticSection<ELFT> {
+ 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 *OutSec;
+ InputSection<ELFT> *InSec;
+ uint64_t Val;
+ const SymbolBody *Sym;
+ };
+ enum KindT { SecAddr, SecSize, SymAddr, PlainInt, InSecAddr } Kind;
+ Entry(int32_t Tag, OutputSectionBase *OutSec, KindT Kind = SecAddr)
+ : Tag(Tag), OutSec(OutSec), Kind(Kind) {}
+ Entry(int32_t Tag, InputSection<ELFT> *Sec)
+ : Tag(Tag), InSec(Sec), Kind(InSecAddr) {}
+ Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {}
+ Entry(int32_t Tag, const SymbolBody *Sym)
+ : Tag(Tag), Sym(Sym), Kind(SymAddr) {}
+ };
+
+ // finalize() fills this vector with the section contents. finalize()
+ // cannot directly create final section contents because when the
+ // function is called, symbol or section addresses are not fixed yet.
+ std::vector<Entry> Entries;
+
+public:
+ DynamicSection();
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Size; }
+
+private:
+ void addEntries();
+ void add(Entry E) { Entries.push_back(E); }
+ uintX_t Size = 0;
+};
+
+template <class ELFT>
+class RelocationSection final : public SyntheticSection<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 empty() const override { return Relocs.empty(); }
+ size_t getSize() const override { return Relocs.size() * this->Entsize; }
+ size_t getRelativeRelocCount() const { return NumRelativeRelocs; }
+
+private:
+ bool Sort;
+ size_t NumRelativeRelocs = 0;
+ std::vector<DynamicReloc<ELFT>> Relocs;
+};
+
+struct SymbolTableEntry {
+ SymbolBody *Symbol;
+ size_t StrTabOffset;
+};
+
+template <class ELFT>
+class SymbolTableSection final : public SyntheticSection<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;
+ size_t getSize() const override { return getNumSymbols() * sizeof(Elf_Sym); }
+ void addGlobal(SymbolBody *Body);
+ void addLocal(SymbolBody *Body);
+ StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
+ unsigned getNumSymbols() const { return Symbols.size() + 1; }
+ size_t getSymbolIndex(SymbolBody *Body);
+
+ ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
+
+ static const OutputSectionBase *getOutputSection(SymbolBody *Sym);
+
+private:
+ void writeLocalSymbols(uint8_t *&Buf);
+ void writeGlobalSymbols(uint8_t *Buf);
+
+ // A vector of symbols and their string table offsets.
+ std::vector<SymbolTableEntry> Symbols;
+
+ StringTableSection<ELFT> &StrTabSec;
+
+ unsigned NumLocals = 0;
+};
+
+// Outputs GNU Hash section. For detailed explanation see:
+// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
+template <class ELFT>
+class GnuHashTableSection final : public SyntheticSection<ELFT> {
+ typedef typename ELFT::Off Elf_Off;
+ typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ GnuHashTableSection();
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return this->Size; }
+
+ // Adds symbols to the hash table.
+ // Sorts the input to satisfy GNU hash section requirements.
+ void addSymbols(std::vector<SymbolTableEntry> &Symbols);
+
+private:
+ static unsigned calcNBuckets(unsigned NumHashed);
+ static unsigned calcMaskWords(unsigned NumHashed);
+
+ 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;
+ uintX_t Size = 0;
+};
+
+template <class ELFT>
+class HashTableSection final : public SyntheticSection<ELFT> {
+ typedef typename ELFT::Word Elf_Word;
+
+public:
+ HashTableSection();
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return this->Size; }
+
+private:
+ size_t Size = 0;
+};
+
+template <class ELFT> class PltSection final : public SyntheticSection<ELFT> {
+public:
+ PltSection();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override;
+ void addEntry(SymbolBody &Sym);
+ bool empty() const override { return Entries.empty(); }
+
+private:
+ std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
+};
+
+// The IpltSection is a variant of Plt for recording entries for GNU Ifunc
+// symbols that will be subject to a Target->IRelativeRel
+// The IpltSection immediately follows the Plt section in the Output Section
+template <class ELFT> class IpltSection final : public SyntheticSection<ELFT> {
+public:
+ IpltSection();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override;
+ void addEntry(SymbolBody &Sym);
+ bool empty() const override { return Entries.empty(); }
+
+private:
+ std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
+};
+
+template <class ELFT>
+class GdbIndexSection final : public SyntheticSection<ELFT> {
+ typedef typename ELFT::uint uintX_t;
+
+ const unsigned OffsetTypeSize = 4;
+ const unsigned CuListOffset = 6 * OffsetTypeSize;
+ const unsigned CompilationUnitSize = 16;
+ const unsigned AddressEntrySize = 16 + OffsetTypeSize;
+ const unsigned SymTabEntrySize = 2 * OffsetTypeSize;
+
+public:
+ GdbIndexSection();
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override;
+ bool empty() const override;
+
+ // Pairs of [CU Offset, CU length].
+ std::vector<std::pair<uintX_t, uintX_t>> CompilationUnits;
+
+ llvm::StringTableBuilder StringPool;
+
+ GdbHashTab SymbolTable;
+
+ // The CU vector portion of the constant pool.
+ std::vector<std::vector<std::pair<uint32_t, uint8_t>>> CuVectors;
+
+ std::vector<AddressEntry<ELFT>> AddressArea;
+
+private:
+ void parseDebugSections();
+ void readDwarf(InputSection<ELFT> *I);
+
+ uint32_t CuTypesOffset;
+ uint32_t SymTabOffset;
+ uint32_t ConstantPoolOffset;
+ uint32_t StringPoolOffset;
+
+ size_t CuVectorsSize = 0;
+ std::vector<size_t> CuVectorsOffset;
+
+ bool Finalized = false;
+};
+
+// --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 SyntheticSection<ELFT> {
+ typedef typename ELFT::uint uintX_t;
+
+public:
+ EhFrameHeader();
+ void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override;
+ void addFde(uint32_t Pc, uint32_t FdeVA);
+ bool empty() const override;
+
+private:
+ struct FdeData {
+ uint32_t Pc;
+ uint32_t FdeVA;
+ };
+
+ std::vector<FdeData> Fdes;
+};
+
+// 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 SyntheticSection<ELFT> {
+ typedef typename ELFT::Verdef Elf_Verdef;
+ typedef typename ELFT::Verdaux Elf_Verdaux;
+
+public:
+ VersionDefinitionSection();
+ void finalize() override;
+ size_t getSize() const 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 SyntheticSection<ELFT> {
+ typedef typename ELFT::Versym Elf_Versym;
+
+public:
+ VersionTableSection();
+ void finalize() override;
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const 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 SyntheticSection<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 getSize() const override;
+ size_t getNeedNum() const { return Needed.size(); }
+ bool empty() const override;
+};
+
+// .MIPS.abiflags section.
+template <class ELFT>
+class MipsAbiFlagsSection final : public SyntheticSection<ELFT> {
+ typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags;
+
+public:
+ static MipsAbiFlagsSection *create();
+
+ MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags);
+ size_t getSize() const override { return sizeof(Elf_Mips_ABIFlags); }
+ void writeTo(uint8_t *Buf) override;
+
+private:
+ Elf_Mips_ABIFlags Flags;
+};
+
+// .MIPS.options section.
+template <class ELFT>
+class MipsOptionsSection final : public SyntheticSection<ELFT> {
+ typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
+ typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+ static MipsOptionsSection *create();
+
+ MipsOptionsSection(Elf_Mips_RegInfo Reginfo);
+ void writeTo(uint8_t *Buf) override;
+
+ size_t getSize() const override {
+ return sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+ }
+
+private:
+ Elf_Mips_RegInfo Reginfo;
+};
+
+// MIPS .reginfo section.
+template <class ELFT>
+class MipsReginfoSection final : public SyntheticSection<ELFT> {
+ typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
+
+public:
+ static MipsReginfoSection *create();
+
+ MipsReginfoSection(Elf_Mips_RegInfo Reginfo);
+ size_t getSize() const override { return sizeof(Elf_Mips_RegInfo); }
+ void writeTo(uint8_t *Buf) override;
+
+private:
+ Elf_Mips_RegInfo Reginfo;
+};
+
+// This is a MIPS specific section to hold a space within the data segment
+// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
+// See "Dynamic section" in Chapter 5 in the following document:
+// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+template <class ELFT> class MipsRldMapSection : public SyntheticSection<ELFT> {
+public:
+ MipsRldMapSection();
+ size_t getSize() const override { return sizeof(typename ELFT::uint); }
+ void writeTo(uint8_t *Buf) override;
+};
+
+template <class ELFT> class ARMExidxSentinelSection : public SyntheticSection<ELFT> {
+public:
+ ARMExidxSentinelSection();
+ size_t getSize() const override { return 8; }
+ void writeTo(uint8_t *Buf) override;
+};
+
+template <class ELFT> InputSection<ELFT> *createCommonSection();
+template <class ELFT> InputSection<ELFT> *createInterpSection();
+template <class ELFT> MergeInputSection<ELFT> *createCommentSection();
+
+// Linker generated sections which can be used as inputs.
+template <class ELFT> struct In {
+ static InputSection<ELFT> *ARMAttributes;
+ static BuildIdSection<ELFT> *BuildId;
+ static InputSection<ELFT> *Common;
+ static DynamicSection<ELFT> *Dynamic;
+ static StringTableSection<ELFT> *DynStrTab;
+ static SymbolTableSection<ELFT> *DynSymTab;
+ static EhFrameHeader<ELFT> *EhFrameHdr;
+ static GnuHashTableSection<ELFT> *GnuHashTab;
+ static GdbIndexSection<ELFT> *GdbIndex;
+ static GotSection<ELFT> *Got;
+ static MipsGotSection<ELFT> *MipsGot;
+ static GotPltSection<ELFT> *GotPlt;
+ static IgotPltSection<ELFT> *IgotPlt;
+ static HashTableSection<ELFT> *HashTab;
+ static InputSection<ELFT> *Interp;
+ static MipsRldMapSection<ELFT> *MipsRldMap;
+ static PltSection<ELFT> *Plt;
+ static IpltSection<ELFT> *Iplt;
+ static RelocationSection<ELFT> *RelaDyn;
+ static RelocationSection<ELFT> *RelaPlt;
+ static RelocationSection<ELFT> *RelaIplt;
+ static StringTableSection<ELFT> *ShStrTab;
+ static StringTableSection<ELFT> *StrTab;
+ static SymbolTableSection<ELFT> *SymTab;
+ static VersionDefinitionSection<ELFT> *VerDef;
+ static VersionTableSection<ELFT> *VerSym;
+ static VersionNeedSection<ELFT> *VerNeed;
+};
+
+template <class ELFT> InputSection<ELFT> *In<ELFT>::ARMAttributes;
+template <class ELFT> BuildIdSection<ELFT> *In<ELFT>::BuildId;
+template <class ELFT> InputSection<ELFT> *In<ELFT>::Common;
+template <class ELFT> DynamicSection<ELFT> *In<ELFT>::Dynamic;
+template <class ELFT> StringTableSection<ELFT> *In<ELFT>::DynStrTab;
+template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::DynSymTab;
+template <class ELFT> EhFrameHeader<ELFT> *In<ELFT>::EhFrameHdr;
+template <class ELFT> GdbIndexSection<ELFT> *In<ELFT>::GdbIndex;
+template <class ELFT> GnuHashTableSection<ELFT> *In<ELFT>::GnuHashTab;
+template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
+template <class ELFT> MipsGotSection<ELFT> *In<ELFT>::MipsGot;
+template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt;
+template <class ELFT> IgotPltSection<ELFT> *In<ELFT>::IgotPlt;
+template <class ELFT> HashTableSection<ELFT> *In<ELFT>::HashTab;
+template <class ELFT> InputSection<ELFT> *In<ELFT>::Interp;
+template <class ELFT> MipsRldMapSection<ELFT> *In<ELFT>::MipsRldMap;
+template <class ELFT> PltSection<ELFT> *In<ELFT>::Plt;
+template <class ELFT> IpltSection<ELFT> *In<ELFT>::Iplt;
+template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaDyn;
+template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaPlt;
+template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaIplt;
+template <class ELFT> StringTableSection<ELFT> *In<ELFT>::ShStrTab;
+template <class ELFT> StringTableSection<ELFT> *In<ELFT>::StrTab;
+template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::SymTab;
+template <class ELFT> VersionDefinitionSection<ELFT> *In<ELFT>::VerDef;
+template <class ELFT> VersionTableSection<ELFT> *In<ELFT>::VerSym;
+template <class ELFT> VersionNeedSection<ELFT> *In<ELFT>::VerNeed;
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Target.cpp b/contrib/llvm/tools/lld/ELF/Target.cpp
index 0375eb9..55fcf17 100644
--- a/contrib/llvm/tools/lld/ELF/Target.cpp
+++ b/contrib/llvm/tools/lld/ELF/Target.cpp
@@ -10,7 +10,7 @@
// Machine-specific things, such as applying relocations, creation of
// GOT or PLT entries, etc., are handled in this file.
//
-// Refer the ELF spec for the single letter varaibles, S, A or P, used
+// Refer the ELF spec for the single letter variables, S, A or P, used
// in this file.
//
// Some functions defined in this file has "relaxTls" as part of their names.
@@ -27,54 +27,89 @@
#include "Target.h"
#include "Error.h"
#include "InputFiles.h"
+#include "Memory.h"
#include "OutputSections.h"
+#include "SymbolTable.h"
#include "Symbols.h"
+#include "SyntheticSections.h"
#include "Thunks.h"
-
+#include "Writer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/Endian.h"
#include "llvm/Support/ELF.h"
+#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
+std::string lld::toString(uint32_t Type) {
+ return getELFRelocationTypeName(elf::Config->EMachine, Type);
+}
+
namespace lld {
namespace elf {
TargetInfo *Target;
static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
+static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); }
+
+template <class ELFT> static std::string getErrorLoc(uint8_t *Loc) {
+ for (InputSectionData *D : Symtab<ELFT>::X->Sections) {
+ auto *IS = dyn_cast_or_null<InputSection<ELFT>>(D);
+ if (!IS || !IS->OutSec)
+ continue;
-StringRef getRelName(uint32_t Type) {
- return getELFRelocationTypeName(Config->EMachine, Type);
+ uint8_t *ISLoc = cast<OutputSection<ELFT>>(IS->OutSec)->Loc + IS->OutSecOff;
+ if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
+ return IS->getLocation(Loc - ISLoc) + ": ";
+ }
+ return "";
+}
+
+static std::string getErrorLocation(uint8_t *Loc) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return getErrorLoc<ELF32LE>(Loc);
+ case ELF32BEKind:
+ return getErrorLoc<ELF32BE>(Loc);
+ case ELF64LEKind:
+ return getErrorLoc<ELF64LE>(Loc);
+ case ELF64BEKind:
+ return getErrorLoc<ELF64BE>(Loc);
+ default:
+ llvm_unreachable("unknown ELF type");
+ }
}
-template <unsigned N> static void checkInt(int64_t V, uint32_t Type) {
+template <unsigned N>
+static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) {
if (!isInt<N>(V))
- error("relocation " + getRelName(Type) + " out of range");
+ error(getErrorLocation(Loc) + "relocation " + toString(Type) +
+ " out of range");
}
-template <unsigned N> static void checkUInt(uint64_t V, uint32_t Type) {
+template <unsigned N>
+static void checkUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
if (!isUInt<N>(V))
- error("relocation " + getRelName(Type) + " out of range");
+ error(getErrorLocation(Loc) + "relocation " + toString(Type) +
+ " out of range");
}
-template <unsigned N> static void checkIntUInt(uint64_t V, uint32_t Type) {
+template <unsigned N>
+static void checkIntUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
if (!isInt<N>(V) && !isUInt<N>(V))
- error("relocation " + getRelName(Type) + " out of range");
+ error(getErrorLocation(Loc) + "relocation " + toString(Type) +
+ " out of range");
}
-template <unsigned N> static void checkAlignment(uint64_t V, uint32_t Type) {
+template <unsigned N>
+static void checkAlignment(uint8_t *Loc, uint64_t V, uint32_t Type) {
if ((V & (N - 1)) != 0)
- error("improper alignment for relocation " + getRelName(Type));
-}
-
-static void errorDynRel(uint32_t Type) {
- error("relocation " + getRelName(Type) +
- " cannot be used against shared object; recompile with -fPIC.");
+ error(getErrorLocation(Loc) + "improper alignment for relocation " +
+ toString(Type));
}
namespace {
@@ -89,6 +124,7 @@ public:
bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
@@ -106,7 +142,7 @@ template <class ELFT> class X86_64TargetInfo final : public TargetInfo {
public:
X86_64TargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- uint32_t getDynRel(uint32_t Type) const override;
+ bool isPicRel(uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
@@ -150,7 +186,7 @@ class AArch64TargetInfo final : public TargetInfo {
public:
AArch64TargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- uint32_t getDynRel(uint32_t Type) const override;
+ bool isPicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
@@ -176,14 +212,18 @@ class ARMTargetInfo final : public TargetInfo {
public:
ARMTargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ bool isPicRel(uint32_t Type) const override;
uint32_t getDynRel(uint32_t Type) const override;
uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ bool isTlsLocalDynamicRel(uint32_t Type) const override;
+ bool isTlsGlobalDynamicRel(uint32_t Type) const override;
+ bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
- RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType,
- const InputFile &File,
+ RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
@@ -193,6 +233,7 @@ public:
MipsTargetInfo();
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ bool isPicRel(uint32_t Type) const override;
uint32_t getDynRel(uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
bool isTlsGlobalDynamicRel(uint32_t Type) const override;
@@ -200,8 +241,7 @@ public:
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
- RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType,
- const InputFile &File,
+ RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
bool usesOnlyLowPageBits(uint32_t Type) const override;
@@ -211,34 +251,35 @@ public:
TargetInfo *createTarget() {
switch (Config->EMachine) {
case EM_386:
- return new X86TargetInfo();
+ case EM_IAMCU:
+ return make<X86TargetInfo>();
case EM_AARCH64:
- return new AArch64TargetInfo();
+ return make<AArch64TargetInfo>();
case EM_AMDGPU:
- return new AMDGPUTargetInfo();
+ return make<AMDGPUTargetInfo>();
case EM_ARM:
- return new ARMTargetInfo();
+ return make<ARMTargetInfo>();
case EM_MIPS:
switch (Config->EKind) {
case ELF32LEKind:
- return new MipsTargetInfo<ELF32LE>();
+ return make<MipsTargetInfo<ELF32LE>>();
case ELF32BEKind:
- return new MipsTargetInfo<ELF32BE>();
+ return make<MipsTargetInfo<ELF32BE>>();
case ELF64LEKind:
- return new MipsTargetInfo<ELF64LE>();
+ return make<MipsTargetInfo<ELF64LE>>();
case ELF64BEKind:
- return new MipsTargetInfo<ELF64BE>();
+ return make<MipsTargetInfo<ELF64BE>>();
default:
fatal("unsupported MIPS target");
}
case EM_PPC:
- return new PPCTargetInfo();
+ return make<PPCTargetInfo>();
case EM_PPC64:
- return new PPC64TargetInfo();
+ return make<PPC64TargetInfo>();
case EM_X86_64:
if (Config->EKind == ELF32LEKind)
- return new X86_64TargetInfo<ELF32LE>();
- return new X86_64TargetInfo<ELF64LE>();
+ return make<X86_64TargetInfo<ELF32LE>>();
+ return make<X86_64TargetInfo<ELF64LE>>();
}
fatal("unknown target machine");
}
@@ -262,8 +303,10 @@ bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
bool TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return false; }
-bool TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
- return false;
+bool TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const { return false; }
+
+void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ writeGotPlt(Buf, S);
}
RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
@@ -313,7 +356,9 @@ X86TargetInfo::X86TargetInfo() {
RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
switch (Type) {
- default:
+ case R_386_16:
+ case R_386_32:
+ case R_386_TLS_LDO_32:
return R_ABS;
case R_386_TLS_GD:
return R_TLSGD;
@@ -321,10 +366,11 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
return R_TLSLD;
case R_386_PLT32:
return R_PLT_PC;
+ case R_386_PC16:
case R_386_PC32:
return R_PC;
case R_386_GOTPC:
- return R_GOTONLY_PC;
+ return R_GOTONLY_PC_FROM_END;
case R_386_TLS_IE:
return R_GOT;
case R_386_GOT32:
@@ -332,11 +378,17 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
case R_386_TLS_GOTIE:
return R_GOT_FROM_END;
case R_386_GOTOFF:
- return R_GOTREL;
+ return R_GOTREL_FROM_END;
case R_386_TLS_LE:
return R_TLS;
case R_386_TLS_LE_32:
return R_NEG_TLS;
+ case R_386_NONE:
+ return R_HINT;
+ default:
+ error("do not know how to handle relocation '" + toString(Type) + "' (" +
+ Twine(Type) + ")");
+ return R_HINT;
}
}
@@ -353,7 +405,7 @@ RelExpr X86TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
}
void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
- write32le(Buf, Out<ELF32LE>::Dynamic->getVA());
+ write32le(Buf, In<ELF32LE>::Dynamic->getVA());
}
void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
@@ -362,6 +414,11 @@ void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
write32le(Buf, S.getPltVA<ELF32LE>() + 6);
}
+void X86TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ // An x86 entry is the address of the ifunc resolver function.
+ write32le(Buf, S.getVA<ELF32LE>());
+}
+
uint32_t X86TargetInfo::getDynRel(uint32_t Type) const {
if (Type == R_386_TLS_LE)
return R_386_TLS_TPOFF;
@@ -401,7 +458,7 @@ void X86TargetInfo::writePltHeader(uint8_t *Buf) const {
0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
};
memcpy(Buf, PltData, sizeof(PltData));
- uint32_t Got = Out<ELF32LE>::GotPlt->getVA();
+ uint32_t Got = In<ELF32LE>::GotPlt->getVA();
write32le(Buf + 2, Got + 4);
write32le(Buf + 8, Got + 8);
}
@@ -418,7 +475,7 @@ void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
// jmp *foo@GOT(%ebx) or jmp *foo_in_GOT
Buf[1] = Config->Pic ? 0xa3 : 0x25;
- uint32_t Got = Out<ELF32LE>::GotPlt->getVA();
+ uint32_t Got = In<ELF32LE>::GotPlt->getVA();
write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
write32le(Buf + 7, RelOff);
write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
@@ -429,6 +486,9 @@ uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
switch (Type) {
default:
return 0;
+ case R_386_16:
+ case R_386_PC16:
+ return read16le(Buf);
case R_386_32:
case R_386_GOT32:
case R_386_GOT32X:
@@ -443,7 +503,14 @@ uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
- checkInt<32>(Val, Type);
+ checkInt<32>(Loc, Val, Type);
+
+ // R_386_PC16 and R_386_16 are not part of the current i386 psABI. They are
+ // used by 16-bit x86 objects, like boot loaders.
+ if (Type == R_386_16 || Type == R_386_PC16) {
+ write16le(Loc, Val);
+ return;
+ }
write32le(Loc, Val);
}
@@ -555,13 +622,20 @@ template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
+ // Align to the large page size (known as a superpage or huge page).
+ // FreeBSD automatically promotes large, superpage-aligned allocations.
+ DefaultImageBase = 0x200000;
}
template <class ELFT>
RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
const SymbolBody &S) const {
switch (Type) {
- default:
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ case R_X86_64_64:
+ case R_X86_64_DTPOFF32:
+ case R_X86_64_DTPOFF64:
return R_ABS;
case R_X86_64_TPOFF32:
return R_TLS;
@@ -578,12 +652,19 @@ RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
case R_X86_64_PC64:
return R_PC;
case R_X86_64_GOT32:
+ case R_X86_64_GOT64:
return R_GOT_FROM_END;
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
case R_X86_64_GOTTPOFF:
return R_GOT_PC;
+ case R_X86_64_NONE:
+ return R_HINT;
+ default:
+ error("do not know how to handle relocation '" + toString(Type) + "' (" +
+ Twine(Type) + ")");
+ return R_HINT;
}
}
@@ -593,7 +674,7 @@ void X86_64TargetInfo<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
// required, but it is documented in the psabi and the glibc dynamic linker
// seems to use it (note that this is relevant for linking ld.so, not any
// other program).
- write64le(Buf, Out<ELFT>::Dynamic->getVA());
+ write64le(Buf, In<ELFT>::Dynamic->getVA());
}
template <class ELFT>
@@ -611,8 +692,8 @@ void X86_64TargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
0x0f, 0x1f, 0x40, 0x00 // nopl 0x0(rax)
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t Got = Out<ELFT>::GotPlt->getVA();
- uint64_t Plt = Out<ELFT>::Plt->getVA();
+ uint64_t Got = In<ELFT>::GotPlt->getVA();
+ uint64_t Plt = In<ELFT>::Plt->getVA();
write32le(Buf + 2, Got - Plt + 2); // GOT+8
write32le(Buf + 8, Got - Plt + 4); // GOT+16
}
@@ -634,10 +715,8 @@ void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
}
template <class ELFT>
-uint32_t X86_64TargetInfo<ELFT>::getDynRel(uint32_t Type) const {
- if (Type == R_X86_64_PC32 || Type == R_X86_64_32)
- errorDynRel(Type);
- return Type;
+bool X86_64TargetInfo<ELFT>::isPicRel(uint32_t Type) const {
+ return Type != R_X86_64_PC32 && Type != R_X86_64_32;
}
template <class ELFT>
@@ -736,7 +815,8 @@ void X86_64TargetInfo<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
memcpy(Inst, "\x48\xc7", 2);
*RegSlot = 0xc0 | Reg;
} else {
- fatal("R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
+ error(getErrorLocation(Loc - 3) +
+ "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
}
// The original code used a PC relative relocation.
@@ -778,7 +858,7 @@ void X86_64TargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
switch (Type) {
case R_X86_64_32:
- checkUInt<32>(Val, Type);
+ checkUInt<32>(Loc, Val, Type);
write32le(Loc, Val);
break;
case R_X86_64_32S:
@@ -794,17 +874,19 @@ void X86_64TargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
case R_X86_64_TLSLD:
case R_X86_64_DTPOFF32:
case R_X86_64_SIZE32:
- checkInt<32>(Val, Type);
+ checkInt<32>(Loc, Val, Type);
write32le(Loc, Val);
break;
case R_X86_64_64:
case R_X86_64_DTPOFF64:
- case R_X86_64_SIZE64:
+ case R_X86_64_GLOB_DAT:
case R_X86_64_PC64:
+ case R_X86_64_SIZE64:
+ case R_X86_64_GOT64:
write64le(Loc, Val);
break;
default:
- fatal("unrecognized reloc " + Twine(Type));
+ llvm_unreachable("unexpected relocation");
}
}
@@ -965,13 +1047,26 @@ void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
case R_PPC_ADDR16_LO:
write16be(Loc, applyPPCLo(Val));
break;
+ case R_PPC_ADDR32:
+ case R_PPC_REL32:
+ write32be(Loc, Val);
+ break;
+ case R_PPC_REL24:
+ or32be(Loc, Val & 0x3FFFFFC);
+ break;
default:
- fatal("unrecognized reloc " + Twine(Type));
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
- return R_ABS;
+ switch (Type) {
+ case R_PPC_REL24:
+ case R_PPC_REL32:
+ return R_PC;
+ default:
+ return R_ABS;
+ }
}
PPC64TargetInfo::PPC64TargetInfo() {
@@ -984,7 +1079,7 @@ PPC64TargetInfo::PPC64TargetInfo() {
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
- PageSize = 65536;
+ DefaultMaxPageSize = 65536;
// The PPC64 ELF ABI v1 spec, says:
//
@@ -1004,7 +1099,7 @@ uint64_t getPPC64TocBase() {
// TOC starts where the first of these sections starts. We always create a
// .got when we see a relocation that uses it, so for us the start is always
// the .got.
- uint64_t TocVA = Out<ELF64BE>::Got->getVA();
+ uint64_t TocVA = In<ELF64BE>::Got->getVA();
// Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
// thus permitting a full 64 Kbytes segment. Note that the glibc startup
@@ -1042,26 +1137,33 @@ void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
// be a pointer to the function descriptor in the .opd section. Using
// this scheme is simpler, but requires an extra indirection per PLT dispatch.
- write32be(Buf, 0xf8410028); // std %r2, 40(%r1)
- write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
- write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
- write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
- write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
- write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
- write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
- write32be(Buf + 28, 0x4e800420); // bctr
+ write32be(Buf, 0xf8410028); // std %r2, 40(%r1)
+ write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
+ write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
+ write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
+ write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
+ write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
+ write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
+ write32be(Buf + 28, 0x4e800420); // bctr
}
static std::pair<uint32_t, uint64_t> toAddr16Rel(uint32_t Type, uint64_t Val) {
uint64_t V = Val - PPC64TocOffset;
switch (Type) {
- case R_PPC64_TOC16: return {R_PPC64_ADDR16, V};
- case R_PPC64_TOC16_DS: return {R_PPC64_ADDR16_DS, V};
- case R_PPC64_TOC16_HA: return {R_PPC64_ADDR16_HA, V};
- case R_PPC64_TOC16_HI: return {R_PPC64_ADDR16_HI, V};
- case R_PPC64_TOC16_LO: return {R_PPC64_ADDR16_LO, V};
- case R_PPC64_TOC16_LO_DS: return {R_PPC64_ADDR16_LO_DS, V};
- default: return {Type, Val};
+ case R_PPC64_TOC16:
+ return {R_PPC64_ADDR16, V};
+ case R_PPC64_TOC16_DS:
+ return {R_PPC64_ADDR16_DS, V};
+ case R_PPC64_TOC16_HA:
+ return {R_PPC64_ADDR16_HA, V};
+ case R_PPC64_TOC16_HI:
+ return {R_PPC64_ADDR16_HI, V};
+ case R_PPC64_TOC16_LO:
+ return {R_PPC64_ADDR16_LO, V};
+ case R_PPC64_TOC16_LO_DS:
+ return {R_PPC64_ADDR16_LO_DS, V};
+ default:
+ return {Type, Val};
}
}
@@ -1073,18 +1175,18 @@ void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
switch (Type) {
case R_PPC64_ADDR14: {
- checkAlignment<4>(Val, Type);
+ checkAlignment<4>(Loc, Val, Type);
// Preserve the AA/LK bits in the branch instruction
uint8_t AALK = Loc[3];
write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
break;
}
case R_PPC64_ADDR16:
- checkInt<16>(Val, Type);
+ checkInt<16>(Loc, Val, Type);
write16be(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
- checkInt<16>(Val, Type);
+ checkInt<16>(Loc, Val, Type);
write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
break;
case R_PPC64_ADDR16_HA:
@@ -1116,7 +1218,7 @@ void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
break;
case R_PPC64_ADDR32:
case R_PPC64_REL32:
- checkInt<32>(Val, Type);
+ checkInt<32>(Loc, Val, Type);
write32be(Loc, Val);
break;
case R_PPC64_ADDR64:
@@ -1126,12 +1228,12 @@ void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
break;
case R_PPC64_REL24: {
uint32_t Mask = 0x03FFFFFC;
- checkInt<24>(Val, Type);
+ checkInt<24>(Loc, Val, Type);
write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
break;
}
default:
- fatal("unrecognized reloc " + Twine(Type));
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
@@ -1147,6 +1249,7 @@ AArch64TargetInfo::AArch64TargetInfo() {
GotPltEntrySize = 8;
PltEntrySize = 16;
PltHeaderSize = 32;
+ DefaultMaxPageSize = 65536;
// It doesn't seem to be documented anywhere, but tls on aarch64 uses variant
// 1 of the tls structures and the tcb size is 16.
@@ -1164,7 +1267,7 @@ RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
case R_AARCH64_TLSDESC_ADD_LO12_NC:
return R_TLSDESC;
case R_AARCH64_TLSDESC_CALL:
- return R_HINT;
+ return R_TLSDESC_CALL;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
return R_TLS;
@@ -1222,19 +1325,18 @@ bool AArch64TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
}
-uint32_t AArch64TargetInfo::getDynRel(uint32_t Type) const {
- if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64)
- return Type;
- // Keep it going with a dummy value so that we can find more reloc errors.
- errorDynRel(Type);
- return R_AARCH64_ABS32;
+bool AArch64TargetInfo::isPicRel(uint32_t Type) const {
+ return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64;
}
void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
- write64le(Buf, Out<ELF64LE>::Plt->getVA());
+ write64le(Buf, In<ELF64LE>::Plt->getVA());
}
-static uint64_t getAArch64Page(uint64_t Expr) {
+// 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.)
+uint64_t getAArch64Page(uint64_t Expr) {
return Expr & (~static_cast<uint64_t>(0xFFF));
}
@@ -1251,8 +1353,8 @@ void AArch64TargetInfo::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t Got = Out<ELF64LE>::GotPlt->getVA();
- uint64_t Plt = Out<ELF64LE>::Plt->getVA();
+ uint64_t Got = In<ELF64LE>::GotPlt->getVA();
+ uint64_t Plt = In<ELF64LE>::Plt->getVA();
relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
@@ -1276,14 +1378,22 @@ void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotEntryAddr);
}
-static void updateAArch64Addr(uint8_t *L, uint64_t Imm) {
+static void write32AArch64Addr(uint8_t *L, uint64_t Imm) {
uint32_t ImmLo = (Imm & 0x3) << 29;
uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
}
-static inline void updateAArch64Add(uint8_t *L, uint64_t Imm) {
+// Return the bits [Start, End] from Val shifted Start bits.
+// For instance, getBits(0xF0, 4, 8) returns 0xF.
+static uint64_t getBits(uint64_t Val, int Start, int End) {
+ uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1;
+ return (Val >> Start) & Mask;
+}
+
+// Update the immediate field in a AARCH64 ldr, str, and add instruction.
+static void or32AArch64Imm(uint8_t *L, uint64_t Imm) {
or32le(L, (Imm & 0xFFF) << 10);
}
@@ -1292,80 +1402,89 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
switch (Type) {
case R_AARCH64_ABS16:
case R_AARCH64_PREL16:
- checkIntUInt<16>(Val, Type);
+ checkIntUInt<16>(Loc, Val, Type);
write16le(Loc, Val);
break;
case R_AARCH64_ABS32:
case R_AARCH64_PREL32:
- checkIntUInt<32>(Val, Type);
+ checkIntUInt<32>(Loc, Val, Type);
write32le(Loc, Val);
break;
case R_AARCH64_ABS64:
+ case R_AARCH64_GLOB_DAT:
case R_AARCH64_PREL64:
write64le(Loc, Val);
break;
case R_AARCH64_ADD_ABS_LO12_NC:
- // This relocation stores 12 bits and there's no instruction
- // to do it. Instead, we do a 32 bits store of the value
- // of r_addend bitwise-or'ed Loc. This assumes that the addend
- // bits in Loc are zero.
- or32le(Loc, (Val & 0xFFF) << 10);
+ or32AArch64Imm(Loc, Val);
break;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSDESC_ADR_PAGE21:
- checkInt<33>(Val, Type);
- updateAArch64Addr(Loc, Val >> 12);
+ checkInt<33>(Loc, Val, Type);
+ write32AArch64Addr(Loc, Val >> 12);
break;
case R_AARCH64_ADR_PREL_LO21:
- checkInt<21>(Val, Type);
- updateAArch64Addr(Loc, Val);
+ checkInt<21>(Loc, Val, Type);
+ write32AArch64Addr(Loc, Val);
break;
case R_AARCH64_CALL26:
case R_AARCH64_JUMP26:
- checkInt<28>(Val, Type);
+ checkInt<28>(Loc, Val, Type);
or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
break;
case R_AARCH64_CONDBR19:
- checkInt<21>(Val, Type);
+ checkInt<21>(Loc, Val, Type);
or32le(Loc, (Val & 0x1FFFFC) << 3);
break;
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case R_AARCH64_TLSDESC_LD64_LO12_NC:
- checkAlignment<8>(Val, Type);
+ checkAlignment<8>(Loc, Val, Type);
or32le(Loc, (Val & 0xFF8) << 7);
break;
- case R_AARCH64_LDST128_ABS_LO12_NC:
- or32le(Loc, (Val & 0x0FF8) << 6);
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ or32AArch64Imm(Loc, getBits(Val, 0, 11));
break;
case R_AARCH64_LDST16_ABS_LO12_NC:
- or32le(Loc, (Val & 0x0FFC) << 9);
- break;
- case R_AARCH64_LDST8_ABS_LO12_NC:
- or32le(Loc, (Val & 0xFFF) << 10);
+ or32AArch64Imm(Loc, getBits(Val, 1, 11));
break;
case R_AARCH64_LDST32_ABS_LO12_NC:
- or32le(Loc, (Val & 0xFFC) << 8);
+ or32AArch64Imm(Loc, getBits(Val, 2, 11));
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
- or32le(Loc, (Val & 0xFF8) << 7);
+ or32AArch64Imm(Loc, getBits(Val, 3, 11));
+ break;
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ or32AArch64Imm(Loc, getBits(Val, 4, 11));
+ break;
+ case R_AARCH64_MOVW_UABS_G0_NC:
+ or32le(Loc, (Val & 0xFFFF) << 5);
+ break;
+ case R_AARCH64_MOVW_UABS_G1_NC:
+ or32le(Loc, (Val & 0xFFFF0000) >> 11);
+ break;
+ case R_AARCH64_MOVW_UABS_G2_NC:
+ or32le(Loc, (Val & 0xFFFF00000000) >> 27);
+ break;
+ case R_AARCH64_MOVW_UABS_G3:
+ or32le(Loc, (Val & 0xFFFF000000000000) >> 43);
break;
case R_AARCH64_TSTBR14:
- checkInt<16>(Val, Type);
+ checkInt<16>(Loc, Val, Type);
or32le(Loc, (Val & 0xFFFC) << 3);
break;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
- checkInt<24>(Val, Type);
- updateAArch64Add(Loc, Val >> 12);
+ checkInt<24>(Loc, Val, Type);
+ or32AArch64Imm(Loc, Val >> 12);
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_ADD_LO12_NC:
- updateAArch64Add(Loc, Val);
+ or32AArch64Imm(Loc, Val);
break;
default:
- fatal("unrecognized reloc " + Twine(Type));
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
@@ -1382,7 +1501,7 @@ void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
// movk x0, #0x10
// nop
// nop
- checkUInt<32>(Val, Type);
+ checkUInt<32>(Loc, Val, Type);
switch (Type) {
case R_AARCH64_TLSDESC_ADD_LO12_NC:
@@ -1434,7 +1553,7 @@ void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
- checkUInt<32>(Val, Type);
+ checkUInt<32>(Loc, Val, Type);
if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
// Generate MOVZ.
@@ -1452,6 +1571,7 @@ void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
}
AMDGPUTargetInfo::AMDGPUTargetInfo() {
+ RelativeRel = R_AMDGPU_REL64;
GotRel = R_AMDGPU_ABS64;
GotEntrySize = 8;
}
@@ -1459,20 +1579,37 @@ AMDGPUTargetInfo::AMDGPUTargetInfo() {
void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
switch (Type) {
+ case R_AMDGPU_ABS32:
case R_AMDGPU_GOTPCREL:
+ case R_AMDGPU_GOTPCREL32_LO:
case R_AMDGPU_REL32:
+ case R_AMDGPU_REL32_LO:
write32le(Loc, Val);
break;
+ case R_AMDGPU_ABS64:
+ write64le(Loc, Val);
+ break;
+ case R_AMDGPU_GOTPCREL32_HI:
+ case R_AMDGPU_REL32_HI:
+ write32le(Loc, Val >> 32);
+ break;
default:
- fatal("unrecognized reloc " + Twine(Type));
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
switch (Type) {
+ case R_AMDGPU_ABS32:
+ case R_AMDGPU_ABS64:
+ return R_ABS;
case R_AMDGPU_REL32:
+ case R_AMDGPU_REL32_LO:
+ case R_AMDGPU_REL32_HI:
return R_PC;
case R_AMDGPU_GOTPCREL:
+ case R_AMDGPU_GOTPCREL32_LO:
+ case R_AMDGPU_GOTPCREL32_HI:
return R_GOT_PC;
default:
fatal("do not know how to handle relocation " + Twine(Type));
@@ -1492,6 +1629,9 @@ ARMTargetInfo::ARMTargetInfo() {
GotPltEntrySize = 4;
PltEntrySize = 16;
PltHeaderSize = 20;
+ // ARM uses Variant 1 TLS
+ TcbSize = 8;
+ NeedsThunks = true;
}
RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
@@ -1504,6 +1644,7 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
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:
case R_ARM_THM_CALL:
@@ -1515,8 +1656,21 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
// GOT(S) + A - GOT_ORG
return R_GOT_OFF;
case R_ARM_GOT_PREL:
- // GOT(S) + - GOT_ORG
+ case R_ARM_TLS_IE32:
+ // GOT(S) + A - P
return R_GOT_PC;
+ case R_ARM_TARGET1:
+ return Config->Target1Rel ? R_PC : R_ABS;
+ case R_ARM_TARGET2:
+ if (Config->Target2 == Target2Policy::Rel)
+ return R_PC;
+ if (Config->Target2 == Target2Policy::Abs)
+ return R_ABS;
+ return R_GOT_PC;
+ case R_ARM_TLS_GD32:
+ return R_TLSGD_PC;
+ case R_ARM_TLS_LDM32:
+ return R_TLSLD_PC;
case R_ARM_BASE_PREL:
// B(S) + A - P
// FIXME: currently B(S) assumed to be .got, this may not hold for all
@@ -1524,24 +1678,38 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
return R_GOTONLY_PC;
case R_ARM_MOVW_PREL_NC:
case R_ARM_MOVT_PREL:
- case R_ARM_PREL31:
case R_ARM_REL32:
case R_ARM_THM_MOVW_PREL_NC:
case R_ARM_THM_MOVT_PREL:
return R_PC;
+ case R_ARM_NONE:
+ return R_HINT;
+ case R_ARM_TLS_LE32:
+ return R_TLS;
}
}
+bool ARMTargetInfo::isPicRel(uint32_t Type) const {
+ return (Type == R_ARM_TARGET1 && !Config->Target1Rel) ||
+ (Type == R_ARM_ABS32);
+}
+
uint32_t ARMTargetInfo::getDynRel(uint32_t Type) const {
+ if (Type == R_ARM_TARGET1 && !Config->Target1Rel)
+ return R_ARM_ABS32;
if (Type == R_ARM_ABS32)
return Type;
// Keep it going with a dummy value so that we can find more reloc errors.
- errorDynRel(Type);
return R_ARM_ABS32;
}
void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
- write32le(Buf, Out<ELF32LE>::Plt->getVA());
+ write32le(Buf, In<ELF32LE>::Plt->getVA());
+}
+
+void ARMTargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ // An ARM entry is the address of the ifunc resolver function.
+ write32le(Buf, S.getVA<ELF32LE>());
}
void ARMTargetInfo::writePltHeader(uint8_t *Buf) const {
@@ -1553,8 +1721,8 @@ void ARMTargetInfo::writePltHeader(uint8_t *Buf) const {
0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t GotPlt = Out<ELF32LE>::GotPlt->getVA();
- uint64_t L1 = Out<ELF32LE>::Plt->getVA() + 8;
+ uint64_t GotPlt = In<ELF32LE>::GotPlt->getVA();
+ uint64_t L1 = In<ELF32LE>::Plt->getVA() + 8;
write32le(Buf + 16, GotPlt - L1 - 8);
}
@@ -1578,6 +1746,12 @@ void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
const InputFile &File,
const SymbolBody &S) const {
+ // If S is an undefined weak symbol in an executable we don't need a Thunk.
+ // In a DSO calls to undefined symbols, including weak ones get PLT entries
+ // which may need a thunk.
+ if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak()
+ && !Config->Shared)
+ return Expr;
// A state change from ARM to Thumb and vice versa must go through an
// interworking thunk if the relocation type is not R_ARM_CALL or
// R_ARM_THM_CALL.
@@ -1606,18 +1780,29 @@ RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
switch (Type) {
- case R_ARM_NONE:
- break;
case R_ARM_ABS32:
case R_ARM_BASE_PREL:
+ case R_ARM_GLOB_DAT:
case R_ARM_GOTOFF32:
case R_ARM_GOT_BREL:
case R_ARM_GOT_PREL:
case R_ARM_REL32:
+ case R_ARM_RELATIVE:
+ case R_ARM_TARGET1:
+ case R_ARM_TARGET2:
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LDM32:
+ case R_ARM_TLS_LDO32:
+ case R_ARM_TLS_LE32:
+ case R_ARM_TLS_TPOFF32:
write32le(Loc, Val);
break;
+ case R_ARM_TLS_DTPMOD32:
+ write32le(Loc, 1);
+ break;
case R_ARM_PREL31:
- checkInt<31>(Val, Type);
+ checkInt<31>(Loc, Val, Type);
write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
break;
case R_ARM_CALL:
@@ -1626,7 +1811,7 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
if (Val & 1) {
// If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
// The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
- checkInt<26>(Val, Type);
+ checkInt<26>(Loc, Val, Type);
write32le(Loc, 0xfa000000 | // opcode
((Val & 2) << 23) | // H
((Val >> 2) & 0x00ffffff)); // imm24
@@ -1636,20 +1821,20 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
// BLX (always unconditional) instruction to an ARM Target, select an
// unconditional BL.
write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff));
- // fall through as BL encoding is shared with B
+ // fall through as BL encoding is shared with B
case R_ARM_JUMP24:
case R_ARM_PC24:
case R_ARM_PLT32:
- checkInt<26>(Val, Type);
+ checkInt<26>(Loc, Val, Type);
write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
break;
case R_ARM_THM_JUMP11:
- checkInt<12>(Val, Type);
+ checkInt<12>(Loc, Val, Type);
write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
break;
case R_ARM_THM_JUMP19:
// Encoding T3: Val = S:J2:J1:imm6:imm11:0
- checkInt<21>(Val, Type);
+ checkInt<21>(Loc, Val, Type);
write16le(Loc,
(read16le(Loc) & 0xfbc0) | // opcode cond
((Val >> 10) & 0x0400) | // S
@@ -1670,11 +1855,11 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
}
// Bit 12 is 0 for BLX, 1 for BL
write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12);
- // Fall through as rest of encoding is the same as B.W
+ // Fall through as rest of encoding is the same as B.W
case R_ARM_THM_JUMP24:
// Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
// FIXME: Use of I1 and I2 require v6T2ops
- checkInt<25>(Val, Type);
+ checkInt<25>(Loc, Val, Type);
write16le(Loc,
0xf000 | // opcode
((Val >> 14) & 0x0400) | // S
@@ -1692,14 +1877,14 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
break;
case R_ARM_MOVT_ABS:
case R_ARM_MOVT_PREL:
- checkInt<32>(Val, Type);
+ checkInt<32>(Loc, Val, Type);
write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
(((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
break;
case R_ARM_THM_MOVT_ABS:
case R_ARM_THM_MOVT_PREL:
// Encoding T1: A = imm4:i:imm3:imm8
- checkInt<32>(Val, Type);
+ checkInt<32>(Loc, Val, Type);
write16le(Loc,
0xf2c0 | // opcode
((Val >> 17) & 0x0400) | // i
@@ -1722,7 +1907,7 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
(Val & 0x00ff)); // imm8
break;
default:
- fatal("unrecognized reloc " + Twine(Type));
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
@@ -1737,6 +1922,13 @@ uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
case R_ARM_GOT_BREL:
case R_ARM_GOT_PREL:
case R_ARM_REL32:
+ case R_ARM_TARGET1:
+ case R_ARM_TARGET2:
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_LDM32:
+ case R_ARM_TLS_LDO32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LE32:
return SignExtend64<32>(read32le(Buf));
case R_ARM_PREL31:
return SignExtend64<31>(read32le(Buf));
@@ -1794,15 +1986,28 @@ uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
}
}
+bool ARMTargetInfo::isTlsLocalDynamicRel(uint32_t Type) const {
+ return Type == R_ARM_TLS_LDO32 || Type == R_ARM_TLS_LDM32;
+}
+
+bool ARMTargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
+ return Type == R_ARM_TLS_GD32;
+}
+
+bool ARMTargetInfo::isTlsInitialExecRel(uint32_t Type) const {
+ return Type == R_ARM_TLS_IE32;
+}
+
template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
GotPltHeaderEntriesNum = 2;
- PageSize = 65536;
+ DefaultMaxPageSize = 65536;
GotEntrySize = sizeof(typename ELFT::uint);
GotPltEntrySize = sizeof(typename ELFT::uint);
PltEntrySize = 16;
PltHeaderSize = 32;
CopyRel = R_MIPS_COPY;
PltRel = R_MIPS_JUMP_SLOT;
+ NeedsThunks = true;
if (ELFT::Is64Bits) {
RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
TlsGotRel = R_MIPS_TLS_TPREL64;
@@ -1819,8 +2024,8 @@ template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
template <class ELFT>
RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
const SymbolBody &S) const {
- if (ELFT::Is64Bits)
- // See comment in the calculateMips64RelChain.
+ // See comment in the calculateMipsRelChain.
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
Type &= 0xff;
switch (Type) {
default:
@@ -1829,16 +2034,16 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
return R_HINT;
case R_MIPS_GPREL16:
case R_MIPS_GPREL32:
- return R_GOTREL;
+ return R_MIPS_GOTREL;
case R_MIPS_26:
return R_PLT;
case R_MIPS_HI16:
case R_MIPS_LO16:
case R_MIPS_GOT_OFST:
- // MIPS _gp_disp designates offset between start of function and 'gp'
- // pointer into GOT. __gnu_local_gp is equal to the current value of
- // the 'gp'. Therefore any relocations against them do not require
- // dynamic relocation.
+ // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
+ // offset between start of function and 'gp' value which by default
+ // equal to the start of .got section. In that case we consider these
+ // relocations as relative.
if (&S == ElfSym<ELFT>::MipsGpDisp)
return R_PC;
return R_ABS;
@@ -1858,6 +2063,11 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
case R_MIPS_GOT_DISP:
case R_MIPS_TLS_GOTTPREL:
return R_MIPS_GOT_OFF;
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_CALL_LO16:
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_GOT_LO16:
+ return R_MIPS_GOT_OFF32;
case R_MIPS_GOT_PAGE:
return R_MIPS_GOT_LOCAL_PAGE;
case R_MIPS_TLS_GD:
@@ -1867,13 +2077,13 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
}
}
+template <class ELFT> bool MipsTargetInfo<ELFT>::isPicRel(uint32_t Type) const {
+ return Type == R_MIPS_32 || Type == R_MIPS_64;
+}
+
template <class ELFT>
uint32_t MipsTargetInfo<ELFT>::getDynRel(uint32_t Type) const {
- if (Type == R_MIPS_32 || Type == R_MIPS_64)
- return RelativeRel;
- // Keep it going with a dummy value so that we can find more reloc errors.
- errorDynRel(Type);
- return R_MIPS_32;
+ return RelativeRel;
}
template <class ELFT>
@@ -1888,11 +2098,9 @@ bool MipsTargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
template <class ELFT>
void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
- write32<ELFT::TargetEndianness>(Buf, Out<ELFT>::Plt->getVA());
+ write32<ELFT::TargetEndianness>(Buf, In<ELFT>::Plt->getVA());
}
-static uint16_t mipsHigh(uint64_t V) { return (V + 0x8000) >> 16; }
-
template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
static int64_t getPcRelocAddend(const uint8_t *Loc) {
uint32_t Instr = read32<E>(Loc);
@@ -1905,35 +2113,59 @@ static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) {
uint32_t Mask = 0xffffffff >> (32 - BSIZE);
uint32_t Instr = read32<E>(Loc);
if (SHIFT > 0)
- checkAlignment<(1 << SHIFT)>(V, Type);
- checkInt<BSIZE + SHIFT>(V, Type);
+ checkAlignment<(1 << SHIFT)>(Loc, V, Type);
+ checkInt<BSIZE + SHIFT>(Loc, V, Type);
write32<E>(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask));
}
-template <endianness E>
-static void writeMipsHi16(uint8_t *Loc, uint64_t V) {
+template <endianness E> static void writeMipsHi16(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ uint16_t Res = ((V + 0x8000) >> 16) & 0xffff;
+ write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E> static void writeMipsHigher(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff;
+ write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E> static void writeMipsHighest(uint8_t *Loc, uint64_t V) {
uint32_t Instr = read32<E>(Loc);
- write32<E>(Loc, (Instr & 0xffff0000) | mipsHigh(V));
+ uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff;
+ write32<E>(Loc, (Instr & 0xffff0000) | Res);
}
-template <endianness E>
-static void writeMipsLo16(uint8_t *Loc, uint64_t V) {
+template <endianness E> static void writeMipsLo16(uint8_t *Loc, uint64_t V) {
uint32_t Instr = read32<E>(Loc);
write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
}
+template <class ELFT> static bool isMipsR6() {
+ const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
+ uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH;
+ return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
+}
+
template <class ELFT>
void MipsTargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
const endianness E = ELFT::TargetEndianness;
- write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
- write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
- write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
- write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28
+ if (Config->MipsN32Abi) {
+ write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14)
+ write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
+ write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14
+ } else {
+ write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
+ write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
+ write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28
+ }
write32<E>(Buf + 16, 0x03e07825); // move $15, $31
write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
write32<E>(Buf + 24, 0x0320f809); // jalr $25
write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
- uint64_t Got = Out<ELFT>::GotPlt->getVA();
+ uint64_t Got = In<ELFT>::GotPlt->getVA();
writeMipsHi16<E>(Buf, Got);
writeMipsLo16<E>(Buf + 4, Got);
writeMipsLo16<E>(Buf + 8, Got);
@@ -1944,9 +2176,10 @@ void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const endianness E = ELFT::TargetEndianness;
- write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
- write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
- write32<E>(Buf + 8, 0x03200008); // jr $25
+ write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
+ write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
+ // jr $25
+ write32<E>(Buf + 8, isMipsR6<ELFT>() ? 0x03200009 : 0x03200008);
write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
writeMipsHi16<E>(Buf, GotEntryAddr);
writeMipsLo16<E>(Buf + 4, GotEntryAddr);
@@ -1971,14 +2204,9 @@ RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type,
if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
return Expr;
auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
- if (!D || !D->Section)
- return Expr;
// LA25 is required if target file has PIC code
// or target symbol is a PIC symbol.
- const ELFFile<ELFT> &DefFile = D->Section->getFile()->getObj();
- bool PicFile = DefFile.getHeader()->e_flags & EF_MIPS_PIC;
- bool PicSym = (D->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC;
- return (PicFile || PicSym) ? R_THUNK_ABS : Expr;
+ return D && D->isMipsPIC() ? R_THUNK_ABS : Expr;
}
template <class ELFT>
@@ -1990,12 +2218,14 @@ uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
return 0;
case R_MIPS_32:
case R_MIPS_GPREL32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
return read32<E>(Buf);
case R_MIPS_26:
// FIXME (simon): If the relocation target symbol is not a PLT entry
// we should use another expression for calculation:
// ((A << 2) | (P & 0xf0000000)) >> 2
- return SignExtend64<28>(read32<E>(Buf) << 2);
+ return SignExtend64<28>((read32<E>(Buf) & 0x3ffffff) << 2);
case R_MIPS_GPREL16:
case R_MIPS_LO16:
case R_MIPS_PCLO16:
@@ -2017,8 +2247,8 @@ uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
}
}
-static std::pair<uint32_t, uint64_t> calculateMips64RelChain(uint32_t Type,
- uint64_t Val) {
+static std::pair<uint32_t, uint64_t>
+calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) {
// MIPS N64 ABI packs multiple relocations into the single relocation
// record. In general, all up to three relocations can have arbitrary
// types. In fact, Clang and GCC uses only a few combinations. For now,
@@ -2039,7 +2269,8 @@ static std::pair<uint32_t, uint64_t> calculateMips64RelChain(uint32_t Type,
return std::make_pair(Type2, Val);
if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
return std::make_pair(Type3, -Val);
- error("unsupported relocations combination " + Twine(Type));
+ error(getErrorLocation(Loc) + "unsupported relocations combination " +
+ Twine(Type));
return std::make_pair(Type & 0xff, Val);
}
@@ -2049,22 +2280,28 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
const endianness E = ELFT::TargetEndianness;
// Thread pointer and DRP offsets from the start of TLS data area.
// https://www.linux-mips.org/wiki/NPTL
- if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16)
+ if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 ||
+ Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64)
Val -= 0x8000;
- else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16)
+ else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 ||
+ Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64)
Val -= 0x7000;
- if (ELFT::Is64Bits)
- std::tie(Type, Val) = calculateMips64RelChain(Type, Val);
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
+ std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
switch (Type) {
case R_MIPS_32:
case R_MIPS_GPREL32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
write32<E>(Loc, Val);
break;
case R_MIPS_64:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
write64<E>(Loc, Val);
break;
case R_MIPS_26:
- write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | (Val >> 2));
+ write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff));
break;
case R_MIPS_GOT_DISP:
case R_MIPS_GOT_PAGE:
@@ -2072,9 +2309,11 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
case R_MIPS_GPREL16:
case R_MIPS_TLS_GD:
case R_MIPS_TLS_LDM:
- checkInt<16>(Val, Type);
+ checkInt<16>(Loc, Val, Type);
// fallthrough
case R_MIPS_CALL16:
+ case R_MIPS_CALL_LO16:
+ case R_MIPS_GOT_LO16:
case R_MIPS_GOT_OFST:
case R_MIPS_LO16:
case R_MIPS_PCLO16:
@@ -2083,12 +2322,20 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
case R_MIPS_TLS_TPREL_LO16:
writeMipsLo16<E>(Loc, Val);
break;
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_GOT_HI16:
case R_MIPS_HI16:
case R_MIPS_PCHI16:
case R_MIPS_TLS_DTPREL_HI16:
case R_MIPS_TLS_TPREL_HI16:
writeMipsHi16<E>(Loc, Val);
break;
+ case R_MIPS_HIGHER:
+ writeMipsHigher<E>(Loc, Val);
+ break;
+ case R_MIPS_HIGHEST:
+ writeMipsHighest<E>(Loc, Val);
+ break;
case R_MIPS_JALR:
// Ignore this optimization relocation for now
break;
@@ -2108,7 +2355,7 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
applyMipsPcReloc<E, 32, 0>(Loc, Type, Val);
break;
default:
- fatal("unrecognized reloc " + Twine(Type));
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
diff --git a/contrib/llvm/tools/lld/ELF/Target.h b/contrib/llvm/tools/lld/ELF/Target.h
index d335c1e..752f9cd 100644
--- a/contrib/llvm/tools/lld/ELF/Target.h
+++ b/contrib/llvm/tools/lld/ELF/Target.h
@@ -26,9 +26,11 @@ public:
virtual bool isTlsInitialExecRel(uint32_t Type) const;
virtual bool isTlsLocalDynamicRel(uint32_t Type) const;
virtual bool isTlsGlobalDynamicRel(uint32_t Type) const;
+ virtual bool isPicRel(uint32_t Type) const { return true; }
virtual uint32_t getDynRel(uint32_t Type) const { return Type; }
virtual void writeGotPltHeader(uint8_t *Buf) const {}
virtual void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {};
+ virtual void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const;
virtual uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const;
// If lazy binding is supported, the first entry of the PLT has code
@@ -62,13 +64,12 @@ public:
unsigned TlsGdRelaxSkip = 1;
unsigned PageSize = 4096;
+ unsigned DefaultMaxPageSize = 4096;
- // On freebsd x86_64 the first page cannot be mmaped.
- // On linux that is controled by vm.mmap_min_addr. At least on some x86_64
+ // On FreeBSD x86_64 the first page cannot be mmaped.
+ // On Linux that is controled by vm.mmap_min_addr. At least on some x86_64
// installs that is 65536, so the first 15 pages cannot be used.
// Given that, the smallest value that can be used in here is 0x10000.
- // If using 2MB pages, the smallest page aligned address that works is
- // 0x200000, but it looks like every OS uses 4k pages for executables.
uint64_t DefaultImageBase = 0x10000;
uint32_t CopyRel;
@@ -80,8 +81,8 @@ public:
uint32_t TlsGotRel;
uint32_t TlsModuleIndexRel;
uint32_t TlsOffsetRel;
- unsigned GotEntrySize;
- unsigned GotPltEntrySize;
+ unsigned GotEntrySize = 0;
+ unsigned GotPltEntrySize = 0;
unsigned PltEntrySize;
unsigned PltHeaderSize;
@@ -92,6 +93,8 @@ public:
// Set to 0 for variant 2
unsigned TcbSize = 0;
+ bool NeedsThunks = false;
+
virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
RelExpr Expr) const;
virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;
@@ -101,14 +104,14 @@ public:
virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
};
-StringRef getRelName(uint32_t Type);
uint64_t getPPC64TocBase();
-
-const unsigned MipsGPOffset = 0x7ff0;
+uint64_t getAArch64Page(uint64_t Expr);
extern TargetInfo *Target;
TargetInfo *createTarget();
}
+
+std::string toString(uint32_t RelType);
}
#endif
diff --git a/contrib/llvm/tools/lld/ELF/Threads.h b/contrib/llvm/tools/lld/ELF/Threads.h
new file mode 100644
index 0000000..c03e152
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Threads.h
@@ -0,0 +1,90 @@
+//===- Threads.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LLD supports threads to distribute workloads to multiple cores. Using
+// multicore is most effective when more than one core are idle. At the
+// last step of a build, it is often the case that a linker is the only
+// active process on a computer. So, we are naturally interested in using
+// threads wisely to reduce latency to deliver results to users.
+//
+// That said, we don't want to do "too clever" things using threads.
+// Complex multi-threaded algorithms are sometimes extremely hard to
+// justify the correctness and can easily mess up the entire design.
+//
+// Fortunately, when a linker links large programs (when the link time is
+// most critical), it spends most of the time to work on massive number of
+// small pieces of data of the same kind, and there are opportunities for
+// large parallelism there. Here are examples:
+//
+// - We have hundreds of thousands of input sections that need to be
+// copied to a result file at the last step of link. Once we fix a file
+// layout, each section can be copied to its destination and its
+// relocations can be applied independently.
+//
+// - We have tens of millions of small strings when constructing a
+// mergeable string section.
+//
+// For the cases such as the former, we can just use parallel_for_each
+// instead of std::for_each (or a plain for loop). Because tasks are
+// completely independent from each other, we can run them in parallel
+// without any coordination between them. That's very easy to understand
+// and justify.
+//
+// For the cases such as the latter, we can use parallel algorithms to
+// deal with massive data. We have to write code for a tailored algorithm
+// for each problem, but the complexity of multi-threading is isolated in
+// a single pass and doesn't affect the linker's overall design.
+//
+// The above approach seems to be working fairly well. As an example, when
+// linking Chromium (output size 1.6 GB), using 4 cores reduces latency to
+// 75% compared to single core (from 12.66 seconds to 9.55 seconds) on my
+// Ivy Bridge Xeon 2.8 GHz machine. Using 40 cores reduces it to 63% (from
+// 12.66 seconds to 7.95 seconds). Because of the Amdahl's law, the
+// speedup is not linear, but as you add more cores, it gets faster.
+//
+// On a final note, if you are trying to optimize, keep the axiom "don't
+// guess, measure!" in mind. Some important passes of the linker are not
+// that slow. For example, resolving all symbols is not a very heavy pass,
+// although it would be very hard to parallelize it. You want to first
+// identify a slow pass and then optimize it.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_THREADS_H
+#define LLD_ELF_THREADS_H
+
+#include "Config.h"
+
+#include "lld/Core/Parallel.h"
+#include <algorithm>
+#include <functional>
+
+namespace lld {
+namespace elf {
+
+template <class IterTy, class FuncTy>
+void forEach(IterTy Begin, IterTy End, FuncTy Fn) {
+ if (Config->Threads)
+ parallel_for_each(Begin, End, Fn);
+ else
+ std::for_each(Begin, End, Fn);
+}
+
+inline void forLoop(size_t Begin, size_t End, std::function<void(size_t)> Fn) {
+ if (Config->Threads) {
+ parallel_for(Begin, End, Fn);
+ } else {
+ for (size_t I = Begin; I < End; ++I)
+ Fn(I);
+ }
+}
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/Thunks.cpp b/contrib/llvm/tools/lld/ELF/Thunks.cpp
index 1ebbb17..397a0ee 100644
--- a/contrib/llvm/tools/lld/ELF/Thunks.cpp
+++ b/contrib/llvm/tools/lld/ELF/Thunks.cpp
@@ -22,17 +22,20 @@
//===---------------------------------------------------------------------===//
#include "Thunks.h"
+#include "Config.h"
#include "Error.h"
-#include "InputFiles.h"
#include "InputSection.h"
+#include "Memory.h"
#include "OutputSections.h"
#include "Symbols.h"
#include "Target.h"
-#include "llvm/Support/Allocator.h"
-
-#include "llvm/Object/ELF.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+#include <cstring>
using namespace llvm;
using namespace llvm::object;
@@ -43,6 +46,7 @@ namespace lld {
namespace elf {
namespace {
+
// Specific ARM Thunk implementations. The naming convention is:
// Source State, TargetState, Target Requirement, ABS or PI, Range
template <class ELFT>
@@ -96,11 +100,13 @@ public:
uint32_t size() const override { return 16; }
void writeTo(uint8_t *Buf) const override;
};
-} // anonymous namespace
+
+} // end anonymous namespace
// ARM Target Thunks
template <class ELFT> static uint64_t getARMThunkDestVA(const SymbolBody &S) {
- return S.isInPlt() ? S.getPltVA<ELFT>() : S.getVA<ELFT>();
+ uint64_t V = S.isInPlt() ? S.getPltVA<ELFT>() : S.getVA<ELFT>();
+ return SignExtend64<32>(V);
}
template <class ELFT>
@@ -177,10 +183,10 @@ Thunk<ELFT>::Thunk(const SymbolBody &D, const InputSection<ELFT> &O)
: Destination(D), Owner(O), Offset(O.getThunkOff() + O.getThunksSize()) {}
template <class ELFT> typename ELFT::uint Thunk<ELFT>::getVA() const {
- return Owner.OutSec->getVA() + Owner.OutSecOff + Offset;
+ return Owner.OutSec->Addr + Owner.OutSecOff + Offset;
}
-template <class ELFT> Thunk<ELFT>::~Thunk() {}
+template <class ELFT> Thunk<ELFT>::~Thunk() = default;
// Creates a thunk for Thumb-ARM interworking.
template <class ELFT>
@@ -189,19 +195,18 @@ static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S,
// ARM relocations need ARM to Thumb interworking Thunks.
// Thumb relocations need Thumb to ARM relocations.
// Use position independent Thunks if we require position independent code.
- BumpPtrAllocator &Alloc = IS.getFile()->Alloc;
switch (Reloc) {
case R_ARM_PC24:
case R_ARM_PLT32:
case R_ARM_JUMP24:
if (Config->Pic)
- return new (Alloc) ARMToThumbV7PILongThunk<ELFT>(S, IS);
- return new (Alloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS);
+ return new (BAlloc) ARMToThumbV7PILongThunk<ELFT>(S, IS);
+ return new (BAlloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS);
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
if (Config->Pic)
- return new (Alloc) ThumbToARMV7PILongThunk<ELFT>(S, IS);
- return new (Alloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS);
+ return new (BAlloc) ThumbToARMV7PILongThunk<ELFT>(S, IS);
+ return new (BAlloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS);
}
fatal("unrecognized relocation type");
}
@@ -221,6 +226,8 @@ static void addThunkARM(uint32_t Reloc, SymbolBody &S, InputSection<ELFT> &IS) {
Sym->ThunkData = T;
else if (auto *Sym = dyn_cast<SharedSymbol<ELFT>>(&S))
Sym->ThunkData = T;
+ else if (auto *Sym = dyn_cast<Undefined<ELFT>>(&S))
+ Sym->ThunkData = T;
else
fatal("symbol not DefinedRegular or Shared");
}
@@ -235,7 +242,7 @@ static void addThunkMips(uint32_t RelocType, SymbolBody &S,
// Mips Thunks are added to the InputSection defining S.
auto *R = cast<DefinedRegular<ELFT>>(&S);
auto *Sec = cast<InputSection<ELFT>>(R->Section);
- auto *T = new (IS.getFile()->Alloc) MipsThunk<ELFT>(S, *Sec);
+ auto *T = new (BAlloc) MipsThunk<ELFT>(S, *Sec);
Sec->addThunk(T);
R->ThunkData = T;
}
@@ -264,5 +271,5 @@ template class Thunk<ELF32BE>;
template class Thunk<ELF64LE>;
template class Thunk<ELF64BE>;
-} // namespace elf
-} // namespace lld
+} // end namespace elf
+} // end namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/Writer.cpp b/contrib/llvm/tools/lld/ELF/Writer.cpp
index 387bec3..01f6f8e 100644
--- a/contrib/llvm/tools/lld/ELF/Writer.cpp
+++ b/contrib/llvm/tools/lld/ELF/Writer.cpp
@@ -10,21 +10,26 @@
#include "Writer.h"
#include "Config.h"
#include "LinkerScript.h"
+#include "Memory.h"
#include "OutputSections.h"
#include "Relocations.h"
#include "Strings.h"
#include "SymbolTable.h"
+#include "SyntheticSections.h"
#include "Target.h"
-
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
+#include <climits>
+#include <thread>
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;
@@ -40,32 +45,25 @@ public:
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::Rela Elf_Rela;
- Writer(SymbolTable<ELFT> &S) : Symtab(S) {}
void run();
private:
- // This describes a program header entry.
- // Each contains type, access flags and range of output sections that will be
- // placed in it.
- struct Phdr {
- Phdr(unsigned Type, unsigned Flags) {
- H.p_type = Type;
- H.p_flags = Flags;
- }
- Elf_Phdr H = {};
- OutputSectionBase<ELFT> *First = nullptr;
- OutputSectionBase<ELFT> *Last = nullptr;
- };
-
+ void createSyntheticSections();
void copyLocalSymbols();
void addReservedSymbols();
+ void addInputSec(InputSectionBase<ELFT> *S);
void createSections();
+ void forEachRelSec(std::function<void(InputSectionBase<ELFT> &)> Fn);
+ void sortSections();
+ void finalizeSections();
void addPredefinedSections();
- bool needsGot();
- void createPhdrs();
+ std::vector<PhdrEntry> createPhdrs();
+ void removeEmptyPTLoad();
+ void addPtArmExid(std::vector<PhdrEntry> &Phdrs);
void assignAddresses();
void assignFileOffsets();
+ void assignFileOffsetsBinary();
void setPhdrs();
void fixHeaders();
void fixSectionAlignments();
@@ -73,214 +71,312 @@ private:
void openFile();
void writeHeader();
void writeSections();
+ void writeSectionsBinary();
void writeBuildId();
- bool needsInterpSection() const {
- return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();
- }
- bool isOutputDynamic() const {
- return !Symtab.getSharedFiles().empty() || Config->Pic;
- }
-
- void addCommonSymbols(std::vector<DefinedCommon *> &Syms);
std::unique_ptr<FileOutputBuffer> Buffer;
- BumpPtrAllocator Alloc;
- std::vector<OutputSectionBase<ELFT> *> OutputSections;
- std::vector<std::unique_ptr<OutputSectionBase<ELFT>>> OwningSections;
+ std::vector<OutputSectionBase *> OutputSections;
+ OutputSectionFactory<ELFT> Factory;
void addRelIpltSymbols();
void addStartEndSymbols();
- void addStartStopSymbols(OutputSectionBase<ELFT> *Sec);
+ void addStartStopSymbols(OutputSectionBase *Sec);
+ uintX_t getEntryAddr();
+ OutputSectionBase *findSection(StringRef Name);
- SymbolTable<ELFT> &Symtab;
- std::vector<Phdr> Phdrs;
+ std::vector<PhdrEntry> Phdrs;
uintX_t FileSize;
uintX_t SectionHeaderOff;
+ bool AllocateHeader = true;
};
} // anonymous namespace
-template <class ELFT>
-StringRef elf::getOutputSectionName(InputSectionBase<ELFT> *S) {
- StringRef Dest = Script<ELFT>::X->getOutputSection(S);
- if (!Dest.empty())
- return Dest;
-
- StringRef Name = S->getSectionName();
- for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.",
- ".init_array.", ".fini_array.", ".ctors.", ".dtors.",
- ".tbss.", ".gcc_except_table.", ".tdata."})
- if (Name.startswith(V))
- return V.drop_back();
+StringRef elf::getOutputSectionName(StringRef Name) {
+ if (Config->Relocatable)
+ return Name;
+
+ for (StringRef V :
+ {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.",
+ ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
+ ".gcc_except_table.", ".tdata.", ".ARM.exidx."}) {
+ StringRef Prefix = V.drop_back();
+ if (Name.startswith(V) || Name == Prefix)
+ return Prefix;
+ }
+
+ // CommonSection is identified as "COMMON" in linker scripts.
+ // By default, it should go to .bss section.
+ if (Name == "COMMON")
+ return ".bss";
+
+ // ".zdebug_" is a prefix for ZLIB-compressed sections.
+ // Because we decompressed input sections, we want to remove 'z'.
+ if (Name.startswith(".zdebug_"))
+ return Saver.save(Twine(".") + Name.substr(2));
return Name;
}
-template <class ELFT>
-void elf::reportDiscarded(InputSectionBase<ELFT> *IS,
- const std::unique_ptr<elf::ObjectFile<ELFT>> &File) {
- if (!Config->PrintGcSections || !IS || IS->Live)
+template <class ELFT> void elf::reportDiscarded(InputSectionBase<ELFT> *IS) {
+ if (!Config->PrintGcSections)
return;
- errs() << "removing unused section from '" << IS->getSectionName()
- << "' in file '" << File->getName() << "'\n";
+ errs() << "removing unused section from '" << IS->Name << "' in file '"
+ << IS->getFile()->getName() << "'\n";
}
-template <class ELFT> void elf::writeResult(SymbolTable<ELFT> *Symtab) {
- typedef typename ELFT::uint uintX_t;
- typedef typename ELFT::Ehdr Elf_Ehdr;
+template <class ELFT> static bool needsInterpSection() {
+ return !Symtab<ELFT>::X->getSharedFiles().empty() &&
+ !Config->DynamicLinker.empty() &&
+ !Script<ELFT>::X->ignoreInterpSection();
+}
- // Create singleton output sections.
- OutputSection<ELFT> Bss(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
- DynamicSection<ELFT> Dynamic;
- EhOutputSection<ELFT> EhFrame;
- GotSection<ELFT> Got;
- InterpSection<ELFT> Interp;
- PltSection<ELFT> Plt;
- RelocationSection<ELFT> RelaDyn(Config->Rela ? ".rela.dyn" : ".rel.dyn",
- Config->ZCombreloc);
- StringTableSection<ELFT> DynStrTab(".dynstr", true);
- StringTableSection<ELFT> ShStrTab(".shstrtab", false);
- SymbolTableSection<ELFT> DynSymTab(DynStrTab);
- VersionTableSection<ELFT> VerSym;
- VersionNeedSection<ELFT> VerNeed;
-
- OutputSectionBase<ELFT> ElfHeader("", 0, SHF_ALLOC);
- ElfHeader.setSize(sizeof(Elf_Ehdr));
- OutputSectionBase<ELFT> ProgramHeaders("", 0, SHF_ALLOC);
- ProgramHeaders.updateAlignment(sizeof(uintX_t));
-
- // Instantiate optional output sections if they are needed.
- std::unique_ptr<BuildIdSection<ELFT>> BuildId;
- std::unique_ptr<EhFrameHeader<ELFT>> EhFrameHdr;
- std::unique_ptr<GnuHashTableSection<ELFT>> GnuHashTab;
- std::unique_ptr<GotPltSection<ELFT>> GotPlt;
- std::unique_ptr<HashTableSection<ELFT>> HashTab;
- std::unique_ptr<RelocationSection<ELFT>> RelaPlt;
- std::unique_ptr<StringTableSection<ELFT>> StrTab;
- std::unique_ptr<SymbolTableSection<ELFT>> SymTabSec;
- std::unique_ptr<OutputSection<ELFT>> MipsRldMap;
- std::unique_ptr<VersionDefinitionSection<ELFT>> VerDef;
-
- if (Config->BuildId == BuildIdKind::Fnv1)
- BuildId.reset(new BuildIdFnv1<ELFT>);
- else if (Config->BuildId == BuildIdKind::Md5)
- BuildId.reset(new BuildIdMd5<ELFT>);
- else if (Config->BuildId == BuildIdKind::Sha1)
- BuildId.reset(new BuildIdSha1<ELFT>);
- else if (Config->BuildId == BuildIdKind::Hexstring)
- BuildId.reset(new BuildIdHexstring<ELFT>);
-
- if (Config->EhFrameHdr)
- EhFrameHdr.reset(new EhFrameHeader<ELFT>);
-
- if (Config->GnuHash)
- GnuHashTab.reset(new GnuHashTableSection<ELFT>);
- if (Config->SysvHash)
- HashTab.reset(new HashTableSection<ELFT>);
- StringRef S = Config->Rela ? ".rela.plt" : ".rel.plt";
- GotPlt.reset(new GotPltSection<ELFT>);
- RelaPlt.reset(new RelocationSection<ELFT>(S, false /*Sort*/));
- if (!Config->StripAll) {
- StrTab.reset(new StringTableSection<ELFT>(".strtab", false));
- SymTabSec.reset(new SymbolTableSection<ELFT>(*StrTab));
- }
- if (Config->EMachine == EM_MIPS && !Config->Shared) {
- // This is a MIPS specific section to hold a space within the data segment
- // of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
- // See "Dynamic section" in Chapter 5 in the following document:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- MipsRldMap.reset(new OutputSection<ELFT>(".rld_map", SHT_PROGBITS,
- SHF_ALLOC | SHF_WRITE));
- MipsRldMap->setSize(sizeof(uintX_t));
- MipsRldMap->updateAlignment(sizeof(uintX_t));
- }
- if (!Config->VersionDefinitions.empty())
- VerDef.reset(new VersionDefinitionSection<ELFT>());
-
- Out<ELFT>::Bss = &Bss;
- Out<ELFT>::BuildId = BuildId.get();
- Out<ELFT>::DynStrTab = &DynStrTab;
- Out<ELFT>::DynSymTab = &DynSymTab;
- Out<ELFT>::Dynamic = &Dynamic;
- Out<ELFT>::EhFrame = &EhFrame;
- Out<ELFT>::EhFrameHdr = EhFrameHdr.get();
- Out<ELFT>::GnuHashTab = GnuHashTab.get();
- Out<ELFT>::Got = &Got;
- Out<ELFT>::GotPlt = GotPlt.get();
- Out<ELFT>::HashTab = HashTab.get();
- Out<ELFT>::Interp = &Interp;
- Out<ELFT>::Plt = &Plt;
- Out<ELFT>::RelaDyn = &RelaDyn;
- Out<ELFT>::RelaPlt = RelaPlt.get();
- Out<ELFT>::ShStrTab = &ShStrTab;
- Out<ELFT>::StrTab = StrTab.get();
- Out<ELFT>::SymTab = SymTabSec.get();
- Out<ELFT>::VerDef = VerDef.get();
- Out<ELFT>::VerSym = &VerSym;
- Out<ELFT>::VerNeed = &VerNeed;
- Out<ELFT>::MipsRldMap = MipsRldMap.get();
- Out<ELFT>::Opd = nullptr;
- Out<ELFT>::OpdBuf = nullptr;
- Out<ELFT>::TlsPhdr = nullptr;
- Out<ELFT>::ElfHeader = &ElfHeader;
- Out<ELFT>::ProgramHeaders = &ProgramHeaders;
-
- Writer<ELFT>(*Symtab).run();
+template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); }
+
+template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
+ auto I = std::remove_if(Phdrs.begin(), Phdrs.end(), [&](const PhdrEntry &P) {
+ if (P.p_type != PT_LOAD)
+ return false;
+ if (!P.First)
+ return true;
+ uintX_t Size = P.Last->Addr + P.Last->Size - P.First->Addr;
+ return Size == 0;
+ });
+ Phdrs.erase(I, Phdrs.end());
}
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
- if (!Config->DiscardAll)
+ // Create linker-synthesized sections such as .got or .plt.
+ // Such sections are of type input section.
+ createSyntheticSections();
+
+ // We need to create some reserved symbols such as _end. Create them.
+ if (!Config->Relocatable)
+ addReservedSymbols();
+
+ // Some architectures use small displacements for jump instructions.
+ // It is linker's responsibility to create thunks containing long
+ // jump instructions if jump targets are too far. Create thunks.
+ if (Target->NeedsThunks)
+ forEachRelSec(createThunks<ELFT>);
+
+ // Create output sections.
+ Script<ELFT>::X->OutputSections = &OutputSections;
+ if (ScriptConfig->HasSections) {
+ // If linker script contains SECTIONS commands, let it create sections.
+ Script<ELFT>::X->processCommands(Factory);
+
+ // Linker scripts may have left some input sections unassigned.
+ // Assign such sections using the default rule.
+ Script<ELFT>::X->addOrphanSections(Factory);
+ } else {
+ // If linker script does not contain SECTIONS commands, create
+ // output sections by default rules. We still need to give the
+ // linker script a chance to run, because it might contain
+ // non-SECTIONS commands such as ASSERT.
+ createSections();
+ Script<ELFT>::X->processCommands(Factory);
+ }
+
+ if (Config->Discard != DiscardPolicy::All)
copyLocalSymbols();
- addReservedSymbols();
- createSections();
- if (HasError)
+
+ // Now that we have a complete set of output sections. This function
+ // completes section contents. For example, we need to add strings
+ // to the string table, and add entries to .got and .plt.
+ // finalizeSections does that.
+ finalizeSections();
+ if (ErrorCount)
return;
if (Config->Relocatable) {
assignFileOffsets();
} else {
- createPhdrs();
- fixHeaders();
- if (ScriptConfig->DoLayout) {
- Script<ELFT>::X->assignAddresses(OutputSections);
+ if (ScriptConfig->HasSections) {
+ Script<ELFT>::X->assignAddresses(Phdrs);
} else {
fixSectionAlignments();
assignAddresses();
}
- assignFileOffsets();
+
+ // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
+ // 0 sized region. This has to be done late since only after assignAddresses
+ // we know the size of the sections.
+ removeEmptyPTLoad();
+
+ if (!Config->OFormatBinary)
+ assignFileOffsets();
+ else
+ assignFileOffsetsBinary();
+
setPhdrs();
fixAbsoluteSymbols();
}
+ // Write the result down to a file.
openFile();
- if (HasError)
+ if (ErrorCount)
return;
- writeHeader();
- writeSections();
+ if (!Config->OFormatBinary) {
+ writeHeader();
+ writeSections();
+ } else {
+ writeSectionsBinary();
+ }
+
+ // Backfill .note.gnu.build-id section content. This is done at last
+ // because the content is usually a hash value of the entire output file.
writeBuildId();
- if (HasError)
+ if (ErrorCount)
return;
+
if (auto EC = Buffer->commit())
error(EC, "failed to write to the output file");
+
+ // Flush the output streams and exit immediately. A full shutdown
+ // is a good test that we are keeping track of all allocated memory,
+ // but actually freeing it is a waste of time in a regular linker run.
+ if (Config->ExitEarly)
+ exitLld(0);
}
-template <class ELFT>
-static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
- if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
- return;
+// Initialize Out<ELFT> members.
+template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
+ // Initialize all pointers with NULL. This is needed because
+ // you can call lld::elf::main more than once as a library.
+ memset(&Out<ELFT>::First, 0, sizeof(Out<ELFT>));
- if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT &&
- Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef)
- return;
+ // Create singleton output sections.
+ Out<ELFT>::Bss =
+ make<OutputSection<ELFT>>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+ Out<ELFT>::BssRelRo = make<OutputSection<ELFT>>(".bss.rel.ro", SHT_NOBITS,
+ SHF_ALLOC | SHF_WRITE);
+ In<ELFT>::DynStrTab = make<StringTableSection<ELFT>>(".dynstr", true);
+ In<ELFT>::Dynamic = make<DynamicSection<ELFT>>();
+ Out<ELFT>::EhFrame = make<EhOutputSection<ELFT>>();
+ In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>(
+ Config->Rela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
+ In<ELFT>::ShStrTab = make<StringTableSection<ELFT>>(".shstrtab", false);
+
+ Out<ELFT>::ElfHeader = make<OutputSectionBase>("", 0, SHF_ALLOC);
+ Out<ELFT>::ElfHeader->Size = sizeof(Elf_Ehdr);
+ Out<ELFT>::ProgramHeaders = make<OutputSectionBase>("", 0, SHF_ALLOC);
+ Out<ELFT>::ProgramHeaders->updateAlignment(sizeof(uintX_t));
+
+ if (needsInterpSection<ELFT>()) {
+ In<ELFT>::Interp = createInterpSection<ELFT>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Interp);
+ } else {
+ In<ELFT>::Interp = nullptr;
+ }
- std::string Msg = "undefined symbol: " + Sym->getName().str();
- if (Sym->File)
- Msg += " in " + getFilename(Sym->File);
- if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn)
- warning(Msg);
- else
- error(Msg);
+ if (!Config->Relocatable)
+ Symtab<ELFT>::X->Sections.push_back(createCommentSection<ELFT>());
+
+ if (Config->Strip != StripPolicy::All) {
+ In<ELFT>::StrTab = make<StringTableSection<ELFT>>(".strtab", false);
+ In<ELFT>::SymTab = make<SymbolTableSection<ELFT>>(*In<ELFT>::StrTab);
+ }
+
+ if (Config->BuildId != BuildIdKind::None) {
+ In<ELFT>::BuildId = make<BuildIdSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::BuildId);
+ }
+
+ InputSection<ELFT> *Common = createCommonSection<ELFT>();
+ if (!Common->Data.empty()) {
+ In<ELFT>::Common = Common;
+ Symtab<ELFT>::X->Sections.push_back(Common);
+ }
+
+ // Add MIPS-specific sections.
+ bool HasDynSymTab = !Symtab<ELFT>::X->getSharedFiles().empty() || Config->Pic;
+ if (Config->EMachine == EM_MIPS) {
+ if (!Config->Shared && HasDynSymTab) {
+ In<ELFT>::MipsRldMap = make<MipsRldMapSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::MipsRldMap);
+ }
+ if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
+ Symtab<ELFT>::X->Sections.push_back(Sec);
+ if (auto *Sec = MipsOptionsSection<ELFT>::create())
+ Symtab<ELFT>::X->Sections.push_back(Sec);
+ if (auto *Sec = MipsReginfoSection<ELFT>::create())
+ Symtab<ELFT>::X->Sections.push_back(Sec);
+ }
+
+ if (HasDynSymTab) {
+ In<ELFT>::DynSymTab = make<SymbolTableSection<ELFT>>(*In<ELFT>::DynStrTab);
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::DynSymTab);
+
+ In<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::VerSym);
+
+ if (!Config->VersionDefinitions.empty()) {
+ In<ELFT>::VerDef = make<VersionDefinitionSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::VerDef);
+ }
+
+ In<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::VerNeed);
+
+ if (Config->GnuHash) {
+ In<ELFT>::GnuHashTab = make<GnuHashTableSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::GnuHashTab);
+ }
+
+ if (Config->SysvHash) {
+ In<ELFT>::HashTab = make<HashTableSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::HashTab);
+ }
+
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Dynamic);
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::DynStrTab);
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaDyn);
+ }
+
+ // Add .got. MIPS' .got is so different from the other archs,
+ // it has its own class.
+ if (Config->EMachine == EM_MIPS) {
+ In<ELFT>::MipsGot = make<MipsGotSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::MipsGot);
+ } else {
+ In<ELFT>::Got = make<GotSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Got);
+ }
+
+ In<ELFT>::GotPlt = make<GotPltSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::GotPlt);
+ In<ELFT>::IgotPlt = make<IgotPltSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::IgotPlt);
+
+ if (Config->GdbIndex) {
+ In<ELFT>::GdbIndex = make<GdbIndexSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::GdbIndex);
+ }
+
+ // We always need to add rel[a].plt to output if it has entries.
+ // Even for static linking it can contain R_[*]_IRELATIVE relocations.
+ In<ELFT>::RelaPlt = make<RelocationSection<ELFT>>(
+ Config->Rela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaPlt);
+
+ // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
+ // that the IRelative relocations are processed last by the dynamic loader
+ In<ELFT>::RelaIplt = make<RelocationSection<ELFT>>(
+ (Config->EMachine == EM_ARM) ? ".rel.dyn" : In<ELFT>::RelaPlt->Name,
+ false /*Sort*/);
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaIplt);
+
+ In<ELFT>::Plt = make<PltSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Plt);
+ In<ELFT>::Iplt = make<IpltSection<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Iplt);
+
+ if (Config->EhFrameHdr) {
+ In<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>();
+ Symtab<ELFT>::X->Sections.push_back(In<ELFT>::EhFrameHdr);
+ }
}
template <class ELFT>
@@ -297,7 +393,7 @@ static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
if (Sec == &InputSection<ELFT>::Discarded)
return false;
- if (Config->DiscardNone)
+ if (Config->Discard == DiscardPolicy::None)
return true;
// In ELF assembly .L symbols are normally discarded by the assembler.
@@ -308,16 +404,22 @@ static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
if (!SymName.startswith(".L") && !SymName.empty())
return true;
- if (Config->DiscardLocals)
+ if (Config->Discard == DiscardPolicy::Locals)
return false;
- return !(Sec->getSectionHdr()->sh_flags & SHF_MERGE);
+ return !Sec || !(Sec->Flags & SHF_MERGE);
}
template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj)
return false;
+ // If --retain-symbols-file is given, we'll keep only symbols listed in that
+ // file.
+ if (Config->Discard == DiscardPolicy::RetainFile &&
+ !Config->RetainSymbolsFile.count(B.getName()))
+ return false;
+
if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
// Always include absolute symbols.
if (!D->Section)
@@ -335,27 +437,25 @@ template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
// Local symbols are not in the linker's symbol table. This function scans
// each object file's symbol table to copy local symbols to the output.
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
- if (!Out<ELFT>::SymTab)
+ if (!In<ELFT>::SymTab)
return;
- for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
- Symtab.getObjectFiles()) {
- const char *StrTab = F->getStringTable().data();
+ for (elf::ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles()) {
for (SymbolBody *B : F->getLocalSymbols()) {
+ if (!B->IsLocal)
+ fatal(toString(F) +
+ ": broken object: getLocalSymbols returns a non-local symbol");
auto *DR = dyn_cast<DefinedRegular<ELFT>>(B);
+
// No reason to keep local undefined symbol in symtab.
if (!DR)
continue;
if (!includeInSymtab<ELFT>(*B))
continue;
- StringRef SymName(StrTab + B->getNameOffset());
+
InputSectionBase<ELFT> *Sec = DR->Section;
- if (!shouldKeepInSymtab<ELFT>(Sec, SymName, *B))
+ if (!shouldKeepInSymtab<ELFT>(Sec, B->getName(), *B))
continue;
- ++Out<ELFT>::SymTab->NumLocals;
- if (Config->Relocatable)
- B->DynsymIndex = Out<ELFT>::SymTab->NumLocals;
- F->KeptLocalSyms.push_back(
- std::make_pair(DR, Out<ELFT>::SymTab->StrTabSec.addString(SymName)));
+ In<ELFT>::SymTab->addLocal(B);
}
}
}
@@ -376,136 +476,200 @@ static int getPPC64SectionRank(StringRef SectionName) {
.Default(1);
}
-template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) {
+// All sections with SHF_MIPS_GPREL flag should be grouped together
+// because data in these sections is addressable with a gp relative address.
+static int getMipsSectionRank(const OutputSectionBase *S) {
+ if ((S->Flags & SHF_MIPS_GPREL) == 0)
+ return 0;
+ if (S->getName() == ".got")
+ return 1;
+ return 2;
+}
+
+template <class ELFT> bool elf::isRelroSection(const OutputSectionBase *Sec) {
if (!Config->ZRelro)
return false;
- typename ELFT::uint Flags = Sec->getFlags();
+ uint64_t Flags = Sec->Flags;
if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE))
return false;
if (Flags & SHF_TLS)
return true;
- uint32_t Type = Sec->getType();
+ uint32_t Type = Sec->Type;
if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY ||
Type == SHT_PREINIT_ARRAY)
return true;
- if (Sec == Out<ELFT>::GotPlt)
+ if (Sec == In<ELFT>::GotPlt->OutSec)
return Config->ZNow;
- if (Sec == Out<ELFT>::Dynamic || Sec == Out<ELFT>::Got)
+ if (Sec == In<ELFT>::Dynamic->OutSec)
+ return true;
+ if (In<ELFT>::Got && Sec == In<ELFT>::Got->OutSec)
+ return true;
+ if (Sec == Out<ELFT>::BssRelRo)
return true;
StringRef S = Sec->getName();
return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
- S == ".eh_frame";
+ S == ".eh_frame" || S == ".openbsd.randomdata";
}
-// Output section ordering is determined by this function.
template <class ELFT>
-static bool compareSections(OutputSectionBase<ELFT> *A,
- OutputSectionBase<ELFT> *B) {
- typedef typename ELFT::uint uintX_t;
-
- int Comp = Script<ELFT>::X->compareSections(A->getName(), B->getName());
- if (Comp != 0)
- return Comp < 0;
-
- uintX_t AFlags = A->getFlags();
- uintX_t BFlags = B->getFlags();
+static bool compareSectionsNonScript(const OutputSectionBase *A,
+ const OutputSectionBase *B) {
+ // Put .interp first because some loaders want to see that section
+ // on the first page of the executable file when loaded into memory.
+ bool AIsInterp = A->getName() == ".interp";
+ bool BIsInterp = B->getName() == ".interp";
+ if (AIsInterp != BIsInterp)
+ return AIsInterp;
// Allocatable sections go first to reduce the total PT_LOAD size and
// so debug info doesn't change addresses in actual code.
- bool AIsAlloc = AFlags & SHF_ALLOC;
- bool BIsAlloc = BFlags & SHF_ALLOC;
+ bool AIsAlloc = A->Flags & SHF_ALLOC;
+ bool BIsAlloc = B->Flags & SHF_ALLOC;
if (AIsAlloc != BIsAlloc)
return AIsAlloc;
- // We don't have any special requirements for the relative order of
- // two non allocatable sections.
+ // We don't have any special requirements for the relative order of two non
+ // allocatable sections.
if (!AIsAlloc)
return false;
+ // We want to put section specified by -T option first, so we
+ // can start assigning VA starting from them later.
+ auto AAddrSetI = Config->SectionStartMap.find(A->getName());
+ auto BAddrSetI = Config->SectionStartMap.find(B->getName());
+ bool AHasAddrSet = AAddrSetI != Config->SectionStartMap.end();
+ bool BHasAddrSet = BAddrSetI != Config->SectionStartMap.end();
+ if (AHasAddrSet != BHasAddrSet)
+ return AHasAddrSet;
+ if (AHasAddrSet)
+ return AAddrSetI->second < BAddrSetI->second;
+
// We want the read only sections first so that they go in the PT_LOAD
// covering the program headers at the start of the file.
- bool AIsWritable = AFlags & SHF_WRITE;
- bool BIsWritable = BFlags & SHF_WRITE;
+ bool AIsWritable = A->Flags & SHF_WRITE;
+ bool BIsWritable = B->Flags & SHF_WRITE;
if (AIsWritable != BIsWritable)
return BIsWritable;
- // For a corresponding reason, put non exec sections first (the program
- // header PT_LOAD is not executable).
- bool AIsExec = AFlags & SHF_EXECINSTR;
- bool BIsExec = BFlags & SHF_EXECINSTR;
- if (AIsExec != BIsExec)
- return BIsExec;
+ if (!Config->SingleRoRx) {
+ // For a corresponding reason, put non exec sections first (the program
+ // header PT_LOAD is not executable).
+ // We only do that if we are not using linker scripts, since with linker
+ // scripts ro and rx sections are in the same PT_LOAD, so their relative
+ // order is not important. The same applies for -no-rosegment.
+ bool AIsExec = A->Flags & SHF_EXECINSTR;
+ bool BIsExec = B->Flags & SHF_EXECINSTR;
+ if (AIsExec != BIsExec)
+ return BIsExec;
+ }
// If we got here we know that both A and B are in the same PT_LOAD.
+ bool AIsTls = A->Flags & SHF_TLS;
+ bool BIsTls = B->Flags & SHF_TLS;
+ bool AIsNoBits = A->Type == SHT_NOBITS;
+ bool BIsNoBits = B->Type == SHT_NOBITS;
+
+ // The first requirement we have is to put (non-TLS) nobits sections last. The
+ // reason is that the only thing the dynamic linker will see about them is a
+ // p_memsz that is larger than p_filesz. Seeing that it zeros the end of the
+ // PT_LOAD, so that has to correspond to the nobits sections.
+ bool AIsNonTlsNoBits = AIsNoBits && !AIsTls;
+ bool BIsNonTlsNoBits = BIsNoBits && !BIsTls;
+ if (AIsNonTlsNoBits != BIsNonTlsNoBits)
+ return BIsNonTlsNoBits;
+
+ // We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo
+ // sections after r/w ones, so that the RelRo sections are contiguous.
+ bool AIsRelRo = isRelroSection<ELFT>(A);
+ bool BIsRelRo = isRelroSection<ELFT>(B);
+ if (AIsRelRo != BIsRelRo)
+ return AIsNonTlsNoBits ? AIsRelRo : BIsRelRo;
+
// The TLS initialization block needs to be a single contiguous block in a R/W
- // PT_LOAD, so stick TLS sections directly before R/W sections. The TLS NOBITS
- // sections are placed here as they don't take up virtual address space in the
- // PT_LOAD.
- bool AIsTls = AFlags & SHF_TLS;
- bool BIsTls = BFlags & SHF_TLS;
+ // PT_LOAD, so stick TLS sections directly before the other RelRo R/W
+ // sections. The TLS NOBITS sections are placed here as they don't take up
+ // virtual address space in the PT_LOAD.
if (AIsTls != BIsTls)
return AIsTls;
- // The next requirement we have is to put nobits sections last. The
- // reason is that the only thing the dynamic linker will see about
- // them is a p_memsz that is larger than p_filesz. Seeing that it
- // zeros the end of the PT_LOAD, so that has to correspond to the
- // nobits sections.
- bool AIsNoBits = A->getType() == SHT_NOBITS;
- bool BIsNoBits = B->getType() == SHT_NOBITS;
+ // Within the TLS initialization block, the non-nobits sections need to appear
+ // first.
if (AIsNoBits != BIsNoBits)
return BIsNoBits;
- // We place RelRo section before plain r/w ones.
- bool AIsRelRo = isRelroSection(A);
- bool BIsRelRo = isRelroSection(B);
- if (AIsRelRo != BIsRelRo)
- return AIsRelRo;
-
// Some architectures have additional ordering restrictions for sections
// within the same PT_LOAD.
if (Config->EMachine == EM_PPC64)
return getPPC64SectionRank(A->getName()) <
getPPC64SectionRank(B->getName());
+ if (Config->EMachine == EM_MIPS)
+ return getMipsSectionRank(A) < getMipsSectionRank(B);
return false;
}
-// Until this function is called, common symbols do not belong to any section.
-// This function adds them to end of BSS section.
+// Output section ordering is determined by this function.
template <class ELFT>
-void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) {
- if (Syms.empty())
- return;
+static bool compareSections(const OutputSectionBase *A,
+ const OutputSectionBase *B) {
+ // For now, put sections mentioned in a linker script first.
+ int AIndex = Script<ELFT>::X->getSectionIndex(A->getName());
+ int BIndex = Script<ELFT>::X->getSectionIndex(B->getName());
+ bool AInScript = AIndex != INT_MAX;
+ bool BInScript = BIndex != INT_MAX;
+ if (AInScript != BInScript)
+ return AInScript;
+ // If both are in the script, use that order.
+ if (AInScript)
+ return AIndex < BIndex;
+
+ return compareSectionsNonScript<ELFT>(A, B);
+}
- // Sort the common symbols by alignment as an heuristic to pack them better.
- std::stable_sort(Syms.begin(), Syms.end(),
- [](const DefinedCommon *A, const DefinedCommon *B) {
- return A->Alignment > B->Alignment;
- });
-
- uintX_t Off = Out<ELFT>::Bss->getSize();
- for (DefinedCommon *C : Syms) {
- Off = alignTo(Off, C->Alignment);
- Out<ELFT>::Bss->updateAlignment(C->Alignment);
- C->OffsetInBss = Off;
- Off += C->Size;
- }
+// Program header entry
+PhdrEntry::PhdrEntry(unsigned Type, unsigned Flags) {
+ p_type = Type;
+ p_flags = Flags;
+}
- Out<ELFT>::Bss->setSize(Off);
+void PhdrEntry::add(OutputSectionBase *Sec) {
+ Last = Sec;
+ if (!First)
+ First = Sec;
+ p_align = std::max(p_align, Sec->Addralign);
+ if (p_type == PT_LOAD)
+ Sec->FirstInPtLoad = First;
}
template <class ELFT>
-static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name,
- OutputSectionBase<ELFT> *Sec,
- typename ELFT::uint Val) {
- SymbolBody *S = Table.find(Name);
+static void addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec,
+ typename ELFT::uint Val,
+ uint8_t StOther = STV_HIDDEN) {
+ if (SymbolBody *S = Symtab<ELFT>::X->find(Name))
+ if (!S->isInCurrentDSO())
+ Symtab<ELFT>::X->addSynthetic(Name, Sec, Val, StOther);
+}
+
+template <class ELFT>
+static Symbol *addRegular(StringRef Name, InputSectionBase<ELFT> *Sec,
+ typename ELFT::uint Value) {
+ // The linker generated symbols are added as STB_WEAK to allow user defined
+ // ones to override them.
+ return Symtab<ELFT>::X->addRegular(Name, STV_HIDDEN, STT_NOTYPE, Value,
+ /*Size=*/0, STB_WEAK, Sec,
+ /*File=*/nullptr);
+}
+
+template <class ELFT>
+static Symbol *addOptionalRegular(StringRef Name, InputSectionBase<ELFT> *IS,
+ typename ELFT::uint Value) {
+ SymbolBody *S = Symtab<ELFT>::X->find(Name);
if (!S)
return nullptr;
- if (!S->isUndefined() && !S->isShared())
+ if (S->isInCurrentDSO())
return S->symbol();
- return Table.addSynthetic(Name, Sec, Val);
+ return addRegular(Name, IS, Value);
}
// The beginning and the ending of .rel[a].plt section are marked
@@ -515,14 +679,13 @@ static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name,
// need these symbols, since IRELATIVE relocs are resolved through GOT
// and PLT. For details, see http://www.airs.com/blog/archives/403.
template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
- if (isOutputDynamic() || !Out<ELFT>::RelaPlt)
+ if (In<ELFT>::DynSymTab)
return;
StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
- addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, 0);
+ addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0);
S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
- addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt,
- DefinedSynthetic<ELFT>::SectionEnd);
+ addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, -1);
}
// The linker is expected to define some symbols depending on
@@ -530,24 +693,28 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
if (Config->EMachine == EM_MIPS) {
// Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
- // so that it points to an absolute address which is relative to GOT.
+ // so that it points to an absolute address which by default is relative
+ // to GOT. Default offset is 0x7ff0.
// See "Global Data Symbols" in Chapter 6 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- Symtab.addSynthetic("_gp", Out<ELFT>::Got, MipsGPOffset);
+ ElfSym<ELFT>::MipsGp =
+ Symtab<ELFT>::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL);
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
- // start of function and 'gp' pointer into GOT.
- Symbol *Sym =
- addOptionalSynthetic(Symtab, "_gp_disp", Out<ELFT>::Got, MipsGPOffset);
- if (Sym)
- ElfSym<ELFT>::MipsGpDisp = Sym->body();
+ // start of function and 'gp' pointer into GOT. To simplify relocation
+ // calculation we assign _gp value to it and calculate corresponding
+ // relocations as relative to this value.
+ if (Symtab<ELFT>::X->find("_gp_disp"))
+ ElfSym<ELFT>::MipsGpDisp =
+ Symtab<ELFT>::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL);
// The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
// pointer. This symbol is used in the code generated by .cpload pseudo-op
// in case of using -mno-shared option.
// https://sourceware.org/ml/binutils/2004-12/msg00094.html
- addOptionalSynthetic(Symtab, "__gnu_local_gp", Out<ELFT>::Got,
- MipsGPOffset);
+ if (Symtab<ELFT>::X->find("__gnu_local_gp"))
+ ElfSym<ELFT>::MipsLocalGp =
+ Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL);
}
// In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
@@ -562,27 +729,35 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
// an undefined symbol in the .o files.
// Given that the symbol is effectively unused, we just create a dummy
// hidden one to avoid the undefined symbol error.
- if (!Config->Relocatable)
- Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
+ Symtab<ELFT>::X->addIgnored("_GLOBAL_OFFSET_TABLE_");
// __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
// static linking the linker is required to optimize away any references to
// __tls_get_addr, so it's not defined anywhere. Create a hidden definition
- // to avoid the undefined symbol error.
- if (!isOutputDynamic())
- Symtab.addIgnored("__tls_get_addr");
+ // to avoid the undefined symbol error. As usual special cases are ARM and
+ // MIPS - the libc for these targets defines __tls_get_addr itself because
+ // there are no TLS optimizations for these targets.
+ if (!In<ELFT>::DynSymTab &&
+ (Config->EMachine != EM_MIPS && Config->EMachine != EM_ARM))
+ Symtab<ELFT>::X->addIgnored("__tls_get_addr");
+
+ // If linker script do layout we do not need to create any standart symbols.
+ if (ScriptConfig->HasSections)
+ return;
+
+ ElfSym<ELFT>::EhdrStart = Symtab<ELFT>::X->addIgnored("__ehdr_start");
auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1,
DefinedRegular<ELFT> *&Sym2) {
- Sym1 = Symtab.addIgnored(S, STV_DEFAULT);
+ Sym1 = Symtab<ELFT>::X->addIgnored(S, STV_DEFAULT);
// The name without the underscore is not a reserved name,
// so it is defined only when there is a reference against it.
assert(S.startswith("_"));
S = S.substr(1);
- if (SymbolBody *B = Symtab.find(S))
+ if (SymbolBody *B = Symtab<ELFT>::X->find(S))
if (B->isUndefined())
- Sym2 = Symtab.addAbsolute(S, STV_DEFAULT);
+ Sym2 = Symtab<ELFT>::X->addAbsolute(S, STV_DEFAULT);
};
Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2);
@@ -592,65 +767,239 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
-template <class ELFT> static void sortInitFini(OutputSectionBase<ELFT> *S) {
+template <class ELFT> static void sortInitFini(OutputSectionBase *S) {
if (S)
reinterpret_cast<OutputSection<ELFT> *>(S)->sortInitFini();
}
// Sort input sections by the special rule for .ctors and .dtors.
-template <class ELFT> static void sortCtorsDtors(OutputSectionBase<ELFT> *S) {
+template <class ELFT> static void sortCtorsDtors(OutputSectionBase *S) {
if (S)
reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors();
}
-// Create output section objects and add them to OutputSections.
-template <class ELFT> void Writer<ELFT>::createSections() {
- // Create output sections for input object file sections.
- std::vector<OutputSectionBase<ELFT> *> RegularSections;
- OutputSectionFactory<ELFT> Factory;
- for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
- Symtab.getObjectFiles()) {
- for (InputSectionBase<ELFT> *C : F->getSections()) {
- if (isDiscarded(C)) {
- reportDiscarded(C, F);
+// Sort input sections using the list provided by --symbol-ordering-file.
+template <class ELFT>
+static void sortBySymbolsOrder(ArrayRef<OutputSectionBase *> OutputSections) {
+ if (Config->SymbolOrderingFile.empty())
+ return;
+
+ // Build a map from symbols to their priorities. Symbols that didn't
+ // appear in the symbol ordering file have the lowest priority 0.
+ // All explicitly mentioned symbols have negative (higher) priorities.
+ DenseMap<StringRef, int> SymbolOrder;
+ int Priority = -Config->SymbolOrderingFile.size();
+ for (StringRef S : Config->SymbolOrderingFile)
+ SymbolOrder.insert({S, Priority++});
+
+ // Build a map from sections to their priorities.
+ DenseMap<InputSectionBase<ELFT> *, int> SectionOrder;
+ for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles()) {
+ for (SymbolBody *Body : File->getSymbols()) {
+ auto *D = dyn_cast<DefinedRegular<ELFT>>(Body);
+ if (!D || !D->Section)
continue;
- }
- OutputSectionBase<ELFT> *Sec;
- bool IsNew;
- std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C));
- if (IsNew) {
- OwningSections.emplace_back(Sec);
- OutputSections.push_back(Sec);
- RegularSections.push_back(Sec);
- }
- Sec->addSection(C);
+ int &Priority = SectionOrder[D->Section];
+ Priority = std::min(Priority, SymbolOrder.lookup(D->getName()));
}
}
- // If we have a .opd section (used under PPC64 for function descriptors),
- // store a pointer to it here so that we can use it later when processing
- // relocations.
- Out<ELFT>::Opd = Factory.lookup(".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC);
+ // Sort sections by priority.
+ for (OutputSectionBase *Base : OutputSections)
+ if (auto *Sec = dyn_cast<OutputSection<ELFT>>(Base))
+ Sec->sort([&](InputSection<ELFT> *S) { return SectionOrder.lookup(S); });
+}
+
+template <class ELFT>
+void Writer<ELFT>::forEachRelSec(
+ std::function<void(InputSectionBase<ELFT> &)> Fn) {
+ for (InputSectionBase<ELFT> *IS : Symtab<ELFT>::X->Sections) {
+ if (!IS->Live)
+ continue;
+ // 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 (!(IS->Flags & SHF_ALLOC))
+ continue;
+ if (isa<InputSection<ELFT>>(IS) || isa<EhInputSection<ELFT>>(IS))
+ Fn(*IS);
+ }
+}
+
+template <class ELFT>
+void Writer<ELFT>::addInputSec(InputSectionBase<ELFT> *IS) {
+ if (!IS)
+ return;
+
+ if (!IS->Live) {
+ reportDiscarded(IS);
+ return;
+ }
+ OutputSectionBase *Sec;
+ bool IsNew;
+ StringRef OutsecName = getOutputSectionName(IS->Name);
+ std::tie(Sec, IsNew) = Factory.create(IS, OutsecName);
+ if (IsNew)
+ OutputSections.push_back(Sec);
+ Sec->addSection(IS);
+}
+
+template <class ELFT> void Writer<ELFT>::createSections() {
+ for (InputSectionBase<ELFT> *IS : Symtab<ELFT>::X->Sections)
+ addInputSec(IS);
+
+ sortBySymbolsOrder<ELFT>(OutputSections);
+ sortInitFini<ELFT>(findSection(".init_array"));
+ sortInitFini<ELFT>(findSection(".fini_array"));
+ sortCtorsDtors<ELFT>(findSection(".ctors"));
+ sortCtorsDtors<ELFT>(findSection(".dtors"));
+
+ for (OutputSectionBase *Sec : OutputSections)
+ Sec->assignOffsets();
+}
+
+template <class ELFT>
+static bool canSharePtLoad(const OutputSectionBase &S1,
+ const OutputSectionBase &S2) {
+ if (!(S1.Flags & SHF_ALLOC) || !(S2.Flags & SHF_ALLOC))
+ return false;
+
+ bool S1IsWrite = S1.Flags & SHF_WRITE;
+ bool S2IsWrite = S2.Flags & SHF_WRITE;
+ if (S1IsWrite != S2IsWrite)
+ return false;
+
+ if (!S1IsWrite)
+ return true; // RO and RX share a PT_LOAD with linker scripts.
+ return (S1.Flags & SHF_EXECINSTR) == (S2.Flags & SHF_EXECINSTR);
+}
+
+template <class ELFT> void Writer<ELFT>::sortSections() {
+ // Don't sort if using -r. It is not necessary and we want to preserve the
+ // relative order for SHF_LINK_ORDER sections.
+ if (Config->Relocatable)
+ return;
+ if (!ScriptConfig->HasSections) {
+ std::stable_sort(OutputSections.begin(), OutputSections.end(),
+ compareSectionsNonScript<ELFT>);
+ return;
+ }
+ Script<ELFT>::X->adjustSectionsBeforeSorting();
+
+ // The order of the sections in the script is arbitrary and may not agree with
+ // compareSectionsNonScript. This means that we cannot easily define a
+ // strict weak ordering. To see why, consider a comparison of a section in the
+ // script and one not in the script. We have a two simple options:
+ // * Make them equivalent (a is not less than b, and b is not less than a).
+ // The problem is then that equivalence has to be transitive and we can
+ // have sections a, b and c with only b in a script and a less than c
+ // which breaks this property.
+ // * Use compareSectionsNonScript. Given that the script order doesn't have
+ // to match, we can end up with sections a, b, c, d where b and c are in the
+ // script and c is compareSectionsNonScript less than b. In which case d
+ // can be equivalent to c, a to b and d < a. As a concrete example:
+ // .a (rx) # not in script
+ // .b (rx) # in script
+ // .c (ro) # in script
+ // .d (ro) # not in script
+ //
+ // The way we define an order then is:
+ // * First put script sections at the start and sort the script and
+ // non-script sections independently.
+ // * Move each non-script section to its preferred position. We try
+ // to put each section in the last position where it it can share
+ // a PT_LOAD.
+
+ std::stable_sort(OutputSections.begin(), OutputSections.end(),
+ compareSections<ELFT>);
- Out<ELFT>::Dynamic->PreInitArraySec = Factory.lookup(
- ".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC);
- Out<ELFT>::Dynamic->InitArraySec =
- Factory.lookup(".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC);
- Out<ELFT>::Dynamic->FiniArraySec =
- Factory.lookup(".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC);
+ auto I = OutputSections.begin();
+ auto E = OutputSections.end();
+ auto NonScriptI =
+ std::find_if(OutputSections.begin(), E, [](OutputSectionBase *S) {
+ return Script<ELFT>::X->getSectionIndex(S->getName()) == INT_MAX;
+ });
+ while (NonScriptI != E) {
+ auto BestPos = std::max_element(
+ I, NonScriptI, [&](OutputSectionBase *&A, OutputSectionBase *&B) {
+ bool ACanSharePtLoad = canSharePtLoad<ELFT>(**NonScriptI, *A);
+ bool BCanSharePtLoad = canSharePtLoad<ELFT>(**NonScriptI, *B);
+ if (ACanSharePtLoad != BCanSharePtLoad)
+ return BCanSharePtLoad;
+
+ bool ACmp = compareSectionsNonScript<ELFT>(*NonScriptI, A);
+ bool BCmp = compareSectionsNonScript<ELFT>(*NonScriptI, B);
+ if (ACmp != BCmp)
+ return BCmp; // FIXME: missing test
+
+ size_t PosA = &A - &OutputSections[0];
+ size_t PosB = &B - &OutputSections[0];
+ return ACmp ? PosA > PosB : PosA < PosB;
+ });
+
+ // max_element only returns NonScriptI if the range is empty. If the range
+ // is not empty we should consider moving the the element forward one
+ // position.
+ if (BestPos != NonScriptI &&
+ !compareSectionsNonScript<ELFT>(*NonScriptI, *BestPos))
+ ++BestPos;
+ std::rotate(BestPos, NonScriptI, NonScriptI + 1);
+ ++NonScriptI;
+ }
- // Sort section contents for __attribute__((init_priority(N)).
- sortInitFini(Out<ELFT>::Dynamic->InitArraySec);
- sortInitFini(Out<ELFT>::Dynamic->FiniArraySec);
- sortCtorsDtors(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
- sortCtorsDtors(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC));
+ Script<ELFT>::X->adjustSectionsAfterSorting();
+}
+
+template <class ELFT>
+static void
+finalizeSynthetic(const std::vector<SyntheticSection<ELFT> *> &Sections) {
+ for (SyntheticSection<ELFT> *SS : Sections)
+ if (SS && SS->OutSec && !SS->empty()) {
+ SS->finalize();
+ SS->OutSec->Size = 0;
+ SS->OutSec->assignOffsets();
+ }
+}
+
+// We need to add input synthetic sections early in createSyntheticSections()
+// to make them visible from linkescript side. But not all sections are always
+// required to be in output. For example we don't need dynamic section content
+// sometimes. This function filters out such unused sections from output.
+template <class ELFT>
+static void removeUnusedSyntheticSections(std::vector<OutputSectionBase *> &V) {
+ // Input synthetic sections are placed after all regular ones. We iterate over
+ // them all and exit at first non-synthetic.
+ for (InputSectionBase<ELFT> *S : llvm::reverse(Symtab<ELFT>::X->Sections)) {
+ SyntheticSection<ELFT> *SS = dyn_cast<SyntheticSection<ELFT>>(S);
+ if (!SS)
+ return;
+ if (!SS->empty() || !SS->OutSec)
+ continue;
+
+ OutputSection<ELFT> *OutSec = cast<OutputSection<ELFT>>(SS->OutSec);
+ OutSec->Sections.erase(
+ std::find(OutSec->Sections.begin(), OutSec->Sections.end(), SS));
+ // If there is no other sections in output section, remove it from output.
+ if (OutSec->Sections.empty())
+ V.erase(std::find(V.begin(), V.end(), OutSec));
+ }
+}
+
+// Create output section objects and add them to OutputSections.
+template <class ELFT> void Writer<ELFT>::finalizeSections() {
+ Out<ELFT>::DebugInfo = findSection(".debug_info");
+ Out<ELFT>::PreinitArray = findSection(".preinit_array");
+ Out<ELFT>::InitArray = findSection(".init_array");
+ Out<ELFT>::FiniArray = findSection(".fini_array");
// The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
// symbols for sections, so that the runtime can get the start and end
// addresses of each section by section name. Add such symbols.
if (!Config->Relocatable) {
addStartEndSymbols();
- for (OutputSectionBase<ELFT> *Sec : RegularSections)
+ for (OutputSectionBase *Sec : OutputSections)
addStartStopSymbols(Sec);
}
@@ -658,16 +1007,12 @@ template <class ELFT> void Writer<ELFT>::createSections() {
// It should be okay as no one seems to care about the type.
// Even the author of gold doesn't remember why gold behaves that way.
// https://sourceware.org/ml/binutils/2002-03/msg00360.html
- if (isOutputDynamic())
- Symtab.addSynthetic("_DYNAMIC", Out<ELFT>::Dynamic, 0);
+ if (In<ELFT>::DynSymTab)
+ addRegular("_DYNAMIC", In<ELFT>::Dynamic, 0);
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
- // Add scripted symbols with zero values now.
- // Real values will be assigned later
- Script<ELFT>::X->addScriptedSymbols();
-
if (!Out<ELFT>::EhFrame->empty()) {
OutputSections.push_back(Out<ELFT>::EhFrame);
Out<ELFT>::EhFrame->finalize();
@@ -675,190 +1020,104 @@ template <class ELFT> void Writer<ELFT>::createSections() {
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
- for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
- Symtab.getObjectFiles()) {
- for (InputSectionBase<ELFT> *C : F->getSections()) {
- if (isDiscarded(C))
- continue;
- if (auto *S = dyn_cast<InputSection<ELFT>>(C)) {
- scanRelocations(*S);
- continue;
- }
- if (auto *S = dyn_cast<EhInputSection<ELFT>>(C))
- if (S->RelocSection)
- scanRelocations(*S, *S->RelocSection);
- }
- }
-
- for (OutputSectionBase<ELFT> *Sec : OutputSections)
- Sec->assignOffsets();
+ forEachRelSec(scanRelocations<ELFT>);
// Now that we have defined all possible symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
- std::vector<DefinedCommon *> CommonSymbols;
- for (Symbol *S : Symtab.getSymbols()) {
+ for (Symbol *S : Symtab<ELFT>::X->getSymbols()) {
SymbolBody *Body = S->body();
- // We only report undefined symbols in regular objects. This means that we
- // will accept an undefined reference in bitcode if it can be optimized out.
- if (S->IsUsedInRegularObj && Body->isUndefined() && !S->isWeak())
- reportUndefined<ELFT>(Symtab, Body);
-
- if (auto *C = dyn_cast<DefinedCommon>(Body))
- CommonSymbols.push_back(C);
-
if (!includeInSymtab<ELFT>(*Body))
continue;
- if (Out<ELFT>::SymTab)
- Out<ELFT>::SymTab->addSymbol(Body);
+ if (In<ELFT>::SymTab)
+ In<ELFT>::SymTab->addGlobal(Body);
- if (isOutputDynamic() && S->includeInDynsym()) {
- Out<ELFT>::DynSymTab->addSymbol(Body);
+ if (In<ELFT>::DynSymTab && S->includeInDynsym()) {
+ In<ELFT>::DynSymTab->addGlobal(Body);
if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body))
if (SS->file()->isNeeded())
- Out<ELFT>::VerNeed->addSymbol(SS);
+ In<ELFT>::VerNeed->addSymbol(SS);
}
}
// Do not proceed if there was an undefined symbol.
- if (HasError)
+ if (ErrorCount)
return;
- addCommonSymbols(CommonSymbols);
-
// So far we have added sections from input object files.
// This function adds linker-created Out<ELFT>::* sections.
addPredefinedSections();
+ removeUnusedSyntheticSections<ELFT>(OutputSections);
- std::stable_sort(OutputSections.begin(), OutputSections.end(),
- compareSections<ELFT>);
+ sortSections();
unsigned I = 1;
- for (OutputSectionBase<ELFT> *Sec : OutputSections) {
+ for (OutputSectionBase *Sec : OutputSections) {
Sec->SectionIndex = I++;
- Sec->setSHName(Out<ELFT>::ShStrTab->addString(Sec->getName()));
+ Sec->ShName = In<ELFT>::ShStrTab->addString(Sec->getName());
}
- // Finalizers fix each section's size.
- // .dynsym is finalized early since that may fill up .gnu.hash.
- if (isOutputDynamic())
- Out<ELFT>::DynSymTab->finalize();
+ // Binary and relocatable output does not have PHDRS.
+ // The headers have to be created before finalize as that can influence the
+ // image base and the dynamic section on mips includes the image base.
+ if (!Config->Relocatable && !Config->OFormatBinary) {
+ Phdrs = Script<ELFT>::X->hasPhdrsCommands() ? Script<ELFT>::X->createPhdrs()
+ : createPhdrs();
+ addPtArmExid(Phdrs);
+ fixHeaders();
+ }
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
- // of finalizing other sections. The dynamic string table is
- // finalized once the .dynamic finalizer has added a few last
- // strings. See DynamicSection::finalize()
- for (OutputSectionBase<ELFT> *Sec : OutputSections)
- if (Sec != Out<ELFT>::DynStrTab && Sec != Out<ELFT>::Dynamic)
- Sec->finalize();
-
- if (isOutputDynamic())
- Out<ELFT>::Dynamic->finalize();
-
- // Now that all output offsets are fixed. Finalize mergeable sections
- // to fix their maps from input offsets to output offsets.
- for (OutputSectionBase<ELFT> *Sec : OutputSections)
- Sec->finalizePieces();
-}
-
-template <class ELFT> bool Writer<ELFT>::needsGot() {
- if (!Out<ELFT>::Got->empty())
- return true;
-
- // We add the .got section to the result for dynamic MIPS target because
- // its address and properties are mentioned in the .dynamic section.
- if (Config->EMachine == EM_MIPS)
- return true;
-
- // 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 Out<ELFT>::Got->HasGotOffRel;
+ // of finalizing other sections.
+ for (OutputSectionBase *Sec : OutputSections)
+ Sec->finalize();
+
+ // Dynamic section must be the last one in this list and dynamic
+ // symbol table section (DynSymTab) must be the first one.
+ finalizeSynthetic<ELFT>(
+ {In<ELFT>::DynSymTab, In<ELFT>::GnuHashTab, In<ELFT>::HashTab,
+ In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab,
+ In<ELFT>::VerDef, In<ELFT>::DynStrTab, In<ELFT>::GdbIndex,
+ In<ELFT>::Got, In<ELFT>::MipsGot, In<ELFT>::IgotPlt,
+ In<ELFT>::GotPlt, In<ELFT>::RelaDyn, In<ELFT>::RelaIplt,
+ In<ELFT>::RelaPlt, In<ELFT>::Plt, In<ELFT>::Iplt,
+ In<ELFT>::Plt, In<ELFT>::EhFrameHdr, In<ELFT>::VerSym,
+ In<ELFT>::VerNeed, In<ELFT>::Dynamic});
}
-// This function add Out<ELFT>::* sections to OutputSections.
template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
- auto Add = [&](OutputSectionBase<ELFT> *C) {
- if (C)
- OutputSections.push_back(C);
- };
-
- // A core file does not usually contain unmodified segments except
- // the first page of the executable. Add the build ID section to beginning of
- // the file so that the section is included in the first page.
- if (Out<ELFT>::BuildId)
- OutputSections.insert(OutputSections.begin(), Out<ELFT>::BuildId);
-
- // Add .interp at first because some loaders want to see that section
- // on the first page of the executable file when loaded into memory.
- if (needsInterpSection())
- OutputSections.insert(OutputSections.begin(), Out<ELFT>::Interp);
-
- // This order is not the same as the final output order
- // because we sort the sections using their attributes below.
- Add(Out<ELFT>::SymTab);
- Add(Out<ELFT>::ShStrTab);
- Add(Out<ELFT>::StrTab);
- if (isOutputDynamic()) {
- Add(Out<ELFT>::DynSymTab);
-
- bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0;
- if (Out<ELFT>::VerDef || HasVerNeed)
- Add(Out<ELFT>::VerSym);
- Add(Out<ELFT>::VerDef);
- if (HasVerNeed)
- Add(Out<ELFT>::VerNeed);
-
- Add(Out<ELFT>::GnuHashTab);
- Add(Out<ELFT>::HashTab);
- Add(Out<ELFT>::Dynamic);
- Add(Out<ELFT>::DynStrTab);
- if (Out<ELFT>::RelaDyn->hasRelocs())
- Add(Out<ELFT>::RelaDyn);
- Add(Out<ELFT>::MipsRldMap);
- }
-
- // We always need to add rel[a].plt to output if it has entries.
- // Even during static linking it can contain R_[*]_IRELATIVE relocations.
- if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) {
- Add(Out<ELFT>::RelaPlt);
- Out<ELFT>::RelaPlt->Static = !isOutputDynamic();
- }
-
- if (needsGot())
- Add(Out<ELFT>::Got);
- if (Out<ELFT>::GotPlt && !Out<ELFT>::GotPlt->empty())
- Add(Out<ELFT>::GotPlt);
- if (!Out<ELFT>::Plt->empty())
- Add(Out<ELFT>::Plt);
- if (!Out<ELFT>::EhFrame->empty())
- Add(Out<ELFT>::EhFrameHdr);
- if (Out<ELFT>::Bss->getSize() > 0)
- Add(Out<ELFT>::Bss);
+ if (Out<ELFT>::Bss->Size > 0)
+ OutputSections.push_back(Out<ELFT>::Bss);
+ if (Out<ELFT>::BssRelRo->Size > 0)
+ OutputSections.push_back(Out<ELFT>::BssRelRo);
+
+ auto OS = dyn_cast_or_null<OutputSection<ELFT>>(findSection(".ARM.exidx"));
+ if (OS && !OS->Sections.empty() && !Config->Relocatable)
+ OS->addSection(make<ARMExidxSentinelSection<ELFT>>());
+
+ addInputSec(In<ELFT>::SymTab);
+ addInputSec(In<ELFT>::ShStrTab);
+ addInputSec(In<ELFT>::StrTab);
}
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
- auto Define = [&](StringRef Start, StringRef End,
- OutputSectionBase<ELFT> *OS) {
- if (OS) {
- this->Symtab.addSynthetic(Start, OS, 0);
- this->Symtab.addSynthetic(End, OS, DefinedSynthetic<ELFT>::SectionEnd);
- } else {
- addOptionalSynthetic(this->Symtab, Start,
- (OutputSectionBase<ELFT> *)nullptr, 0);
- addOptionalSynthetic(this->Symtab, End,
- (OutputSectionBase<ELFT> *)nullptr, 0);
- }
+ auto Define = [&](StringRef Start, StringRef End, OutputSectionBase *OS) {
+ // These symbols resolve to the image base if the section does not exist.
+ // A special value -1 indicates end of the section.
+ addOptionalSynthetic<ELFT>(Start, OS, 0);
+ addOptionalSynthetic<ELFT>(End, OS, OS ? -1 : 0);
};
Define("__preinit_array_start", "__preinit_array_end",
- Out<ELFT>::Dynamic->PreInitArraySec);
- Define("__init_array_start", "__init_array_end",
- Out<ELFT>::Dynamic->InitArraySec);
- Define("__fini_array_start", "__fini_array_end",
- Out<ELFT>::Dynamic->FiniArraySec);
+ Out<ELFT>::PreinitArray);
+ Define("__init_array_start", "__init_array_end", Out<ELFT>::InitArray);
+ Define("__fini_array_start", "__fini_array_end", Out<ELFT>::FiniArray);
+
+ if (OutputSectionBase *Sec = findSection(".ARM.exidx"))
+ Define("__exidx_start", "__exidx_end", Sec);
}
// If a section name is valid as a C identifier (which is rare because of
@@ -867,189 +1126,271 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
// respectively. This is not requested by the ELF standard, but GNU ld and
// gold provide the feature, and used by many programs.
template <class ELFT>
-void Writer<ELFT>::addStartStopSymbols(OutputSectionBase<ELFT> *Sec) {
+void Writer<ELFT>::addStartStopSymbols(OutputSectionBase *Sec) {
StringRef S = Sec->getName();
if (!isValidCIdentifier(S))
return;
- StringSaver Saver(Alloc);
- StringRef Start = Saver.save("__start_" + S);
- StringRef Stop = Saver.save("__stop_" + S);
- if (SymbolBody *B = Symtab.find(Start))
- if (B->isUndefined())
- Symtab.addSynthetic(Start, Sec, 0);
- if (SymbolBody *B = Symtab.find(Stop))
- if (B->isUndefined())
- Symtab.addSynthetic(Stop, Sec, DefinedSynthetic<ELFT>::SectionEnd);
+ addOptionalSynthetic<ELFT>(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT);
+ addOptionalSynthetic<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
}
-template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) {
- if (!(Sec->getFlags() & SHF_ALLOC))
+template <class ELFT>
+OutputSectionBase *Writer<ELFT>::findSection(StringRef Name) {
+ for (OutputSectionBase *Sec : OutputSections)
+ if (Sec->getName() == Name)
+ return Sec;
+ return nullptr;
+}
+
+template <class ELFT> static bool needsPtLoad(OutputSectionBase *Sec) {
+ if (!(Sec->Flags & SHF_ALLOC))
return false;
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
// responsible for allocating space for them, not the PT_LOAD that
// contains the TLS initialization image.
- if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS)
+ if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS)
return false;
return true;
}
-static uint32_t toPhdrFlags(uint64_t Flags) {
- uint32_t Ret = PF_R;
- if (Flags & SHF_WRITE)
- Ret |= PF_W;
- if (Flags & SHF_EXECINSTR)
- Ret |= PF_X;
- return Ret;
+// Linker scripts are responsible for aligning addresses. Unfortunately, most
+// linker scripts are designed for creating two PT_LOADs only, one RX and one
+// RW. This means that there is no alignment in the RO to RX transition and we
+// cannot create a PT_LOAD there.
+template <class ELFT>
+static typename ELFT::uint computeFlags(typename ELFT::uint F) {
+ if (Config->OMagic)
+ return PF_R | PF_W | PF_X;
+ if (Config->SingleRoRx && !(F & PF_W))
+ return F | PF_X;
+ return F;
}
// Decide which program headers to create and which sections to include in each
// one.
-template <class ELFT> void Writer<ELFT>::createPhdrs() {
- auto AddHdr = [this](unsigned Type, unsigned Flags) {
- return &*Phdrs.emplace(Phdrs.end(), Type, Flags);
- };
-
- auto AddSec = [](Phdr &Hdr, OutputSectionBase<ELFT> *Sec) {
- Hdr.Last = Sec;
- if (!Hdr.First)
- Hdr.First = Sec;
- Hdr.H.p_align = std::max<uintX_t>(Hdr.H.p_align, Sec->getAlignment());
+template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
+ std::vector<PhdrEntry> Ret;
+ auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * {
+ Ret.emplace_back(Type, Flags);
+ return &Ret.back();
};
// The first phdr entry is PT_PHDR which describes the program header itself.
- Phdr &Hdr = *AddHdr(PT_PHDR, PF_R);
- AddSec(Hdr, Out<ELFT>::ProgramHeaders);
+ PhdrEntry &Hdr = *AddHdr(PT_PHDR, PF_R);
+ Hdr.add(Out<ELFT>::ProgramHeaders);
// PT_INTERP must be the second entry if exists.
- if (needsInterpSection()) {
- Phdr &Hdr = *AddHdr(PT_INTERP, toPhdrFlags(Out<ELFT>::Interp->getFlags()));
- AddSec(Hdr, Out<ELFT>::Interp);
+ if (OutputSectionBase *Sec = findSection(".interp")) {
+ PhdrEntry &Hdr = *AddHdr(PT_INTERP, Sec->getPhdrFlags());
+ Hdr.add(Sec);
}
// Add the first PT_LOAD segment for regular output sections.
- uintX_t Flags = PF_R;
- Phdr *Load = AddHdr(PT_LOAD, Flags);
- AddSec(*Load, Out<ELFT>::ElfHeader);
- AddSec(*Load, Out<ELFT>::ProgramHeaders);
-
- Phdr TlsHdr(PT_TLS, PF_R);
- Phdr RelRo(PT_GNU_RELRO, PF_R);
- Phdr Note(PT_NOTE, PF_R);
- for (OutputSectionBase<ELFT> *Sec : OutputSections) {
- if (!(Sec->getFlags() & SHF_ALLOC))
+ uintX_t Flags = computeFlags<ELFT>(PF_R);
+ PhdrEntry *Load = AddHdr(PT_LOAD, Flags);
+
+ PhdrEntry TlsHdr(PT_TLS, PF_R);
+ PhdrEntry RelRo(PT_GNU_RELRO, PF_R);
+ PhdrEntry Note(PT_NOTE, PF_R);
+ for (OutputSectionBase *Sec : OutputSections) {
+ if (!(Sec->Flags & SHF_ALLOC))
break;
// If we meet TLS section then we create TLS header
- // and put all TLS sections inside for futher use when
+ // and put all TLS sections inside for further use when
// assign addresses.
- if (Sec->getFlags() & SHF_TLS)
- AddSec(TlsHdr, Sec);
+ if (Sec->Flags & SHF_TLS)
+ TlsHdr.add(Sec);
if (!needsPtLoad<ELFT>(Sec))
continue;
- // If flags changed then we want new load segment.
- uintX_t NewFlags = toPhdrFlags(Sec->getFlags());
- if (Flags != NewFlags) {
+ // Segments are contiguous memory regions that has the same attributes
+ // (e.g. executable or writable). There is one phdr for each segment.
+ // Therefore, we need to create a new phdr when the next section has
+ // different flags or is loaded at a discontiguous address using AT linker
+ // script command.
+ uintX_t NewFlags = computeFlags<ELFT>(Sec->getPhdrFlags());
+ if (Script<ELFT>::X->hasLMA(Sec->getName()) || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
Flags = NewFlags;
}
- AddSec(*Load, Sec);
+ Load->add(Sec);
- if (isRelroSection(Sec))
- AddSec(RelRo, Sec);
- if (Sec->getType() == SHT_NOTE)
- AddSec(Note, Sec);
+ if (isRelroSection<ELFT>(Sec))
+ RelRo.add(Sec);
+ if (Sec->Type == SHT_NOTE)
+ Note.add(Sec);
}
// Add the TLS segment unless it's empty.
if (TlsHdr.First)
- Phdrs.push_back(std::move(TlsHdr));
+ Ret.push_back(std::move(TlsHdr));
// Add an entry for .dynamic.
- if (isOutputDynamic()) {
- Phdr &H = *AddHdr(PT_DYNAMIC, toPhdrFlags(Out<ELFT>::Dynamic->getFlags()));
- AddSec(H, Out<ELFT>::Dynamic);
+ if (In<ELFT>::DynSymTab) {
+ PhdrEntry &H =
+ *AddHdr(PT_DYNAMIC, In<ELFT>::Dynamic->OutSec->getPhdrFlags());
+ H.add(In<ELFT>::Dynamic->OutSec);
}
// PT_GNU_RELRO includes all sections that should be marked as
// read-only by dynamic linker after proccessing relocations.
if (RelRo.First)
- Phdrs.push_back(std::move(RelRo));
+ Ret.push_back(std::move(RelRo));
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
- if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr) {
- Phdr &Hdr = *AddHdr(PT_GNU_EH_FRAME,
- toPhdrFlags(Out<ELFT>::EhFrameHdr->getFlags()));
- AddSec(Hdr, Out<ELFT>::EhFrameHdr);
+ if (!Out<ELFT>::EhFrame->empty() && In<ELFT>::EhFrameHdr) {
+ PhdrEntry &Hdr =
+ *AddHdr(PT_GNU_EH_FRAME, In<ELFT>::EhFrameHdr->OutSec->getPhdrFlags());
+ Hdr.add(In<ELFT>::EhFrameHdr->OutSec);
+ }
+
+ // PT_OPENBSD_RANDOMIZE specifies the location and size of a part of the
+ // memory image of the program that must be filled with random data before any
+ // code in the object is executed.
+ if (OutputSectionBase *Sec = findSection(".openbsd.randomdata")) {
+ PhdrEntry &Hdr = *AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags());
+ Hdr.add(Sec);
}
// PT_GNU_STACK is a special section to tell the loader to make the
// pages for the stack non-executable.
- if (!Config->ZExecStack)
- AddHdr(PT_GNU_STACK, PF_R | PF_W);
+ if (!Config->ZExecstack) {
+ PhdrEntry &Hdr = *AddHdr(PT_GNU_STACK, PF_R | PF_W);
+ if (Config->ZStackSize != uint64_t(-1))
+ Hdr.p_memsz = Config->ZStackSize;
+ }
+
+ // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable
+ // is expected to perform W^X violations, such as calling mprotect(2) or
+ // mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on
+ // OpenBSD.
+ if (Config->ZWxneeded)
+ AddHdr(PT_OPENBSD_WXNEEDED, PF_X);
if (Note.First)
- Phdrs.push_back(std::move(Note));
+ Ret.push_back(std::move(Note));
+ return Ret;
+}
- Out<ELFT>::ProgramHeaders->setSize(sizeof(Elf_Phdr) * Phdrs.size());
+template <class ELFT>
+void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) {
+ if (Config->EMachine != EM_ARM)
+ return;
+ auto I = std::find_if(
+ OutputSections.begin(), OutputSections.end(),
+ [](OutputSectionBase *Sec) { return Sec->Type == SHT_ARM_EXIDX; });
+ if (I == OutputSections.end())
+ return;
+
+ // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME
+ PhdrEntry ARMExidx(PT_ARM_EXIDX, PF_R);
+ ARMExidx.add(*I);
+ Phdrs.push_back(ARMExidx);
}
-// The first section of each PT_LOAD and the first section after PT_GNU_RELRO
-// have to be page aligned so that the dynamic linker can set the permissions.
+// The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the
+// first section after PT_GNU_RELRO have to be page aligned so that the dynamic
+// linker can set the permissions.
template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
- for (const Phdr &P : Phdrs)
- if (P.H.p_type == PT_LOAD)
+ for (const PhdrEntry &P : Phdrs)
+ if (P.p_type == PT_LOAD && P.First)
P.First->PageAlign = true;
- for (const Phdr &P : Phdrs) {
- if (P.H.p_type != PT_GNU_RELRO)
+ for (const PhdrEntry &P : Phdrs) {
+ if (P.p_type != PT_GNU_RELRO)
continue;
+ if (P.First)
+ P.First->PageAlign = true;
// Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
// have to align it to a page.
auto End = OutputSections.end();
auto I = std::find(OutputSections.begin(), End, P.Last);
if (I == End || (I + 1) == End)
continue;
- OutputSectionBase<ELFT> *Sec = *(I + 1);
- if (needsPtLoad(Sec))
+ OutputSectionBase *Sec = *(I + 1);
+ if (needsPtLoad<ELFT>(Sec))
Sec->PageAlign = true;
}
}
+template <class ELFT>
+void elf::allocateHeaders(MutableArrayRef<PhdrEntry> Phdrs,
+ ArrayRef<OutputSectionBase *> OutputSections) {
+ auto FirstPTLoad =
+ std::find_if(Phdrs.begin(), Phdrs.end(),
+ [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
+ if (FirstPTLoad == Phdrs.end())
+ return;
+ if (FirstPTLoad->First)
+ for (OutputSectionBase *Sec : OutputSections)
+ if (Sec->FirstInPtLoad == FirstPTLoad->First)
+ Sec->FirstInPtLoad = Out<ELFT>::ElfHeader;
+ FirstPTLoad->First = Out<ELFT>::ElfHeader;
+ if (!FirstPTLoad->Last)
+ FirstPTLoad->Last = Out<ELFT>::ProgramHeaders;
+}
+
// We should set file offsets and VAs for elf header and program headers
// sections. These are special, we do not include them into output sections
// list, but have them to simplify the code.
template <class ELFT> void Writer<ELFT>::fixHeaders() {
- uintX_t BaseVA = ScriptConfig->DoLayout ? 0 : Config->ImageBase;
- Out<ELFT>::ElfHeader->setVA(BaseVA);
- uintX_t Off = Out<ELFT>::ElfHeader->getSize();
- Out<ELFT>::ProgramHeaders->setVA(Off + BaseVA);
+ Out<ELFT>::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
+ // If the script has SECTIONS, assignAddresses will compute the values.
+ if (ScriptConfig->HasSections)
+ return;
+
+ uintX_t HeaderSize = getHeaderSize<ELFT>();
+ // When -T<section> option is specified, lower the base to make room for those
+ // sections.
+ if (!Config->SectionStartMap.empty()) {
+ uint64_t Min = -1;
+ for (const auto &P : Config->SectionStartMap)
+ Min = std::min(Min, P.second);
+ if (HeaderSize < Min)
+ Min -= HeaderSize;
+ else
+ AllocateHeader = false;
+ if (Min < Config->ImageBase)
+ Config->ImageBase = alignDown(Min, Config->MaxPageSize);
+ }
+
+ if (AllocateHeader)
+ allocateHeaders<ELFT>(Phdrs, OutputSections);
+
+ uintX_t BaseVA = Config->ImageBase;
+ Out<ELFT>::ElfHeader->Addr = BaseVA;
+ Out<ELFT>::ProgramHeaders->Addr = BaseVA + Out<ELFT>::ElfHeader->Size;
}
// Assign VAs (addresses at run-time) to output sections.
template <class ELFT> void Writer<ELFT>::assignAddresses() {
- uintX_t VA = Config->ImageBase + Out<ELFT>::ElfHeader->getSize() +
- Out<ELFT>::ProgramHeaders->getSize();
-
+ uintX_t VA = Config->ImageBase;
+ if (AllocateHeader)
+ VA += getHeaderSize<ELFT>();
uintX_t ThreadBssOffset = 0;
- for (OutputSectionBase<ELFT> *Sec : OutputSections) {
- uintX_t Alignment = Sec->getAlignment();
+ for (OutputSectionBase *Sec : OutputSections) {
+ uintX_t Alignment = Sec->Addralign;
if (Sec->PageAlign)
- Alignment = std::max<uintX_t>(Alignment, Target->PageSize);
+ Alignment = std::max<uintX_t>(Alignment, Config->MaxPageSize);
+
+ auto I = Config->SectionStartMap.find(Sec->getName());
+ if (I != Config->SectionStartMap.end())
+ VA = I->second;
// We only assign VAs to allocated sections.
if (needsPtLoad<ELFT>(Sec)) {
VA = alignTo(VA, Alignment);
- Sec->setVA(VA);
- VA += Sec->getSize();
- } else if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS) {
+ Sec->Addr = VA;
+ VA += Sec->Size;
+ } else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) {
uintX_t TVA = VA + ThreadBssOffset;
TVA = alignTo(TVA, Alignment);
- Sec->setVA(TVA);
- ThreadBssOffset = TVA - VA + Sec->getSize();
+ Sec->Addr = TVA;
+ ThreadBssOffset = TVA - VA + Sec->Size;
}
}
}
@@ -1059,38 +1400,50 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
// virtual address (modulo the page size) so that the loader can load
// executables without any address adjustment.
template <class ELFT, class uintX_t>
-static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase<ELFT> *Sec) {
- uintX_t Alignment = Sec->getAlignment();
- if (Sec->PageAlign)
- Alignment = std::max<uintX_t>(Alignment, Target->PageSize);
- Off = alignTo(Off, Alignment);
-
- // Relocatable output does not have program headers
- // and does not need any other offset adjusting.
- if (Config->Relocatable || !(Sec->getFlags() & SHF_ALLOC))
- return Off;
- return alignTo(Off, Target->PageSize, Sec->getVA());
+static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase *Sec) {
+ OutputSectionBase *First = Sec->FirstInPtLoad;
+ // If the section is not in a PT_LOAD, we just have to align it.
+ if (!First)
+ return alignTo(Off, Sec->Addralign);
+
+ // The first section in a PT_LOAD has to have congruent offset and address
+ // module the page size.
+ if (Sec == First)
+ return alignTo(Off, Config->MaxPageSize, Sec->Addr);
+
+ // If two sections share the same PT_LOAD the file offset is calculated
+ // using this formula: Off2 = Off1 + (VA2 - VA1).
+ return First->Offset + Sec->Addr - First->Addr;
+}
+
+template <class ELFT, class uintX_t>
+void setOffset(OutputSectionBase *Sec, uintX_t &Off) {
+ if (Sec->Type == SHT_NOBITS) {
+ Sec->Offset = Off;
+ return;
+ }
+
+ Off = getFileAlignment<ELFT>(Off, Sec);
+ Sec->Offset = Off;
+ Off += Sec->Size;
+}
+
+template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
+ uintX_t Off = 0;
+ for (OutputSectionBase *Sec : OutputSections)
+ if (Sec->Flags & SHF_ALLOC)
+ setOffset<ELFT>(Sec, Off);
+ FileSize = alignTo(Off, sizeof(uintX_t));
}
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
uintX_t Off = 0;
+ setOffset<ELFT>(Out<ELFT>::ElfHeader, Off);
+ setOffset<ELFT>(Out<ELFT>::ProgramHeaders, Off);
- auto Set = [&](OutputSectionBase<ELFT> *Sec) {
- if (Sec->getType() == SHT_NOBITS) {
- Sec->setFileOffset(Off);
- return;
- }
-
- Off = getFileAlignment<ELFT>(Off, Sec);
- Sec->setFileOffset(Off);
- Off += Sec->getSize();
- };
-
- Set(Out<ELFT>::ElfHeader);
- Set(Out<ELFT>::ProgramHeaders);
- for (OutputSectionBase<ELFT> *Sec : OutputSections)
- Set(Sec);
+ for (OutputSectionBase *Sec : OutputSections)
+ setOffset<ELFT>(Sec, Off);
SectionHeaderOff = alignTo(Off, sizeof(uintX_t));
FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
@@ -1099,50 +1452,62 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
// Finalize the program headers. We call this function after we assign
// file offsets and VAs to all sections.
template <class ELFT> void Writer<ELFT>::setPhdrs() {
- for (Phdr &P : Phdrs) {
- Elf_Phdr &H = P.H;
- OutputSectionBase<ELFT> *First = P.First;
- OutputSectionBase<ELFT> *Last = P.Last;
+ for (PhdrEntry &P : Phdrs) {
+ OutputSectionBase *First = P.First;
+ OutputSectionBase *Last = P.Last;
if (First) {
- H.p_filesz = Last->getFileOff() - First->getFileOff();
- if (Last->getType() != SHT_NOBITS)
- H.p_filesz += Last->getSize();
- H.p_memsz = Last->getVA() + Last->getSize() - First->getVA();
- H.p_offset = First->getFileOff();
- H.p_vaddr = First->getVA();
+ P.p_filesz = Last->Offset - First->Offset;
+ if (Last->Type != SHT_NOBITS)
+ P.p_filesz += Last->Size;
+ P.p_memsz = Last->Addr + Last->Size - First->Addr;
+ P.p_offset = First->Offset;
+ P.p_vaddr = First->Addr;
+ if (!P.HasLMA)
+ P.p_paddr = First->getLMA();
}
- if (H.p_type == PT_LOAD)
- H.p_align = Target->PageSize;
- else if (H.p_type == PT_GNU_RELRO)
- H.p_align = 1;
- H.p_paddr = H.p_vaddr;
+ if (P.p_type == PT_LOAD)
+ P.p_align = Config->MaxPageSize;
+ else if (P.p_type == PT_GNU_RELRO)
+ P.p_align = 1;
// The TLS pointer goes after PT_TLS. At least glibc will align it,
// so round up the size to make sure the offsets are correct.
- if (H.p_type == PT_TLS) {
- Out<ELFT>::TlsPhdr = &H;
- H.p_memsz = alignTo(H.p_memsz, H.p_align);
+ if (P.p_type == PT_TLS) {
+ Out<ELFT>::TlsPhdr = &P;
+ if (P.p_memsz)
+ P.p_memsz = alignTo(P.p_memsz, P.p_align);
}
}
}
-static uint32_t getMipsEFlags(bool Is64Bits) {
- // FIXME: In fact ELF flags depends on ELF flags of input object files
- // and selected emulation. For now just use hard coded values.
- if (Is64Bits)
- return EF_MIPS_CPIC | EF_MIPS_PIC | EF_MIPS_ARCH_64R2;
-
- uint32_t V = EF_MIPS_CPIC | EF_MIPS_ABI_O32 | EF_MIPS_ARCH_32R2;
- if (Config->Shared)
- V |= EF_MIPS_PIC;
- return V;
-}
+// The entry point address is chosen in the following ways.
+//
+// 1. the '-e' entry command-line option;
+// 2. the ENTRY(symbol) command in a linker control script;
+// 3. the value of the symbol start, if present;
+// 4. the address of the first byte of the .text section, if present;
+// 5. the address 0.
+template <class ELFT> typename ELFT::uint Writer<ELFT>::getEntryAddr() {
+ // Case 1, 2 or 3. As a special case, if the symbol is actually
+ // a number, we'll use that number as an address.
+ if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Entry))
+ return B->getVA<ELFT>();
+ uint64_t Addr;
+ if (!Config->Entry.getAsInteger(0, Addr))
+ return Addr;
+
+ // Case 4
+ if (OutputSectionBase *Sec = findSection(".text")) {
+ if (Config->WarnMissingEntry)
+ warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" +
+ utohexstr(Sec->Addr));
+ return Sec->Addr;
+ }
-template <class ELFT> static typename ELFT::uint getEntryAddr() {
- if (Symbol *S = Config->EntrySym)
- return S->body()->getVA<ELFT>();
- if (Config->EntryAddr != uint64_t(-1))
- return Config->EntryAddr;
+ // Case 5
+ if (Config->WarnMissingEntry)
+ warn("cannot find entry symbol " + Config->Entry +
+ "; not setting start address");
return 0;
}
@@ -1164,6 +1529,10 @@ static uint16_t getELFType() {
// to each section. This function fixes some predefined absolute
// symbol values that depend on section address and size.
template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
+ // __ehdr_start is the location of program headers.
+ if (ElfSym<ELFT>::EhdrStart)
+ ElfSym<ELFT>::EhdrStart->Value = Out<ELFT>::ProgramHeaders->Addr;
+
auto Set = [](DefinedRegular<ELFT> *S1, DefinedRegular<ELFT> *S2, uintX_t V) {
if (S1)
S1->Value = V;
@@ -1174,45 +1543,66 @@ template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
// _etext is the first location after the last read-only loadable segment.
// _edata is the first location after the last read-write loadable segment.
// _end is the first location after the uninitialized data region.
- for (Phdr &P : Phdrs) {
- Elf_Phdr &H = P.H;
- if (H.p_type != PT_LOAD)
+ for (PhdrEntry &P : Phdrs) {
+ if (P.p_type != PT_LOAD)
continue;
- Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, H.p_vaddr + H.p_memsz);
+ Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, P.p_vaddr + P.p_memsz);
- uintX_t Val = H.p_vaddr + H.p_filesz;
- if (H.p_flags & PF_W)
+ uintX_t Val = P.p_vaddr + P.p_filesz;
+ if (P.p_flags & PF_W)
Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, Val);
else
Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, Val);
}
+
+ // Setup MIPS _gp_disp/__gnu_local_gp symbols which should
+ // be equal to the _gp symbol's value.
+ if (Config->EMachine == EM_MIPS) {
+ if (!ElfSym<ELFT>::MipsGp->Value) {
+ // Find GP-relative section with the lowest address
+ // and use this address to calculate default _gp value.
+ uintX_t Gp = -1;
+ for (const OutputSectionBase * OS : OutputSections)
+ if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp)
+ Gp = OS->Addr;
+ if (Gp != (uintX_t)-1)
+ ElfSym<ELFT>::MipsGp->Value = Gp + 0x7ff0;
+ }
+ if (ElfSym<ELFT>::MipsGpDisp)
+ ElfSym<ELFT>::MipsGpDisp->Value = ElfSym<ELFT>::MipsGp->Value;
+ if (ElfSym<ELFT>::MipsLocalGp)
+ ElfSym<ELFT>::MipsLocalGp->Value = ElfSym<ELFT>::MipsGp->Value;
+ }
}
template <class ELFT> void Writer<ELFT>::writeHeader() {
uint8_t *Buf = Buffer->getBufferStart();
memcpy(Buf, "\177ELF", 4);
- auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
-
// Write the ELF header.
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
EHdr->e_ident[EI_DATA] = getELFEncoding<ELFT>();
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
- EHdr->e_ident[EI_OSABI] = FirstObj.getOSABI();
+ EHdr->e_ident[EI_OSABI] = Config->OSABI;
EHdr->e_type = getELFType();
- EHdr->e_machine = FirstObj.EMachine;
+ EHdr->e_machine = Config->EMachine;
EHdr->e_version = EV_CURRENT;
- EHdr->e_entry = getEntryAddr<ELFT>();
+ EHdr->e_entry = getEntryAddr();
EHdr->e_shoff = SectionHeaderOff;
EHdr->e_ehsize = sizeof(Elf_Ehdr);
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
EHdr->e_shnum = OutputSections.size() + 1;
- EHdr->e_shstrndx = Out<ELFT>::ShStrTab->SectionIndex;
+ EHdr->e_shstrndx = In<ELFT>::ShStrTab->OutSec->SectionIndex;
- if (Config->EMachine == EM_MIPS)
- EHdr->e_flags = getMipsEFlags(ELFT::Is64Bits);
+ if (Config->EMachine == EM_ARM)
+ // We don't currently use any features incompatible with EF_ARM_EABI_VER5,
+ // but we don't have any firm guarantees of conformance. Linux AArch64
+ // kernels (as of 2016) require an EABI version to be set.
+ EHdr->e_flags = EF_ARM_EABI_VER5;
+ else if (Config->EMachine == EM_MIPS)
+ EHdr->e_flags = getMipsEFlags<ELFT>();
if (!Config->Relocatable) {
EHdr->e_phoff = sizeof(Elf_Ehdr);
@@ -1221,63 +1611,133 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
// Write the program header table.
auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff);
- for (Phdr &P : Phdrs)
- *HBuf++ = P.H;
+ for (PhdrEntry &P : Phdrs) {
+ HBuf->p_type = P.p_type;
+ HBuf->p_flags = P.p_flags;
+ HBuf->p_offset = P.p_offset;
+ HBuf->p_vaddr = P.p_vaddr;
+ HBuf->p_paddr = P.p_paddr;
+ HBuf->p_filesz = P.p_filesz;
+ HBuf->p_memsz = P.p_memsz;
+ HBuf->p_align = P.p_align;
+ ++HBuf;
+ }
// Write the section header table. Note that the first table entry is null.
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
- for (OutputSectionBase<ELFT> *Sec : OutputSections)
- Sec->writeHeaderTo(++SHdrs);
+ for (OutputSectionBase *Sec : OutputSections)
+ Sec->writeHeaderTo<ELFT>(++SHdrs);
}
+// Removes a given file asynchronously. This is a performance hack,
+// so remove this when operating systems are improved.
+//
+// On Linux (and probably on other Unix-like systems), unlink(2) is a
+// noticeably slow system call. As of 2016, unlink takes 250
+// milliseconds to remove a 1 GB file on ext4 filesystem on my machine.
+//
+// To create a new result file, we first remove existing file. So, if
+// you repeatedly link a 1 GB program in a regular compile-link-debug
+// cycle, every cycle wastes 250 milliseconds only to remove a file.
+// Since LLD can link a 1 GB binary in about 5 seconds, that waste
+// actually counts.
+//
+// This function spawns a background thread to call unlink.
+// The calling thread returns almost immediately.
+static void unlinkAsync(StringRef Path) {
+ if (!Config->Threads || !sys::fs::exists(Config->OutputFile))
+ return;
+
+ // First, rename Path to avoid race condition. We cannot remove
+ // Path from a different thread because we are now going to create
+ // Path as a new file. If we do that in a different thread, the new
+ // thread can remove the new file.
+ SmallString<128> TempPath;
+ if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath))
+ return;
+ if (sys::fs::rename(Path, TempPath)) {
+ sys::fs::remove(TempPath);
+ return;
+ }
+
+ // Remove TempPath in background.
+ std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach();
+}
+
+// Open a result file.
template <class ELFT> void Writer<ELFT>::openFile() {
+ unlinkAsync(Config->OutputFile);
ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
FileOutputBuffer::create(Config->OutputFile, FileSize,
FileOutputBuffer::F_executable);
+
if (auto EC = BufferOrErr.getError())
error(EC, "failed to open " + Config->OutputFile);
else
Buffer = std::move(*BufferOrErr);
}
+template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
+ uint8_t *Buf = Buffer->getBufferStart();
+ for (OutputSectionBase *Sec : OutputSections)
+ if (Sec->Flags & SHF_ALLOC)
+ Sec->writeTo(Buf + Sec->Offset);
+}
+
// Write section contents to a mmap'ed file.
template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
- // PPC64 needs to process relocations in the .opd section before processing
- // relocations in code-containing sections.
- if (OutputSectionBase<ELFT> *Sec = Out<ELFT>::Opd) {
- Out<ELFT>::OpdBuf = Buf + Sec->getFileOff();
- Sec->writeTo(Buf + Sec->getFileOff());
+ // PPC64 needs to process relocations in the .opd section
+ // before processing relocations in code-containing sections.
+ Out<ELFT>::Opd = findSection(".opd");
+ if (Out<ELFT>::Opd) {
+ Out<ELFT>::OpdBuf = Buf + Out<ELFT>::Opd->Offset;
+ Out<ELFT>::Opd->writeTo(Buf + Out<ELFT>::Opd->Offset);
}
- for (OutputSectionBase<ELFT> *Sec : OutputSections)
- if (Sec != Out<ELFT>::Opd)
- Sec->writeTo(Buf + Sec->getFileOff());
+ OutputSectionBase *EhFrameHdr =
+ In<ELFT>::EhFrameHdr ? In<ELFT>::EhFrameHdr->OutSec : nullptr;
+ for (OutputSectionBase *Sec : OutputSections)
+ if (Sec != Out<ELFT>::Opd && Sec != EhFrameHdr)
+ Sec->writeTo(Buf + Sec->Offset);
+
+ // The .eh_frame_hdr depends on .eh_frame section contents, therefore
+ // it should be written after .eh_frame is written.
+ if (!Out<ELFT>::EhFrame->empty() && EhFrameHdr)
+ EhFrameHdr->writeTo(Buf + EhFrameHdr->Offset);
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {
- if (!Out<ELFT>::BuildId)
+ if (!In<ELFT>::BuildId || !In<ELFT>::BuildId->OutSec)
return;
- // Compute a hash of all sections except .debug_* sections.
- // We skip debug sections because they tend to be very large
- // and their contents are very likely to be the same as long as
- // other sections are the same.
+ // Compute a hash of all sections of the output file.
uint8_t *Start = Buffer->getBufferStart();
- uint8_t *Last = Start;
- std::vector<ArrayRef<uint8_t>> Regions;
- for (OutputSectionBase<ELFT> *Sec : OutputSections) {
- uint8_t *End = Start + Sec->getFileOff();
- if (!Sec->getName().startswith(".debug_"))
- Regions.push_back({Last, End});
- Last = End;
- }
- Regions.push_back({Last, Start + FileSize});
- Out<ELFT>::BuildId->writeBuildId(Regions);
+ uint8_t *End = Start + FileSize;
+ In<ELFT>::BuildId->writeBuildId({Start, End});
}
-template void elf::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab);
-template void elf::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab);
-template void elf::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab);
-template void elf::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab);
+template void elf::writeResult<ELF32LE>();
+template void elf::writeResult<ELF32BE>();
+template void elf::writeResult<ELF64LE>();
+template void elf::writeResult<ELF64BE>();
+
+template void elf::allocateHeaders<ELF32LE>(MutableArrayRef<PhdrEntry>,
+ ArrayRef<OutputSectionBase *>);
+template void elf::allocateHeaders<ELF32BE>(MutableArrayRef<PhdrEntry>,
+ ArrayRef<OutputSectionBase *>);
+template void elf::allocateHeaders<ELF64LE>(MutableArrayRef<PhdrEntry>,
+ ArrayRef<OutputSectionBase *>);
+template void elf::allocateHeaders<ELF64BE>(MutableArrayRef<PhdrEntry>,
+ ArrayRef<OutputSectionBase *>);
+
+template bool elf::isRelroSection<ELF32LE>(const OutputSectionBase *);
+template bool elf::isRelroSection<ELF32BE>(const OutputSectionBase *);
+template bool elf::isRelroSection<ELF64LE>(const OutputSectionBase *);
+template bool elf::isRelroSection<ELF64BE>(const OutputSectionBase *);
+
+template void elf::reportDiscarded<ELF32LE>(InputSectionBase<ELF32LE> *);
+template void elf::reportDiscarded<ELF32BE>(InputSectionBase<ELF32BE> *);
+template void elf::reportDiscarded<ELF64LE>(InputSectionBase<ELF64LE> *);
+template void elf::reportDiscarded<ELF64BE>(InputSectionBase<ELF64BE> *);
diff --git a/contrib/llvm/tools/lld/ELF/Writer.h b/contrib/llvm/tools/lld/ELF/Writer.h
index df25d8e..718e313 100644
--- a/contrib/llvm/tools/lld/ELF/Writer.h
+++ b/contrib/llvm/tools/lld/ELF/Writer.h
@@ -10,28 +10,56 @@
#ifndef LLD_ELF_WRITER_H
#define LLD_ELF_WRITER_H
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
#include <memory>
-namespace llvm {
- class StringRef;
-}
-
namespace lld {
namespace elf {
+class InputFile;
+class OutputSectionBase;
template <class ELFT> class InputSectionBase;
template <class ELFT> class ObjectFile;
template <class ELFT> class SymbolTable;
+template <class ELFT> void writeResult();
+template <class ELFT> void markLive();
+template <class ELFT> bool isRelroSection(const OutputSectionBase *Sec);
-template <class ELFT> void writeResult(SymbolTable<ELFT> *Symtab);
+// This describes a program header entry.
+// Each contains type, access flags and range of output sections that will be
+// placed in it.
+struct PhdrEntry {
+ PhdrEntry(unsigned Type, unsigned Flags);
+ void add(OutputSectionBase *Sec);
-template <class ELFT> void markLive();
+ uint64_t p_paddr = 0;
+ uint64_t p_vaddr = 0;
+ uint64_t p_align = 0;
+ uint64_t p_memsz = 0;
+ uint64_t p_filesz = 0;
+ uint64_t p_offset = 0;
+ uint32_t p_type = 0;
+ uint32_t p_flags = 0;
-template <class ELFT>
-llvm::StringRef getOutputSectionName(InputSectionBase<ELFT> *S);
+ OutputSectionBase *First = nullptr;
+ OutputSectionBase *Last = nullptr;
+ bool HasLMA = false;
+};
+
+llvm::StringRef getOutputSectionName(llvm::StringRef Name);
template <class ELFT>
-void reportDiscarded(InputSectionBase<ELFT> *IS,
- const std::unique_ptr<elf::ObjectFile<ELFT>> &File);
+void allocateHeaders(llvm::MutableArrayRef<PhdrEntry>,
+ llvm::ArrayRef<OutputSectionBase *>);
+template <class ELFT> void reportDiscarded(InputSectionBase<ELFT> *IS);
+
+template <class ELFT> uint32_t getMipsEFlags();
+
+uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
+ llvm::StringRef FileName);
+
+bool isMipsN32Abi(const InputFile *F);
}
}
OpenPOWER on IntegriCloud