aboutsummaryrefslogtreecommitdiffstats
path: root/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-06-26 20:33:45 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-06-26 20:33:45 +0000
commit4ea16835ba66f2240d050ffcaee44cee6c97cab9 (patch)
treed2f3d66f3352a3ec22362de0b7a5c1366fc25df8 /ELF
parent15f7a1a3796209b21af2817fdf11ca9932165c70 (diff)
downloadsrc-4ea16835ba66f2240d050ffcaee44cee6c97cab9.tar.gz
src-4ea16835ba66f2240d050ffcaee44cee6c97cab9.zip
Vendor import of lld trunk r306325:vendor/lld/lld-trunk-r306325
Notes
Notes: svn path=/vendor/lld/dist/; revision=320382 svn path=/vendor/lld/lld-trunk-r306325/; revision=320383; tag=vendor/lld/lld-trunk-r306325
Diffstat (limited to 'ELF')
-rw-r--r--ELF/Arch/AArch64.cpp6
-rw-r--r--ELF/Arch/AMDGPU.cpp6
-rw-r--r--ELF/Arch/ARM.cpp7
-rw-r--r--ELF/Arch/AVR.cpp6
-rw-r--r--ELF/Arch/Mips.cpp15
-rw-r--r--ELF/Arch/MipsArchTree.cpp (renamed from ELF/Mips.cpp)2
-rw-r--r--ELF/Arch/PPC.cpp8
-rw-r--r--ELF/Arch/PPC64.cpp6
-rw-r--r--ELF/Arch/X86.cpp11
-rw-r--r--ELF/Arch/X86_64.cpp17
-rw-r--r--ELF/CMakeLists.txt2
-rw-r--r--ELF/Config.h2
-rw-r--r--ELF/Driver.cpp53
-rw-r--r--ELF/Driver.h2
-rw-r--r--ELF/DriverUtils.cpp6
-rw-r--r--ELF/InputFiles.cpp3
-rw-r--r--ELF/InputFiles.h2
-rw-r--r--ELF/InputSection.cpp27
-rw-r--r--ELF/LinkerScript.cpp36
-rw-r--r--ELF/MarkLive.cpp2
-rw-r--r--ELF/Options.td4
-rw-r--r--ELF/OutputSections.cpp4
-rw-r--r--ELF/Relocations.cpp2
-rw-r--r--ELF/SymbolTable.cpp35
-rw-r--r--ELF/SymbolTable.h2
-rw-r--r--ELF/Symbols.cpp1
-rw-r--r--ELF/Symbols.h6
-rw-r--r--ELF/Target.cpp28
-rw-r--r--ELF/Target.h26
-rw-r--r--ELF/Writer.cpp31
30 files changed, 240 insertions, 118 deletions
diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp
index 113d0960d5f5..b26cf0815109 100644
--- a/ELF/Arch/AArch64.cpp
+++ b/ELF/Arch/AArch64.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "Error.h"
-#include "Memory.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -371,4 +370,7 @@ void AArch64::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
}
-TargetInfo *elf::createAArch64TargetInfo() { return make<AArch64>(); }
+TargetInfo *elf::getAArch64TargetInfo() {
+ static AArch64 Target;
+ return &Target;
+}
diff --git a/ELF/Arch/AMDGPU.cpp b/ELF/Arch/AMDGPU.cpp
index 68e516f9e6cf..de566c617ac0 100644
--- a/ELF/Arch/AMDGPU.cpp
+++ b/ELF/Arch/AMDGPU.cpp
@@ -9,7 +9,6 @@
#include "Error.h"
#include "InputFiles.h"
-#include "Memory.h"
#include "Symbols.h"
#include "Target.h"
#include "llvm/Object/ELF.h"
@@ -79,4 +78,7 @@ RelExpr AMDGPU::getRelExpr(uint32_t Type, const SymbolBody &S,
}
}
-TargetInfo *elf::createAMDGPUTargetInfo() { return make<AMDGPU>(); }
+TargetInfo *elf::getAMDGPUTargetInfo() {
+ static AMDGPU Target;
+ return &Target;
+}
diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp
index b245cbd7005a..e4b06ade4487 100644
--- a/ELF/Arch/ARM.cpp
+++ b/ELF/Arch/ARM.cpp
@@ -9,7 +9,6 @@
#include "Error.h"
#include "InputFiles.h"
-#include "Memory.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -58,6 +57,7 @@ ARM::ARM() {
GotPltEntrySize = 4;
PltEntrySize = 16;
PltHeaderSize = 20;
+ TrapInstr = 0xd4d4d4d4;
// ARM uses Variant 1 TLS
TcbSize = 8;
NeedsThunks = true;
@@ -429,4 +429,7 @@ int64_t ARM::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
}
}
-TargetInfo *elf::createARMTargetInfo() { return make<ARM>(); }
+TargetInfo *elf::getARMTargetInfo() {
+ static ARM Target;
+ return &Target;
+}
diff --git a/ELF/Arch/AVR.cpp b/ELF/Arch/AVR.cpp
index 86343a6faa16..3853248f8fbd 100644
--- a/ELF/Arch/AVR.cpp
+++ b/ELF/Arch/AVR.cpp
@@ -28,7 +28,6 @@
#include "Error.h"
#include "InputFiles.h"
-#include "Memory.h"
#include "Symbols.h"
#include "Target.h"
#include "llvm/Object/ELF.h"
@@ -75,4 +74,7 @@ void AVR::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
}
}
-TargetInfo *elf::createAVRTargetInfo() { return make<AVR>(); }
+TargetInfo *elf::getAVRTargetInfo() {
+ static AVR Target;
+ return &Target;
+}
diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp
index 79642df8a885..b8d796f5897a 100644
--- a/ELF/Arch/Mips.cpp
+++ b/ELF/Arch/Mips.cpp
@@ -9,7 +9,6 @@
#include "Error.h"
#include "InputFiles.h"
-#include "Memory.h"
#include "OutputSections.h"
#include "Symbols.h"
#include "SyntheticSections.h"
@@ -55,6 +54,7 @@ template <class ELFT> MIPS<ELFT>::MIPS() {
CopyRel = R_MIPS_COPY;
PltRel = R_MIPS_JUMP_SLOT;
NeedsThunks = true;
+ TrapInstr = 0xefefefef;
if (ELFT::Is64Bits) {
RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
@@ -412,11 +412,12 @@ bool MIPS<ELFT>::usesOnlyLowPageBits(uint32_t Type) const {
return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST;
}
-template <class ELFT> TargetInfo *elf::createMipsTargetInfo() {
- return make<MIPS<ELFT>>();
+template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
+ static MIPS<ELFT> Target;
+ return &Target;
}
-template TargetInfo *elf::createMipsTargetInfo<ELF32LE>();
-template TargetInfo *elf::createMipsTargetInfo<ELF32BE>();
-template TargetInfo *elf::createMipsTargetInfo<ELF64LE>();
-template TargetInfo *elf::createMipsTargetInfo<ELF64BE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF32LE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF32BE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF64LE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF64BE>();
diff --git a/ELF/Mips.cpp b/ELF/Arch/MipsArchTree.cpp
index af92fb9d24fd..ed183e9a3061 100644
--- a/ELF/Mips.cpp
+++ b/ELF/Arch/MipsArchTree.cpp
@@ -1,4 +1,4 @@
-//===- Mips.cpp ----------------------------------------------------------===//
+//===- MipsArchTree.cpp --------------------------------------------------===//
//
// The LLVM Linker
//
diff --git a/ELF/Arch/PPC.cpp b/ELF/Arch/PPC.cpp
index b5f0d5b4c687..19e10729a00e 100644
--- a/ELF/Arch/PPC.cpp
+++ b/ELF/Arch/PPC.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "Error.h"
-#include "Memory.h"
#include "Symbols.h"
#include "Target.h"
#include "llvm/Support/Endian.h"
@@ -22,7 +21,7 @@ using namespace lld::elf;
namespace {
class PPC final : public TargetInfo {
public:
- PPC() {}
+ PPC() { GotBaseSymOff = 0x8000; }
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const override;
@@ -60,4 +59,7 @@ RelExpr PPC::getRelExpr(uint32_t Type, const SymbolBody &S,
}
}
-TargetInfo *elf::createPPCTargetInfo() { return make<PPC>(); }
+TargetInfo *elf::getPPCTargetInfo() {
+ static PPC Target;
+ return &Target;
+}
diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp
index eb1e917d5790..bf414d75bec7 100644
--- a/ELF/Arch/PPC64.cpp
+++ b/ELF/Arch/PPC64.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "Error.h"
-#include "Memory.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -212,4 +211,7 @@ void PPC64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
}
}
-TargetInfo *elf::createPPC64TargetInfo() { return make<PPC64>(); }
+TargetInfo *elf::getPPC64TargetInfo() {
+ static PPC64 Target;
+ return &Target;
+}
diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp
index bc0d2b81a613..a1e9bcaf1b12 100644
--- a/ELF/Arch/X86.cpp
+++ b/ELF/Arch/X86.cpp
@@ -9,7 +9,6 @@
#include "Error.h"
#include "InputFiles.h"
-#include "Memory.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -47,6 +46,7 @@ public:
} // namespace
X86::X86() {
+ GotBaseSymOff = -1;
CopyRel = R_386_COPY;
GotRel = R_386_GLOB_DAT;
PltRel = R_386_JUMP_SLOT;
@@ -60,9 +60,7 @@ X86::X86() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
-
- // 0xCC is the "int3" (call debug exception handler) instruction.
- TrapInstr = 0xcccccccc;
+ TrapInstr = 0xcccccccc; // 0xcc = INT3
}
RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &S,
@@ -360,4 +358,7 @@ void X86::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
memcpy(Loc - 2, Inst, sizeof(Inst));
}
-TargetInfo *elf::createX86TargetInfo() { return make<X86>(); }
+TargetInfo *elf::getX86TargetInfo() {
+ static X86 Target;
+ return &Target;
+}
diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp
index b790868c7125..10179f57ee93 100644
--- a/ELF/Arch/X86_64.cpp
+++ b/ELF/Arch/X86_64.cpp
@@ -9,7 +9,6 @@
#include "Error.h"
#include "InputFiles.h"
-#include "Memory.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -52,6 +51,7 @@ private:
} // namespace
template <class ELFT> X86_64<ELFT>::X86_64() {
+ GotBaseSymOff = -1;
CopyRel = R_X86_64_COPY;
GotRel = R_X86_64_GLOB_DAT;
PltRel = R_X86_64_JUMP_SLOT;
@@ -65,13 +65,11 @@ template <class ELFT> X86_64<ELFT>::X86_64() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
+ TrapInstr = 0xcccccccc; // 0xcc = INT3
// Align to the large page size (known as a superpage or huge page).
// FreeBSD automatically promotes large, superpage-aligned allocations.
DefaultImageBase = 0x200000;
-
- // 0xCC is the "int3" (call debug exception handler) instruction.
- TrapInstr = 0xcccccccc;
}
template <class ELFT>
@@ -464,5 +462,12 @@ void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
write32le(Loc - 1, Val + 1);
}
-TargetInfo *elf::createX32TargetInfo() { return make<X86_64<ELF32LE>>(); }
-TargetInfo *elf::createX86_64TargetInfo() { return make<X86_64<ELF64LE>>(); }
+TargetInfo *elf::getX32TargetInfo() {
+ static X86_64<ELF32LE> Target;
+ return &Target;
+}
+
+TargetInfo *elf::getX86_64TargetInfo() {
+ static X86_64<ELF64LE> Target;
+ return &Target;
+}
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
index 09a19fee14b2..b4bc215a77eb 100644
--- a/ELF/CMakeLists.txt
+++ b/ELF/CMakeLists.txt
@@ -12,6 +12,7 @@ add_lld_library(lldELF
Arch/ARM.cpp
Arch/AVR.cpp
Arch/Mips.cpp
+ Arch/MipsArchTree.cpp
Arch/PPC.cpp
Arch/PPC64.cpp
Arch/X86.cpp
@@ -29,7 +30,6 @@ add_lld_library(lldELF
LinkerScript.cpp
MapFile.cpp
MarkLive.cpp
- Mips.cpp
OutputSections.cpp
Relocations.cpp
ScriptLexer.cpp
diff --git a/ELF/Config.h b/ELF/Config.h
index 9c73b4c9c068..32e86b0ec7b6 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -70,7 +70,7 @@ struct VersionDefinition {
// Structure for mapping renamed symbols
struct RenamedSymbol {
Symbol *Target;
- uint8_t OrigBinding;
+ uint8_t OriginalBinding;
};
// This struct contains the global configuration for the linker.
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index f24c941fe773..5fb33caea46f 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -200,6 +200,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
error("attempted static link of dynamic object " + Path);
return;
}
+
// DSOs usually have DT_SONAME tags in their ELF headers, and the
// sonames are used to identify DSOs. But if they are missing,
// they are identified by filenames. We don't know whether the new
@@ -210,8 +211,8 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
// If a file was specified by -lfoo, the directory part is not
// significant, as a user did not specify it. This behavior is
// compatible with GNU.
- Files.push_back(createSharedFile(
- MBRef, WithLOption ? sys::path::filename(Path) : Path));
+ Files.push_back(
+ createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path));
return;
default:
if (InLib)
@@ -301,7 +302,7 @@ static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key,
for (auto *Arg : Args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('=');
if (KV.first == Key) {
- uint64_t Result;
+ uint64_t Result = Default;
if (!to_integer(KV.second, Result))
error("invalid " + Key + ": " + KV.second);
return Result;
@@ -907,12 +908,47 @@ getDefsym(opt::InputArgList &Args) {
return Ret;
}
+// Parses `--exclude-libs=lib,lib,...`.
+// The library names may be delimited by commas or colons.
+static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {
+ DenseSet<StringRef> Ret;
+ for (auto *Arg : Args.filtered(OPT_exclude_libs)) {
+ StringRef S = Arg->getValue();
+ for (;;) {
+ size_t Pos = S.find_first_of(",:");
+ if (Pos == StringRef::npos)
+ break;
+ Ret.insert(S.substr(0, Pos));
+ S = S.substr(Pos + 1);
+ }
+ Ret.insert(S);
+ }
+ return Ret;
+}
+
+// Handles the -exclude-libs option. If a static library file is specified
+// by the -exclude-libs option, all public symbols from the archive become
+// private unless otherwise specified by version scripts or something.
+// A special library name "ALL" means all archive files.
+//
+// This is not a popular option, but some programs such as bionic libc use it.
+static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) {
+ DenseSet<StringRef> Libs = getExcludeLibs(Args);
+ bool All = Libs.count("ALL");
+
+ for (InputFile *File : Files)
+ if (auto *F = dyn_cast<ArchiveFile>(File))
+ if (All || Libs.count(path::filename(F->getName())))
+ for (Symbol *Sym : F->getSymbols())
+ Sym->VersionId = VER_NDX_LOCAL;
+}
+
// Do actual linking. Note that when this function is called,
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
SymbolTable<ELFT> Symtab;
elf::Symtab<ELFT>::X = &Symtab;
- Target = createTarget();
+ Target = getTarget();
Config->MaxPageSize = getMaxPageSize(Args);
Config->ImageBase = getImageBase(Args);
@@ -958,8 +994,17 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (ErrorCount)
return;
+ // Handle the `--undefined <sym>` options.
Symtab.scanUndefinedFlags();
+
+ // Handle undefined symbols in DSOs.
Symtab.scanShlibUndefined();
+
+ // Handle the -exclude-libs option.
+ if (Args.hasArg(OPT_exclude_libs))
+ excludeLibs(Args, Files);
+
+ // Apply version scripts.
Symtab.scanVersionScript();
// Create wrapped symbols for -wrap option.
diff --git a/ELF/Driver.h b/ELF/Driver.h
index af88341632f4..076dda7730ac 100644
--- a/ELF/Driver.h
+++ b/ELF/Driver.h
@@ -58,7 +58,7 @@ public:
// Create enum with OPT_xxx values for each option in Options.td
enum {
OPT_INVALID = 0,
-#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
#include "Options.inc"
#undef OPTION
};
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
index f4eadeee9e43..5adb09176a3a 100644
--- a/ELF/DriverUtils.cpp
+++ b/ELF/DriverUtils.cpp
@@ -42,9 +42,9 @@ 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},
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
+ {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
+ X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
#include "Options.inc"
#undef OPTION
};
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 3d11239bf88f..1ff0b4224e70 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -632,8 +632,9 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
File(std::move(File)) {}
template <class ELFT> void ArchiveFile::parse() {
+ Symbols.reserve(File->getNumberOfSymbols());
for (const Archive::Symbol &Sym : File->symbols())
- Symtab<ELFT>::X->addLazyArchive(this, Sym);
+ Symbols.push_back(Symtab<ELFT>::X->addLazyArchive(this, Sym));
}
// Returns a buffer pointing to a member file containing a given symbol.
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 2eec78444837..544a0b009b39 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -251,6 +251,7 @@ public:
explicit ArchiveFile(std::unique_ptr<Archive> &&File);
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
template <class ELFT> void parse();
+ ArrayRef<Symbol *> getSymbols() { return Symbols; }
// 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
@@ -261,6 +262,7 @@ public:
private:
std::unique_ptr<Archive> File;
llvm::DenseSet<uint64_t> Seen;
+ std::vector<Symbol *> Symbols;
};
class BitcodeFile : public InputFile {
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 9aae82bc2992..b1d5e1349460 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -399,9 +399,16 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
}
}
+// The ARM and AArch64 ABI handle pc-relative relocations to undefined weak
+// references specially. The general rule is that the value of the symbol in
+// this context is the address of the place P. A further special case is that
+// branch relocations to an undefined weak reference resolve to the next
+// instruction.
static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A,
uint32_t P) {
switch (Type) {
+ // Unresolved branch relocations to weak references resolve to next
+ // instruction, this will be either 2 or 4 bytes on from P.
case R_ARM_THM_JUMP11:
return P + 2 + A;
case R_ARM_CALL:
@@ -415,22 +422,38 @@ static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A,
case R_ARM_THM_CALL:
// We don't want an interworking BLX to ARM
return P + 5 + A;
- default:
+ // Unresolved non branch pc-relative relocations
+ // R_ARM_TARGET2 which can be resolved relatively is not present as it never
+ // targets a weak-reference.
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL:
+ case R_ARM_REL32:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL:
return P + A;
}
+ llvm_unreachable("ARM pc-relative relocation expected\n");
}
+// The comment above getARMUndefinedRelativeWeakVA applies to this function.
static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
uint64_t P) {
switch (Type) {
+ // Unresolved branch relocations to weak references resolve to next
+ // instruction, this is 4 bytes on from P.
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
case R_AARCH64_JUMP26:
case R_AARCH64_TSTBR14:
return P + 4 + A;
- default:
+ // Unresolved non branch pc-relative relocations
+ case R_AARCH64_PREL16:
+ case R_AARCH64_PREL32:
+ case R_AARCH64_PREL64:
+ case R_AARCH64_ADR_PREL_LO21:
return P + A;
}
+ llvm_unreachable("AArch64 pc-relative relocation expected\n");
}
// ARM SBREL relocations are of the form S + A - B where B is the static base
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index f5a59f0c8c4d..d369a6f978a2 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -338,8 +338,9 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
void LinkerScript::discard(ArrayRef<InputSectionBase *> V) {
for (InputSectionBase *S : V) {
S->Live = false;
- if (S == InX::ShStrTab)
- error("discarding .shstrtab section is not allowed");
+ if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab ||
+ S == InX::DynStrTab)
+ error("discarding " + S->Name + " section is not allowed");
discard(S->DependentSections);
}
}
@@ -463,11 +464,6 @@ void LinkerScript::fabricateDefaultCommands() {
OSCmd->Sec = Sec;
SecToCommand[Sec] = OSCmd;
- // Prefer user supplied address over additional alignment constraint
- auto I = Config->SectionStartMap.find(Sec->Name);
- if (I != Config->SectionStartMap.end())
- OSCmd->AddrExpr = [=] { return I->second; };
-
Commands.push_back(OSCmd);
if (Sec->Sections.size()) {
auto *ISD = make<InputSectionDescription>("");
@@ -953,6 +949,8 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) {
template <class ELFT>
static void finalizeShtGroup(OutputSection *OS,
ArrayRef<InputSection *> Sections) {
+ assert(Config->Relocatable && Sections.size() == 1);
+
// sh_link field for SHT_GROUP sections should contain the section index of
// the symbol table.
OS->Link = InX::SymTab->getParent()->SectionIndex;
@@ -960,7 +958,6 @@ static void finalizeShtGroup(OutputSection *OS,
// sh_info then contain index of an entry in symbol table section which
// provides signature of the section group.
elf::ObjectFile<ELFT> *Obj = Sections[0]->getFile<ELFT>();
- assert(Config->Relocatable && Sections.size() == 1);
ArrayRef<SymbolBody *> Symbols = Obj->getSymbols();
OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]);
}
@@ -1044,8 +1041,9 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
Sec->Loc = Buf;
- // We may have already rendered compressed content when using
- // -compress-debug-sections option. Write it together with header.
+ // If -compress-debug-section is specified and if this is a debug seciton,
+ // we've already compressed section contents. If that's the case,
+ // just write it down.
if (!Sec->CompressedData.empty()) {
memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size());
memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(),
@@ -1109,18 +1107,27 @@ ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; }
+static const size_t NoPhdr = -1;
+
// Returns indices of ELF headers containing specific section. Each index is a
// zero based number of ELF header listed within PHDRS {} script block.
std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Sec) {
if (OutputSectionCommand *Cmd = getCmd(Sec)) {
std::vector<size_t> Ret;
- for (StringRef PhdrName : Cmd->Phdrs)
- Ret.push_back(getPhdrIndex(Cmd->Location, PhdrName));
+ for (StringRef PhdrName : Cmd->Phdrs) {
+ size_t Index = getPhdrIndex(Cmd->Location, PhdrName);
+ if (Index != NoPhdr)
+ Ret.push_back(Index);
+ }
return Ret;
}
return {};
}
+// Returns the index of the segment named PhdrName if found otherwise
+// NoPhdr. When not found, if PhdrName is not the special case value 'NONE'
+// (which can be used to explicitly specify that a section isn't assigned to a
+// segment) then error.
size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
size_t I = 0;
for (PhdrsCommand &Cmd : Opt.PhdrsCommands) {
@@ -1128,8 +1135,9 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
return I;
++I;
}
- error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
- return 0;
+ if (PhdrName != "NONE")
+ error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
+ return NoPhdr;
}
template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf);
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index 0b4a78f8da6b..bde3eefc6d5f 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -78,7 +78,7 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel,
typename ELFT::uint Offset = D->Value;
if (D->isSection())
Offset += getAddend<ELFT>(Sec, Rel);
- Fn({cast<InputSectionBase>(D->Section)->Repl, Offset});
+ Fn({cast<InputSectionBase>(D->Section), Offset});
} else if (auto *U = dyn_cast<Undefined>(&B)) {
for (InputSectionBase *Sec : CNamedSections.lookup(U->getName()))
Fn({Sec, 0});
diff --git a/ELF/Options.td b/ELF/Options.td
index 335c7ade6db2..29e14c530c6a 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -92,6 +92,9 @@ def error_limit: S<"error-limit">,
def error_unresolved_symbols: F<"error-unresolved-symbols">,
HelpText<"Report unresolved symbols as errors">;
+def exclude_libs: S<"exclude-libs">,
+ HelpText<"Exclude static libraries from automatic export">;
+
def export_dynamic: F<"export-dynamic">,
HelpText<"Put symbols in the dynamic symbol table">;
@@ -298,6 +301,7 @@ def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_entry_entry: J<"entry=">, Alias<entry>;
def alias_error_limit: J<"error-limit=">, Alias<error_limit>;
+def alias_exclude_libs: J<"exclude-libs=">, Alias<exclude_libs>;
def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">,
Alias<export_dynamic_symbol>;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 6f04a04be8d0..c0bf6b32e6e2 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -273,7 +273,7 @@ void elf::reportDiscarded(InputSectionBase *IS) {
if (!Config->PrintGcSections)
return;
message("removing unused section from '" + IS->Name + "' in file '" +
- IS->File->getName());
+ IS->File->getName() + "'");
}
void OutputSectionFactory::addInputSec(InputSectionBase *IS,
@@ -305,7 +305,7 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS,
SectionKey Key = createKey(IS, OutsecName);
OutputSection *&Sec = Map[Key];
- return addInputSec(IS, OutsecName, Sec);
+ addInputSec(IS, OutsecName, Sec);
}
void OutputSectionFactory::addInputSec(InputSectionBase *IS,
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index 1ac3bce769ee..fd823fe0ed42 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -361,7 +361,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
// These expressions always compute a constant
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_GOT_GP_PC,
- R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC,
+ R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
return true;
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index a223aec98624..ab8802c86d8e 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -167,8 +167,8 @@ template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) {
// Tell LTO not to eliminate this symbol
Wrap->IsUsedInRegularObj = true;
- Config->RenamedSymbols[Real] = RenamedSymbol{Sym, Real->Binding};
- Config->RenamedSymbols[Sym] = RenamedSymbol{Wrap, Sym->Binding};
+ Config->RenamedSymbols[Real] = {Sym, Real->Binding};
+ Config->RenamedSymbols[Sym] = {Wrap, Sym->Binding};
}
// Creates alias for symbol. Used to implement --defsym=ALIAS=SYM.
@@ -184,7 +184,7 @@ template <class ELFT> void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias,
// Tell LTO not to eliminate this symbol
Sym->IsUsedInRegularObj = true;
- Config->RenamedSymbols[AliasSym] = RenamedSymbol{Sym, AliasSym->Binding};
+ Config->RenamedSymbols[AliasSym] = {Sym, AliasSym->Binding};
}
// Apply symbol renames created by -wrap and -defsym. The renames are created
@@ -193,14 +193,16 @@ template <class ELFT> void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias,
// symbols are finalized, we can perform the replacement.
template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() {
for (auto &KV : Config->RenamedSymbols) {
- Symbol *Sym = KV.first;
- Symbol *Rename = KV.second.Target;
- Sym->Binding = KV.second.OrigBinding;
-
- // We rename symbols by replacing the old symbol's SymbolBody with the new
- // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
- // old symbol to instead refer to the new symbol.
- memcpy(Sym->Body.buffer, Rename->Body.buffer, sizeof(Sym->Body));
+ Symbol *Dst = KV.first;
+ Symbol *Src = KV.second.Target;
+ Dst->Binding = KV.second.OriginalBinding;
+
+ // We rename symbols by replacing the old symbol's SymbolBody with
+ // the new symbol's SymbolBody. The only attribute we want to keep
+ // is the symbol name, so that two symbols don't have the same name.
+ StringRef S = Dst->body()->getName();
+ memcpy(Dst->Body.buffer, Src->Body.buffer, sizeof(Symbol::Body));
+ Dst->body()->setName(S);
}
}
@@ -518,18 +520,18 @@ SymbolBody *SymbolTable<ELFT>::findInCurrentDSO(StringRef Name) {
}
template <class ELFT>
-void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
- const object::Archive::Symbol Sym) {
+Symbol *SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
+ const object::Archive::Symbol Sym) {
Symbol *S;
bool WasInserted;
StringRef Name = Sym.getName();
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType);
- return;
+ return S;
}
if (!S->body()->isUndefined())
- return;
+ return S;
// Weak undefined symbols should not fetch members from archives. If we were
// to keep old symbol we would not know that an archive member was available
@@ -540,11 +542,12 @@ void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
// to preserve its type. FIXME: Move the Type field to Symbol.
if (S->isWeak()) {
replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
- return;
+ return S;
}
std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym);
if (!MBInfo.first.getBuffer().empty())
addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second));
+ return S;
}
template <class ELFT>
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
index f38d09760c7e..316d9c9bf373 100644
--- a/ELF/SymbolTable.h
+++ b/ELF/SymbolTable.h
@@ -66,7 +66,7 @@ public:
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);
+ Symbol *addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
void addLazyObject(StringRef Name, LazyObjectFile &Obj);
Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File);
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index 8f9b20477b29..5dce71a32c9c 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -35,6 +35,7 @@ DefinedRegular *ElfSym::Edata1;
DefinedRegular *ElfSym::Edata2;
DefinedRegular *ElfSym::End1;
DefinedRegular *ElfSym::End2;
+DefinedRegular *ElfSym::GlobalOffsetTable;
DefinedRegular *ElfSym::MipsGp;
DefinedRegular *ElfSym::MipsGpDisp;
DefinedRegular *ElfSym::MipsLocalGp;
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index 030527f63744..406fd8e0f57b 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -69,6 +69,7 @@ public:
bool isLocal() const { return IsLocal; }
bool isPreemptible() const;
StringRef getName() const { return Name; }
+ void setName(StringRef S) { Name = S; }
uint8_t getVisibility() const { return StOther & 0x3; }
void parseSymbolVersion();
@@ -317,6 +318,11 @@ struct ElfSym {
static DefinedRegular *End1;
static DefinedRegular *End2;
+ // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
+ // be at some offset from the base of the .got section, usually 0 or
+ // the end of the .got.
+ static DefinedRegular *GlobalOffsetTable;
+
// _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS.
static DefinedRegular *MipsGp;
static DefinedRegular *MipsGpDisp;
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index df3f4d6773f0..c1a85e165258 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -47,40 +47,40 @@ std::string lld::toString(uint32_t Type) {
return S;
}
-TargetInfo *elf::createTarget() {
+TargetInfo *elf::getTarget() {
switch (Config->EMachine) {
case EM_386:
case EM_IAMCU:
- return createX86TargetInfo();
+ return getX86TargetInfo();
case EM_AARCH64:
- return createAArch64TargetInfo();
+ return getAArch64TargetInfo();
case EM_AMDGPU:
- return createAMDGPUTargetInfo();
+ return getAMDGPUTargetInfo();
case EM_ARM:
- return createARMTargetInfo();
+ return getARMTargetInfo();
case EM_AVR:
- return createAVRTargetInfo();
+ return getAVRTargetInfo();
case EM_MIPS:
switch (Config->EKind) {
case ELF32LEKind:
- return createMipsTargetInfo<ELF32LE>();
+ return getMipsTargetInfo<ELF32LE>();
case ELF32BEKind:
- return createMipsTargetInfo<ELF32BE>();
+ return getMipsTargetInfo<ELF32BE>();
case ELF64LEKind:
- return createMipsTargetInfo<ELF64LE>();
+ return getMipsTargetInfo<ELF64LE>();
case ELF64BEKind:
- return createMipsTargetInfo<ELF64BE>();
+ return getMipsTargetInfo<ELF64BE>();
default:
fatal("unsupported MIPS target");
}
case EM_PPC:
- return createPPCTargetInfo();
+ return getPPCTargetInfo();
case EM_PPC64:
- return createPPC64TargetInfo();
+ return getPPC64TargetInfo();
case EM_X86_64:
if (Config->EKind == ELF32LEKind)
- return createX32TargetInfo();
- return createX86_64TargetInfo();
+ return getX32TargetInfo();
+ return getX86_64TargetInfo();
}
fatal("unknown target machine");
}
diff --git a/ELF/Target.h b/ELF/Target.h
index 79b03f876d0d..bf703fd0086a 100644
--- a/ELF/Target.h
+++ b/ELF/Target.h
@@ -66,6 +66,10 @@ public:
// Given that, the smallest value that can be used in here is 0x10000.
uint64_t DefaultImageBase = 0x10000;
+ // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for
+ // end of .got
+ uint64_t GotBaseSymOff = 0;
+
uint32_t CopyRel;
uint32_t GotRel;
uint32_t PltRel;
@@ -102,16 +106,16 @@ public:
virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
};
-TargetInfo *createAArch64TargetInfo();
-TargetInfo *createAMDGPUTargetInfo();
-TargetInfo *createARMTargetInfo();
-TargetInfo *createAVRTargetInfo();
-TargetInfo *createPPC64TargetInfo();
-TargetInfo *createPPCTargetInfo();
-TargetInfo *createX32TargetInfo();
-TargetInfo *createX86TargetInfo();
-TargetInfo *createX86_64TargetInfo();
-template <class ELFT> TargetInfo *createMipsTargetInfo();
+TargetInfo *getAArch64TargetInfo();
+TargetInfo *getAMDGPUTargetInfo();
+TargetInfo *getARMTargetInfo();
+TargetInfo *getAVRTargetInfo();
+TargetInfo *getPPC64TargetInfo();
+TargetInfo *getPPCTargetInfo();
+TargetInfo *getX32TargetInfo();
+TargetInfo *getX86TargetInfo();
+TargetInfo *getX86_64TargetInfo();
+template <class ELFT> TargetInfo *getMipsTargetInfo();
std::string getErrorLocation(const uint8_t *Loc);
@@ -119,7 +123,7 @@ uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t Expr);
extern TargetInfo *Target;
-TargetInfo *createTarget();
+TargetInfo *getTarget();
template <unsigned N>
static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) {
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 4ff06388ec78..4c12b18836bf 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -87,6 +87,8 @@ private:
uint64_t FileSize;
uint64_t SectionHeaderOff;
+
+ bool HasGotBaseSym = false;
};
} // anonymous namespace
@@ -815,19 +817,13 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL);
}
- // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
- // is magical and is used to produce a R_386_GOTPC relocation.
- // The R_386_GOTPC relocation value doesn't actually depend on the
- // symbol value, so it could use an index of STN_UNDEF which, according
- // to the spec, means the symbol value is 0.
- // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
- // the object file.
- // The situation is even stranger on x86_64 where the assembly doesn't
- // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
- // an undefined symbol in the .o files.
- // Given that the symbol is effectively unused, we just create a dummy
- // hidden one to avoid the undefined symbol error.
- Symtab<ELFT>::X->addIgnored("_GLOBAL_OFFSET_TABLE_");
+ // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
+ // be at some offset from the base of the .got section, usually 0 or the end
+ // of the .got
+ InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
+ : cast<InputSection>(InX::Got);
+ ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>(
+ "_GLOBAL_OFFSET_TABLE_", GotSection, Target->GotBaseSymOff);
// __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
@@ -1147,6 +1143,8 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
OutputSection *OS = SS->getParent();
if (!SS->empty() || !OS)
continue;
+ if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable)
+ continue;
OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS));
SS->Live = false;
// If there are no other sections in the output section, remove it from the
@@ -1231,6 +1229,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
OutputSectionCommands.push_back(Cmd);
+ // Prefer command line supplied address over other constraints.
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ auto I = Config->SectionStartMap.find(Cmd->Name);
+ if (I != Config->SectionStartMap.end())
+ Cmd->AddrExpr = [=] { return I->second; };
+ }
+
// This is a bit of a hack. A value of 0 means undef, so we set it
// to 1 t make __ehdr_start defined. The section number is not
// particularly relevant.