aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-02-05 18:39:57 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-02-05 18:39:57 +0000
commit774c33a182f027f50320a37542a6b47a0f9caeb3 (patch)
treef45104cc1788b146352f7c54fef4d851704fd451
parent70a65b6fdde671ba81d93b87098b719ccf7bfb42 (diff)
Vendor import of lld release_80 branch r353167:vendor/lld/lld-release_80-r353167
Notes
Notes: svn path=/vendor/lld/dist-release_80/; revision=343802 svn path=/vendor/lld/lld-release_80-r353167/; revision=343803; tag=vendor/lld/lld-release_80-r353167
-rw-r--r--COFF/Chunks.cpp24
-rw-r--r--COFF/Chunks.h13
-rw-r--r--COFF/DLL.cpp16
-rw-r--r--COFF/ICF.cpp20
-rw-r--r--COFF/Writer.cpp60
-rw-r--r--ELF/ICF.cpp25
-rw-r--r--ELF/InputFiles.cpp44
-rw-r--r--ELF/InputFiles.h1
-rw-r--r--ELF/ScriptParser.cpp65
-rw-r--r--ELF/SyntheticSections.cpp4
-rw-r--r--MinGW/Options.td6
-rw-r--r--docs/ReleaseNotes.rst10
-rw-r--r--test/COFF/arm-thumb-thunks-pdb.s18
-rw-r--r--test/COFF/arm64-branch-range.test16
-rw-r--r--test/COFF/arm64-thunks.s27
-rw-r--r--test/COFF/imports.test13
-rw-r--r--test/ELF/arm-gnu-ifunc.s5
-rw-r--r--test/ELF/comdat-linkonce.s7
-rw-r--r--test/ELF/emulation-aarch64.s23
-rw-r--r--test/ELF/emulation-ppc.s32
-rw-r--r--test/ELF/emulation-x86.s10
-rw-r--r--test/ELF/no-discard-this_module.s41
-rw-r--r--test/ELF/sht-group-empty.test55
23 files changed, 411 insertions, 124 deletions
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
index 29131d7eb8db..2bb9aa01e539 100644
--- a/COFF/Chunks.cpp
+++ b/COFF/Chunks.cpp
@@ -669,18 +669,38 @@ const uint8_t ArmThunk[] = {
0xe7, 0x44, // L1: add pc, ip
};
-size_t RangeExtensionThunk::getSize() const {
+size_t RangeExtensionThunkARM::getSize() const {
assert(Config->Machine == ARMNT);
return sizeof(ArmThunk);
}
-void RangeExtensionThunk::writeTo(uint8_t *Buf) const {
+void RangeExtensionThunkARM::writeTo(uint8_t *Buf) const {
assert(Config->Machine == ARMNT);
uint64_t Offset = Target->getRVA() - RVA - 12;
memcpy(Buf + OutputSectionOff, ArmThunk, sizeof(ArmThunk));
applyMOV32T(Buf + OutputSectionOff, uint32_t(Offset));
}
+// A position independent ARM64 adrp+add thunk, with a maximum range of
+// +/- 4 GB, which is enough for any PE-COFF.
+const uint8_t Arm64Thunk[] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, :lo12:Dest
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+};
+
+size_t RangeExtensionThunkARM64::getSize() const {
+ assert(Config->Machine == ARM64);
+ return sizeof(Arm64Thunk);
+}
+
+void RangeExtensionThunkARM64::writeTo(uint8_t *Buf) const {
+ assert(Config->Machine == ARM64);
+ memcpy(Buf + OutputSectionOff, Arm64Thunk, sizeof(Arm64Thunk));
+ applyArm64Addr(Buf + OutputSectionOff + 0, Target->getRVA(), RVA, 12);
+ applyArm64Imm(Buf + OutputSectionOff + 4, Target->getRVA() & 0xfff, 0);
+}
+
void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
Res->emplace_back(getRVA());
}
diff --git a/COFF/Chunks.h b/COFF/Chunks.h
index f8a0ddd8ef3b..e132fdf8adfa 100644
--- a/COFF/Chunks.h
+++ b/COFF/Chunks.h
@@ -355,9 +355,18 @@ private:
Defined *ImpSymbol;
};
-class RangeExtensionThunk : public Chunk {
+class RangeExtensionThunkARM : public Chunk {
public:
- explicit RangeExtensionThunk(Defined *T) : Target(T) {}
+ explicit RangeExtensionThunkARM(Defined *T) : Target(T) {}
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+ Defined *Target;
+};
+
+class RangeExtensionThunkARM64 : public Chunk {
+public:
+ explicit RangeExtensionThunkARM64(Defined *T) : Target(T) {}
size_t getSize() const override;
void writeTo(uint8_t *Buf) const override;
diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp
index 599cc5892a16..c06027d3e5c3 100644
--- a/COFF/DLL.cpp
+++ b/COFF/DLL.cpp
@@ -47,6 +47,7 @@ public:
}
void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
write16le(Buf + OutputSectionOff, Hint);
memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size());
}
@@ -63,7 +64,10 @@ public:
size_t getSize() const override { return Config->Wordsize; }
void writeTo(uint8_t *Buf) const override {
- write32le(Buf + OutputSectionOff, HintName->getRVA());
+ if (Config->is64())
+ write64le(Buf + OutputSectionOff, HintName->getRVA());
+ else
+ write32le(Buf + OutputSectionOff, HintName->getRVA());
}
Chunk *HintName;
@@ -99,6 +103,8 @@ public:
size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
+
auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff);
E->ImportLookupTableRVA = LookupTab->getRVA();
E->NameRVA = DLLName->getRVA();
@@ -118,6 +124,10 @@ public:
bool hasData() const override { return false; }
size_t getSize() const override { return Size; }
+ void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, Size);
+ }
+
private:
size_t Size;
};
@@ -160,6 +170,8 @@ public:
}
void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
+
auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff);
E->Attributes = 1;
E->Name = DLLName->getRVA();
@@ -392,6 +404,8 @@ public:
}
void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
+
auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff);
E->NameRVA = DLLName->getRVA();
E->OrdinalBase = 0;
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
index 34ea360fa925..f6904eb7d24f 100644
--- a/COFF/ICF.cpp
+++ b/COFF/ICF.cpp
@@ -263,19 +263,21 @@ void ICF::run(ArrayRef<Chunk *> Vec) {
// Initially, we use hash values to partition sections.
parallelForEach(Chunks, [&](SectionChunk *SC) {
- SC->Class[1] = xxHash64(SC->getContents());
+ SC->Class[0] = xxHash64(SC->getContents());
});
// Combine the hashes of the sections referenced by each section into its
// hash.
- parallelForEach(Chunks, [&](SectionChunk *SC) {
- uint32_t Hash = SC->Class[1];
- for (Symbol *B : SC->symbols())
- if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
- Hash ^= Sym->getChunk()->Class[1];
- // Set MSB to 1 to avoid collisions with non-hash classs.
- SC->Class[0] = Hash | (1U << 31);
- });
+ for (unsigned Cnt = 0; Cnt != 2; ++Cnt) {
+ parallelForEach(Chunks, [&](SectionChunk *SC) {
+ uint32_t Hash = SC->Class[Cnt % 2];
+ for (Symbol *B : SC->symbols())
+ if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
+ Hash += Sym->getChunk()->Class[Cnt % 2];
+ // Set MSB to 1 to avoid collisions with non-hash classs.
+ SC->Class[(Cnt + 1) % 2] = Hash | (1U << 31);
+ });
+ }
// From now on, sections in Chunks are ordered so that sections in
// the same group are consecutive in the vector.
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
index 258796ea6057..6acfaf9a4454 100644
--- a/COFF/Writer.cpp
+++ b/COFF/Writer.cpp
@@ -306,16 +306,31 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) {
// Check whether the target address S is in range from a relocation
// of type RelType at address P.
static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) {
- assert(Config->Machine == ARMNT);
- int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
- switch (RelType) {
- case IMAGE_REL_ARM_BRANCH20T:
- return isInt<21>(Diff);
- case IMAGE_REL_ARM_BRANCH24T:
- case IMAGE_REL_ARM_BLX23T:
- return isInt<25>(Diff);
- default:
- return true;
+ if (Config->Machine == ARMNT) {
+ int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
+ switch (RelType) {
+ case IMAGE_REL_ARM_BRANCH20T:
+ return isInt<21>(Diff);
+ case IMAGE_REL_ARM_BRANCH24T:
+ case IMAGE_REL_ARM_BLX23T:
+ return isInt<25>(Diff);
+ default:
+ return true;
+ }
+ } else if (Config->Machine == ARM64) {
+ int64_t Diff = AbsoluteDifference(S, P) + Margin;
+ switch (RelType) {
+ case IMAGE_REL_ARM64_BRANCH26:
+ return isInt<28>(Diff);
+ case IMAGE_REL_ARM64_BRANCH19:
+ return isInt<21>(Diff);
+ case IMAGE_REL_ARM64_BRANCH14:
+ return isInt<16>(Diff);
+ default:
+ return true;
+ }
+ } else {
+ llvm_unreachable("Unexpected architecture");
}
}
@@ -327,7 +342,17 @@ getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P,
Defined *&LastThunk = LastThunks[Target->getRVA()];
if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin))
return {LastThunk, false};
- RangeExtensionThunk *C = make<RangeExtensionThunk>(Target);
+ Chunk *C;
+ switch (Config->Machine) {
+ case ARMNT:
+ C = make<RangeExtensionThunkARM>(Target);
+ break;
+ case ARM64:
+ C = make<RangeExtensionThunkARM64>(Target);
+ break;
+ default:
+ llvm_unreachable("Unexpected architecture");
+ }
Defined *D = make<DefinedSynthetic>("", C);
LastThunk = D;
return {D, true};
@@ -344,14 +369,14 @@ getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P,
// After adding thunks, we verify that all relocations are in range (with
// no extra margin requirements). If this failed, we restart (throwing away
// the previously created thunks) and retry with a wider margin.
-static bool createThunks(std::vector<Chunk *> &Chunks, int Margin) {
+static bool createThunks(OutputSection *OS, int Margin) {
bool AddressesChanged = false;
DenseMap<uint64_t, Defined *> LastThunks;
size_t ThunksSize = 0;
// Recheck Chunks.size() each iteration, since we can insert more
// elements into it.
- for (size_t I = 0; I != Chunks.size(); ++I) {
- SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Chunks[I]);
+ for (size_t I = 0; I != OS->Chunks.size(); ++I) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(OS->Chunks[I]);
if (!SC)
continue;
size_t ThunkInsertionSpot = I + 1;
@@ -388,7 +413,8 @@ static bool createThunks(std::vector<Chunk *> &Chunks, int Margin) {
Chunk *ThunkChunk = Thunk->getChunk();
ThunkChunk->setRVA(
ThunkInsertionRVA); // Estimate of where it will be located.
- Chunks.insert(Chunks.begin() + ThunkInsertionSpot, ThunkChunk);
+ ThunkChunk->setOutputSection(OS);
+ OS->Chunks.insert(OS->Chunks.begin() + ThunkInsertionSpot, ThunkChunk);
ThunkInsertionSpot++;
ThunksSize += ThunkChunk->getSize();
ThunkInsertionRVA += ThunkChunk->getSize();
@@ -428,7 +454,7 @@ static bool verifyRanges(const std::vector<Chunk *> Chunks) {
// Assign addresses and add thunks if necessary.
void Writer::finalizeAddresses() {
assignAddresses();
- if (Config->Machine != ARMNT)
+ if (Config->Machine != ARMNT && Config->Machine != ARM64)
return;
size_t OrigNumChunks = 0;
@@ -477,7 +503,7 @@ void Writer::finalizeAddresses() {
// to avoid things going out of range due to the added thunks.
bool AddressesChanged = false;
for (OutputSection *Sec : OutputSections)
- AddressesChanged |= createThunks(Sec->Chunks, Margin);
+ AddressesChanged |= createThunks(Sec, Margin);
// If the verification above thought we needed thunks, we should have
// added some.
assert(AddressesChanged);
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index e917ae76a689..d08ac73ded80 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -426,16 +426,17 @@ void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> Fn) {
// Combine the hashes of the sections referenced by the given section into its
// hash.
template <class ELFT, class RelTy>
-static void combineRelocHashes(InputSection *IS, ArrayRef<RelTy> Rels) {
- uint32_t Hash = IS->Class[1];
+static void combineRelocHashes(unsigned Cnt, InputSection *IS,
+ ArrayRef<RelTy> Rels) {
+ uint32_t Hash = IS->Class[Cnt % 2];
for (RelTy Rel : Rels) {
Symbol &S = IS->template getFile<ELFT>()->getRelocTargetSym(Rel);
if (auto *D = dyn_cast<Defined>(&S))
if (auto *RelSec = dyn_cast_or_null<InputSection>(D->Section))
- Hash ^= RelSec->Class[1];
+ Hash += RelSec->Class[Cnt % 2];
}
// Set MSB to 1 to avoid collisions with non-hash IDs.
- IS->Class[0] = Hash | (1U << 31);
+ IS->Class[(Cnt + 1) % 2] = Hash | (1U << 31);
}
static void print(const Twine &S) {
@@ -453,15 +454,17 @@ template <class ELFT> void ICF<ELFT>::run() {
// Initially, we use hash values to partition sections.
parallelForEach(Sections, [&](InputSection *S) {
- S->Class[1] = xxHash64(S->data());
+ S->Class[0] = xxHash64(S->data());
});
- parallelForEach(Sections, [&](InputSection *S) {
- if (S->AreRelocsRela)
- combineRelocHashes<ELFT>(S, S->template relas<ELFT>());
- else
- combineRelocHashes<ELFT>(S, S->template rels<ELFT>());
- });
+ for (unsigned Cnt = 0; Cnt != 2; ++Cnt) {
+ parallelForEach(Sections, [&](InputSection *S) {
+ if (S->AreRelocsRela)
+ combineRelocHashes<ELFT>(Cnt, S, S->template relas<ELFT>());
+ else
+ combineRelocHashes<ELFT>(Cnt, S, S->template rels<ELFT>());
+ });
+ }
// From now on, sections in Sections vector are ordered so that sections
// in the same equivalence class are consecutive in the vector.
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index e4d1dec7cbcb..bc7e61072e64 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -320,17 +320,6 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
return Signature;
}
-template <class ELFT>
-ArrayRef<typename ObjFile<ELFT>::Elf_Word>
-ObjFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
- const ELFFile<ELFT> &Obj = this->getObj();
- ArrayRef<Elf_Word> Entries =
- CHECK(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), this);
- if (Entries.empty() || Entries[0] != GRP_COMDAT)
- fatal(toString(this) + ": unsupported SHT_GROUP format");
- return Entries.slice(1);
-}
-
template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
// On a regular link we don't merge sections if -O0 (default is -O1). This
// sometimes makes the linker significantly faster, although the output will
@@ -440,26 +429,34 @@ void ObjFile<ELFT>::initializeSections(
case SHT_GROUP: {
// De-duplicate section groups by their signatures.
StringRef Signature = getShtGroupSignature(ObjSections, Sec);
- bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
this->Sections[I] = &InputSection::Discarded;
- // We only support GRP_COMDAT type of group. Get the all entries of the
- // section here to let getShtGroupEntries to check the type early for us.
- ArrayRef<Elf_Word> Entries = getShtGroupEntries(Sec);
- // If it is a new section group, we want to keep group members.
- // Group leader sections, which contain indices of group members, are
- // discarded because they are useless beyond this point. The only
- // exception is the -r option because in order to produce re-linkable
- // object files, we want to pass through basically everything.
+ ArrayRef<Elf_Word> Entries =
+ CHECK(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), this);
+ if (Entries.empty())
+ fatal(toString(this) + ": empty SHT_GROUP");
+
+ // The first word of a SHT_GROUP section contains flags. Currently,
+ // the standard defines only "GRP_COMDAT" flag for the COMDAT group.
+ // An group with the empty flag doesn't define anything; such sections
+ // are just skipped.
+ if (Entries[0] == 0)
+ continue;
+
+ if (Entries[0] != GRP_COMDAT)
+ fatal(toString(this) + ": unsupported SHT_GROUP format");
+
+ bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
if (IsNew) {
if (Config->Relocatable)
this->Sections[I] = createInputSection(Sec);
- continue;
+ continue;
}
+
// Otherwise, discard group members.
- for (uint32_t SecIndex : Entries) {
+ for (uint32_t SecIndex : Entries.slice(1)) {
if (SecIndex >= Size)
fatal(toString(this) +
": invalid section index in group: " + Twine(SecIndex));
@@ -739,7 +736,8 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
// 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."))
+ if (Name == ".gnu.linkonce.t.__x86.get_pc_thunk.bx" ||
+ Name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx")
return &InputSection::Discarded;
// If we are creating a new .build-id section, strip existing .build-id
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 5094ddd804a5..d7cbbc67a365 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -175,7 +175,6 @@ template <class ELFT> class ObjFile : public ELFFileBase<ELFT> {
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec);
- ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec);
public:
static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; }
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index eee3f0e330cc..7cce94659c9e 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -94,7 +94,6 @@ private:
SortSectionPolicy readSortKind();
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
SymbolAssignment *readAssignment(StringRef Tok);
- std::tuple<ELFKind, uint16_t, bool> readBfdName();
void readSort();
Expr readAssert();
Expr readConstant();
@@ -385,39 +384,24 @@ void ScriptParser::readOutputArch() {
skip();
}
-std::tuple<ELFKind, uint16_t, bool> ScriptParser::readBfdName() {
- StringRef S = unquote(next());
- if (S == "elf32-i386")
- return std::make_tuple(ELF32LEKind, EM_386, false);
- if (S == "elf32-iamcu")
- return std::make_tuple(ELF32LEKind, EM_IAMCU, false);
- if (S == "elf32-littlearm")
- return std::make_tuple(ELF32LEKind, EM_ARM, false);
- if (S == "elf32-x86-64")
- return std::make_tuple(ELF32LEKind, EM_X86_64, false);
- if (S == "elf64-littleaarch64")
- return std::make_tuple(ELF64LEKind, EM_AARCH64, false);
- if (S == "elf64-powerpc")
- return std::make_tuple(ELF64BEKind, EM_PPC64, false);
- if (S == "elf64-powerpcle")
- return std::make_tuple(ELF64LEKind, EM_PPC64, false);
- if (S == "elf64-x86-64")
- return std::make_tuple(ELF64LEKind, EM_X86_64, false);
- if (S == "elf32-tradbigmips")
- return std::make_tuple(ELF32BEKind, EM_MIPS, false);
- if (S == "elf32-ntradbigmips")
- return std::make_tuple(ELF32BEKind, EM_MIPS, true);
- if (S == "elf32-tradlittlemips")
- return std::make_tuple(ELF32LEKind, EM_MIPS, false);
- if (S == "elf32-ntradlittlemips")
- return std::make_tuple(ELF32LEKind, EM_MIPS, true);
- if (S == "elf64-tradbigmips")
- return std::make_tuple(ELF64BEKind, EM_MIPS, false);
- if (S == "elf64-tradlittlemips")
- return std::make_tuple(ELF64LEKind, EM_MIPS, false);
-
- setError("unknown output format name: " + S);
- return std::make_tuple(ELFNoneKind, EM_NONE, false);
+static std::pair<ELFKind, uint16_t> parseBfdName(StringRef S) {
+ return StringSwitch<std::pair<ELFKind, uint16_t>>(S)
+ .Case("elf32-i386", {ELF32LEKind, EM_386})
+ .Case("elf32-iamcu", {ELF32LEKind, EM_IAMCU})
+ .Case("elf32-littlearm", {ELF32LEKind, EM_ARM})
+ .Case("elf32-x86-64", {ELF32LEKind, EM_X86_64})
+ .Case("elf64-aarch64", {ELF64LEKind, EM_AARCH64})
+ .Case("elf64-littleaarch64", {ELF64LEKind, EM_AARCH64})
+ .Case("elf64-powerpc", {ELF64BEKind, EM_PPC64})
+ .Case("elf64-powerpcle", {ELF64LEKind, EM_PPC64})
+ .Case("elf64-x86-64", {ELF64LEKind, EM_X86_64})
+ .Case("elf32-tradbigmips", {ELF32BEKind, EM_MIPS})
+ .Case("elf32-ntradbigmips", {ELF32BEKind, EM_MIPS})
+ .Case("elf32-tradlittlemips", {ELF32LEKind, EM_MIPS})
+ .Case("elf32-ntradlittlemips", {ELF32LEKind, EM_MIPS})
+ .Case("elf64-tradbigmips", {ELF64BEKind, EM_MIPS})
+ .Case("elf64-tradlittlemips", {ELF64LEKind, EM_MIPS})
+ .Default({ELFNoneKind, EM_NONE});
}
// Parse OUTPUT_FORMAT(bfdname) or OUTPUT_FORMAT(bfdname, big, little).
@@ -425,9 +409,16 @@ std::tuple<ELFKind, uint16_t, bool> ScriptParser::readBfdName() {
void ScriptParser::readOutputFormat() {
expect("(");
- std::tuple<ELFKind, uint16_t, bool> BfdTuple = readBfdName();
- if (Config->EKind == ELFNoneKind)
- std::tie(Config->EKind, Config->EMachine, Config->MipsN32Abi) = BfdTuple;
+ StringRef Name = unquote(next());
+ StringRef S = Name;
+ if (S.consume_back("-freebsd"))
+ Config->OSABI = ELFOSABI_FREEBSD;
+
+ std::tie(Config->EKind, Config->EMachine) = parseBfdName(S);
+ if (Config->EMachine == EM_NONE)
+ setError("unknown output format name: " + Name);
+ if (S == "elf32-ntradlittlemips" || S == "elf32-ntradbigmips")
+ Config->MipsN32Abi = true;
if (consume(")"))
return;
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index f459c1b6b479..b1a3f8bc70ae 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -1513,8 +1513,10 @@ void RelocationBaseSection::finalizeContents() {
else
getParent()->Link = 0;
- if (In.RelaIplt == this || In.RelaPlt == this)
+ if (In.RelaPlt == this)
getParent()->Info = In.GotPlt->getParent()->SectionIndex;
+ if (In.RelaIplt == this)
+ getParent()->Info = In.IgotPlt->getParent()->SectionIndex;
}
RelrBaseSection::RelrBaseSection()
diff --git a/MinGW/Options.td b/MinGW/Options.td
index 948faa687521..0cda2447e522 100644
--- a/MinGW/Options.td
+++ b/MinGW/Options.td
@@ -78,3 +78,9 @@ def version: F<"version">, HelpText<"Display the version number and exit">;
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_strip_s: Flag<["-"], "s">, Alias<strip_all>;
def alias_strip_S: Flag<["-"], "S">, Alias<strip_debug>;
+
+// Ignored options
+def: S<"plugin">;
+def: J<"plugin=">;
+def: S<"plugin-opt">;
+def: J<"plugin-opt=">;
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index dc5df6795d99..c02cc586c795 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -40,6 +40,9 @@ ELF Improvements
* The following flags have been added: ``-z interpose``, ``-z global``
+* lld now uses the ``sigrie`` instruction as a trap instruction for
+ MIPS targets.
+
COFF Improvements
-----------------
@@ -66,6 +69,13 @@ MinGW Improvements
linked in a different order than with GNU ld, inserting a DWARF exception
table terminator too early.)
+* lld now supports COFF embedded directives for linking to nondefault
+ libraries, just like for the normal COFF target.
+
+* Actually generate a codeview build id signature, even if not creating a PDB.
+ Previously, the ``--build-id`` option did not actually generate a build id
+ unless ``--pdb`` was specified.
+
MachO Improvements
------------------
diff --git a/test/COFF/arm-thumb-thunks-pdb.s b/test/COFF/arm-thumb-thunks-pdb.s
new file mode 100644
index 000000000000..9e972a78d37f
--- /dev/null
+++ b/test/COFF/arm-thumb-thunks-pdb.s
@@ -0,0 +1,18 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7-windows %s -o %t.obj
+// RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe -debug -pdb:%t.pdb -verbose 2>&1 | FileCheck %s --check-prefix=VERBOSE
+
+// VERBOSE: Added 1 thunks with margin {{.*}} in {{.*}} passes
+
+ .syntax unified
+ .globl main
+ .globl func1
+ .text
+main:
+ bne func1
+ bx lr
+ .section .text$a, "xr"
+ .space 0x100000
+ .section .text$b, "xr"
+func1:
+ bx lr
diff --git a/test/COFF/arm64-branch-range.test b/test/COFF/arm64-branch-range.test
deleted file mode 100644
index 0b581e9c464d..000000000000
--- a/test/COFF/arm64-branch-range.test
+++ /dev/null
@@ -1,16 +0,0 @@
-// REQUIRES: aarch64
-
-// RUN: echo -e '.globl _start\n _start:\n bl too_far26\n' > %t.main26.s
-// RUN: echo -e '.globl _start\n _start:\n b.ne too_far19\n' > %t.main19.s
-// RUN: echo -e '.globl _start\n _start:\n tbz x0, #0, too_far14\n' > %t.main14.s
-
-// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main26.s -o %t.main26.obj
-// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main19.s -o %t.main19.obj
-// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main14.s -o %t.main14.obj
-// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/far-arm64-abs.s -o %t.far.obj
-
-// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main26.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
-// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main19.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
-// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main14.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
-
-// CHECK: relocation out of range
diff --git a/test/COFF/arm64-thunks.s b/test/COFF/arm64-thunks.s
new file mode 100644
index 000000000000..49004544c438
--- /dev/null
+++ b/test/COFF/arm64-thunks.s
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %s -o %t.obj
+// RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe -verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
+// RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s
+
+// VERBOSE: Added 1 thunks with margin {{.*}} in 1 passes
+
+ .globl main
+ .globl func1
+ .text
+main:
+ tbz w0, #0, func1
+ ret
+ .section .text$a, "xr"
+ .space 0x8000
+ .section .text$b, "xr"
+func1:
+ ret
+
+// DISASM: 0000000140001000 .text:
+// DISASM: 140001000: 40 00 00 36 tbz w0, #0, #8 <.text+0x8>
+// DISASM: 140001004: c0 03 5f d6 ret
+// DISASM: 140001008: 50 00 00 90 adrp x16, #32768
+// DISASM: 14000100c: 10 52 00 91 add x16, x16, #20
+// DISASM: 140001010: 00 02 1f d6 br x16
+
+// DISASM: 140009014: c0 03 5f d6 ret
diff --git a/test/COFF/imports.test b/test/COFF/imports.test
index 64f3900a1c2f..f54bdfd88dfa 100644
--- a/test/COFF/imports.test
+++ b/test/COFF/imports.test
@@ -34,3 +34,16 @@ IMPORT-NEXT: Symbol: ExitProcess (0)
IMPORT-NEXT: Symbol: (50)
IMPORT-NEXT: Symbol: MessageBoxA (1)
IMPORT-NEXT: }
+
+# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /merge:.rdata=.text \
+# RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib /include:ExitProcess
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=MERGE %s
+
+MERGE: Import {
+MERGE-NEXT: Name: std64.dll
+MERGE-NEXT: ImportLookupTableRVA: 0x1090
+MERGE-NEXT: ImportAddressTableRVA: 0x10B0
+MERGE-NEXT: Symbol: ExitProcess (0)
+MERGE-NEXT: Symbol: (50)
+MERGE-NEXT: Symbol: MessageBoxA (1)
+MERGE-NEXT: }
diff --git a/test/ELF/arm-gnu-ifunc.s b/test/ELF/arm-gnu-ifunc.s
index 8a7cb0ae237a..92f87b5d5fae 100644
--- a/test/ELF/arm-gnu-ifunc.s
+++ b/test/ELF/arm-gnu-ifunc.s
@@ -35,6 +35,8 @@ _start:
// CHECK-NEXT: Address: 0x100F4
// CHECK-NEXT: Offset: 0xF4
// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info: 4
// CHECK: Name: .plt
// CHECK-NEXT: Type: SHT_PROGBITS
// CHECK-NEXT: Flags [
@@ -44,7 +46,8 @@ _start:
// CHECK-NEXT: Address: 0x11020
// CHECK-NEXT: Offset: 0x1020
// CHECK-NEXT: Size: 32
-// CHECK: Name: .got
+// CHECK: Index: 4
+// CHECK-NEXT: Name: .got
// CHECK-NEXT: Type: SHT_PROGBITS
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_ALLOC
diff --git a/test/ELF/comdat-linkonce.s b/test/ELF/comdat-linkonce.s
index 8721f58bb20c..8b1d4b362e86 100644
--- a/test/ELF/comdat-linkonce.s
+++ b/test/ELF/comdat-linkonce.s
@@ -4,7 +4,12 @@
// RUN: ld.lld -shared %t.o %t2.o -o %t
// RUN: ld.lld -shared %t2.o %t.o -o %t
-.section .gnu.linkonce.t.zed
+.section .gnu.linkonce.t.__x86.get_pc_thunk.bx
.globl abc
abc:
nop
+
+.section .gnu.linkonce.t.__i686.get_pc_thunk.bx
+.globl def
+def:
+nop
diff --git a/test/ELF/emulation-aarch64.s b/test/ELF/emulation-aarch64.s
index b9a6428fa953..c0edc9a69d36 100644
--- a/test/ELF/emulation-aarch64.s
+++ b/test/ELF/emulation-aarch64.s
@@ -30,5 +30,28 @@
# AARCH64-NEXT: Flags [ (0x0)
# AARCH64-NEXT: ]
+# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %taarch64fbsd
+# RUN: echo 'OUTPUT_FORMAT(elf64-aarch64-freebsd)' > %taarch64fbsd.script
+# RUN: ld.lld %taarch64fbsd.script %taarch64fbsd -o %t2aarch64fbsd
+# RUN: llvm-readobj -file-headers %t2aarch64fbsd | FileCheck --check-prefix=AARCH64-FBSD %s
+# AARCH64-FBSD: ElfHeader {
+# AARCH64-FBSD-NEXT: Ident {
+# AARCH64-FBSD-NEXT: Magic: (7F 45 4C 46)
+# AARCH64-FBSD-NEXT: Class: 64-bit (0x2)
+# AARCH64-FBSD-NEXT: DataEncoding: LittleEndian (0x1)
+# AARCH64-FBSD-NEXT: FileVersion: 1
+# AARCH64-FBSD-NEXT: OS/ABI: FreeBSD (0x9)
+# AARCH64-FBSD-NEXT: ABIVersion: 0
+# AARCH64-FBSD-NEXT: Unused: (00 00 00 00 00 00 00)
+# AARCH64-FBSD-NEXT: }
+# AARCH64-FBSD-NEXT: Type: Executable (0x2)
+# AARCH64-FBSD-NEXT: Machine: EM_AARCH64 (0xB7)
+# AARCH64-FBSD-NEXT: Version: 1
+# AARCH64-FBSD-NEXT: Entry:
+# AARCH64-FBSD-NEXT: ProgramHeaderOffset: 0x40
+# AARCH64-FBSD-NEXT: SectionHeaderOffset:
+# AARCH64-FBSD-NEXT: Flags [ (0x0)
+# AARCH64-FBSD-NEXT: ]
+
.globl _start
_start:
diff --git a/test/ELF/emulation-ppc.s b/test/ELF/emulation-ppc.s
index 12e84782252f..843e77604779 100644
--- a/test/ELF/emulation-ppc.s
+++ b/test/ELF/emulation-ppc.s
@@ -35,6 +35,38 @@
# PPC64-NEXT: StringTableSectionIndex:
# PPC64-NEXT: }
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-freebsd %s -o %tppc64fbsd
+# RUN: echo 'OUTPUT_FORMAT(elf64-powerpc-freebsd)' > %tppc64fbsd.script
+# RUN: ld.lld %tppc64fbsd.script %tppc64fbsd -o %t2ppc64fbsd
+# RUN: llvm-readobj -file-headers %t2ppc64fbsd | FileCheck --check-prefix=PPC64-FBSD %s
+
+# PPC64-FBSD: ElfHeader {
+# PPC64-FBSD-NEXT: Ident {
+# PPC64-FBSD-NEXT: Magic: (7F 45 4C 46)
+# PPC64-FBSD-NEXT: Class: 64-bit (0x2)
+# PPC64-FBSD-NEXT: DataEncoding: BigEndian (0x2)
+# PPC64-FBSD-NEXT: FileVersion: 1
+# PPC64-FBSD-NEXT: OS/ABI: FreeBSD (0x9)
+# PPC64-FBSD-NEXT: ABIVersion: 0
+# PPC64-FBSD-NEXT: Unused: (00 00 00 00 00 00 00)
+# PPC64-FBSD-NEXT: }
+# PPC64-FBSD-NEXT: Type: Executable (0x2)
+# PPC64-FBSD-NEXT: Machine: EM_PPC64 (0x15)
+# PPC64-FBSD-NEXT: Version: 1
+# PPC64-FBSD-NEXT: Entry:
+# PPC64-FBSD-NEXT: ProgramHeaderOffset: 0x40
+# PPC64-FBSD-NEXT: SectionHeaderOffset:
+# PPC64-FBSD-NEXT: Flags [ (0x2)
+# PPC64-FBSD-NEXT: 0x2
+# PPC64-FBSD-NEXT: ]
+# PPC64-FBSD-NEXT: HeaderSize: 64
+# PPC64-FBSD-NEXT: ProgramHeaderEntrySize: 56
+# PPC64-FBSD-NEXT: ProgramHeaderCount:
+# PPC64-FBSD-NEXT: SectionHeaderEntrySize: 64
+# PPC64-FBSD-NEXT: SectionHeaderCount:
+# PPC64-FBSD-NEXT: StringTableSectionIndex:
+# PPC64-FBSD-NEXT: }
+
# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %tppc64le
# RUN: ld.lld -m elf64lppc %tppc64le -o %t2ppc64le
# RUN: llvm-readobj -file-headers %t2ppc64le | FileCheck --check-prefix=PPC64LE %s
diff --git a/test/ELF/emulation-x86.s b/test/ELF/emulation-x86.s
index 65d807c67f2f..02b894356692 100644
--- a/test/ELF/emulation-x86.s
+++ b/test/ELF/emulation-x86.s
@@ -7,6 +7,9 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.sysv
# RUN: ld.lld -m elf_amd64_fbsd %t.sysv -o %t.freebsd
# RUN: llvm-readobj -file-headers %t.freebsd | FileCheck --check-prefix=AMD64 %s
+# RUN: echo 'OUTPUT_FORMAT(elf64-x86-64-freebsd)' > %t4x64.script
+# RUN: ld.lld %t4x64.script %tx64 -o %t4x64
+# RUN: llvm-readobj -file-headers %t4x64 | FileCheck --check-prefix=AMD64 %s
# AMD64: ElfHeader {
# AMD64-NEXT: Ident {
# AMD64-NEXT: Magic: (7F 45 4C 46)
@@ -137,10 +140,13 @@
# X86-NEXT: }
# RUN: llvm-mc -filetype=obj -triple=i686-unknown-freebsd %s -o %tx86fbsd
-# RUN: ld.lld -m elf_i386_fbsd %tx86fbsd -o %t2x86_fbsd
-# RUN: llvm-readobj -file-headers %t2x86_fbsd | FileCheck --check-prefix=X86FBSD %s
+# RUN: ld.lld -m elf_i386_fbsd %tx86fbsd -o %t2x86fbsd
+# RUN: llvm-readobj -file-headers %t2x86fbsd | FileCheck --check-prefix=X86FBSD %s
# RUN: ld.lld %tx86fbsd -o %t3x86fbsd
# RUN: llvm-readobj -file-headers %t3x86fbsd | FileCheck --check-prefix=X86FBSD %s
+# RUN: echo 'OUTPUT_FORMAT(elf32-i386-freebsd)' > %t4x86fbsd.script
+# RUN: ld.lld %t4x86fbsd.script %tx86fbsd -o %t4x86fbsd
+# RUN: llvm-readobj -file-headers %t4x86fbsd | FileCheck --check-prefix=X86FBSD %s
# X86FBSD: ElfHeader {
# X86FBSD-NEXT: Ident {
# X86FBSD-NEXT: Magic: (7F 45 4C 46)
diff --git a/test/ELF/no-discard-this_module.s b/test/ELF/no-discard-this_module.s
new file mode 100644
index 000000000000..3ce56d165fc1
--- /dev/null
+++ b/test/ELF/no-discard-this_module.s
@@ -0,0 +1,41 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -save-temp-labels %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s
+
+.global _start
+_start:
+
+// This section and symbol is used by Linux kernel modules. Ensure it's not
+// accidentally discarded.
+.section .gnu.linkonce.this_module:
+__this_module:
+.byte 0x00
+
+// CHECK: Section {
+// CHECK: Index:
+// CHECK: Name: .gnu.linkonce.this_module
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 00 |.|
+// CHECK-NEXT: )
+// CHECK-NEXT: }
+
+// CHECK: Symbol {
+// CHECK: Name: __this_module
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other:
+// CHECK-NEXT: Section: .gnu.linkonce.this_module:
+// CHECK-NEXT: }
diff --git a/test/ELF/sht-group-empty.test b/test/ELF/sht-group-empty.test
new file mode 100644
index 000000000000..46c77f332e7e
--- /dev/null
+++ b/test/ELF/sht-group-empty.test
@@ -0,0 +1,55 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o %t.o -o %t -r
+# RUN: llvm-readobj -s %t | FileCheck %s
+
+# CHECK: Name: .text.foo
+# CHECK: Name: .rela.text.foo
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ Info: foo
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .text.foo
+ - SectionOrType: .text.bar
+ - SectionOrType: .note
+ - Name: .note
+ Type: SHT_NOTE
+ Flags: [ SHF_GROUP ]
+ - Name: .text.foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ - Name: .text.bar
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ - Name: .rela.text.foo
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK, SHF_GROUP ]
+ Link: .symtab
+ Info: .text.foo
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: foo
+ Type: R_X86_64_64
+ - Name: .rela.text.bar
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK, SHF_GROUP ]
+ Link: .symtab
+ Info: .text.bar
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: bar
+ Type: R_X86_64_64
+Symbols:
+ Global:
+ - Name: foo
+ - Name: bar
+