diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-05-16 19:47:41 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-05-16 19:47:41 +0000 |
commit | 022ebf5bbf58ca2dd943d3376cc95a6b206db799 (patch) | |
tree | 4069ef3b75eed2d68683cb6224a627c24cd95b15 | |
parent | fbe69f787ace06f44b6cb1bd3cd45ac703a16a05 (diff) |
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
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); -} |