Vendor import of lld trunk r303197:

https://llvm.org/svn/llvm-project/lld/trunk@303197
This commit is contained in:
Dimitry Andric 2017-05-16 19:47:41 +00:00
parent fbe69f787a
commit 022ebf5bbf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/lld/dist/; revision=318376
svn path=/vendor/lld/lld-trunk-r303197/; revision=318377; tag=vendor/lld/lld-trunk-r303197
57 changed files with 1213 additions and 1239 deletions

View File

@ -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>

View File

@ -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);

View File

@ -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]);

View File

@ -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";

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -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");
}

View File

@ -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));

View File

@ -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 @@ class LinkerScript {
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 @@ class LinkerScript {
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();

View File

@ -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);

View File

@ -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 {

View File

@ -50,6 +50,7 @@ class OutputSection final : public SectionBase {
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
unsigned SectionIndex;
unsigned SortRank;
uint32_t getPhdrFlags() const;

View File

@ -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;
}

View File

@ -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();

View File

@ -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 {};
}

View File

@ -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;

View File

@ -78,7 +78,7 @@ class SymbolBody {
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;

View File

@ -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>;

View File

@ -104,10 +104,9 @@ template <class ELFT> class EhFrameSection final : public SyntheticSection {
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 @@ template <class ELFT> class GotSection final : public SyntheticSection {
// 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 @@ class ThunkSection : public SyntheticSection {
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;

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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) {
// 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;
// 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
};
// 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;
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.
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 (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.
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.
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)
return getPPC64SectionRank(A->Name) < getPPC64SectionRank(B->Name);
if (Config->EMachine == EM_MIPS)
return getMipsSectionRank(A) < getMipsSectionRank(B);
// // 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;
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;
// 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);
}
bool S1IsWrite = S1.Flags & SHF_WRITE;
bool S2IsWrite = S2.Flags & SHF_WRITE;
if (S1IsWrite != S2IsWrite)
return false;
// 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;
if (!S1IsWrite)
return true; // RO and RX share a PT_LOAD with linker scripts.
return (S1.Flags & SHF_EXECINSTR) == (S2.Flags & SHF_EXECINSTR);
// 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;
auto Pos = findOrphanPos<ELFT>(I, NonScriptI);
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;
// 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 *);

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -12,7 +12,6 @@ add_lld_library(lldCore
Resolver.cpp
SymbolTable.cpp
TargetOptionsCommandFlags.cpp
TaskGroup.cpp
Writer.cpp
ADDITIONAL_HEADER_DIRS

View File

@ -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();
});
}

View File

@ -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);

View File

@ -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
...

View File

@ -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
...

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

116
test/ELF/gdb-index-empty.s Normal file
View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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 { \

View File

@ -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

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -1,7 +0,0 @@
add_lld_unittest(CoreTests
ParallelTest.cpp
)
target_link_libraries(CoreTests
lldCore ${LLVM_PTHREAD_LIB}
)

View File

@ -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);
}