aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-16 19:47:41 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-16 19:47:41 +0000
commit022ebf5bbf58ca2dd943d3376cc95a6b206db799 (patch)
tree4069ef3b75eed2d68683cb6224a627c24cd95b15
parentfbe69f787ace06f44b6cb1bd3cd45ac703a16a05 (diff)
downloadsrc-022ebf5bbf58ca2dd943d3376cc95a6b206db799.tar.gz
src-022ebf5bbf58ca2dd943d3376cc95a6b206db799.zip
Vendor import of lld trunk r303197:vendor/lld/lld-trunk-r303197
Notes
Notes: svn path=/vendor/lld/dist/; revision=318376 svn path=/vendor/lld/lld-trunk-r303197/; revision=318377; tag=vendor/lld/lld-trunk-r303197
-rw-r--r--COFF/Driver.cpp2
-rw-r--r--COFF/ICF.cpp4
-rw-r--r--COFF/MapFile.cpp4
-rw-r--r--COFF/Writer.cpp16
-rw-r--r--ELF/Config.h1
-rw-r--r--ELF/Driver.cpp8
-rw-r--r--ELF/GdbIndex.h2
-rw-r--r--ELF/ICF.cpp2
-rw-r--r--ELF/InputFiles.cpp6
-rw-r--r--ELF/InputSection.cpp56
-rw-r--r--ELF/LinkerScript.cpp84
-rw-r--r--ELF/LinkerScript.h11
-rw-r--r--ELF/MapFile.cpp2
-rw-r--r--ELF/OutputSections.cpp13
-rw-r--r--ELF/OutputSections.h1
-rw-r--r--ELF/Relocations.cpp80
-rw-r--r--ELF/ScriptParser.cpp24
-rw-r--r--ELF/Strings.cpp4
-rw-r--r--ELF/Symbols.cpp9
-rw-r--r--ELF/Symbols.h2
-rw-r--r--ELF/SyntheticSections.cpp217
-rw-r--r--ELF/SyntheticSections.h51
-rw-r--r--ELF/Target.cpp60
-rw-r--r--ELF/Threads.h21
-rw-r--r--ELF/Thunks.cpp18
-rw-r--r--ELF/Writer.cpp472
-rw-r--r--ELF/Writer.h2
-rw-r--r--docs/CMakeLists.txt2
-rw-r--r--include/lld/Core/Parallel.h166
-rw-r--r--include/lld/Core/TaskGroup.h65
-rw-r--r--lib/Core/CMakeLists.txt1
-rw-r--r--lib/Core/TaskGroup.cpp141
-rw-r--r--lib/ReaderWriter/MachO/LayoutPass.cpp10
-rw-r--r--test/COFF/constant-export.test85
-rw-r--r--test/COFF/constant-export.yaml83
-rw-r--r--test/ELF/Inputs/i386-static-tls-model1.s10
-rw-r--r--test/ELF/Inputs/i386-static-tls-model2.s9
-rw-r--r--test/ELF/Inputs/i386-static-tls-model3.s9
-rw-r--r--test/ELF/Inputs/i386-static-tls-model4.s9
-rw-r--r--test/ELF/gdb-index-empty.s116
-rw-r--r--test/ELF/gdb-index-gc-sections.s157
-rw-r--r--test/ELF/i386-static-tls-model.s20
-rw-r--r--test/ELF/i386-tls-ie-shared.s52
-rw-r--r--test/ELF/incompatible-section-types2.s6
-rw-r--r--test/ELF/linkerscript/early-assign-symbol.s14
-rw-r--r--test/ELF/linkerscript/ehdr_start.s14
-rw-r--r--test/ELF/linkerscript/sections-constraint.s2
-rw-r--r--test/ELF/linkerscript/sections.s5
-rw-r--r--test/ELF/linkerscript/symbol-memoryexpr.s33
-rw-r--r--test/ELF/many-alloc-sections.s106
-rw-r--r--test/ELF/many-sections.s9
-rw-r--r--test/ELF/tls-dynamic-i686.s46
-rw-r--r--test/ELF/tls-opt-iele-i686-nopic.s44
-rw-r--r--test/ELF/x86-64-reloc-tpoff32-fpic.s14
-rw-r--r--unittests/CMakeLists.txt1
-rw-r--r--unittests/CoreTests/CMakeLists.txt7
-rw-r--r--unittests/CoreTests/ParallelTest.cpp46
57 files changed, 1214 insertions, 1240 deletions
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index 5a15b5b11507..4c0ea44b875e 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -18,7 +18,6 @@
#include "lld/Driver/Driver.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/LibDriver/LibDriver.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
@@ -29,6 +28,7 @@
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
#include <algorithm>
#include <memory>
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
index 9a43f2bd43f5..3b7cc424f0a2 100644
--- a/COFF/ICF.cpp
+++ b/COFF/ICF.cpp
@@ -21,9 +21,9 @@
#include "Chunks.h"
#include "Error.h"
#include "Symbols.h"
-#include "lld/Core/Parallel.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Parallel.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <atomic>
@@ -192,7 +192,7 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
// Split sections into 256 shards and call Fn in parallel.
size_t NumShards = 256;
size_t Step = Chunks.size() / NumShards;
- parallel_for(size_t(0), NumShards, [&](size_t I) {
+ for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) {
forEachClassRange(I * Step, (I + 1) * Step, Fn);
});
forEachClassRange(Step * NumShards, Chunks.size(), Fn);
diff --git a/COFF/MapFile.cpp b/COFF/MapFile.cpp
index 4e596e602fee..b63d4672c7d5 100644
--- a/COFF/MapFile.cpp
+++ b/COFF/MapFile.cpp
@@ -25,7 +25,7 @@
#include "Symbols.h"
#include "Writer.h"
-#include "lld/Core/Parallel.h"
+#include "llvm/Support/Parallel.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -76,7 +76,7 @@ static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
static DenseMap<DefinedRegular *, std::string>
getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
std::vector<std::string> Str(Syms.size());
- parallel_for((size_t)0, Syms.size(), [&](size_t I) {
+ for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]);
writeHeader(OS, Syms[I]->getRVA(), 0, 0);
OS << indent(2) << toString(*Syms[I]);
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
index 8762b88c4d6b..5c9c8375dadc 100644
--- a/COFF/Writer.cpp
+++ b/COFF/Writer.cpp
@@ -17,13 +17,13 @@
#include "PDB.h"
#include "SymbolTable.h"
#include "Symbols.h"
-#include "lld/Core/Parallel.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Parallel.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -745,8 +745,8 @@ void Writer::writeSections() {
// ADD instructions).
if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE)
memset(SecBuf, 0xCC, Sec->getRawSize());
- parallel_for_each(Sec->getChunks().begin(), Sec->getChunks().end(),
- [&](Chunk *C) { C->writeTo(SecBuf); });
+ for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(),
+ [&](Chunk *C) { C->writeTo(SecBuf); });
}
}
@@ -760,16 +760,14 @@ void Writer::sortExceptionTable() {
uint8_t *End = Begin + Sec->getVirtualSize();
if (Config->Machine == AMD64) {
struct Entry { ulittle32_t Begin, End, Unwind; };
- parallel_sort(
- (Entry *)Begin, (Entry *)End,
- [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ sort(parallel::par, (Entry *)Begin, (Entry *)End,
+ [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
return;
}
if (Config->Machine == ARMNT) {
struct Entry { ulittle32_t Begin, Unwind; };
- parallel_sort(
- (Entry *)Begin, (Entry *)End,
- [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ sort(parallel::par, (Entry *)Begin, (Entry *)End,
+ [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
return;
}
errs() << "warning: don't know how to handle .pdata.\n";
diff --git a/ELF/Config.h b/ELF/Config.h
index 0321c84e7106..57a0e5a5ec73 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -73,7 +73,6 @@ struct VersionDefinition {
// Most fields are initialized by the driver.
struct Configuration {
InputFile *FirstElf = nullptr;
- bool HasStaticTlsModel = false;
uint8_t OSABI = 0;
llvm::CachePruningPolicy ThinLTOCachePolicy;
llvm::StringMap<uint64_t> SectionStartMap;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index c2cfe3c4129e..737c6a6bf114 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -284,7 +284,7 @@ static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
int V = Default;
if (auto *Arg = Args.getLastArg(Key)) {
StringRef S = Arg->getValue();
- if (S.getAsInteger(10, V))
+ if (!to_integer(S, V, 10))
error(Arg->getSpelling() + ": number expected, but got " + S);
}
return V;
@@ -311,7 +311,7 @@ static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key,
if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) {
Value = Value.substr(Pos + 1);
uint64_t Result;
- if (Value.getAsInteger(0, Result))
+ if (!to_integer(Value, Result))
error("invalid " + Key + ": " + Value);
return Result;
}
@@ -522,7 +522,7 @@ 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))
+ if (!to_integer(S, VA, 16))
error("invalid argument: " + toString(Arg));
return VA;
}
@@ -886,7 +886,7 @@ static uint64_t getImageBase(opt::InputArgList &Args) {
StringRef S = Arg->getValue();
uint64_t V;
- if (S.getAsInteger(0, V)) {
+ if (!to_integer(S, V)) {
error("-image-base: number expected, but got " + S);
return 0;
}
diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h
index a36b92714def..03fec64f9bd5 100644
--- a/ELF/GdbIndex.h
+++ b/ELF/GdbIndex.h
@@ -21,7 +21,7 @@ class InputSection;
// Struct represents single entry of address area of gdb index.
struct AddressEntry {
- InputSectionBase *Section;
+ InputSection *Section;
uint64_t LowAddress;
uint64_t HighAddress;
size_t CuIndex;
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index dcf01ea80011..3722d4e3ed2f 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -325,7 +325,7 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
// Split sections into 256 shards and call Fn in parallel.
size_t NumShards = 256;
size_t Step = Sections.size() / NumShards;
- parallelFor(0, NumShards, [&](size_t I) {
+ parallelForEachN(0, NumShards, [&](size_t I) {
forEachClassRange(I * Step, (I + 1) * Step, Fn);
});
forEachClassRange(Step * NumShards, Sections.size(), Fn);
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 5f94fc9338a4..fe036a644f41 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -383,9 +383,9 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
// 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>(this, &Sec, Name);
- return In<ELFT>::ARMAttributes;
+ if (InX::ARMAttributes == nullptr) {
+ InX::ARMAttributes = make<InputSection>(this, &Sec, Name);
+ return InX::ARMAttributes;
}
return &InputSection::Discarded;
case SHT_RELA:
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index c082f128a9bc..87896ec96b29 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -324,7 +324,7 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
// section, but for --emit-relocs it is an virtual address.
P->r_offset = RelocatedSection->OutSec->Addr +
RelocatedSection->getOffset(Rel.r_offset);
- P->setSymbolAndType(In<ELFT>::SymTab->getSymbolIndex(&Body), Type,
+ P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Body), Type,
Config->IsMips64EL);
if (Body.Type == STT_SECTION) {
@@ -400,40 +400,40 @@ getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
return Body.getVA(A);
case R_GOT:
case R_RELAX_TLS_GD_TO_IE_ABS:
- return Body.getGotVA<ELFT>() + A;
+ return Body.getGotVA() + A;
case R_GOTONLY_PC:
- return In<ELFT>::Got->getVA() + A - P;
+ return InX::Got->getVA() + A - P;
case R_GOTONLY_PC_FROM_END:
- return In<ELFT>::Got->getVA() + A - P + In<ELFT>::Got->getSize();
+ return InX::Got->getVA() + A - P + InX::Got->getSize();
case R_GOTREL:
- return Body.getVA(A) - In<ELFT>::Got->getVA();
+ return Body.getVA(A) - InX::Got->getVA();
case R_GOTREL_FROM_END:
- return Body.getVA(A) - In<ELFT>::Got->getVA() - In<ELFT>::Got->getSize();
+ return Body.getVA(A) - InX::Got->getVA() - InX::Got->getSize();
case R_GOT_FROM_END:
case R_RELAX_TLS_GD_TO_IE_END:
- return Body.getGotOffset() + A - In<ELFT>::Got->getSize();
+ return Body.getGotOffset() + A - InX::Got->getSize();
case R_GOT_OFF:
return Body.getGotOffset() + A;
case R_GOT_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
- return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
+ return getAArch64Page(Body.getGotVA() + A) - getAArch64Page(P);
case R_GOT_PC:
case R_RELAX_TLS_GD_TO_IE:
- return Body.getGotVA<ELFT>() + A - P;
+ return Body.getGotVA() + A - P;
case R_HINT:
case R_NONE:
case R_TLSDESC_CALL:
llvm_unreachable("cannot relocate hint relocs");
case R_MIPS_GOTREL:
- return Body.getVA(A) - In<ELFT>::MipsGot->getGp();
+ return Body.getVA(A) - InX::MipsGot->getGp();
case R_MIPS_GOT_GP:
- return In<ELFT>::MipsGot->getGp() + A;
+ return InX::MipsGot->getGp() + A;
case R_MIPS_GOT_GP_PC: {
// R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
// is _gp_disp symbol. In that case we should use the following
// formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- uint64_t V = In<ELFT>::MipsGot->getGp() + A - P;
+ uint64_t V = InX::MipsGot->getGp() + A - P;
if (Type == R_MIPS_LO16)
V += 4;
return V;
@@ -442,24 +442,21 @@ getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
// 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 In<ELFT>::MipsGot->getVA() +
- In<ELFT>::MipsGot->getPageEntryOffset(Body, A) -
- In<ELFT>::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Body, A) -
+ InX::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 In<ELFT>::MipsGot->getVA() +
- In<ELFT>::MipsGot->getBodyEntryOffset(Body, A) -
- In<ELFT>::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getBodyEntryOffset(Body, A) -
+ InX::MipsGot->getGp();
case R_MIPS_TLSGD:
- return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
- In<ELFT>::MipsGot->getGlobalDynOffset(Body) -
- In<ELFT>::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
+ InX::MipsGot->getGlobalDynOffset(Body) - InX::MipsGot->getGp();
case R_MIPS_TLSLD:
- return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
- In<ELFT>::MipsGot->getTlsIndexOff() - In<ELFT>::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
+ InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp();
case R_PAGE_PC:
case R_PLT_PAGE_PC:
if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
@@ -523,19 +520,18 @@ getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
case R_SIZE:
return Body.getSize<ELFT>() + A;
case R_TLSDESC:
- return In<ELFT>::Got->getGlobalDynAddr(Body) + A;
+ return InX::Got->getGlobalDynAddr(Body) + A;
case R_TLSDESC_PAGE:
- return getAArch64Page(In<ELFT>::Got->getGlobalDynAddr(Body) + A) -
+ return getAArch64Page(InX::Got->getGlobalDynAddr(Body) + A) -
getAArch64Page(P);
case R_TLSGD:
- return In<ELFT>::Got->getGlobalDynOffset(Body) + A -
- In<ELFT>::Got->getSize();
+ return InX::Got->getGlobalDynOffset(Body) + A - InX::Got->getSize();
case R_TLSGD_PC:
- return In<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+ return InX::Got->getGlobalDynAddr(Body) + A - P;
case R_TLSLD:
- return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
+ return InX::Got->getTlsIndexOff() + A - InX::Got->getSize();
case R_TLSLD_PC:
- return In<ELFT>::Got->getTlsIndexVA() + A - P;
+ return InX::Got->getTlsIndexVA() + A - P;
}
llvm_unreachable("Invalid expression");
}
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index d7858e173c7b..161909abf00d 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -48,8 +48,12 @@ using namespace lld::elf;
LinkerScript *elf::Script;
uint64_t ExprValue::getValue() const {
- if (Sec)
- return Sec->getOffset(Val) + Sec->getOutputSection()->Addr;
+ if (Sec) {
+ if (Sec->getOutputSection())
+ return Sec->getOffset(Val) + Sec->getOutputSection()->Addr;
+ error("unable to evaluate expression: input section " + Sec->Name +
+ " has no output section assigned");
+ }
return Val;
}
@@ -411,6 +415,7 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
if (OutputSection *Sec = Cmd->Sec) {
assert(Sec->SectionIndex == INT_MAX);
Sec->SectionIndex = I;
+ SecToCommand[Sec] = Cmd;
}
}
}
@@ -440,6 +445,7 @@ void LinkerScript::fabricateDefaultCommands() {
auto *OSCmd = make<OutputSectionCommand>(Sec->Name);
OSCmd->Sec = Sec;
+ SecToCommand[Sec] = OSCmd;
// Prefer user supplied address over additional alignment constraint
auto I = Config->SectionStartMap.find(Sec->Name);
@@ -484,6 +490,7 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
auto *Cmd = cast<OutputSectionCommand>(*I);
Factory.addInputSec(S, Name, Cmd->Sec);
if (OutputSection *Sec = Cmd->Sec) {
+ SecToCommand[Sec] = Cmd;
unsigned Index = std::distance(Opt.Commands.begin(), I);
assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index);
Sec->SectionIndex = Index;
@@ -699,6 +706,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
OutSec->SectionIndex = I;
OutputSections->push_back(OutSec);
Cmd->Sec = OutSec;
+ SecToCommand[OutSec] = Cmd;
}
}
@@ -822,16 +830,14 @@ void LinkerScript::placeOrphanSections() {
// If there is no command corresponding to this output section,
// create one and put a InputSectionDescription in it so that both
// representations agree on which input sections to use.
- auto Pos = std::find_if(CmdIter, E, [&](BaseCommand *Base) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
- return Cmd && Cmd->Name == Name;
- });
- if (Pos == E) {
- auto *Cmd = make<OutputSectionCommand>(Name);
+ OutputSectionCommand *Cmd = getCmd(Sec);
+ if (!Cmd) {
+ Cmd = make<OutputSectionCommand>(Name);
Opt.Commands.insert(CmdIter, Cmd);
++CmdIndex;
Cmd->Sec = Sec;
+ SecToCommand[Sec] = Cmd;
auto *ISD = make<InputSectionDescription>("");
for (InputSection *IS : Sec->Sections)
ISD->Sections.push_back(IS);
@@ -841,7 +847,11 @@ void LinkerScript::placeOrphanSections() {
}
// Continue from where we found it.
- CmdIndex = (Pos - Opt.Commands.begin()) + 1;
+ while (*CmdIter != Cmd) {
+ ++CmdIter;
+ ++CmdIndex;
+ }
+ ++CmdIndex;
}
}
@@ -1000,7 +1010,7 @@ std::vector<PhdrEntry> LinkerScript::createPhdrs() {
break;
// Assign headers specified by linker script
- for (size_t Id : getPhdrIndices(Sec->Name)) {
+ for (size_t Id : getPhdrIndices(Sec)) {
Ret[Id].add(Sec);
if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
Ret[Id].p_flags |= Sec->getPhdrFlags();
@@ -1020,11 +1030,16 @@ bool LinkerScript::ignoreInterpSection() {
return true;
}
-Optional<uint32_t> LinkerScript::getFiller(StringRef Name) {
- for (BaseCommand *Base : Opt.Commands)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
- if (Cmd->Name == Name)
- return Cmd->Filler;
+OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {
+ auto I = SecToCommand.find(Sec);
+ if (I == SecToCommand.end())
+ return nullptr;
+ return I->second;
+}
+
+Optional<uint32_t> LinkerScript::getFiller(OutputSection *Sec) {
+ if (OutputSectionCommand *Cmd = getCmd(Sec))
+ return Cmd->Filler;
return None;
}
@@ -1042,26 +1057,16 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
}
void LinkerScript::writeDataBytes(OutputSection *Sec, uint8_t *Buf) {
- auto I = std::find_if(Opt.Commands.begin(), Opt.Commands.end(),
- [=](BaseCommand *Base) {
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
- if (Cmd->Sec == Sec)
- return true;
- return false;
- });
- if (I == Opt.Commands.end())
- return;
- auto *Cmd = cast<OutputSectionCommand>(*I);
- for (BaseCommand *Base : Cmd->Commands)
- if (auto *Data = dyn_cast<BytesDataCommand>(Base))
- writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
+ if (OutputSectionCommand *Cmd = getCmd(Sec))
+ for (BaseCommand *Base : Cmd->Commands)
+ if (auto *Data = dyn_cast<BytesDataCommand>(Base))
+ writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
}
-bool LinkerScript::hasLMA(StringRef Name) {
- for (BaseCommand *Base : Opt.Commands)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
- if (Cmd->LMAExpr && Cmd->Name == Name)
- return true;
+bool LinkerScript::hasLMA(OutputSection *Sec) {
+ if (OutputSectionCommand *Cmd = getCmd(Sec))
+ if (Cmd->LMAExpr)
+ return true;
return false;
}
@@ -1080,15 +1085,10 @@ ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; }
-// 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.
-std::vector<size_t> LinkerScript::getPhdrIndices(StringRef SectionName) {
- for (BaseCommand *Base : Opt.Commands) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
- if (!Cmd || Cmd->Name != SectionName)
- continue;
-
+// 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));
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index 7bcd21c87602..d0a4d83d72b0 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -211,8 +211,9 @@ struct ScriptConfiguration {
std::vector<llvm::StringRef> ReferencedSymbols;
};
-class LinkerScript {
-protected:
+class LinkerScript final {
+ llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
+ OutputSectionCommand *getCmd(OutputSection *Sec) const;
void assignSymbol(SymbolAssignment *Cmd, bool InSec);
void setDot(Expr E, const Twine &Loc, bool InSec);
@@ -222,7 +223,7 @@ protected:
std::vector<InputSectionBase *>
createInputSectionList(OutputSectionCommand &Cmd);
- std::vector<size_t> getPhdrIndices(StringRef SectionName);
+ std::vector<size_t> getPhdrIndices(OutputSection *Sec);
size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
@@ -262,8 +263,8 @@ public:
std::vector<PhdrEntry> createPhdrs();
bool ignoreInterpSection();
- llvm::Optional<uint32_t> getFiller(StringRef Name);
- bool hasLMA(StringRef Name);
+ llvm::Optional<uint32_t> getFiller(OutputSection *Sec);
+ bool hasLMA(OutputSection *Sec);
bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd);
void placeOrphanSections();
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
index af5bc3c2c813..23c63e845c9a 100644
--- a/ELF/MapFile.cpp
+++ b/ELF/MapFile.cpp
@@ -84,7 +84,7 @@ template <class ELFT>
DenseMap<DefinedRegular *, std::string>
getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
std::vector<std::string> Str(Syms.size());
- parallelFor(0, Syms.size(), [&](size_t I) {
+ parallelForEachN(0, Syms.size(), [&](size_t I) {
raw_string_ostream OS(Str[I]);
writeHeader<ELFT>(OS, Syms[I]->getVA(), Syms[I]->template getSize<ELFT>(),
0);
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index cb9c57657af3..dcefd03766d7 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -133,7 +133,7 @@ template <class ELFT> void OutputSection::finalize() {
if (isa<SyntheticSection>(First))
return;
- this->Link = In<ELFT>::SymTab->OutSec->SectionIndex;
+ this->Link = InX::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 *S = First->getRelocatedSection();
@@ -273,7 +273,7 @@ uint32_t OutputSection::getFiller() {
// linker script. If nothing is specified and this is an executable section,
// fall back to trap instructions to prevent bad diassembly and detect invalid
// jumps to padding.
- if (Optional<uint32_t> Filler = Script->getFiller(Name))
+ if (Optional<uint32_t> Filler = Script->getFiller(this))
return *Filler;
if (Flags & SHF_EXECINSTR)
return Target->TrapInstr;
@@ -297,7 +297,7 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
if (Filler)
fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
- parallelFor(0, Sections.size(), [=](size_t I) {
+ parallelForEachN(0, Sections.size(), [=](size_t I) {
InputSection *Sec = Sections[I];
Sec->writeTo<ELFT>(Buf);
@@ -429,8 +429,11 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS,
if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type))
Sec->Type = SHT_PROGBITS;
else
- error("Section has different type from others with the same name " +
- toString(IS));
+ error("section type mismatch for " + IS->Name +
+ "\n>>> " + toString(IS) + ": " +
+ getELFSectionTypeName(Config->EMachine, IS->Type) +
+ "\n>>> output section " + Sec->Name + ": " +
+ getELFSectionTypeName(Config->EMachine, Sec->Type));
}
Sec->Flags |= Flags;
} else {
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 6405fb38c6d6..413871b60cf7 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -50,6 +50,7 @@ public:
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
unsigned SectionIndex;
+ unsigned SortRank;
uint32_t getPhdrFlags() const;
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index f5db931e9755..ea7477e03842 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -106,21 +106,21 @@ static unsigned handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
InputSectionBase &C, uint64_t Offset,
int64_t Addend, RelExpr Expr) {
if (Expr == R_MIPS_TLSLD) {
- if (In<ELFT>::MipsGot->addTlsIndex() && Config->Pic)
- In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::MipsGot,
- In<ELFT>::MipsGot->getTlsIndexOff(), false,
+ if (InX::MipsGot->addTlsIndex() && Config->Pic)
+ In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot,
+ InX::MipsGot->getTlsIndexOff(), false,
nullptr, 0});
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
if (Expr == R_MIPS_TLSGD) {
- if (In<ELFT>::MipsGot->addDynTlsEntry(Body) && Body.isPreemptible()) {
- uint64_t Off = In<ELFT>::MipsGot->getGlobalDynOffset(Body);
+ if (InX::MipsGot->addDynTlsEntry(Body) && Body.isPreemptible()) {
+ uint64_t Off = InX::MipsGot->getGlobalDynOffset(Body);
In<ELFT>::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, In<ELFT>::MipsGot, Off, false, &Body, 0});
+ {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Body, 0});
if (Body.isPreemptible())
- In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::MipsGot,
+ In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot,
Off + Config->Wordsize, false, &Body, 0});
}
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
@@ -156,17 +156,17 @@ static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body,
auto AddTlsReloc = [&](uint64_t Off, uint32_t Type, SymbolBody *Dest,
bool Dyn) {
if (Dyn)
- In<ELFT>::RelaDyn->addReloc({Type, In<ELFT>::Got, Off, false, Dest, 0});
+ In<ELFT>::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0});
else
- In<ELFT>::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
+ InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
};
// Local Dynamic is for access to module local TLS variables, while still
// being suitable for being dynamically loaded via dlopen.
// GOT[e0] is the module index, with a special value of 0 for the current
// module. GOT[e1] is unused. There only needs to be one module index entry.
- if (Expr == R_TLSLD_PC && In<ELFT>::Got->addTlsIndex()) {
- AddTlsReloc(In<ELFT>::Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
+ if (Expr == R_TLSLD_PC && InX::Got->addTlsIndex()) {
+ AddTlsReloc(InX::Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
NeedDynId ? nullptr : &Body, NeedDynId);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
@@ -176,8 +176,8 @@ static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body,
// the module index and offset of symbol in TLS block we can fill these in
// using static GOT relocations.
if (Expr == R_TLSGD_PC) {
- if (In<ELFT>::Got->addDynTlsEntry(Body)) {
- uint64_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
+ if (InX::Got->addDynTlsEntry(Body)) {
+ uint64_t Off = InX::Got->getGlobalDynOffset(Body);
AddTlsReloc(Off, Target->TlsModuleIndexRel, &Body, NeedDynId);
AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Body,
NeedDynOff);
@@ -207,10 +207,10 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
bool IsPreemptible = isPreemptible(Body, Type);
if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
Config->Shared) {
- if (In<ELFT>::Got->addDynTlsEntry(Body)) {
- uint64_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
- In<ELFT>::RelaDyn->addReloc({Target->TlsDescRel, In<ELFT>::Got, Off,
- !IsPreemptible, &Body, 0});
+ if (InX::Got->addDynTlsEntry(Body)) {
+ uint64_t Off = InX::Got->getGlobalDynOffset(Body);
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->TlsDescRel, InX::Got, Off, !IsPreemptible, &Body, 0});
}
if (Expr != R_TLSDESC_CALL)
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
@@ -224,10 +224,10 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
{R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
return 2;
}
- if (In<ELFT>::Got->addTlsIndex())
- In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::Got,
- In<ELFT>::Got->getTlsIndexOff(), false,
- nullptr, 0});
+ if (InX::Got->addTlsIndex())
+ In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got,
+ InX::Got->getTlsIndexOff(), false, nullptr,
+ 0});
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
@@ -242,19 +242,19 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD,
R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
- if (In<ELFT>::Got->addDynTlsEntry(Body)) {
- uint64_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
+ if (InX::Got->addDynTlsEntry(Body)) {
+ uint64_t Off = InX::Got->getGlobalDynOffset(Body);
In<ELFT>::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, In<ELFT>::Got, Off, false, &Body, 0});
+ {Target->TlsModuleIndexRel, InX::Got, Off, false, &Body, 0});
// If the symbol is preemptible we need the dynamic linker to write
// the offset too.
uint64_t OffsetOff = Off + Config->Wordsize;
if (IsPreemptible)
- In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::Got,
- OffsetOff, false, &Body, 0});
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Body, 0});
else
- In<ELFT>::Got->Relocations.push_back(
+ InX::Got->Relocations.push_back(
{R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Body});
}
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
@@ -268,8 +268,8 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
Offset, Addend, &Body});
if (!Body.isInGot()) {
- In<ELFT>::Got->addEntry(Body);
- In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, In<ELFT>::Got,
+ InX::Got->addEntry(Body);
+ In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, InX::Got,
Body.getGotOffset(), false, &Body, 0});
}
} else {
@@ -518,7 +518,7 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol *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<ELFT>(SS);
- BssSection *Sec = IsReadOnly ? In<ELFT>::BssRelRo : In<ELFT>::Bss;
+ BssSection *Sec = IsReadOnly ? InX::BssRelRo : InX::Bss;
uint64_t Off = Sec->reserveSpace(SymSize, SS->getAlignment<ELFT>());
// Look through the DSO's dynamic symbol table for aliases and create a
@@ -774,7 +774,7 @@ static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
template <class ELFT>
static void addGotEntry(SymbolBody &Sym, bool Preemptible) {
- In<ELFT>::Got->addEntry(Sym);
+ InX::Got->addEntry(Sym);
uint64_t Off = Sym.getGotOffset();
uint32_t DynType;
@@ -792,10 +792,10 @@ static void addGotEntry(SymbolBody &Sym, bool Preemptible) {
bool Constant = !Preemptible && !(Config->Pic && !isAbsolute(Sym));
if (!Constant)
In<ELFT>::RelaDyn->addReloc(
- {DynType, In<ELFT>::Got, Off, !Preemptible, &Sym, 0});
+ {DynType, InX::Got, Off, !Preemptible, &Sym, 0});
if (Constant || (!Config->IsRela && !Preemptible))
- In<ELFT>::Got->Relocations.push_back({Expr, DynType, Off, 0, &Sym});
+ InX::Got->Relocations.push_back({Expr, DynType, Off, 0, &Sym});
}
// The reason we have to do this early scan is as follows
@@ -856,7 +856,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
// needs it to be created. Here we request for that.
if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
- In<ELFT>::Got->HasGotOffRel = true;
+ InX::Got->HasGotOffRel = true;
// Read an addend.
int64_t Addend = computeAddend<ELFT>(Rel, Sec.Data.data());
@@ -874,11 +874,11 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
// If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
if (needsPlt(Expr) && !Body.isInPlt()) {
if (Body.isGnuIFunc() && !Preemptible)
- addPltEntry(InX::Iplt, In<ELFT>::IgotPlt, In<ELFT>::RelaIplt,
+ addPltEntry(InX::Iplt, InX::IgotPlt, In<ELFT>::RelaIplt,
Target->IRelativeRel, Body, true);
else
- addPltEntry(InX::Plt, In<ELFT>::GotPlt, In<ELFT>::RelaPlt,
- Target->PltRel, Body, !Preemptible);
+ addPltEntry(InX::Plt, InX::GotPlt, In<ELFT>::RelaPlt, Target->PltRel,
+ Body, !Preemptible);
}
// Create a GOT slot if a relocation needs GOT.
@@ -891,9 +891,9 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
// 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
- In<ELFT>::MipsGot->addEntry(Body, Addend, Expr);
+ InX::MipsGot->addEntry(Body, Addend, Expr);
if (Body.isTls() && Body.isPreemptible())
- In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, In<ELFT>::MipsGot,
+ In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot,
Body.getGotOffset(), false, &Body, 0});
} else if (!Body.isInGot()) {
addGotEntry<ELFT>(Body, Preemptible);
@@ -927,7 +927,7 @@ static void scanRelocs(InputSectionBase &Sec, 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)
- In<ELFT>::MipsGot->addEntry(Body, Addend, Expr);
+ InX::MipsGot->addEntry(Body, Addend, Expr);
continue;
}
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index 032ecd50f3e3..f1bc245c9256 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -639,7 +639,7 @@ ScriptParser::readOutputSectionDescription(StringRef OutSec) {
// We are compatible with ld.gold because it's easier to implement.
uint32_t ScriptParser::parseFill(StringRef Tok) {
uint32_t V = 0;
- if (Tok.getAsInteger(0, V))
+ if (!to_integer(Tok, V))
setError("invalid filler expression: " + Tok);
uint32_t Buf;
@@ -778,23 +778,23 @@ static Optional<uint64_t> parseInt(StringRef Tok) {
// Hexadecimal
uint64_t Val;
- if (Tok.startswith_lower("0x") && !Tok.substr(2).getAsInteger(16, Val))
+ if (Tok.startswith_lower("0x") && to_integer(Tok.substr(2), Val, 16))
return Val;
- if (Tok.endswith_lower("H") && !Tok.drop_back().getAsInteger(16, Val))
+ if (Tok.endswith_lower("H") && to_integer(Tok.drop_back(), Val, 16))
return Val;
// Decimal
if (Tok.endswith_lower("K")) {
- if (Tok.drop_back().getAsInteger(10, Val))
+ if (!to_integer(Tok.drop_back(), Val, 10))
return None;
return Val * 1024;
}
if (Tok.endswith_lower("M")) {
- if (Tok.drop_back().getAsInteger(10, Val))
+ if (!to_integer(Tok.drop_back(), Val, 10))
return None;
return Val * 1024 * 1024;
}
- if (Tok.getAsInteger(10, Val))
+ if (!to_integer(Tok, Val, 10))
return None;
return Val;
}
@@ -900,10 +900,22 @@ Expr ScriptParser::readPrimary() {
StringRef Name = readParenLiteral();
return [=] { return Script->isDefined(Name) ? 1 : 0; };
}
+ if (Tok == "LENGTH") {
+ StringRef Name = readParenLiteral();
+ if (Script->Opt.MemoryRegions.count(Name) == 0)
+ setError("memory region not defined: " + Name);
+ return [=] { return Script->Opt.MemoryRegions[Name].Length; };
+ }
if (Tok == "LOADADDR") {
StringRef Name = readParenLiteral();
return [=] { return Script->getOutputSection(Location, Name)->getLMA(); };
}
+ if (Tok == "ORIGIN") {
+ StringRef Name = readParenLiteral();
+ if (Script->Opt.MemoryRegions.count(Name) == 0)
+ setError("memory region not defined: " + Name);
+ return [=] { return Script->Opt.MemoryRegions[Name].Origin; };
+ }
if (Tok == "SEGMENT_START") {
expect("(");
skip();
diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp
index 29760b492ba9..2e88bfba0fc1 100644
--- a/ELF/Strings.cpp
+++ b/ELF/Strings.cpp
@@ -46,7 +46,7 @@ int elf::getPriority(StringRef S) {
if (Pos == StringRef::npos)
return 65536;
int V;
- if (S.substr(Pos + 1).getAsInteger(10, V))
+ if (!to_integer(S.substr(Pos + 1), V, 10))
return 65536;
return V;
}
@@ -68,7 +68,7 @@ std::vector<uint8_t> elf::parseHex(StringRef S) {
StringRef B = S.substr(0, 2);
S = S.substr(2);
uint8_t H;
- if (B.getAsInteger(16, H)) {
+ if (!to_integer(B, H, 16)) {
error("not a hexadecimal value: " + B);
return {};
}
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index 2090b33e8cd6..7ce1f5354b1b 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -163,8 +163,8 @@ uint64_t SymbolBody::getVA(int64_t Addend) const {
return OutVA + Addend;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
- return In<ELFT>::Got->getVA() + getGotOffset();
+uint64_t SymbolBody::getGotVA() const {
+ return InX::Got->getVA() + getGotOffset();
}
uint64_t SymbolBody::getGotOffset() const {
@@ -370,11 +370,6 @@ std::string lld::toString(const SymbolBody &B) {
return B.getName();
}
-template uint32_t SymbolBody::template getGotVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getGotVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getGotVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getGotVA<ELF64BE>() const;
-
template uint32_t SymbolBody::template getSize<ELF32LE>() const;
template uint32_t SymbolBody::template getSize<ELF32BE>() const;
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index 39a0c0f7b4df..030527f63744 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -78,7 +78,7 @@ public:
uint64_t getVA(int64_t Addend = 0) const;
uint64_t getGotOffset() const;
- template <class ELFT> typename ELFT::uint getGotVA() const;
+ uint64_t getGotVA() const;
uint64_t getGotPltOffset() const;
uint64_t getGotPltVA() const;
uint64_t getPltVA() const;
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index 9c585e41e9f0..5a2c2c37efd8 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -186,7 +186,7 @@ template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
Options->size = getSize();
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
+ Reginfo.ri_gp_value = InX::MipsGot->getGp();
memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
}
@@ -244,7 +244,7 @@ MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
+ Reginfo.ri_gp_value = InX::MipsGot->getGp();
memcpy(Buf, &Reginfo, sizeof(Reginfo));
}
@@ -293,13 +293,12 @@ InputSection *elf::createInterpSection() {
return Sec;
}
-template <class ELFT>
SymbolBody *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
uint64_t Size, InputSectionBase *Section) {
auto *S = make<DefinedRegular>(Name, /*IsLocal*/ true, STV_DEFAULT, Type,
Value, Size, Section, nullptr);
- if (In<ELFT>::SymTab)
- In<ELFT>::SymTab->addSymbol(S);
+ if (InX::SymTab)
+ InX::SymTab->addSymbol(S);
return S;
}
@@ -356,7 +355,7 @@ void BuildIdSection::computeHash(
std::vector<uint8_t> Hashes(Chunks.size() * HashSize);
// Compute hash values.
- parallelFor(0, Chunks.size(), [&](size_t I) {
+ parallelForEachN(0, Chunks.size(), [&](size_t I) {
HashFn(Hashes.data() + I * HashSize, Chunks[I]);
});
@@ -618,17 +617,16 @@ template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) {
}
}
-template <class ELFT>
-GotSection<ELFT>::GotSection()
+GotBaseSection::GotBaseSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
Target->GotEntrySize, ".got") {}
-template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
+void GotBaseSection::addEntry(SymbolBody &Sym) {
Sym.GotIndex = NumEntries;
++NumEntries;
}
-template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) {
if (Sym.GlobalDynIndex != -1U)
return false;
Sym.GlobalDynIndex = NumEntries;
@@ -639,7 +637,7 @@ template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
// 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() {
+bool GotBaseSection::addTlsIndex() {
if (TlsIndexOff != uint32_t(-1))
return false;
TlsIndexOff = NumEntries * Config->Wordsize;
@@ -647,21 +645,19 @@ template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
return true;
}
-template <class ELFT>
-uint64_t GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
+uint64_t GotBaseSection::getGlobalDynAddr(const SymbolBody &B) const {
return this->getVA() + B.GlobalDynIndex * Config->Wordsize;
}
-template <class ELFT>
-uint64_t GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
+uint64_t GotBaseSection::getGlobalDynOffset(const SymbolBody &B) const {
return B.GlobalDynIndex * Config->Wordsize;
}
-template <class ELFT> void GotSection<ELFT>::finalizeContents() {
+void GotBaseSection::finalizeContents() {
Size = NumEntries * Config->Wordsize;
}
-template <class ELFT> bool GotSection<ELFT>::empty() const {
+bool GotBaseSection::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;
@@ -1028,24 +1024,15 @@ 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)});
+ add({DT_AUXILIARY, InX::DynStrTab->addString(S)});
if (!Config->Rpath.empty())
add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
- In<ELFT>::DynStrTab->addString(Config->Rpath)});
+ InX::DynStrTab->addString(Config->Rpath)});
for (SharedFile<ELFT> *F : Symtab<ELFT>::X->getSharedFiles())
if (F->isNeeded())
- add({DT_NEEDED, In<ELFT>::DynStrTab->addString(F->SoName)});
+ add({DT_NEEDED, InX::DynStrTab->addString(F->SoName)});
if (!Config->SoName.empty())
- add({DT_SONAME, In<ELFT>::DynStrTab->addString(Config->SoName)});
-
- if (!Config->Shared && !Config->Relocatable)
- add({DT_DEBUG, (uint64_t)0});
-}
-
-// Add remaining entries to complete .dynamic contents.
-template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
- if (this->Size)
- return; // Already finalized.
+ add({DT_SONAME, InX::DynStrTab->addString(Config->SoName)});
// Set DT_FLAGS and DT_FLAGS_1.
uint32_t DtFlags = 0;
@@ -1064,15 +1051,22 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
DtFlags |= DF_ORIGIN;
DtFlags1 |= DF_1_ORIGIN;
}
- if (Config->HasStaticTlsModel)
- DtFlags |= DF_STATIC_TLS;
if (DtFlags)
add({DT_FLAGS, DtFlags});
if (DtFlags1)
add({DT_FLAGS_1, DtFlags1});
- this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
+ if (!Config->Shared && !Config->Relocatable)
+ add({DT_DEBUG, (uint64_t)0});
+}
+
+// Add remaining entries to complete .dynamic contents.
+template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
+ if (this->Size)
+ return; // Already finalized.
+
+ this->Link = InX::DynStrTab->OutSec->SectionIndex;
if (In<ELFT>::RelaDyn->OutSec->Size > 0) {
bool IsRela = Config->IsRela;
add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
@@ -1093,18 +1087,18 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
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});
+ InX::GotPlt});
add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)});
}
- add({DT_SYMTAB, In<ELFT>::DynSymTab});
+ add({DT_SYMTAB, InX::DynSymTab});
add({DT_SYMENT, sizeof(Elf_Sym)});
- add({DT_STRTAB, In<ELFT>::DynStrTab});
- add({DT_STRSZ, In<ELFT>::DynStrTab->getSize()});
+ add({DT_STRTAB, InX::DynStrTab});
+ add({DT_STRSZ, InX::DynStrTab->getSize()});
if (!Config->ZText)
add({DT_TEXTREL, (uint64_t)0});
- if (In<ELFT>::GnuHashTab)
- add({DT_GNU_HASH, In<ELFT>::GnuHashTab});
+ if (InX::GnuHashTab)
+ add({DT_GNU_HASH, InX::GnuHashTab});
if (In<ELFT>::HashTab)
add({DT_HASH, In<ELFT>::HashTab});
@@ -1142,15 +1136,15 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
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_SYMTABNO, InX::DynSymTab->getNumSymbols()});
+ add({DT_MIPS_LOCAL_GOTNO, InX::MipsGot->getLocalEntriesNum()});
+ if (const SymbolBody *B = InX::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});
+ add({DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols()});
+ add({DT_PLTGOT, InX::MipsGot});
+ if (InX::MipsRldMap)
+ add({DT_MIPS_RLD_MAP, InX::MipsRldMap});
}
this->OutSec->Link = this->Link;
@@ -1235,11 +1229,11 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
if (Config->IsRela)
P->r_addend = Rel.getAddend();
P->r_offset = Rel.getOffset();
- if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In<ELFT>::MipsGot)
+ if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::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->r_offset += InX::MipsGot->getTlsOffset();
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
}
@@ -1259,22 +1253,19 @@ template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
}
template <class ELFT> void RelocationSection<ELFT>::finalizeContents() {
- this->Link = In<ELFT>::DynSymTab ? In<ELFT>::DynSymTab->OutSec->SectionIndex
- : In<ELFT>::SymTab->OutSec->SectionIndex;
+ this->Link = InX::DynSymTab ? InX::DynSymTab->OutSec->SectionIndex
+ : InX::SymTab->OutSec->SectionIndex;
// Set required output section properties.
this->OutSec->Link = this->Link;
}
-template <class ELFT>
-SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
+SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
: SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
Config->Wordsize,
StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
- StrTabSec(StrTabSec) {
- this->Entsize = sizeof(Elf_Sym);
-}
+ StrTabSec(StrTabSec) {}
// Orders symbols according to their positions in the GOT,
// in compliance with MIPS ABI rules.
@@ -1296,7 +1287,7 @@ static bool sortMipsSymbols(const SymbolTableEntry &L,
// symbols precede global symbols, so we sort symbol entries in this
// function. (For .dynsym, we don't do that because symbols for
// dynamic linking are inherently all globals.)
-template <class ELFT> void SymbolTableSection<ELFT>::finalizeContents() {
+void SymbolTableBaseSection::finalizeContents() {
this->OutSec->Link = StrTabSec.OutSec->SectionIndex;
// If it is a .dynsym, there should be no local symbols, but we need
@@ -1306,9 +1297,9 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalizeContents() {
// Because the first symbol entry is a null entry, 1 is the first.
this->OutSec->Info = 1;
- if (In<ELFT>::GnuHashTab) {
+ if (InX::GnuHashTab) {
// NB: It also sorts Symbols to meet the GNU hash table requirements.
- In<ELFT>::GnuHashTab->addSymbols(Symbols);
+ InX::GnuHashTab->addSymbols(Symbols);
} else if (Config->EMachine == EM_MIPS) {
std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
}
@@ -1320,7 +1311,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalizeContents() {
}
}
-template <class ELFT> void SymbolTableSection<ELFT>::postThunkContents() {
+void SymbolTableBaseSection::postThunkContents() {
if (this->Type == SHT_DYNSYM)
return;
// move all local symbols before global symbols.
@@ -1333,7 +1324,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::postThunkContents() {
this->OutSec->Info = NumLocals + 1;
}
-template <class ELFT> void SymbolTableSection<ELFT>::addSymbol(SymbolBody *B) {
+void SymbolTableBaseSection::addSymbol(SymbolBody *B) {
// Adding a local symbol to a .dynsym is a bug.
assert(this->Type != SHT_DYNSYM || !B->isLocal());
@@ -1341,8 +1332,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::addSymbol(SymbolBody *B) {
Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)});
}
-template <class ELFT>
-size_t SymbolTableSection<ELFT>::getSymbolIndex(SymbolBody *Body) {
+size_t SymbolTableBaseSection::getSymbolIndex(SymbolBody *Body) {
auto I = llvm::find_if(Symbols, [&](const SymbolTableEntry &E) {
if (E.Symbol == Body)
return true;
@@ -1358,6 +1348,12 @@ size_t SymbolTableSection<ELFT>::getSymbolIndex(SymbolBody *Body) {
return I - Symbols.begin() + 1;
}
+template <class ELFT>
+SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
+ : SymbolTableBaseSection(StrTabSec) {
+ this->Entsize = sizeof(Elf_Sym);
+}
+
// Write the internal symbol table contents to the output symbol table.
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
// The first entry is a null entry as per the ELF spec.
@@ -1450,13 +1446,12 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
// DSOs very quickly. If you are sure that your dynamic linker knows
// about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a
// safe bet is to specify -hash-style=both for backward compatibilty.
-template <class ELFT>
-GnuHashTableSection<ELFT>::GnuHashTableSection()
+GnuHashTableSection::GnuHashTableSection()
: SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") {
}
-template <class ELFT> void GnuHashTableSection<ELFT>::finalizeContents() {
- this->OutSec->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
+void GnuHashTableSection::finalizeContents() {
+ this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex;
// Computes bloom filter size in word size. We want to allocate 8
// bits for each symbol. It must be a power of two.
@@ -1471,11 +1466,10 @@ template <class ELFT> void GnuHashTableSection<ELFT>::finalizeContents() {
Size += Symbols.size() * 4; // Hash values
}
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
+void GnuHashTableSection::writeTo(uint8_t *Buf) {
// Write a header.
write32(Buf, NBuckets, Config->Endianness);
- write32(Buf + 4, In<ELFT>::DynSymTab->getNumSymbols() - Symbols.size(),
+ write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size(),
Config->Endianness);
write32(Buf + 8, MaskWords, Config->Endianness);
write32(Buf + 12, getShift2(), Config->Endianness);
@@ -1494,8 +1488,7 @@ void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
//
// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
// p.9, https://www.akkadia.org/drepper/dsohowto.pdf
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *Buf) {
+void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
const unsigned C = Config->Wordsize * 8;
for (const Entry &Sym : Symbols) {
size_t I = (Sym.Hash / C) & (MaskWords - 1);
@@ -1506,8 +1499,7 @@ void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *Buf) {
}
}
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
+void GnuHashTableSection::writeHashTable(uint8_t *Buf) {
// Group symbols by hash value.
std::vector<std::vector<Entry>> Syms(NBuckets);
for (const Entry &Ent : Symbols)
@@ -1560,8 +1552,7 @@ static size_t getBucketSize(size_t NumSymbols) {
// 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) {
+void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
// We cannot use 'auto' for Mid because GCC 6.1 cannot deduce
// its type correctly.
std::vector<SymbolTableEntry>::iterator Mid =
@@ -1594,15 +1585,15 @@ HashTableSection<ELFT>::HashTableSection()
}
template <class ELFT> void HashTableSection<ELFT>::finalizeContents() {
- this->OutSec->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
+ this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex;
unsigned NumEntries = 2; // nbucket and nchain.
- NumEntries += In<ELFT>::DynSymTab->getNumSymbols(); // The chain entries.
+ NumEntries += InX::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();
+ NumEntries += InX::DynSymTab->getNumSymbols();
this->Size = NumEntries * 4;
}
@@ -1610,7 +1601,7 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
// A 32-bit integer type in the target endianness.
typedef typename ELFT::Word Elf_Word;
- unsigned NumSymbols = In<ELFT>::DynSymTab->getNumSymbols();
+ unsigned NumSymbols = InX::DynSymTab->getNumSymbols();
auto *P = reinterpret_cast<Elf_Word *>(Buf);
*P++ = NumSymbols; // nbucket
@@ -1619,7 +1610,7 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
Elf_Word *Buckets = P;
Elf_Word *Chains = P + NumSymbols;
- for (const SymbolTableEntry &S : In<ELFT>::DynSymTab->getSymbols()) {
+ for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
SymbolBody *Body = S.Symbol;
StringRef Name = Body->getName();
unsigned I = Body->DynsymIndex;
@@ -1706,13 +1697,14 @@ readCuList(DWARFContext &Dwarf, InputSection *Sec) {
return Ret;
}
-static InputSectionBase *findSection(ArrayRef<InputSectionBase *> Arr,
- uint64_t Offset) {
+static InputSection *findSection(ArrayRef<InputSectionBase *> Arr,
+ uint64_t Offset) {
for (InputSectionBase *S : Arr)
- if (S && S != &InputSection::Discarded)
- if (Offset >= S->getOffsetInFile() &&
- Offset < S->getOffsetInFile() + S->getSize())
- return S;
+ if (auto *IS = dyn_cast_or_null<InputSection>(S))
+ if (IS != &InputSection::Discarded && IS->Live &&
+ Offset >= IS->getOffsetInFile() &&
+ Offset < IS->getOffsetInFile() + IS->getSize())
+ return IS;
return nullptr;
}
@@ -1725,10 +1717,10 @@ readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) {
CU->collectAddressRanges(Ranges);
ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
- for (std::pair<uint64_t, uint64_t> &R : Ranges)
- if (InputSectionBase *S = findSection(Sections, R.first))
- Ret.push_back({S, R.first - S->getOffsetInFile(),
- R.second - S->getOffsetInFile(), CurrentCU});
+ for (DWARFAddressRange &R : Ranges)
+ if (InputSection *S = findSection(Sections, R.LowPC))
+ Ret.push_back({S, R.LowPC - S->getOffsetInFile(),
+ R.HighPC - S->getOffsetInFile(), CurrentCU});
++CurrentCU;
}
return Ret;
@@ -1951,11 +1943,11 @@ static StringRef getFileDefName() {
}
template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() {
- FileDefNameOff = In<ELFT>::DynStrTab->addString(getFileDefName());
+ FileDefNameOff = InX::DynStrTab->addString(getFileDefName());
for (VersionDefinition &V : Config->VersionDefinitions)
- V.NameOff = In<ELFT>::DynStrTab->addString(V.Name);
+ V.NameOff = InX::DynStrTab->addString(V.Name);
- this->OutSec->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
+ this->OutSec->Link = InX::DynStrTab->OutSec->SectionIndex;
// sh_info should be set to the number of definitions. This fact is missed in
// documentation, but confirmed by binutils community:
@@ -2008,16 +2000,16 @@ VersionTableSection<ELFT>::VersionTableSection()
template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() {
// 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 = In<ELFT>::DynSymTab->OutSec->SectionIndex;
+ this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex;
}
template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
- return sizeof(Elf_Versym) * (In<ELFT>::DynSymTab->getSymbols().size() + 1);
+ return sizeof(Elf_Versym) * (InX::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()) {
+ for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
OutVersym->vs_index = S.Symbol->symbol()->VersionId;
++OutVersym;
}
@@ -2051,14 +2043,14 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
// to create one by adding it to our needed list and creating a dynstr entry
// for the soname.
if (File->VerdefMap.empty())
- Needed.push_back({File, In<ELFT>::DynStrTab->addString(File->SoName)});
+ Needed.push_back({File, InX::DynStrTab->addString(File->SoName)});
typename SharedFile<ELFT>::NeededVer &NV = File->VerdefMap[Ver];
// 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(File->getStringTable().data() +
- Ver->getAux()->vda_name);
+ NV.StrTab = InX::DynStrTab->addString(File->getStringTable().data() +
+ Ver->getAux()->vda_name);
NV.Index = NextIndex++;
}
SS->symbol()->VersionId = NV.Index;
@@ -2100,7 +2092,7 @@ template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
}
template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
- this->OutSec->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
+ this->OutSec->Link = InX::DynStrTab->OutSec->SectionIndex;
this->OutSec->Info = Needed.size();
}
@@ -2187,7 +2179,7 @@ MipsRldMapSection::MipsRldMapSection()
void MipsRldMapSection::writeTo(uint8_t *Buf) {
// Apply filler from linker script.
- Optional<uint32_t> Fill = Script->getFiller(this->Name);
+ Optional<uint32_t> Fill = Script->getFiller(this->OutSec);
if (!Fill || *Fill == 0)
return;
@@ -2245,10 +2237,14 @@ BssSection *InX::Bss;
BssSection *InX::BssRelRo;
BuildIdSection *InX::BuildId;
InputSection *InX::Common;
+SyntheticSection *InX::Dynamic;
StringTableSection *InX::DynStrTab;
+SymbolTableBaseSection *InX::DynSymTab;
InputSection *InX::Interp;
GdbIndexSection *InX::GdbIndex;
+GotBaseSection *InX::Got;
GotPltSection *InX::GotPlt;
+GnuHashTableSection *InX::GnuHashTab;
IgotPltSection *InX::IgotPlt;
MipsGotSection *InX::MipsGot;
MipsRldMapSection *InX::MipsRldMap;
@@ -2256,6 +2252,7 @@ PltSection *InX::Plt;
PltSection *InX::Iplt;
StringTableSection *InX::ShStrTab;
StringTableSection *InX::StrTab;
+SymbolTableBaseSection *InX::SymTab;
template void PltSection::addEntry<ELF32LE>(SymbolBody &Sym);
template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym);
@@ -2272,19 +2269,6 @@ template MergeInputSection *elf::createCommentSection<ELF32BE>();
template MergeInputSection *elf::createCommentSection<ELF64LE>();
template MergeInputSection *elf::createCommentSection<ELF64BE>();
-template SymbolBody *elf::addSyntheticLocal<ELF32LE>(StringRef, uint8_t,
- uint64_t, uint64_t,
- InputSectionBase *);
-template SymbolBody *elf::addSyntheticLocal<ELF32BE>(StringRef, uint8_t,
- uint64_t, uint64_t,
- InputSectionBase *);
-template SymbolBody *elf::addSyntheticLocal<ELF64LE>(StringRef, uint8_t,
- uint64_t, uint64_t,
- InputSectionBase *);
-template SymbolBody *elf::addSyntheticLocal<ELF64BE>(StringRef, uint8_t,
- uint64_t, uint64_t,
- InputSectionBase *);
-
template class elf::MipsAbiFlagsSection<ELF32LE>;
template class elf::MipsAbiFlagsSection<ELF32BE>;
template class elf::MipsAbiFlagsSection<ELF64LE>;
@@ -2320,11 +2304,6 @@ 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>;
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index 1098c58a3baf..0477c601a7df 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -104,10 +104,9 @@ private:
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
};
-template <class ELFT> class GotSection final : public SyntheticSection {
+class GotBaseSection : public SyntheticSection {
public:
- GotSection();
- void writeTo(uint8_t *Buf) override;
+ GotBaseSection();
size_t getSize() const override { return Size; }
void finalizeContents() override;
bool empty() const override;
@@ -125,12 +124,17 @@ public:
// that relies on its address.
bool HasGotOffRel = false;
-private:
+protected:
size_t NumEntries = 0;
uint32_t TlsIndexOff = -1;
uint64_t Size = 0;
};
+template <class ELFT> class GotSection final : public GotBaseSection {
+public:
+ void writeTo(uint8_t *Buf) override;
+};
+
// .note.gnu.build-id section.
class BuildIdSection : public SyntheticSection {
// First 16 bytes are a header.
@@ -401,31 +405,35 @@ struct SymbolTableEntry {
size_t StrTabOffset;
};
-template <class ELFT> class SymbolTableSection final : public SyntheticSection {
+class SymbolTableBaseSection : public SyntheticSection {
public:
- typedef typename ELFT::Sym Elf_Sym;
-
- SymbolTableSection(StringTableSection &StrTabSec);
-
+ SymbolTableBaseSection(StringTableSection &StrTabSec);
void finalizeContents() override;
void postThunkContents() override;
- void writeTo(uint8_t *Buf) override;
- size_t getSize() const override { return getNumSymbols() * sizeof(Elf_Sym); }
+ size_t getSize() const override { return getNumSymbols() * Entsize; }
void addSymbol(SymbolBody *Body);
unsigned getNumSymbols() const { return Symbols.size() + 1; }
size_t getSymbolIndex(SymbolBody *Body);
ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
-private:
+protected:
// A vector of symbols and their string table offsets.
std::vector<SymbolTableEntry> Symbols;
StringTableSection &StrTabSec;
};
+template <class ELFT>
+class SymbolTableSection final : public SymbolTableBaseSection {
+ typedef typename ELFT::Sym Elf_Sym;
+
+public:
+ SymbolTableSection(StringTableSection &StrTabSec);
+ 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 SyntheticSection {
public:
GnuHashTableSection();
@@ -739,7 +747,7 @@ private:
template <class ELFT> InputSection *createCommonSection();
InputSection *createInterpSection();
template <class ELFT> MergeInputSection *createCommentSection();
-template <class ELFT>
+
SymbolBody *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
uint64_t Size, InputSectionBase *Section);
@@ -750,9 +758,13 @@ struct InX {
static BssSection *BssRelRo;
static BuildIdSection *BuildId;
static InputSection *Common;
+ static SyntheticSection *Dynamic;
static StringTableSection *DynStrTab;
+ static SymbolTableBaseSection *DynSymTab;
+ static GnuHashTableSection *GnuHashTab;
static InputSection *Interp;
static GdbIndexSection *GdbIndex;
+ static GotBaseSection *Got;
static GotPltSection *GotPlt;
static IgotPltSection *IgotPlt;
static MipsGotSection *MipsGot;
@@ -761,36 +773,27 @@ struct InX {
static PltSection *Iplt;
static StringTableSection *ShStrTab;
static StringTableSection *StrTab;
+ static SymbolTableBaseSection *SymTab;
};
template <class ELFT> struct In : public InX {
- static DynamicSection<ELFT> *Dynamic;
- static SymbolTableSection<ELFT> *DynSymTab;
static EhFrameHeader<ELFT> *EhFrameHdr;
- static GnuHashTableSection<ELFT> *GnuHashTab;
- static GotSection<ELFT> *Got;
static EhFrameSection<ELFT> *EhFrame;
static HashTableSection<ELFT> *HashTab;
static RelocationSection<ELFT> *RelaDyn;
static RelocationSection<ELFT> *RelaPlt;
static RelocationSection<ELFT> *RelaIplt;
- static SymbolTableSection<ELFT> *SymTab;
static VersionDefinitionSection<ELFT> *VerDef;
static VersionTableSection<ELFT> *VerSym;
static VersionNeedSection<ELFT> *VerNeed;
};
-template <class ELFT> DynamicSection<ELFT> *In<ELFT>::Dynamic;
-template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::DynSymTab;
template <class ELFT> EhFrameHeader<ELFT> *In<ELFT>::EhFrameHdr;
-template <class ELFT> GnuHashTableSection<ELFT> *In<ELFT>::GnuHashTab;
-template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
template <class ELFT> EhFrameSection<ELFT> *In<ELFT>::EhFrame;
template <class ELFT> HashTableSection<ELFT> *In<ELFT>::HashTab;
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> 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;
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 4643c1a919aa..781d7fe3bc3f 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -351,15 +351,6 @@ X86TargetInfo::X86TargetInfo() {
RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const {
- // There are 4 different TLS variable models with varying degrees of
- // flexibility and performance. LocalExec and InitialExec models are fast but
- // less-flexible models. They cannot be used for dlopen(). If they are in use,
- // we set DF_STATIC_TLS in the ELF header so that the runtime can reject such
- // DSOs.
- if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32 || Type == R_386_TLS_IE ||
- Type == R_386_TLS_GOTIE)
- Config->HasStaticTlsModel = true;
-
switch (Type) {
case R_386_8:
case R_386_16:
@@ -429,7 +420,7 @@ RelExpr X86TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
}
void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
- write32le(Buf, In<ELF32LE>::Dynamic->getVA());
+ write32le(Buf, InX::Dynamic->getVA());
}
void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
@@ -460,8 +451,8 @@ void X86TargetInfo::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, V, sizeof(V));
- uint32_t Ebx = In<ELF32LE>::Got->getVA() + In<ELF32LE>::Got->getSize();
- uint32_t GotPlt = In<ELF32LE>::GotPlt->getVA() - Ebx;
+ uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ uint32_t GotPlt = InX::GotPlt->getVA() - Ebx;
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
return;
@@ -473,7 +464,7 @@ void X86TargetInfo::writePltHeader(uint8_t *Buf) const {
0x90, 0x90, 0x90, 0x90 // nop
};
memcpy(Buf, PltData, sizeof(PltData));
- uint32_t GotPlt = In<ELF32LE>::GotPlt->getVA();
+ uint32_t GotPlt = InX::GotPlt->getVA();
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
}
@@ -490,7 +481,7 @@ void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
if (Config->Pic) {
// jmp *foo@GOT(%ebx)
- uint32_t Ebx = In<ELF32LE>::Got->getVA() + In<ELF32LE>::Got->getSize();
+ uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
Buf[1] = 0xa3;
write32le(Buf + 2, GotPltEntryAddr - Ebx);
} else {
@@ -718,7 +709,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, In<ELFT>::Dynamic->getVA());
+ write64le(Buf, InX::Dynamic->getVA());
}
template <class ELFT>
@@ -736,8 +727,8 @@ void X86_64TargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
0x0f, 0x1f, 0x40, 0x00 // nop
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t GotPlt = In<ELFT>::GotPlt->getVA();
- uint64_t Plt = In<ELFT>::Plt->getVA();
+ uint64_t GotPlt = InX::GotPlt->getVA();
+ uint64_t Plt = InX::Plt->getVA();
write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8
write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16
}
@@ -760,7 +751,8 @@ void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
template <class ELFT>
bool X86_64TargetInfo<ELFT>::isPicRel(uint32_t Type) const {
- return Type != R_X86_64_PC32 && Type != R_X86_64_32;
+ return Type != R_X86_64_PC32 && Type != R_X86_64_32 &&
+ Type != R_X86_64_TPOFF32;
}
template <class ELFT>
@@ -1140,7 +1132,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 = In<ELF64BE>::Got->getVA();
+ uint64_t TocVA = InX::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
@@ -1369,7 +1361,7 @@ bool AArch64TargetInfo::isPicRel(uint32_t Type) const {
}
void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
- write64le(Buf, In<ELF64LE>::Plt->getVA());
+ write64le(Buf, InX::Plt->getVA());
}
// Page(Expr) is the page address of the expression Expr, defined
@@ -1392,8 +1384,8 @@ void AArch64TargetInfo::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t Got = In<ELF64LE>::GotPlt->getVA();
- uint64_t Plt = In<ELF64LE>::Plt->getVA();
+ uint64_t Got = InX::GotPlt->getVA();
+ uint64_t Plt = InX::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);
@@ -1746,7 +1738,7 @@ uint32_t ARMTargetInfo::getDynRel(uint32_t Type) const {
}
void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
- write32le(Buf, In<ELF32LE>::Plt->getVA());
+ write32le(Buf, InX::Plt->getVA());
}
void ARMTargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
@@ -1763,15 +1755,15 @@ 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 = In<ELF32LE>::GotPlt->getVA();
- uint64_t L1 = In<ELF32LE>::Plt->getVA() + 8;
+ uint64_t GotPlt = InX::GotPlt->getVA();
+ uint64_t L1 = InX::Plt->getVA() + 8;
write32le(Buf + 16, GotPlt - L1 - 8);
}
void ARMTargetInfo::addPltHeaderSymbols(InputSectionBase *ISD) const {
auto *IS = cast<InputSection>(ISD);
- addSyntheticLocal<ELF32LE>("$a", STT_NOTYPE, 0, 0, IS);
- addSyntheticLocal<ELF32LE>("$d", STT_NOTYPE, 16, 0, IS);
+ addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS);
+ addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS);
}
void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
@@ -1793,8 +1785,8 @@ void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
void ARMTargetInfo::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const {
auto *IS = cast<InputSection>(ISD);
- addSyntheticLocal<ELF32LE>("$a", STT_NOTYPE, Off, 0, IS);
- addSyntheticLocal<ELF32LE>("$d", STT_NOTYPE, Off + 12, 0, IS);
+ addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS);
+ addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS);
}
bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
@@ -1874,7 +1866,8 @@ 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
+ LLVM_FALLTHROUGH;
case R_ARM_JUMP24:
case R_ARM_PC24:
case R_ARM_PLT32:
@@ -1908,7 +1901,8 @@ 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
+ LLVM_FALLTHROUGH;
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
@@ -2132,7 +2126,7 @@ uint32_t MipsTargetInfo<ELFT>::getDynRel(uint32_t Type) const {
template <class ELFT>
void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
- write32<ELFT::TargetEndianness>(Buf, In<ELFT>::Plt->getVA());
+ write32<ELFT::TargetEndianness>(Buf, InX::Plt->getVA());
}
template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
@@ -2201,7 +2195,7 @@ void MipsTargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
write32<E>(Buf + 24, 0x0320f809); // jalr $25
write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
- uint64_t GotPlt = In<ELFT>::GotPlt->getVA();
+ uint64_t GotPlt = InX::GotPlt->getVA();
writeMipsHi16<E>(Buf, GotPlt);
writeMipsLo16<E>(Buf + 4, GotPlt);
writeMipsLo16<E>(Buf + 8, GotPlt);
diff --git a/ELF/Threads.h b/ELF/Threads.h
index 897432e69f8e..e01afd4d3fc9 100644
--- a/ELF/Threads.h
+++ b/ELF/Threads.h
@@ -61,8 +61,7 @@
#include "Config.h"
-#include "lld/Core/Parallel.h"
-#include <algorithm>
+#include "llvm/Support/Parallel.h"
#include <functional>
namespace lld {
@@ -71,19 +70,17 @@ namespace elf {
template <class IterTy, class FuncTy>
void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn) {
if (Config->Threads)
- parallel_for_each(Begin, End, Fn);
+ for_each(llvm::parallel::par, Begin, End, Fn);
else
- std::for_each(Begin, End, Fn);
+ for_each(llvm::parallel::seq, Begin, End, Fn);
}
-inline void parallelFor(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);
- }
+inline void parallelForEachN(size_t Begin, size_t End,
+ std::function<void(size_t)> Fn) {
+ if (Config->Threads)
+ for_each_n(llvm::parallel::par, Begin, End, Fn);
+ else
+ for_each_n(llvm::parallel::seq, Begin, End, Fn);
}
}
}
diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp
index 307ca5df2288..80ea69663c01 100644
--- a/ELF/Thunks.cpp
+++ b/ELF/Thunks.cpp
@@ -124,10 +124,10 @@ void ARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &IS) const {
template <class ELFT>
void ARMV7ABSLongThunk<ELFT>::addSymbols(ThunkSection &IS) {
- this->ThunkSym = addSyntheticLocal<ELFT>(
+ this->ThunkSym = addSyntheticLocal(
Saver.save("__ARMv7ABSLongThunk_" + this->Destination.getName()),
STT_FUNC, this->Offset, size(), &IS);
- addSyntheticLocal<ELFT>("$a", STT_NOTYPE, this->Offset, 0, &IS);
+ addSyntheticLocal("$a", STT_NOTYPE, this->Offset, 0, &IS);
}
template <class ELFT>
@@ -145,10 +145,10 @@ void ThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &IS) const {
template <class ELFT>
void ThumbV7ABSLongThunk<ELFT>::addSymbols(ThunkSection &IS) {
- this->ThunkSym = addSyntheticLocal<ELFT>(
+ this->ThunkSym = addSyntheticLocal(
Saver.save("__Thumbv7ABSLongThunk_" + this->Destination.getName()),
STT_FUNC, this->Offset, size(), &IS);
- addSyntheticLocal<ELFT>("$t", STT_NOTYPE, this->Offset, 0, &IS);
+ addSyntheticLocal("$t", STT_NOTYPE, this->Offset, 0, &IS);
}
template <class ELFT>
@@ -168,10 +168,10 @@ void ARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &IS) const {
template <class ELFT>
void ARMV7PILongThunk<ELFT>::addSymbols(ThunkSection &IS) {
- this->ThunkSym = addSyntheticLocal<ELFT>(
+ this->ThunkSym = addSyntheticLocal(
Saver.save("__ARMV7PILongThunk_" + this->Destination.getName()), STT_FUNC,
this->Offset, size(), &IS);
- addSyntheticLocal<ELFT>("$a", STT_NOTYPE, this->Offset, 0, &IS);
+ addSyntheticLocal("$a", STT_NOTYPE, this->Offset, 0, &IS);
}
template <class ELFT>
@@ -191,10 +191,10 @@ void ThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &IS) const {
template <class ELFT>
void ThumbV7PILongThunk<ELFT>::addSymbols(ThunkSection &IS) {
- this->ThunkSym = addSyntheticLocal<ELFT>(
+ this->ThunkSym = addSyntheticLocal(
Saver.save("__ThumbV7PILongThunk_" + this->Destination.getName()),
STT_FUNC, this->Offset, size(), &IS);
- addSyntheticLocal<ELFT>("$t", STT_NOTYPE, this->Offset, 0, &IS);
+ addSyntheticLocal("$t", STT_NOTYPE, this->Offset, 0, &IS);
}
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
@@ -212,7 +212,7 @@ void MipsThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection &) const {
}
template <class ELFT> void MipsThunk<ELFT>::addSymbols(ThunkSection &IS) {
- this->ThunkSym = addSyntheticLocal<ELFT>(
+ this->ThunkSym = addSyntheticLocal(
Saver.save("__LA25Thunk_" + this->Destination.getName()), STT_FUNC,
this->Offset, size(), &IS);
}
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 7f00e37ce7b0..4cdfce76202c 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -164,11 +164,10 @@ static void combineMergableSections() {
uint64_t Flags = MS->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED);
uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
- auto I =
- llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
- return Sec->Name == OutsecName && Sec->Flags == Flags &&
- Sec->Alignment == Alignment;
- });
+ auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
+ return Sec->Name == OutsecName && Sec->Flags == Flags &&
+ Sec->Alignment == Alignment;
+ });
if (I == MergeSections.end()) {
MergeSyntheticSection *Syn =
make<MergeSyntheticSection>(OutsecName, MS->Type, Flags, Alignment);
@@ -312,11 +311,11 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); };
- In<ELFT>::DynStrTab = make<StringTableSection>(".dynstr", true);
- In<ELFT>::Dynamic = make<DynamicSection<ELFT>>();
+ InX::DynStrTab = make<StringTableSection>(".dynstr", true);
+ InX::Dynamic = make<DynamicSection<ELFT>>();
In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>(
Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
- In<ELFT>::ShStrTab = make<StringTableSection>(".shstrtab", false);
+ InX::ShStrTab = make<StringTableSection>(".shstrtab", false);
Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
Out::ElfHeader->Size = sizeof(Elf_Ehdr);
@@ -324,41 +323,41 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
Out::ProgramHeaders->updateAlignment(Config->Wordsize);
if (needsInterpSection<ELFT>()) {
- In<ELFT>::Interp = createInterpSection();
- Add(In<ELFT>::Interp);
+ InX::Interp = createInterpSection();
+ Add(InX::Interp);
} else {
- In<ELFT>::Interp = nullptr;
+ InX::Interp = nullptr;
}
if (!Config->Relocatable)
Add(createCommentSection<ELFT>());
if (Config->Strip != StripPolicy::All) {
- In<ELFT>::StrTab = make<StringTableSection>(".strtab", false);
- In<ELFT>::SymTab = make<SymbolTableSection<ELFT>>(*In<ELFT>::StrTab);
+ InX::StrTab = make<StringTableSection>(".strtab", false);
+ InX::SymTab = make<SymbolTableSection<ELFT>>(*InX::StrTab);
}
if (Config->BuildId != BuildIdKind::None) {
- In<ELFT>::BuildId = make<BuildIdSection>();
- Add(In<ELFT>::BuildId);
+ InX::BuildId = make<BuildIdSection>();
+ Add(InX::BuildId);
}
- In<ELFT>::Common = createCommonSection<ELFT>();
- if (In<ELFT>::Common)
+ InX::Common = createCommonSection<ELFT>();
+ if (InX::Common)
Add(InX::Common);
- In<ELFT>::Bss = make<BssSection>(".bss");
- Add(In<ELFT>::Bss);
- In<ELFT>::BssRelRo = make<BssSection>(".bss.rel.ro");
- Add(In<ELFT>::BssRelRo);
+ InX::Bss = make<BssSection>(".bss");
+ Add(InX::Bss);
+ InX::BssRelRo = make<BssSection>(".bss.rel.ro");
+ Add(InX::BssRelRo);
// Add MIPS-specific sections.
bool HasDynSymTab = !Symtab<ELFT>::X->getSharedFiles().empty() ||
Config->Pic || Config->ExportDynamic;
if (Config->EMachine == EM_MIPS) {
if (!Config->Shared && HasDynSymTab) {
- In<ELFT>::MipsRldMap = make<MipsRldMapSection>();
- Add(In<ELFT>::MipsRldMap);
+ InX::MipsRldMap = make<MipsRldMapSection>();
+ Add(InX::MipsRldMap);
}
if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
Add(Sec);
@@ -369,8 +368,8 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
}
if (HasDynSymTab) {
- In<ELFT>::DynSymTab = make<SymbolTableSection<ELFT>>(*In<ELFT>::DynStrTab);
- Add(In<ELFT>::DynSymTab);
+ InX::DynSymTab = make<SymbolTableSection<ELFT>>(*InX::DynStrTab);
+ Add(InX::DynSymTab);
In<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
Add(In<ELFT>::VerSym);
@@ -384,8 +383,8 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
Add(In<ELFT>::VerNeed);
if (Config->GnuHash) {
- In<ELFT>::GnuHashTab = make<GnuHashTableSection<ELFT>>();
- Add(In<ELFT>::GnuHashTab);
+ InX::GnuHashTab = make<GnuHashTableSection>();
+ Add(InX::GnuHashTab);
}
if (Config->SysvHash) {
@@ -393,29 +392,29 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
Add(In<ELFT>::HashTab);
}
- Add(In<ELFT>::Dynamic);
- Add(In<ELFT>::DynStrTab);
+ Add(InX::Dynamic);
+ Add(InX::DynStrTab);
Add(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>();
- Add(In<ELFT>::MipsGot);
+ InX::MipsGot = make<MipsGotSection>();
+ Add(InX::MipsGot);
} else {
- In<ELFT>::Got = make<GotSection<ELFT>>();
- Add(In<ELFT>::Got);
+ InX::Got = make<GotSection<ELFT>>();
+ Add(InX::Got);
}
- In<ELFT>::GotPlt = make<GotPltSection>();
- Add(In<ELFT>::GotPlt);
- In<ELFT>::IgotPlt = make<IgotPltSection>();
- Add(In<ELFT>::IgotPlt);
+ InX::GotPlt = make<GotPltSection>();
+ Add(InX::GotPlt);
+ InX::IgotPlt = make<IgotPltSection>();
+ Add(InX::IgotPlt);
if (Config->GdbIndex) {
- In<ELFT>::GdbIndex = make<GdbIndexSection>();
- Add(In<ELFT>::GdbIndex);
+ InX::GdbIndex = make<GdbIndexSection>();
+ Add(InX::GdbIndex);
}
// We always need to add rel[a].plt to output if it has entries.
@@ -431,10 +430,10 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
false /*Sort*/);
Add(In<ELFT>::RelaIplt);
- In<ELFT>::Plt = make<PltSection>(Target->PltHeaderSize);
- Add(In<ELFT>::Plt);
- In<ELFT>::Iplt = make<PltSection>(0);
- Add(In<ELFT>::Iplt);
+ InX::Plt = make<PltSection>(Target->PltHeaderSize);
+ Add(InX::Plt);
+ InX::Iplt = make<PltSection>(0);
+ Add(InX::Iplt);
if (!Config->Relocatable) {
if (Config->EhFrameHdr) {
@@ -445,11 +444,11 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
Add(In<ELFT>::EhFrame);
}
- if (In<ELFT>::SymTab)
- Add(In<ELFT>::SymTab);
- Add(In<ELFT>::ShStrTab);
- if (In<ELFT>::StrTab)
- Add(In<ELFT>::StrTab);
+ if (InX::SymTab)
+ Add(InX::SymTab);
+ Add(InX::ShStrTab);
+ if (InX::StrTab)
+ Add(InX::StrTab);
}
static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
@@ -504,7 +503,7 @@ 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 (!In<ELFT>::SymTab)
+ if (!InX::SymTab)
return;
for (elf::ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles()) {
for (SymbolBody *B : F->getLocalSymbols()) {
@@ -522,7 +521,7 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
SectionBase *Sec = DR->Section;
if (!shouldKeepInSymtab(Sec, B->getName(), *B))
continue;
- In<ELFT>::SymTab->addSymbol(B);
+ InX::SymTab->addSymbol(B);
}
}
}
@@ -542,43 +541,17 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
auto *Sym =
make<DefinedRegular>("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION,
/*Value=*/0, /*Size=*/0, IS, nullptr);
- In<ELFT>::SymTab->addSymbol(Sym);
+ InX::SymTab->addSymbol(Sym);
}
}
-// PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections that
-// we would like to make sure appear is a specific order to maximize their
-// coverage by a single signed 16-bit offset from the TOC base pointer.
-// Conversely, the special .tocbss section should be first among all SHT_NOBITS
-// sections. This will put it next to the loaded special PPC64 sections (and,
-// thus, within reach of the TOC base pointer).
-static int getPPC64SectionRank(StringRef SectionName) {
- return StringSwitch<int>(SectionName)
- .Case(".tocbss", 0)
- .Case(".branch_lt", 2)
- .Case(".toc", 3)
- .Case(".toc1", 4)
- .Case(".opd", 5)
- .Default(1);
-}
-
-// 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 OutputSection *S) {
- if ((S->Flags & SHF_MIPS_GPREL) == 0)
- return 0;
- if (S->Name == ".got")
- return 1;
- return 2;
-}
-
// Today's loaders have a feature to make segments read-only after
// processing dynamic relocations to enhance security. PT_GNU_RELRO
// is defined for that.
//
// This function returns true if a section needs to be put into a
// PT_GNU_RELRO segment.
-template <class ELFT> bool elf::isRelroSection(const OutputSection *Sec) {
+bool elf::isRelroSection(const OutputSection *Sec) {
if (!Config->ZRelro)
return false;
@@ -613,27 +586,27 @@ template <class ELFT> bool elf::isRelroSection(const OutputSection *Sec) {
// .got contains pointers to external symbols. They are resolved by
// the dynamic linker when a module is loaded into memory, and after
// that they are not expected to change. So, it can be in RELRO.
- if (In<ELFT>::Got && Sec == In<ELFT>::Got->OutSec)
+ if (InX::Got && Sec == InX::Got->OutSec)
return true;
// .got.plt contains pointers to external function symbols. They are
// by default resolved lazily, so we usually cannot put it into RELRO.
// However, if "-z now" is given, the lazy symbol resolution is
// disabled, which enables us to put it into RELRO.
- if (Sec == In<ELFT>::GotPlt->OutSec)
+ if (Sec == InX::GotPlt->OutSec)
return Config->ZNow;
// .dynamic section contains data for the dynamic linker, and
// there's no need to write to it at runtime, so it's better to put
// it into RELRO.
- if (Sec == In<ELFT>::Dynamic->OutSec)
+ if (Sec == InX::Dynamic->OutSec)
return true;
// .bss.rel.ro is used for copy relocations for read-only symbols.
// Since the dynamic linker needs to process copy relocations, the
// section cannot be read-only, but once initialized, they shouldn't
// change.
- if (Sec == In<ELFT>::BssRelRo->OutSec)
+ if (Sec == InX::BssRelRo->OutSec)
return true;
// Sections with some special names are put into RELRO. This is a
@@ -645,105 +618,149 @@ template <class ELFT> bool elf::isRelroSection(const OutputSection *Sec) {
S == ".eh_frame" || S == ".openbsd.randomdata";
}
-template <class ELFT>
-static bool compareSectionsNonScript(const OutputSection *A,
- const OutputSection *B) {
+// We compute a rank for each section. The rank indicates where the
+// section should be placed in the file. Instead of using simple
+// numbers (0,1,2...), we use a series of flags. One for each decision
+// point when placing the section.
+// Using flags has two key properties:
+// * It is easy to check if a give branch was taken.
+// * It is easy two see how similar two ranks are (see getRankProximity).
+enum RankFlags {
+ RF_NOT_ADDR_SET = 1 << 16,
+ RF_NOT_INTERP = 1 << 15,
+ RF_NOT_ALLOC = 1 << 14,
+ RF_WRITE = 1 << 13,
+ RF_EXEC = 1 << 12,
+ RF_NON_TLS_BSS = 1 << 11,
+ RF_NON_TLS_BSS_RO = 1 << 10,
+ RF_NOT_TLS = 1 << 9,
+ RF_BSS = 1 << 8,
+ RF_PPC_NOT_TOCBSS = 1 << 7,
+ RF_PPC_OPD = 1 << 6,
+ RF_PPC_TOCL = 1 << 5,
+ RF_PPC_TOC = 1 << 4,
+ RF_PPC_BRANCH_LT = 1 << 3,
+ RF_MIPS_GPREL = 1 << 2,
+ RF_MIPS_NOT_GOT = 1 << 1
+};
+
+static unsigned getSectionRank(const OutputSection *Sec) {
+ unsigned Rank = 0;
+
+ // We want to put section specified by -T option first, so we
+ // can start assigning VA starting from them later.
+ if (Config->SectionStartMap.count(Sec->Name))
+ return Rank;
+ Rank |= RF_NOT_ADDR_SET;
+
// 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->Name == ".interp";
- bool BIsInterp = B->Name == ".interp";
- if (AIsInterp != BIsInterp)
- return AIsInterp;
+ if (Sec->Name == ".interp")
+ return Rank;
+ Rank |= RF_NOT_INTERP;
// Allocatable sections go first to reduce the total PT_LOAD size and
// so debug info doesn't change addresses in actual code.
- 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.
- 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->Name);
- auto BAddrSetI = Config->SectionStartMap.find(B->Name);
- bool AHasAddrSet = AAddrSetI != Config->SectionStartMap.end();
- bool BHasAddrSet = BAddrSetI != Config->SectionStartMap.end();
- if (AHasAddrSet != BHasAddrSet)
- return AHasAddrSet;
- if (AHasAddrSet)
- return AAddrSetI->second < BAddrSetI->second;
+ if (!(Sec->Flags & SHF_ALLOC))
+ return Rank | RF_NOT_ALLOC;
// 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 = A->Flags & SHF_WRITE;
- bool BIsWritable = B->Flags & SHF_WRITE;
- if (AIsWritable != BIsWritable)
- return BIsWritable;
+ if (Sec->Flags & SHF_WRITE)
+ Rank |= RF_WRITE;
- if (!Config->SingleRoRx) {
+ if (Sec->Flags & SHF_EXECINSTR) {
// 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 ((Rank & RF_WRITE) || !Config->SingleRoRx)
+ Rank |= RF_EXEC;
}
// 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;
+ bool IsTls = Sec->Flags & SHF_TLS;
+ bool IsNoBits = Sec->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;
+ bool IsNonTlsNoBits = IsNoBits && !IsTls;
+ if (IsNonTlsNoBits)
+ Rank |= RF_NON_TLS_BSS;
// 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;
+ bool IsRelRo = isRelroSection(Sec);
+ if (IsNonTlsNoBits && !IsRelRo)
+ Rank |= RF_NON_TLS_BSS_RO;
+ if (!IsNonTlsNoBits && IsRelRo)
+ Rank |= RF_NON_TLS_BSS_RO;
// The TLS initialization block needs to be a single contiguous block in a R/W
// 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;
+ if (!IsTls)
+ Rank |= RF_NOT_TLS;
// Within the TLS initialization block, the non-nobits sections need to appear
// first.
- if (AIsNoBits != BIsNoBits)
- return BIsNoBits;
+ if (IsNoBits)
+ Rank |= RF_BSS;
+
+ // // Some architectures have additional ordering restrictions for sections
+ // // within the same PT_LOAD.
+ if (Config->EMachine == EM_PPC64) {
+ // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections
+ // that we would like to make sure appear is a specific order to maximize
+ // their coverage by a single signed 16-bit offset from the TOC base
+ // pointer. Conversely, the special .tocbss section should be first among
+ // all SHT_NOBITS sections. This will put it next to the loaded special
+ // PPC64 sections (and, thus, within reach of the TOC base pointer).
+ StringRef Name = Sec->Name;
+ if (Name != ".tocbss")
+ Rank |= RF_PPC_NOT_TOCBSS;
+
+ if (Name == ".opd")
+ Rank |= RF_PPC_OPD;
+
+ if (Name == ".toc1")
+ Rank |= RF_PPC_TOCL;
+
+ if (Name == ".toc")
+ Rank |= RF_PPC_TOC;
+
+ if (Name == ".branch_lt")
+ Rank |= RF_PPC_BRANCH_LT;
+ }
+ if (Config->EMachine == EM_MIPS) {
+ // All sections with SHF_MIPS_GPREL flag should be grouped together
+ // because data in these sections is addressable with a gp relative address.
+ if (Sec->Flags & SHF_MIPS_GPREL)
+ Rank |= RF_MIPS_GPREL;
- // Some architectures have additional ordering restrictions for sections
- // within the same PT_LOAD.
- if (Config->EMachine == EM_PPC64)
- return getPPC64SectionRank(A->Name) < getPPC64SectionRank(B->Name);
- if (Config->EMachine == EM_MIPS)
- return getMipsSectionRank(A) < getMipsSectionRank(B);
+ if (Sec->Name != ".got")
+ Rank |= RF_MIPS_NOT_GOT;
+ }
+ return Rank;
+}
+
+static bool compareSectionsNonScript(const OutputSection *A,
+ const OutputSection *B) {
+ if (A->SortRank != B->SortRank)
+ return A->SortRank < B->SortRank;
+ if (!(A->SortRank & RF_NOT_ADDR_SET))
+ return Config->SectionStartMap.lookup(A->Name) <
+ Config->SectionStartMap.lookup(B->Name);
return false;
}
// Output section ordering is determined by this function.
-template <class ELFT>
static bool compareSections(const OutputSection *A, const OutputSection *B) {
// For now, put sections mentioned in a linker script
// first. Sections not on linker script will have a SectionIndex of
@@ -753,7 +770,7 @@ static bool compareSections(const OutputSection *A, const OutputSection *B) {
if (AIndex != BIndex)
return AIndex < BIndex;
- return compareSectionsNonScript<ELFT>(A, B);
+ return compareSectionsNonScript(A, B);
}
// Program header entry
@@ -802,7 +819,7 @@ addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val,
// 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 (In<ELFT>::DynSymTab)
+ if (InX::DynSymTab)
return;
StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start";
addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
@@ -855,16 +872,19 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
// 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 (!In<ELFT>::DynSymTab)
+ if (!InX::DynSymTab)
Symtab<ELFT>::X->addIgnored("__tls_get_addr");
+ // __ehdr_start is the location of ELF file headers. Note that we define
+ // this symbol unconditionally even when using a linker script, which
+ // differs from the behavior implemented by GNU linker which only define
+ // this symbol if ELF headers are in the memory mapped segment.
+ addOptionalRegular<ELFT>("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN);
+
// If linker script do layout we do not need to create any standart symbols.
if (Script->Opt.HasSections)
return;
- // __ehdr_start is the location of ELF file headers.
- addOptionalRegular<ELFT>("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN);
-
auto Add = [](StringRef S) {
return addOptionalRegular<ELFT>(S, Out::ElfHeader, 0, STV_DEFAULT);
};
@@ -960,18 +980,36 @@ template <class ELFT> void Writer<ELFT>::createSections() {
Sec->assignOffsets();
}
-static bool canSharePtLoad(const OutputSection &S1, const OutputSection &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;
+// We want to find how similar two ranks are.
+// The more branches in getSectionRank that match, the more similar they are.
+// Since each branch corresponds to a bit flag, we can just use
+// countLeadingZeros.
+static unsigned getRankProximity(OutputSection *A, OutputSection *B) {
+ return countLeadingZeros(A->SortRank ^ B->SortRank);
+}
- if (!S1IsWrite)
- return true; // RO and RX share a PT_LOAD with linker scripts.
- return (S1.Flags & SHF_EXECINSTR) == (S2.Flags & SHF_EXECINSTR);
+// We want to place orphan sections so that they share as much
+// characteristics with their neighbors as possible. For example, if
+// both are rw, or both are tls.
+template <typename ELFT>
+static std::vector<OutputSection *>::iterator
+findOrphanPos(std::vector<OutputSection *>::iterator B,
+ std::vector<OutputSection *>::iterator E) {
+ OutputSection *Sec = *E;
+
+ // Find the first element that has as close a rank as possible.
+ auto I = std::max_element(B, E, [=](OutputSection *A, OutputSection *B) {
+ return getRankProximity(Sec, A) < getRankProximity(Sec, B);
+ });
+ if (I == E)
+ return E;
+
+ // Consider all existing sections with the same proximity.
+ unsigned Proximity = getRankProximity(Sec, *I);
+ while (I != E && getRankProximity(Sec, *I) == Proximity &&
+ Sec->SortRank >= (*I)->SortRank)
+ ++I;
+ return I;
}
template <class ELFT> void Writer<ELFT>::sortSections() {
@@ -979,12 +1017,18 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
// relative order for SHF_LINK_ORDER sections.
if (Config->Relocatable)
return;
+
+ if (Script->Opt.HasSections)
+ Script->adjustSectionsBeforeSorting();
+
+ for (OutputSection *Sec : OutputSections)
+ Sec->SortRank = getSectionRank(Sec);
+
if (!Script->Opt.HasSections) {
std::stable_sort(OutputSections.begin(), OutputSections.end(),
- compareSectionsNonScript<ELFT>);
+ compareSectionsNonScript);
return;
}
- Script->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
@@ -1004,14 +1048,13 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
// .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.
+ // * First put script sections at the start and sort the script sections.
// * 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>);
+ compareSections);
auto I = OutputSections.begin();
auto E = OutputSections.end();
@@ -1019,31 +1062,16 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
std::find_if(OutputSections.begin(), E,
[](OutputSection *S) { return S->SectionIndex == INT_MAX; });
while (NonScriptI != E) {
- auto BestPos = std::max_element(
- I, NonScriptI, [&](OutputSection *&A, OutputSection *&B) {
- bool ACanSharePtLoad = canSharePtLoad(**NonScriptI, *A);
- bool BCanSharePtLoad = canSharePtLoad(**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;
+ auto Pos = findOrphanPos<ELFT>(I, NonScriptI);
+
+ // As an optimization, find all sections with the same sort rank
+ // and insert them with one rotate.
+ unsigned Rank = (*NonScriptI)->SortRank;
+ auto End = std::find_if(NonScriptI + 1, E, [=](OutputSection *Sec) {
+ return Sec->SortRank != Rank;
+ });
+ std::rotate(Pos, NonScriptI, End);
+ NonScriptI = End;
}
Script->adjustSectionsAfterSorting();
@@ -1103,8 +1131,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// 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 (In<ELFT>::DynSymTab)
- addRegular<ELFT>("_DYNAMIC", In<ELFT>::Dynamic, 0);
+ if (InX::DynSymTab)
+ addRegular<ELFT>("_DYNAMIC", InX::Dynamic, 0);
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
@@ -1119,10 +1147,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// we can correctly decide if a dynamic relocation is needed.
forEachRelSec(scanRelocations<ELFT>);
- if (In<ELFT>::Plt && !In<ELFT>::Plt->empty())
- In<ELFT>::Plt->addSymbols();
- if (In<ELFT>::Iplt && !In<ELFT>::Iplt->empty())
- In<ELFT>::Iplt->addSymbols();
+ if (InX::Plt && !InX::Plt->empty())
+ InX::Plt->addSymbols();
+ if (InX::Iplt && !InX::Iplt->empty())
+ InX::Iplt->addSymbols();
// Now that we have defined all possible global symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
@@ -1131,11 +1159,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (!includeInSymtab(*Body))
continue;
- if (In<ELFT>::SymTab)
- In<ELFT>::SymTab->addSymbol(Body);
+ if (InX::SymTab)
+ InX::SymTab->addSymbol(Body);
- if (In<ELFT>::DynSymTab && S->includeInDynsym()) {
- In<ELFT>::DynSymTab->addSymbol(Body);
+ if (InX::DynSymTab && S->includeInDynsym()) {
+ InX::DynSymTab->addSymbol(Body);
if (auto *SS = dyn_cast<SharedSymbol>(Body))
if (cast<SharedFile<ELFT>>(SS->File)->isNeeded())
In<ELFT>::VerNeed->addSymbol(SS);
@@ -1161,7 +1189,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
unsigned I = 1;
for (OutputSection *Sec : OutputSections) {
Sec->SectionIndex = I++;
- Sec->ShName = In<ELFT>::ShStrTab->addString(Sec->Name);
+ Sec->ShName = InX::ShStrTab->addString(Sec->Name);
}
// Binary and relocatable output does not have PHDRS.
@@ -1175,15 +1203,14 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Dynamic section must be the last one in this list and dynamic
// symbol table section (DynSymTab) must be the first one.
- applySynthetic({In<ELFT>::DynSymTab, In<ELFT>::Bss, In<ELFT>::BssRelRo,
- 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},
+ applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo,
+ InX::GnuHashTab, In<ELFT>::HashTab, InX::SymTab,
+ InX::ShStrTab, InX::StrTab, In<ELFT>::VerDef,
+ InX::DynStrTab, InX::GdbIndex, InX::Got,
+ InX::MipsGot, InX::IgotPlt, InX::GotPlt,
+ In<ELFT>::RelaDyn, In<ELFT>::RelaIplt, In<ELFT>::RelaPlt,
+ InX::Plt, InX::Iplt, In<ELFT>::EhFrameHdr,
+ In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
[](SyntheticSection *SS) { SS->finalizeContents(); });
// Some architectures use small displacements for jump instructions.
@@ -1198,7 +1225,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// when no more Thunks are added
ThunkCreator<ELFT> TC;
if (TC.createThunks(OutputSections))
- applySynthetic({In<ELFT>::MipsGot},
+ applySynthetic({InX::MipsGot},
[](SyntheticSection *SS) { SS->updateAllocSize(); });
}
// Fill other section headers. The dynamic table is finalized
@@ -1214,7 +1241,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
[](OutputSection *S) { S->maybeCompress<ELFT>(); });
// createThunks may have added local symbols to the static symbol table
- applySynthetic({In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab},
+ applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},
[](SyntheticSection *SS) { SS->postThunkContents(); });
}
@@ -1332,7 +1359,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
// different flags or is loaded at a discontiguous address using AT linker
// script command.
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
- if (Script->hasLMA(Sec->Name) || Flags != NewFlags) {
+ if (Script->hasLMA(Sec) || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
Flags = NewFlags;
}
@@ -1349,15 +1376,15 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
Ret.push_back(std::move(TlsHdr));
// Add an entry for .dynamic.
- if (In<ELFT>::DynSymTab)
- AddHdr(PT_DYNAMIC, In<ELFT>::Dynamic->OutSec->getPhdrFlags())
- ->add(In<ELFT>::Dynamic->OutSec);
+ if (InX::DynSymTab)
+ AddHdr(PT_DYNAMIC, InX::Dynamic->OutSec->getPhdrFlags())
+ ->add(InX::Dynamic->OutSec);
// PT_GNU_RELRO includes all sections that should be marked as
// read-only by dynamic linker after proccessing relocations.
PhdrEntry RelRo(PT_GNU_RELRO, PF_R);
for (OutputSection *Sec : OutputSections)
- if (needsPtLoad(Sec) && isRelroSection<ELFT>(Sec))
+ if (needsPtLoad(Sec) && isRelroSection(Sec))
RelRo.add(Sec);
if (RelRo.First)
Ret.push_back(std::move(RelRo));
@@ -1395,7 +1422,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
PhdrEntry *Note = nullptr;
for (OutputSection *Sec : OutputSections) {
if (Sec->Type == SHT_NOTE) {
- if (!Note || Script->hasLMA(Sec->Name))
+ if (!Note || Script->hasLMA(Sec))
Note = AddHdr(PT_NOTE, PF_R);
Note->add(Sec);
} else {
@@ -1547,7 +1574,7 @@ template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() {
if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Entry))
return B->getVA();
uint64_t Addr;
- if (!Config->Entry.getAsInteger(0, Addr))
+ if (to_integer(Config->Entry, Addr))
return Addr;
// Case 4
@@ -1649,7 +1676,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
EHdr->e_shnum = OutputSections.size() + 1;
- EHdr->e_shstrndx = In<ELFT>::ShStrTab->OutSec->SectionIndex;
+ EHdr->e_shstrndx = InX::ShStrTab->OutSec->SectionIndex;
if (Config->EMachine == EM_ARM)
// We don't currently use any features incompatible with EF_ARM_EABI_VER5,
@@ -1743,21 +1770,16 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {
- if (!In<ELFT>::BuildId || !In<ELFT>::BuildId->OutSec)
+ if (!InX::BuildId || !InX::BuildId->OutSec)
return;
// Compute a hash of all sections of the output file.
uint8_t *Start = Buffer->getBufferStart();
uint8_t *End = Start + FileSize;
- In<ELFT>::BuildId->writeBuildId({Start, End});
+ InX::BuildId->writeBuildId({Start, End});
}
template void elf::writeResult<ELF32LE>();
template void elf::writeResult<ELF32BE>();
template void elf::writeResult<ELF64LE>();
template void elf::writeResult<ELF64BE>();
-
-template bool elf::isRelroSection<ELF32LE>(const OutputSection *);
-template bool elf::isRelroSection<ELF32BE>(const OutputSection *);
-template bool elf::isRelroSection<ELF64LE>(const OutputSection *);
-template bool elf::isRelroSection<ELF64BE>(const OutputSection *);
diff --git a/ELF/Writer.h b/ELF/Writer.h
index 8b965f7beddb..17fbda394a20 100644
--- a/ELF/Writer.h
+++ b/ELF/Writer.h
@@ -24,7 +24,7 @@ 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 OutputSection *Sec);
+bool isRelroSection(const OutputSection *Sec);
// This describes a program header entry.
// Each contains type, access flags and range of output sections that will be
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
index d4f3b058efb7..112ce35e8cf4 100644
--- a/docs/CMakeLists.txt
+++ b/docs/CMakeLists.txt
@@ -1,6 +1,6 @@
if (LLVM_ENABLE_SPHINX)
+ include(AddSphinxTarget)
if (SPHINX_FOUND)
- include(AddSphinxTarget)
if (${SPHINX_OUTPUT_HTML})
add_sphinx_target(html lld)
endif()
diff --git a/include/lld/Core/Parallel.h b/include/lld/Core/Parallel.h
deleted file mode 100644
index 58fa87e85c51..000000000000
--- a/include/lld/Core/Parallel.h
+++ /dev/null
@@ -1,166 +0,0 @@
-//===- lld/Core/Parallel.h - Parallel utilities ---------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_CORE_PARALLEL_H
-#define LLD_CORE_PARALLEL_H
-
-#include "lld/Core/LLVM.h"
-#include "lld/Core/TaskGroup.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Config/llvm-config.h"
-
-#include <algorithm>
-
-#if defined(_MSC_VER) && LLVM_ENABLE_THREADS
-#include <concrt.h>
-#include <ppl.h>
-#endif
-
-namespace lld {
-
-#if !LLVM_ENABLE_THREADS
-template <class RandomAccessIterator, class Comparator>
-void parallel_sort(
- RandomAccessIterator Start, RandomAccessIterator End,
- const Comparator &Comp = std::less<
- typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
- std::sort(Start, End, Comp);
-}
-#elif defined(_MSC_VER)
-// Use ppl parallel_sort on Windows.
-template <class RandomAccessIterator, class Comparator>
-void parallel_sort(
- RandomAccessIterator Start, RandomAccessIterator End,
- const Comparator &Comp = std::less<
- typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
- concurrency::parallel_sort(Start, End, Comp);
-}
-#else
-namespace detail {
-const ptrdiff_t MinParallelSize = 1024;
-
-/// \brief Inclusive median.
-template <class RandomAccessIterator, class Comparator>
-RandomAccessIterator medianOf3(RandomAccessIterator Start,
- RandomAccessIterator End,
- const Comparator &Comp) {
- RandomAccessIterator Mid = Start + (std::distance(Start, End) / 2);
- return Comp(*Start, *(End - 1))
- ? (Comp(*Mid, *(End - 1)) ? (Comp(*Start, *Mid) ? Mid : Start)
- : End - 1)
- : (Comp(*Mid, *Start) ? (Comp(*(End - 1), *Mid) ? Mid : End - 1)
- : Start);
-}
-
-template <class RandomAccessIterator, class Comparator>
-void parallel_quick_sort(RandomAccessIterator Start, RandomAccessIterator End,
- const Comparator &Comp, TaskGroup &TG, size_t Depth) {
- // Do a sequential sort for small inputs.
- if (std::distance(Start, End) < detail::MinParallelSize || Depth == 0) {
- std::sort(Start, End, Comp);
- return;
- }
-
- // Partition.
- auto Pivot = medianOf3(Start, End, Comp);
- // Move Pivot to End.
- std::swap(*(End - 1), *Pivot);
- Pivot = std::partition(Start, End - 1, [&Comp, End](decltype(*Start) V) {
- return Comp(V, *(End - 1));
- });
- // Move Pivot to middle of partition.
- std::swap(*Pivot, *(End - 1));
-
- // Recurse.
- TG.spawn([=, &Comp, &TG] {
- parallel_quick_sort(Start, Pivot, Comp, TG, Depth - 1);
- });
- parallel_quick_sort(Pivot + 1, End, Comp, TG, Depth - 1);
-}
-}
-
-template <class RandomAccessIterator, class Comparator>
-void parallel_sort(
- RandomAccessIterator Start, RandomAccessIterator End,
- const Comparator &Comp = std::less<
- typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
- TaskGroup TG;
- detail::parallel_quick_sort(Start, End, Comp, TG,
- llvm::Log2_64(std::distance(Start, End)) + 1);
-}
-#endif
-
-template <class T> void parallel_sort(T *Start, T *End) {
- parallel_sort(Start, End, std::less<T>());
-}
-
-#if !LLVM_ENABLE_THREADS
-template <class IterTy, class FuncTy>
-void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) {
- std::for_each(Begin, End, Fn);
-}
-
-template <class IndexTy, class FuncTy>
-void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) {
- for (IndexTy I = Begin; I != End; ++I)
- Fn(I);
-}
-#elif defined(_MSC_VER)
-// Use ppl parallel_for_each on Windows.
-template <class IterTy, class FuncTy>
-void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) {
- concurrency::parallel_for_each(Begin, End, Fn);
-}
-
-template <class IndexTy, class FuncTy>
-void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) {
- concurrency::parallel_for(Begin, End, Fn);
-}
-#else
-template <class IterTy, class FuncTy>
-void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) {
- // TaskGroup has a relatively high overhead, so we want to reduce
- // the number of spawn() calls. We'll create up to 1024 tasks here.
- // (Note that 1024 is an arbitrary number. This code probably needs
- // improving to take the number of available cores into account.)
- ptrdiff_t TaskSize = std::distance(Begin, End) / 1024;
- if (TaskSize == 0)
- TaskSize = 1;
-
- TaskGroup TG;
- while (TaskSize <= std::distance(Begin, End)) {
- TG.spawn([=, &Fn] { std::for_each(Begin, Begin + TaskSize, Fn); });
- Begin += TaskSize;
- }
- TG.spawn([=, &Fn] { std::for_each(Begin, End, Fn); });
-}
-
-template <class IndexTy, class FuncTy>
-void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) {
- ptrdiff_t TaskSize = (End - Begin) / 1024;
- if (TaskSize == 0)
- TaskSize = 1;
-
- TaskGroup TG;
- IndexTy I = Begin;
- for (; I + TaskSize < End; I += TaskSize) {
- TG.spawn([=, &Fn] {
- for (IndexTy J = I, E = I + TaskSize; J != E; ++J)
- Fn(J);
- });
- }
- TG.spawn([=, &Fn] {
- for (IndexTy J = I; J < End; ++J)
- Fn(J);
- });
-}
-#endif
-} // End namespace lld
-
-#endif // LLD_CORE_PARALLEL_H
diff --git a/include/lld/Core/TaskGroup.h b/include/lld/Core/TaskGroup.h
deleted file mode 100644
index 82e9122f4ae2..000000000000
--- a/include/lld/Core/TaskGroup.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//===- lld/Core/TaskGroup.h - Task Group ----------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_CORE_TASKGROUP_H
-#define LLD_CORE_TASKGROUP_H
-
-#include "lld/Core/LLVM.h"
-
-#include <condition_variable>
-#include <functional>
-#include <mutex>
-
-namespace lld {
-/// \brief Allows one or more threads to wait on a potentially unknown number of
-/// events.
-///
-/// A latch starts at \p count. inc() increments this, and dec() decrements it.
-/// All calls to sync() will block while the count is not 0.
-///
-/// Calling dec() on a Latch with a count of 0 has undefined behaivor.
-class Latch {
- uint32_t _count;
- mutable std::mutex _condMut;
- mutable std::condition_variable _cond;
-
-public:
- explicit Latch(uint32_t count = 0) : _count(count) {}
- ~Latch() { sync(); }
-
- void inc() {
- std::unique_lock<std::mutex> lock(_condMut);
- ++_count;
- }
-
- void dec() {
- std::unique_lock<std::mutex> lock(_condMut);
- if (--_count == 0)
- _cond.notify_all();
- }
-
- void sync() const {
- std::unique_lock<std::mutex> lock(_condMut);
- _cond.wait(lock, [&] { return _count == 0; });
- }
-};
-
-/// \brief Allows launching a number of tasks and waiting for them to finish
-/// either explicitly via sync() or implicitly on destruction.
-class TaskGroup {
- Latch _latch;
-
-public:
- void spawn(std::function<void()> f);
-
- void sync() const { _latch.sync(); }
-};
-}
-
-#endif
diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt
index cdd4e679ffa2..f2bf90509295 100644
--- a/lib/Core/CMakeLists.txt
+++ b/lib/Core/CMakeLists.txt
@@ -12,7 +12,6 @@ add_lld_library(lldCore
Resolver.cpp
SymbolTable.cpp
TargetOptionsCommandFlags.cpp
- TaskGroup.cpp
Writer.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/lib/Core/TaskGroup.cpp b/lib/Core/TaskGroup.cpp
deleted file mode 100644
index d4de48ce3dc4..000000000000
--- a/lib/Core/TaskGroup.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-//===- lld/Core/TaskGroup.cpp - Task Group --------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lld/Core/TaskGroup.h"
-#include "llvm/Config/llvm-config.h"
-
-#include <atomic>
-#include <stack>
-#include <thread>
-
-#if defined(_MSC_VER) && LLVM_ENABLE_THREADS
-#include <concrt.h>
-#include <ppl.h>
-#endif
-
-using namespace lld;
-
-namespace {
-
-/// \brief An abstract class that takes closures and runs them asynchronously.
-class Executor {
-public:
- virtual ~Executor() = default;
- virtual void add(std::function<void()> func) = 0;
-
- static Executor *getDefaultExecutor();
-};
-
-#if !LLVM_ENABLE_THREADS
-class SyncExecutor : public Executor {
-public:
- virtual void add(std::function<void()> F) { F(); }
-};
-
-Executor *Executor::getDefaultExecutor() {
- static SyncExecutor Exec;
- return &Exec;
-}
-
-#elif defined(_MSC_VER)
-/// \brief An Executor that runs tasks via ConcRT.
-class ConcRTExecutor : public Executor {
- struct Taskish {
- Taskish(std::function<void()> Task) : Task(Task) {}
-
- std::function<void()> Task;
-
- static void run(void *P) {
- Taskish *Self = static_cast<Taskish *>(P);
- Self->Task();
- concurrency::Free(Self);
- }
- };
-
-public:
- virtual void add(std::function<void()> F) {
- Concurrency::CurrentScheduler::ScheduleTask(
- Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F));
- }
-};
-
-Executor *Executor::getDefaultExecutor() {
- static ConcRTExecutor exec;
- return &exec;
-}
-
-#else
-/// \brief An implementation of an Executor that runs closures on a thread pool
-/// in filo order.
-class ThreadPoolExecutor : public Executor {
-public:
- explicit ThreadPoolExecutor(
- unsigned ThreadCount = std::thread::hardware_concurrency())
- : Done(ThreadCount) {
- // Spawn all but one of the threads in another thread as spawning threads
- // can take a while.
- std::thread([&, ThreadCount] {
- for (size_t i = 1; i < ThreadCount; ++i) {
- std::thread([=] { work(); }).detach();
- }
- work();
- }).detach();
- }
-
- ~ThreadPoolExecutor() override {
- std::unique_lock<std::mutex> Lock(Mutex);
- Stop = true;
- Lock.unlock();
- Cond.notify_all();
- // Wait for ~Latch.
- }
-
- void add(std::function<void()> F) override {
- std::unique_lock<std::mutex> Lock(Mutex);
- WorkStack.push(F);
- Lock.unlock();
- Cond.notify_one();
- }
-
-private:
- void work() {
- while (true) {
- std::unique_lock<std::mutex> Lock(Mutex);
- Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); });
- if (Stop)
- break;
- auto Task = WorkStack.top();
- WorkStack.pop();
- Lock.unlock();
- Task();
- }
- Done.dec();
- }
-
- std::atomic<bool> Stop{false};
- std::stack<std::function<void()>> WorkStack;
- std::mutex Mutex;
- std::condition_variable Cond;
- Latch Done;
-};
-
-Executor *Executor::getDefaultExecutor() {
- static ThreadPoolExecutor exec;
- return &exec;
-}
-#endif
-}
-
-void TaskGroup::spawn(std::function<void()> f) {
- _latch.inc();
- Executor::getDefaultExecutor()->add([&, f] {
- f();
- _latch.dec();
- });
-}
diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp
index 24dbf79d3e3b..7bca07eb16d6 100644
--- a/lib/ReaderWriter/MachO/LayoutPass.cpp
+++ b/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -9,12 +9,12 @@
#include "LayoutPass.h"
#include "lld/Core/Instrumentation.h"
-#include "lld/Core/Parallel.h"
#include "lld/Core/PassManager.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Parallel.h"
#include <algorithm>
#include <set>
#include <utility>
@@ -461,10 +461,10 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
});
std::vector<LayoutPass::SortKey> vec = decorate(atomRange);
- parallel_sort(vec.begin(), vec.end(),
- [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
- return compareAtoms(l, r, _customSorter);
- });
+ sort(llvm::parallel::par, vec.begin(), vec.end(),
+ [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
+ return compareAtoms(l, r, _customSorter);
+ });
DEBUG(checkTransitivity(vec, _customSorter));
undecorate(atomRange, vec);
diff --git a/test/COFF/constant-export.test b/test/COFF/constant-export.test
index 18b1f5e30d29..80597660ce19 100644
--- a/test/COFF/constant-export.test
+++ b/test/COFF/constant-export.test
@@ -1,5 +1,5 @@
# RUN: mkdir -p %t
-# RUN: yaml2obj -o %t/constant-export.obj %S/constant-export.yaml
+# RUN: yaml2obj -o %t/constant-export.obj %s
# RUN: lld-link /machine:x86 /dll /entry:__CFConstantStringClassReference -out:%t/constant-export.dll %t/constant-export.obj
# RUN: llvm-readobj -coff-exports %t/constant-export.lib | FileCheck %s
@@ -7,3 +7,86 @@
# CHECK: Name type: noprefix
# CHECK: Symbol: __imp____CFConstantStringClassReference
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: ''
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ''
+ - Name: .bss
+ Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ''
+ - Name: .drectve
+ Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 1
+ SectionData: 20202D6578706F72743A5F5F5F4346436F6E7374616E74537472696E67436C6173735265666572656E63652C434F4E5354414E54
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: .data
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 2
+ - Name: .bss
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 0
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 3
+ - Name: .drectve
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 52
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 1983959296
+ Number: 4
+ - Name: '@feat.00'
+ Value: 1
+ SectionNumber: -1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: ___CFConstantStringClassReference
+ Value: 128
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/constant-export.yaml b/test/COFF/constant-export.yaml
deleted file mode 100644
index 7e44bb70c9d7..000000000000
--- a/test/COFF/constant-export.yaml
+++ /dev/null
@@ -1,83 +0,0 @@
---- !COFF
-header:
- Machine: IMAGE_FILE_MACHINE_I386
- Characteristics: [ ]
-sections:
- - Name: .text
- Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
- Alignment: 4
- SectionData: ''
- - Name: .data
- Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
- Alignment: 4
- SectionData: ''
- - Name: .bss
- Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
- Alignment: 4
- SectionData: ''
- - Name: .drectve
- Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
- Alignment: 1
- SectionData: 20202D6578706F72743A5F5F5F4346436F6E7374616E74537472696E67436C6173735265666572656E63652C434F4E5354414E54
-symbols:
- - Name: .text
- Value: 0
- SectionNumber: 1
- SimpleType: IMAGE_SYM_TYPE_NULL
- ComplexType: IMAGE_SYM_DTYPE_NULL
- StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 0
- NumberOfRelocations: 0
- NumberOfLinenumbers: 0
- CheckSum: 0
- Number: 1
- - Name: .data
- Value: 0
- SectionNumber: 2
- SimpleType: IMAGE_SYM_TYPE_NULL
- ComplexType: IMAGE_SYM_DTYPE_NULL
- StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 0
- NumberOfRelocations: 0
- NumberOfLinenumbers: 0
- CheckSum: 0
- Number: 2
- - Name: .bss
- Value: 0
- SectionNumber: 3
- SimpleType: IMAGE_SYM_TYPE_NULL
- ComplexType: IMAGE_SYM_DTYPE_NULL
- StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 0
- NumberOfRelocations: 0
- NumberOfLinenumbers: 0
- CheckSum: 0
- Number: 3
- - Name: .drectve
- Value: 0
- SectionNumber: 4
- SimpleType: IMAGE_SYM_TYPE_NULL
- ComplexType: IMAGE_SYM_DTYPE_NULL
- StorageClass: IMAGE_SYM_CLASS_STATIC
- SectionDefinition:
- Length: 52
- NumberOfRelocations: 0
- NumberOfLinenumbers: 0
- CheckSum: 1983959296
- Number: 4
- - Name: '@feat.00'
- Value: 1
- SectionNumber: -1
- SimpleType: IMAGE_SYM_TYPE_NULL
- ComplexType: IMAGE_SYM_DTYPE_NULL
- StorageClass: IMAGE_SYM_CLASS_STATIC
- - Name: ___CFConstantStringClassReference
- Value: 128
- SectionNumber: 0
- SimpleType: IMAGE_SYM_TYPE_NULL
- ComplexType: IMAGE_SYM_DTYPE_NULL
- StorageClass: IMAGE_SYM_CLASS_EXTERNAL
-...
diff --git a/test/ELF/Inputs/i386-static-tls-model1.s b/test/ELF/Inputs/i386-static-tls-model1.s
deleted file mode 100644
index e7e584c1fcf1..000000000000
--- a/test/ELF/Inputs/i386-static-tls-model1.s
+++ /dev/null
@@ -1,10 +0,0 @@
-.section ".tdata", "awT", @progbits
-.globl var
-var:
-
-.section .foo, "aw"
-.global _start
-_start:
- movl $var@tpoff, %edx # R_386_TLS_LE_32
- movl %gs:0, %ecx
- subl %edx, %eax
diff --git a/test/ELF/Inputs/i386-static-tls-model2.s b/test/ELF/Inputs/i386-static-tls-model2.s
deleted file mode 100644
index b28a1458742d..000000000000
--- a/test/ELF/Inputs/i386-static-tls-model2.s
+++ /dev/null
@@ -1,9 +0,0 @@
-.section ".tdata", "awT", @progbits
-.globl var
-var:
-
-.section .foo, "aw"
-.global _start
-_start:
- movl %gs:0, %eax
- addl var@gotntpoff(%ebx),%eax # R_386_TLS_GOTIE
diff --git a/test/ELF/Inputs/i386-static-tls-model3.s b/test/ELF/Inputs/i386-static-tls-model3.s
deleted file mode 100644
index f92267ecbdd0..000000000000
--- a/test/ELF/Inputs/i386-static-tls-model3.s
+++ /dev/null
@@ -1,9 +0,0 @@
-.section ".tdata", "awT", @progbits
-.globl var
-var:
-
-.section .foo, "aw"
-.global _start
-_start:
- movl %gs:0, %eax
- addl var@indntpoff, %eax #R_386_TLS_IE
diff --git a/test/ELF/Inputs/i386-static-tls-model4.s b/test/ELF/Inputs/i386-static-tls-model4.s
deleted file mode 100644
index ffb20def4fab..000000000000
--- a/test/ELF/Inputs/i386-static-tls-model4.s
+++ /dev/null
@@ -1,9 +0,0 @@
-.section ".tdata", "awT", @progbits
-.globl var
-var:
-
-.section .foo, "aw"
-.global _start
-_start:
- movl %gs:0, %eax
- leal var@ntpoff(%eax), %eax #R_386_TLS_LE
diff --git a/test/ELF/gdb-index-empty.s b/test/ELF/gdb-index-empty.s
new file mode 100644
index 000000000000..933afed33e2f
--- /dev/null
+++ b/test/ELF/gdb-index-empty.s
@@ -0,0 +1,116 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -o %t %s
+# RUN: ld.lld --gdb-index --gc-sections -o %t2 %t
+# RUN: llvm-dwarfdump -debug-dump=gdb_index %t2 | FileCheck %s
+
+# CHECK: Address area offset = 0x28, has 0 entries:
+
+# Generated with: (clang r302976)
+# echo "void _start() { __builtin_unreachable(); }" | \
+# clang -Os -g -S -o gdb-index-empty.s -x c - -Xclang -fdebug-compilation-dir -Xclang .
+
+ .text
+ .file "-"
+ .globl _start
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+ .cfi_startproc
+# BB#0: # %entry
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-_start
+ .cfi_endproc
+
+ .file 1 "<stdin>"
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 5.0.0 " # string offset=0
+.Linfo_string1:
+ .asciz "-" # string offset=21
+.Linfo_string2:
+ .asciz "." # string offset=23
+.Linfo_string3:
+ .asciz "_start" # string offset=25
+ .section .debug_loc,"",@progbits
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 14 # DW_FORM_strp
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 14 # DW_FORM_strp
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long 60 # Length of Unit
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x35 DW_TAG_compile_unit
+ .long .Linfo_string0 # DW_AT_producer
+ .short 12 # DW_AT_language
+ .long .Linfo_string1 # DW_AT_name
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .long .Linfo_string2 # DW_AT_comp_dir
+ .quad .Lfunc_begin0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_subprogram
+ .quad .Lfunc_begin0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 87
+ .long .Linfo_string3 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ # DW_AT_external
+ .byte 0 # End Of Children Mark
+ .section .debug_ranges,"",@progbits
+ .section .debug_macinfo,"",@progbits
+.Lcu_macro_begin0:
+ .byte 0 # End Of Macro List Mark
+ .section .debug_pubnames,"",@progbits
+ .long .LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info
+.LpubNames_begin0:
+ .short 2 # DWARF Version
+ .long .Lcu_begin0 # Offset of Compilation Unit Info
+ .long 64 # Compilation Unit Length
+ .long 42 # DIE offset
+ .asciz "_start" # External Name
+ .long 0 # End Mark
+.LpubNames_end0:
+
+ .ident "clang version 5.0.0 "
+ .section ".note.GNU-stack","",@progbits
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/test/ELF/gdb-index-gc-sections.s b/test/ELF/gdb-index-gc-sections.s
new file mode 100644
index 000000000000..70a14754656c
--- /dev/null
+++ b/test/ELF/gdb-index-gc-sections.s
@@ -0,0 +1,157 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -o %t %s
+# RUN: ld.lld --gdb-index --gc-sections -o %t2 %t
+# RUN: llvm-dwarfdump -debug-dump=gdb_index %t2 | FileCheck %s
+
+# CHECK: Address area offset = 0x28, has 1 entries:
+# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
+
+# Generated with: (clang r302976)
+# echo "void _start() {} void dead() {}" | \
+# clang -Os -g -S -ffunction-sections -o gdb-index-gc-sections.s -x c - -Xclang -fdebug-compilation-dir -Xclang .
+
+ .text
+ .file "-"
+ .section .text._start,"ax",@progbits
+ .globl _start
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+ .file 1 "<stdin>"
+ .loc 1 1 0 # <stdin>:1:0
+ .cfi_startproc
+# BB#0: # %entry
+ .loc 1 1 16 prologue_end # <stdin>:1:16
+ retq
+.Ltmp0:
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-_start
+ .cfi_endproc
+
+ .section .text.dead,"ax",@progbits
+ .globl dead
+ .type dead,@function
+dead: # @dead
+.Lfunc_begin1:
+ .loc 1 1 0 # <stdin>:1:0
+ .cfi_startproc
+# BB#0: # %entry
+ .loc 1 1 31 prologue_end # <stdin>:1:31
+ retq
+.Ltmp1:
+.Lfunc_end1:
+ .size dead, .Lfunc_end1-dead
+ .cfi_endproc
+
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 5.0.0 " # string offset=0
+.Linfo_string1:
+ .asciz "-" # string offset=21
+.Linfo_string2:
+ .asciz "." # string offset=23
+.Linfo_string3:
+ .asciz "_start" # string offset=25
+.Linfo_string4:
+ .asciz "dead" # string offset=32
+ .section .debug_loc,"",@progbits
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 14 # DW_FORM_strp
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 14 # DW_FORM_strp
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 85 # DW_AT_ranges
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long 81 # Length of Unit
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x4a DW_TAG_compile_unit
+ .long .Linfo_string0 # DW_AT_producer
+ .short 12 # DW_AT_language
+ .long .Linfo_string1 # DW_AT_name
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .long .Linfo_string2 # DW_AT_comp_dir
+ .quad 0 # DW_AT_low_pc
+ .long .Ldebug_ranges0 # DW_AT_ranges
+ .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_subprogram
+ .quad .Lfunc_begin0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 87
+ .long .Linfo_string3 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ # DW_AT_external
+ .byte 2 # Abbrev [2] 0x3f:0x15 DW_TAG_subprogram
+ .quad .Lfunc_begin1 # DW_AT_low_pc
+ .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 87
+ .long .Linfo_string4 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ # DW_AT_external
+ .byte 0 # End Of Children Mark
+ .section .debug_ranges,"",@progbits
+.Ldebug_ranges0:
+ .quad .Lfunc_begin0
+ .quad .Lfunc_end0
+ .quad .Lfunc_begin1
+ .quad .Lfunc_end1
+ .quad 0
+ .quad 0
+ .section .debug_macinfo,"",@progbits
+.Lcu_macro_begin0:
+ .byte 0 # End Of Macro List Mark
+ .section .debug_pubnames,"",@progbits
+ .long .LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info
+.LpubNames_begin0:
+ .short 2 # DWARF Version
+ .long .Lcu_begin0 # Offset of Compilation Unit Info
+ .long 85 # Compilation Unit Length
+ .long 42 # DIE offset
+ .asciz "_start" # External Name
+ .long 63 # DIE offset
+ .asciz "dead" # External Name
+ .long 0 # End Mark
+.LpubNames_end0:
+
+ .ident "clang version 5.0.0 "
+ .section ".note.GNU-stack","",@progbits
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/test/ELF/i386-static-tls-model.s b/test/ELF/i386-static-tls-model.s
deleted file mode 100644
index b2799c4c722f..000000000000
--- a/test/ELF/i386-static-tls-model.s
+++ /dev/null
@@ -1,20 +0,0 @@
-# REQUIRES: x86
-
-# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/i386-static-tls-model1.s -o %t.o
-# RUN: ld.lld %t.o -o %t1 -shared
-# RUN: llvm-readobj -dynamic-table %t1 | FileCheck %s
-
-# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/i386-static-tls-model2.s -o %t.o
-# RUN: ld.lld %t.o -o %t2 -shared
-# RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s
-
-# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/i386-static-tls-model3.s -o %t.o
-# RUN: ld.lld %t.o -o %t3 -shared
-# RUN: llvm-readobj -dynamic-table %t3 | FileCheck %s
-
-# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/i386-static-tls-model4.s -o %t.o
-# RUN: ld.lld %t.o -o %t4 -shared
-# RUN: llvm-readobj -dynamic-table %t4 | FileCheck %s
-
-# CHECK: DynamicSection [
-# CHECK: FLAGS STATIC_TLS
diff --git a/test/ELF/i386-tls-ie-shared.s b/test/ELF/i386-tls-ie-shared.s
index c6dccf84a216..8becc3199f95 100644
--- a/test/ELF/i386-tls-ie-shared.s
+++ b/test/ELF/i386-tls-ie-shared.s
@@ -13,8 +13,8 @@
// GOTRELSHARED-NEXT: SHF_ALLOC
// GOTRELSHARED-NEXT: SHF_WRITE
// GOTRELSHARED-NEXT: ]
-// GOTRELSHARED-NEXT: Address: 0x1060
-// GOTRELSHARED-NEXT: Offset: 0x1060
+// GOTRELSHARED-NEXT: Address: 0x1058
+// GOTRELSHARED-NEXT: Offset: 0x1058
// GOTRELSHARED-NEXT: Size: 16
// GOTRELSHARED-NEXT: Link: 0
// GOTRELSHARED-NEXT: Info: 0
@@ -31,36 +31,36 @@
// GOTRELSHARED-NEXT: 0x202D R_386_RELATIVE - 0x0
// GOTRELSHARED-NEXT: 0x2036 R_386_RELATIVE - 0x0
// GOTRELSHARED-NEXT: 0x203F R_386_RELATIVE - 0x0
-// GOTRELSHARED-NEXT: 0x1060 R_386_TLS_TPOFF tlslocal0 0x0
-// GOTRELSHARED-NEXT: 0x1064 R_386_TLS_TPOFF tlslocal1 0x0
-// GOTRELSHARED-NEXT: 0x1068 R_386_TLS_TPOFF tlsshared0 0x0
-// GOTRELSHARED-NEXT: 0x106C R_386_TLS_TPOFF tlsshared1 0x0
+// GOTRELSHARED-NEXT: 0x1058 R_386_TLS_TPOFF tlslocal0 0x0
+// GOTRELSHARED-NEXT: 0x105C R_386_TLS_TPOFF tlslocal1 0x0
+// GOTRELSHARED-NEXT: 0x1060 R_386_TLS_TPOFF tlsshared0 0x0
+// GOTRELSHARED-NEXT: 0x1064 R_386_TLS_TPOFF tlsshared1 0x0
// GOTRELSHARED-NEXT: }
// GOTRELSHARED-NEXT: ]
// GOTRELSHARED: 0x6FFFFFFA RELCOUNT 8
// DISASMSHARED: Disassembly of section test:
// DISASMSHARED-NEXT: _start:
-// (.got)[0] = 0x1060 = 4192
-// (.got)[1] = 0x1064 = 4196
-// (.got)[2] = 0x1068 = 4200
-// (.got)[3] = 0x106C = 4204
-// DISASMSHARED-NEXT: 2000: {{.*}} movl 4192, %ecx
-// DISASMSHARED-NEXT: 2006: {{.*}} movl %gs:(%ecx), %eax
-// DISASMSHARED-NEXT: 2009: {{.*}} movl 4192, %eax
-// DISASMSHARED-NEXT: 200e: {{.*}} movl %gs:(%eax), %eax
-// DISASMSHARED-NEXT: 2011: {{.*}} addl 4192, %ecx
-// DISASMSHARED-NEXT: 2017: {{.*}} movl %gs:(%ecx), %eax
-// DISASMSHARED-NEXT: 201a: {{.*}} movl 4196, %ecx
-// DISASMSHARED-NEXT: 2020: {{.*}} movl %gs:(%ecx), %eax
-// DISASMSHARED-NEXT: 2023: {{.*}} movl 4196, %eax
-// DISASMSHARED-NEXT: 2028: {{.*}} movl %gs:(%eax), %eax
-// DISASMSHARED-NEXT: 202b: {{.*}} addl 4196, %ecx
-// DISASMSHARED-NEXT: 2031: {{.*}} movl %gs:(%ecx), %eax
-// DISASMSHARED-NEXT: 2034: {{.*}} movl 4200, %ecx
-// DISASMSHARED-NEXT: 203a: {{.*}} movl %gs:(%ecx), %eax
-// DISASMSHARED-NEXT: 203d: {{.*}} addl 4204, %ecx
-// DISASMSHARED-NEXT: 2043: {{.*}} movl %gs:(%ecx), %eax
+// (.got)[0] = 0x2050 = 8272
+// (.got)[1] = 0x2054 = 8276
+// (.got)[2] = 0x2058 = 8280
+// (.got)[3] = 0x205C = 8284
+// DISASMSHARED-NEXT: 2000: 8b 0d 58 10 00 00 movl 4184, %ecx
+// DISASMSHARED-NEXT: 2006: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASMSHARED-NEXT: 2009: a1 58 10 00 00 movl 4184, %eax
+// DISASMSHARED-NEXT: 200e: 65 8b 00 movl %gs:(%eax), %eax
+// DISASMSHARED-NEXT: 2011: 03 0d 58 10 00 00 addl 4184, %ecx
+// DISASMSHARED-NEXT: 2017: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASMSHARED-NEXT: 201a: 8b 0d 5c 10 00 00 movl 4188, %ecx
+// DISASMSHARED-NEXT: 2020: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASMSHARED-NEXT: 2023: a1 5c 10 00 00 movl 4188, %eax
+// DISASMSHARED-NEXT: 2028: 65 8b 00 movl %gs:(%eax), %eax
+// DISASMSHARED-NEXT: 202b: 03 0d 5c 10 00 00 addl 4188, %ecx
+// DISASMSHARED-NEXT: 2031: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASMSHARED-NEXT: 2034: 8b 0d 60 10 00 00 movl 4192, %ecx
+// DISASMSHARED-NEXT: 203a: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASMSHARED-NEXT: 203d: 03 0d 64 10 00 00 addl 4196, %ecx
+// DISASMSHARED-NEXT: 2043: 65 8b 01 movl %gs:(%ecx), %eax
.type tlslocal0,@object
.section .tbss,"awT",@nobits
diff --git a/test/ELF/incompatible-section-types2.s b/test/ELF/incompatible-section-types2.s
index 2cf9b8548aa1..146e680ab271 100644
--- a/test/ELF/incompatible-section-types2.s
+++ b/test/ELF/incompatible-section-types2.s
@@ -1,7 +1,9 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
-// CHECK: error: Section has different type from others with the same name <internal>:(.shstrtab)
+// CHECK: error: section type mismatch for .shstrtab
+// CHECK-NEXT: >>> <internal>:(.shstrtab): SHT_STRTAB
+// CHECK-NEXT: >>> output section .shstrtab: Unknown
-.section .shstrtab,""
+.section .shstrtab,"",@12345
.short 20
diff --git a/test/ELF/linkerscript/early-assign-symbol.s b/test/ELF/linkerscript/early-assign-symbol.s
new file mode 100644
index 000000000000..21940c088393
--- /dev/null
+++ b/test/ELF/linkerscript/early-assign-symbol.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { aaa = 1 + ABSOLUTE(foo - 1); .text : { *(.text*) } }" > %t1.script
+# RUN: not ld.lld -o %t --script %t1.script %t.o 2>&1 | FileCheck %s
+
+# RUN: echo "SECTIONS { aaa = ABSOLUTE(foo - 1) + 1; .text : { *(.text*) } }" > %t2.script
+# RUN: not ld.lld -o %t --script %t2.script %t.o 2>&1 | FileCheck %s
+
+# CHECK: error: unable to evaluate expression: input section .text has no output section assigned
+
+.section .text
+.globl foo
+foo:
diff --git a/test/ELF/linkerscript/ehdr_start.s b/test/ELF/linkerscript/ehdr_start.s
index 935fa2bf3391..4da158a83956 100644
--- a/test/ELF/linkerscript/ehdr_start.s
+++ b/test/ELF/linkerscript/ehdr_start.s
@@ -2,9 +2,17 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: echo "SECTIONS { }" > %t.script
-# RUN: not ld.lld %t.o -script %t.script -o %t 2>&1 | FileCheck %s
-# CHECK: error: undefined symbol: __ehdr_start
-# CHECK: >>> referenced by {{.*}}:(.text+0x0)
+# RUN: ld.lld %t.o -script %t.script -o %t
+# RUN: llvm-readobj -symbols %t | FileCheck %s
+# CHECK: Name: __ehdr_start (1)
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Type: None (0x0)
+# CHECK-NEXT: Other [ (0x2)
+# CHECK-NEXT: STV_HIDDEN (0x2)
+# CHECK-NEXT: ]
+# CHECK-NEXT: Section: .text (0x1)
.text
.global _start, __ehdr_start
diff --git a/test/ELF/linkerscript/sections-constraint.s b/test/ELF/linkerscript/sections-constraint.s
index 4d95ec18336c..796240627170 100644
--- a/test/ELF/linkerscript/sections-constraint.s
+++ b/test/ELF/linkerscript/sections-constraint.s
@@ -24,8 +24,8 @@
# NO1-NEXT: 0 00000000
# NO1: .writable 00000004
# NO1: .foo.2 00000004
-# NO1: .readable 00000004
# NO1: .foo.1 00000004
+# NO1: .readable 00000004
.global _start
_start:
diff --git a/test/ELF/linkerscript/sections.s b/test/ELF/linkerscript/sections.s
index 69c6f19d078d..d5645c303754 100644
--- a/test/ELF/linkerscript/sections.s
+++ b/test/ELF/linkerscript/sections.s
@@ -45,8 +45,9 @@
# SEC-ORDER: 3 .shstrtab 0000003b {{[0-9a-f]*}}
# SEC-ORDER: 4 .symtab 00000030 {{[0-9a-f]*}}
# SEC-ORDER: 5 .strtab 00000008 {{[0-9a-f]*}}
-# SEC-ORDER: 6 .data 00000020 {{[0-9a-f]*}} DATA
-# SEC-ORDER: 7 .text 0000000e {{[0-9a-f]*}} TEXT DATA
+# SEC-ORDER: 6 .comment 00000008 {{[0-9a-f]*}}
+# SEC-ORDER: 7 .data 00000020 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 8 .text 0000000e {{[0-9a-f]*}} TEXT DATA
# .text and .data have swapped names but proper sizes and types.
# RUN: echo "SECTIONS { \
diff --git a/test/ELF/linkerscript/symbol-memoryexpr.s b/test/ELF/linkerscript/symbol-memoryexpr.s
new file mode 100644
index 000000000000..9c75274e1644
--- /dev/null
+++ b/test/ELF/linkerscript/symbol-memoryexpr.s
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# RUN: echo "MEMORY { \
+# RUN: ram (rwx) : ORIGIN = 0x8000, LENGTH = 256K \
+# RUN: } \
+# RUN: SECTIONS { \
+# RUN: origin = ORIGIN(ram); \
+# RUN: length = LENGTH(ram); \
+# RUN: end = ORIGIN(ram) + LENGTH(ram); \
+# RUN: }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck %s
+
+# CHECK: SYMBOL TABLE:
+# CHECK-NEXT: 0000000000000000 *UND* 00000000
+# CHECK-NEXT: 0000000000008000 .text 00000000 _start
+# CHECK-NEXT: 0000000000008000 *ABS* 00000000 origin
+# CHECK-NEXT: 0000000000040000 *ABS* 00000000 length
+# CHECK-NEXT: 0000000000048000 *ABS* 00000000 end
+
+# RUN: echo "SECTIONS { \
+# RUN: no_exist_origin = ORIGIN(ram); \
+# RUN: no_exist_length = LENGTH(ram); \
+# RUN: }" > %t2.script
+# RUN: not ld.lld -o %t2 --script %t2.script %t 2>&1 \
+# RUN: | FileCheck -check-prefix=ERR %s
+# ERR: {{.*}}.script:1: memory region not defined: ram
+
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/many-alloc-sections.s b/test/ELF/many-alloc-sections.s
new file mode 100644
index 000000000000..441e5ff32d08
--- /dev/null
+++ b/test/ELF/many-alloc-sections.s
@@ -0,0 +1,106 @@
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t.o
+// RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } }" > %t.script
+// FIXME: threads are disable because the test is too slow with them (PR32942).
+// RUN: ld.lld -T %t.script %t.o -o %t --no-threads
+// RUN: llvm-readobj -t %t | FileCheck %s
+
+// Test that _start is in the correct section.
+// CHECK: Name: _start
+// CHECK-NEXT: Value: 0x120
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: dm
+
+.macro gen_sections4 x
+ .section a\x,"a"
+ .section b\x,"a"
+ .section c\x,"a"
+ .section d\x,"a"
+.endm
+
+.macro gen_sections8 x
+ gen_sections4 a\x
+ gen_sections4 b\x
+.endm
+
+.macro gen_sections16 x
+ gen_sections8 a\x
+ gen_sections8 b\x
+.endm
+
+.macro gen_sections32 x
+ gen_sections16 a\x
+ gen_sections16 b\x
+.endm
+
+.macro gen_sections64 x
+ gen_sections32 a\x
+ gen_sections32 b\x
+.endm
+
+.macro gen_sections128 x
+ gen_sections64 a\x
+ gen_sections64 b\x
+.endm
+
+.macro gen_sections256 x
+ gen_sections128 a\x
+ gen_sections128 b\x
+.endm
+
+.macro gen_sections512 x
+ gen_sections256 a\x
+ gen_sections256 b\x
+.endm
+
+.macro gen_sections1024 x
+ gen_sections512 a\x
+ gen_sections512 b\x
+.endm
+
+.macro gen_sections2048 x
+ gen_sections1024 a\x
+ gen_sections1024 b\x
+.endm
+
+.macro gen_sections4096 x
+ gen_sections2048 a\x
+ gen_sections2048 b\x
+.endm
+
+.macro gen_sections8192 x
+ gen_sections4096 a\x
+ gen_sections4096 b\x
+.endm
+
+.macro gen_sections16384 x
+ gen_sections8192 a\x
+ gen_sections8192 b\x
+.endm
+
+.macro gen_sections32768 x
+ gen_sections16384 a\x
+ gen_sections16384 b\x
+.endm
+
+ .bss
+ .section bar
+
+gen_sections32768 a
+gen_sections16384 b
+gen_sections8192 c
+gen_sections4096 d
+gen_sections2048 e
+gen_sections1024 f
+gen_sections512 g
+gen_sections128 h
+gen_sections64 i
+gen_sections32 j
+gen_sections16 k
+gen_sections8 l
+gen_sections4 m
+
+.global _start
+_start:
diff --git a/test/ELF/many-sections.s b/test/ELF/many-sections.s
index 77e76c20a60d..ae923889ddc1 100644
--- a/test/ELF/many-sections.s
+++ b/test/ELF/many-sections.s
@@ -11,7 +11,14 @@
// CHECK-NEXT: Section: dm (0xFF00)
-// RUN: ld.lld %t -o %t2
+// FIXME: threads are disable because the test is too slow with them (PR32942).
+// RUN: ld.lld %t -o %t2 --no-threads
+// RUN: llvm-readobj -t %t2 | FileCheck --check-prefix=LINKED %s
+
+// Test also with a linker script.
+// RUN: echo "SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } }" > %t.script
+// FIXME: threads are disable because the test is too slow with them (PR32942).
+// RUN: ld.lld -T %t.script %t -o %t2 --no-threads
// RUN: llvm-readobj -t %t2 | FileCheck --check-prefix=LINKED %s
// Test that _start is in the correct section.
diff --git a/test/ELF/tls-dynamic-i686.s b/test/ELF/tls-dynamic-i686.s
index 04fd13822530..ac88e6eaed31 100644
--- a/test/ELF/tls-dynamic-i686.s
+++ b/test/ELF/tls-dynamic-i686.s
@@ -56,8 +56,8 @@ addl tls1@gotntpoff(%ebx),%eax
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_WRITE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x3070
-// CHECK-NEXT: Offset: 0x3070
+// CHECK-NEXT: Address: 0x3068
+// CHECK-NEXT: Offset: 0x3068
// CHECK-NEXT: Size: 32
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
@@ -66,13 +66,13 @@ addl tls1@gotntpoff(%ebx),%eax
// CHECK: Relocations [
// CHECK: Section ({{.+}}) .rel.dyn {
-// CHECK-NEXT: 0x3080 R_386_TLS_DTPMOD32 - 0x0
-// CHECK-NEXT: 0x3070 R_386_TLS_DTPMOD32 tls0 0x0
-// CHECK-NEXT: 0x3074 R_386_TLS_DTPOFF32 tls0 0x0
-// CHECK-NEXT: 0x3088 R_386_TLS_TPOFF tls0 0x0
-// CHECK-NEXT: 0x3078 R_386_TLS_DTPMOD32 tls1 0x0
-// CHECK-NEXT: 0x307C R_386_TLS_DTPOFF32 tls1 0x0
-// CHECK-NEXT: 0x308C R_386_TLS_TPOFF tls1 0x0
+// CHECK-NEXT: 0x3078 R_386_TLS_DTPMOD32 - 0x0
+// CHECK-NEXT: 0x3068 R_386_TLS_DTPMOD32 tls0 0x0
+// CHECK-NEXT: 0x306C R_386_TLS_DTPOFF32 tls0 0x0
+// CHECK-NEXT: 0x3080 R_386_TLS_TPOFF tls0 0x0
+// CHECK-NEXT: 0x3070 R_386_TLS_DTPMOD32 tls1 0x0
+// CHECK-NEXT: 0x3074 R_386_TLS_DTPOFF32 tls1 0x0
+// CHECK-NEXT: 0x3084 R_386_TLS_TPOFF tls1 0x0
// CHECK-NEXT: }
// DIS: Disassembly of section .text:
@@ -80,20 +80,20 @@ addl tls1@gotntpoff(%ebx),%eax
// General dynamic model:
// -32 and -24 are first and second GOT entries offsets.
// Each one is a pair of records.
-// DIS-NEXT: 1000: {{.*}} leal -32(,%ebx), %eax
-// DIS-NEXT: 1007: {{.*}} calll 100
-// DIS-NEXT: 100c: {{.*}} leal -24(,%ebx), %eax
-// DIS-NEXT: 1013: {{.*}} calll 88
+// DIS-NEXT: 1000: 8d 04 1d e0 ff ff ff leal -32(,%ebx), %eax
+// DIS-NEXT: 1007: e8 64 00 00 00 calll 100
+// DIS-NEXT: 100c: 8d 04 1d e8 ff ff ff leal -24(,%ebx), %eax
+// DIS-NEXT: 1013: e8 58 00 00 00 calll 88
// Local dynamic model:
// -16 is a local module tls index offset.
-// DIS-NEXT: 1018: {{.*}} leal -16(%ebx), %eax
-// DIS-NEXT: 101e: {{.*}} calll 77
-// DIS-NEXT: 1023: {{.*}} leal 8(%eax), %edx
-// DIS-NEXT: 1029: {{.*}} leal -16(%ebx), %eax
-// DIS-NEXT: 102f: {{.*}} calll 60
-// DIS-NEXT: 1034: {{.*}} leal 12(%eax), %edx
+// DIS-NEXT: 1018: 8d 83 f0 ff ff ff leal -16(%ebx), %eax
+// DIS-NEXT: 101e: e8 4d 00 00 00 calll 77
+// DIS-NEXT: 1023: 8d 90 08 00 00 00 leal 8(%eax), %edx
+// DIS-NEXT: 1029: 8d 83 f0 ff ff ff leal -16(%ebx), %eax
+// DIS-NEXT: 102f: e8 3c 00 00 00 calll 60
+// DIS-NEXT: 1034: 8d 90 0c 00 00 00 leal 12(%eax), %edx
// Initial exec model:
-// DIS-NEXT: 103a: {{.*}} movl %gs:0, %eax
-// DIS-NEXT: 1040: {{.*}} addl -8(%ebx), %eax
-// DIS-NEXT: 1046: {{.*}} movl %gs:0, %eax
-// DIS-NEXT: 104c: {{.*}} addl -4(%ebx), %eax
+// DIS-NEXT: 103a: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DIS-NEXT: 1040: 03 83 f8 ff ff ff addl -8(%ebx), %eax
+// DIS-NEXT: 1046: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DIS-NEXT: 104c: 03 83 fc ff ff ff addl -4(%ebx), %eax
diff --git a/test/ELF/tls-opt-iele-i686-nopic.s b/test/ELF/tls-opt-iele-i686-nopic.s
index a883bce511a6..b6608c16551c 100644
--- a/test/ELF/tls-opt-iele-i686-nopic.s
+++ b/test/ELF/tls-opt-iele-i686-nopic.s
@@ -13,8 +13,8 @@
// GOTREL-NEXT: SHF_ALLOC
// GOTREL-NEXT: SHF_WRITE
// GOTREL-NEXT: ]
-// GOTREL-NEXT: Address: 0x12060
-// GOTREL-NEXT: Offset: 0x2060
+// GOTREL-NEXT: Address: 0x12058
+// GOTREL-NEXT: Offset: 0x2058
// GOTREL-NEXT: Size: 8
// GOTREL-NEXT: Link: 0
// GOTREL-NEXT: Info: 0
@@ -23,8 +23,8 @@
// GOTREL-NEXT: }
// GOTREL: Relocations [
// GOTREL-NEXT: Section ({{.*}}) .rel.dyn {
-// GOTREL-NEXT: 0x12060 R_386_TLS_TPOFF tlsshared0 0x0
-// GOTREL-NEXT: 0x12064 R_386_TLS_TPOFF tlsshared1 0x0
+// GOTREL-NEXT: 0x12058 R_386_TLS_TPOFF tlsshared0 0x0
+// GOTREL-NEXT: 0x1205C R_386_TLS_TPOFF tlsshared1 0x0
// GOTREL-NEXT: }
// GOTREL-NEXT: ]
@@ -32,24 +32,24 @@
// DISASM-NEXT: _start:
// 4294967288 = 0xFFFFFFF8
// 4294967292 = 0xFFFFFFFC
-// 73824 = (.got)[0] = 0x12060
-// 73828 = (.got)[1] = 0x12064
-// DISASM-NEXT: 11000: {{.*}} movl $4294967288, %ecx
-// DISASM-NEXT: 11006: {{.*}} movl %gs:(%ecx), %eax
-// DISASM-NEXT: 11009: {{.*}} movl $4294967288, %eax
-// DISASM-NEXT: 1100e: {{.*}} movl %gs:(%eax), %eax
-// DISASM-NEXT: 11011: {{.*}} addl $4294967288, %ecx
-// DISASM-NEXT: 11017: {{.*}} movl %gs:(%ecx), %eax
-// DISASM-NEXT: 1101a: {{.*}} movl $4294967292, %ecx
-// DISASM-NEXT: 11020: {{.*}} movl %gs:(%ecx), %eax
-// DISASM-NEXT: 11023: {{.*}} movl $4294967292, %eax
-// DISASM-NEXT: 11028: {{.*}} movl %gs:(%eax), %eax
-// DISASM-NEXT: 1102b: {{.*}} addl $4294967292, %ecx
-// DISASM-NEXT: 11031: {{.*}} movl %gs:(%ecx), %eax
-// DISASM-NEXT: 11034: {{.*}} movl 73824, %ecx
-// DISASM-NEXT: 1103a: {{.*}} movl %gs:(%ecx), %eax
-// DISASM-NEXT: 1103d: {{.*}} addl 73828, %ecx
-// DISASM-NEXT: 11043: {{.*}} movl %gs:(%ecx), %eax
+// 73808 = (.got)[0] = 0x12058
+// 73812 = (.got)[1] = 0x1205C
+// DISASM-NEXT: 11000: c7 c1 f8 ff ff ff movl $4294967288, %ecx
+// DISASM-NEXT: 11006: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 11009: b8 f8 ff ff ff movl $4294967288, %eax
+// DISASM-NEXT: 1100e: 65 8b 00 movl %gs:(%eax), %eax
+// DISASM-NEXT: 11011: 81 c1 f8 ff ff ff addl $4294967288, %ecx
+// DISASM-NEXT: 11017: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 1101a: c7 c1 fc ff ff ff movl $4294967292, %ecx
+// DISASM-NEXT: 11020: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 11023: b8 fc ff ff ff movl $4294967292, %eax
+// DISASM-NEXT: 11028: 65 8b 00 movl %gs:(%eax), %eax
+// DISASM-NEXT: 1102b: 81 c1 fc ff ff ff addl $4294967292, %ecx
+// DISASM-NEXT: 11031: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 11034: 8b 0d 58 20 01 00 movl 73816, %ecx
+// DISASM-NEXT: 1103a: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 1103d: 03 0d 5c 20 01 00 addl 73820, %ecx
+// DISASM-NEXT: 11043: 65 8b 01 movl %gs:(%ecx), %eax
.type tlslocal0,@object
.section .tbss,"awT",@nobits
diff --git a/test/ELF/x86-64-reloc-tpoff32-fpic.s b/test/ELF/x86-64-reloc-tpoff32-fpic.s
new file mode 100644
index 000000000000..5be3dc317012
--- /dev/null
+++ b/test/ELF/x86-64-reloc-tpoff32-fpic.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -shared -o %t.so 2>&1 | FileCheck %s
+
+# CHECK: relocation R_X86_64_TPOFF32 cannot be used against shared object; recompile with -fPIC
+# CHECK: >>> defined in {{.*}}.o
+# CHECK: >>> referenced by {{.*}}.o:(.tdata+0xC)
+
+.section ".tdata", "awT", @progbits
+.globl var
+var:
+
+movq %fs:0, %rax
+leaq var@TPOFF(%rax),%rax
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 9cd085398c37..84d35d43f4e8 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -12,6 +12,5 @@ function(add_lld_unittest test_dirname)
target_link_libraries(${test_dirname} ${LLVM_COMMON_LIBS})
endfunction()
-add_subdirectory(CoreTests)
add_subdirectory(DriverTests)
add_subdirectory(MachOTests)
diff --git a/unittests/CoreTests/CMakeLists.txt b/unittests/CoreTests/CMakeLists.txt
deleted file mode 100644
index 9f68f56a6c03..000000000000
--- a/unittests/CoreTests/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-add_lld_unittest(CoreTests
- ParallelTest.cpp
- )
-
-target_link_libraries(CoreTests
- lldCore ${LLVM_PTHREAD_LIB}
- )
diff --git a/unittests/CoreTests/ParallelTest.cpp b/unittests/CoreTests/ParallelTest.cpp
deleted file mode 100644
index bd8507026a07..000000000000
--- a/unittests/CoreTests/ParallelTest.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//===- lld/unittest/ParallelTest.cpp --------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Parallel.h unit tests.
-///
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-#include "lld/Core/Parallel.h"
-#include <array>
-#include <random>
-
-uint32_t array[1024 * 1024];
-
-TEST(Parallel, sort) {
- std::mt19937 randEngine;
- std::uniform_int_distribution<uint32_t> dist;
-
- for (auto &i : array)
- i = dist(randEngine);
-
- lld::parallel_sort(std::begin(array), std::end(array));
- ASSERT_TRUE(std::is_sorted(std::begin(array), std::end(array)));
-}
-
-TEST(Parallel, parallel_for) {
- // We need to test the case with a TaskSize > 1. We are white-box testing
- // here. The TaskSize is calculated as (End - Begin) / 1024 at the time of
- // writing.
- uint32_t range[2050];
- std::fill(range, range + 2050, 1);
- lld::parallel_for(0, 2049, [&range](size_t I) { ++range[I]; });
-
- uint32_t expected[2049];
- std::fill(expected, expected + 2049, 2);
- ASSERT_TRUE(std::equal(range, range + 2049, expected));
- // Check that we don't write past the end of the requested range.
- ASSERT_EQ(range[2049], 1u);
-}