Vendor import of lld trunk r303197:
https://llvm.org/svn/llvm-project/lld/trunk@303197
This commit is contained in:
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
@ -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>
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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 {};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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>;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
470
ELF/Writer.cpp
470
ELF/Writer.cpp
@ -164,11 +164,10 @@ static void combineMergableSections() {
|
||||
uint64_t Flags = MS->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED);
|
||||
uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
|
||||
|
||||
auto I =
|
||||
llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
|
||||
return Sec->Name == OutsecName && Sec->Flags == Flags &&
|
||||
Sec->Alignment == Alignment;
|
||||
});
|
||||
auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
|
||||
return Sec->Name == OutsecName && Sec->Flags == Flags &&
|
||||
Sec->Alignment == Alignment;
|
||||
});
|
||||
if (I == MergeSections.end()) {
|
||||
MergeSyntheticSection *Syn =
|
||||
make<MergeSyntheticSection>(OutsecName, MS->Type, Flags, Alignment);
|
||||
@ -312,11 +311,11 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
|
||||
auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); };
|
||||
|
||||
In<ELFT>::DynStrTab = make<StringTableSection>(".dynstr", true);
|
||||
In<ELFT>::Dynamic = make<DynamicSection<ELFT>>();
|
||||
InX::DynStrTab = make<StringTableSection>(".dynstr", true);
|
||||
InX::Dynamic = make<DynamicSection<ELFT>>();
|
||||
In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>(
|
||||
Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
|
||||
In<ELFT>::ShStrTab = make<StringTableSection>(".shstrtab", false);
|
||||
InX::ShStrTab = make<StringTableSection>(".shstrtab", false);
|
||||
|
||||
Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
|
||||
Out::ElfHeader->Size = sizeof(Elf_Ehdr);
|
||||
@ -324,41 +323,41 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
Out::ProgramHeaders->updateAlignment(Config->Wordsize);
|
||||
|
||||
if (needsInterpSection<ELFT>()) {
|
||||
In<ELFT>::Interp = createInterpSection();
|
||||
Add(In<ELFT>::Interp);
|
||||
InX::Interp = createInterpSection();
|
||||
Add(InX::Interp);
|
||||
} else {
|
||||
In<ELFT>::Interp = nullptr;
|
||||
InX::Interp = nullptr;
|
||||
}
|
||||
|
||||
if (!Config->Relocatable)
|
||||
Add(createCommentSection<ELFT>());
|
||||
|
||||
if (Config->Strip != StripPolicy::All) {
|
||||
In<ELFT>::StrTab = make<StringTableSection>(".strtab", false);
|
||||
In<ELFT>::SymTab = make<SymbolTableSection<ELFT>>(*In<ELFT>::StrTab);
|
||||
InX::StrTab = make<StringTableSection>(".strtab", false);
|
||||
InX::SymTab = make<SymbolTableSection<ELFT>>(*InX::StrTab);
|
||||
}
|
||||
|
||||
if (Config->BuildId != BuildIdKind::None) {
|
||||
In<ELFT>::BuildId = make<BuildIdSection>();
|
||||
Add(In<ELFT>::BuildId);
|
||||
InX::BuildId = make<BuildIdSection>();
|
||||
Add(InX::BuildId);
|
||||
}
|
||||
|
||||
In<ELFT>::Common = createCommonSection<ELFT>();
|
||||
if (In<ELFT>::Common)
|
||||
InX::Common = createCommonSection<ELFT>();
|
||||
if (InX::Common)
|
||||
Add(InX::Common);
|
||||
|
||||
In<ELFT>::Bss = make<BssSection>(".bss");
|
||||
Add(In<ELFT>::Bss);
|
||||
In<ELFT>::BssRelRo = make<BssSection>(".bss.rel.ro");
|
||||
Add(In<ELFT>::BssRelRo);
|
||||
InX::Bss = make<BssSection>(".bss");
|
||||
Add(InX::Bss);
|
||||
InX::BssRelRo = make<BssSection>(".bss.rel.ro");
|
||||
Add(InX::BssRelRo);
|
||||
|
||||
// Add MIPS-specific sections.
|
||||
bool HasDynSymTab = !Symtab<ELFT>::X->getSharedFiles().empty() ||
|
||||
Config->Pic || Config->ExportDynamic;
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
if (!Config->Shared && HasDynSymTab) {
|
||||
In<ELFT>::MipsRldMap = make<MipsRldMapSection>();
|
||||
Add(In<ELFT>::MipsRldMap);
|
||||
InX::MipsRldMap = make<MipsRldMapSection>();
|
||||
Add(InX::MipsRldMap);
|
||||
}
|
||||
if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
|
||||
Add(Sec);
|
||||
@ -369,8 +368,8 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
}
|
||||
|
||||
if (HasDynSymTab) {
|
||||
In<ELFT>::DynSymTab = make<SymbolTableSection<ELFT>>(*In<ELFT>::DynStrTab);
|
||||
Add(In<ELFT>::DynSymTab);
|
||||
InX::DynSymTab = make<SymbolTableSection<ELFT>>(*InX::DynStrTab);
|
||||
Add(InX::DynSymTab);
|
||||
|
||||
In<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
|
||||
Add(In<ELFT>::VerSym);
|
||||
@ -384,8 +383,8 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
Add(In<ELFT>::VerNeed);
|
||||
|
||||
if (Config->GnuHash) {
|
||||
In<ELFT>::GnuHashTab = make<GnuHashTableSection<ELFT>>();
|
||||
Add(In<ELFT>::GnuHashTab);
|
||||
InX::GnuHashTab = make<GnuHashTableSection>();
|
||||
Add(InX::GnuHashTab);
|
||||
}
|
||||
|
||||
if (Config->SysvHash) {
|
||||
@ -393,29 +392,29 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
Add(In<ELFT>::HashTab);
|
||||
}
|
||||
|
||||
Add(In<ELFT>::Dynamic);
|
||||
Add(In<ELFT>::DynStrTab);
|
||||
Add(InX::Dynamic);
|
||||
Add(InX::DynStrTab);
|
||||
Add(In<ELFT>::RelaDyn);
|
||||
}
|
||||
|
||||
// Add .got. MIPS' .got is so different from the other archs,
|
||||
// it has its own class.
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
In<ELFT>::MipsGot = make<MipsGotSection>();
|
||||
Add(In<ELFT>::MipsGot);
|
||||
InX::MipsGot = make<MipsGotSection>();
|
||||
Add(InX::MipsGot);
|
||||
} else {
|
||||
In<ELFT>::Got = make<GotSection<ELFT>>();
|
||||
Add(In<ELFT>::Got);
|
||||
InX::Got = make<GotSection<ELFT>>();
|
||||
Add(InX::Got);
|
||||
}
|
||||
|
||||
In<ELFT>::GotPlt = make<GotPltSection>();
|
||||
Add(In<ELFT>::GotPlt);
|
||||
In<ELFT>::IgotPlt = make<IgotPltSection>();
|
||||
Add(In<ELFT>::IgotPlt);
|
||||
InX::GotPlt = make<GotPltSection>();
|
||||
Add(InX::GotPlt);
|
||||
InX::IgotPlt = make<IgotPltSection>();
|
||||
Add(InX::IgotPlt);
|
||||
|
||||
if (Config->GdbIndex) {
|
||||
In<ELFT>::GdbIndex = make<GdbIndexSection>();
|
||||
Add(In<ELFT>::GdbIndex);
|
||||
InX::GdbIndex = make<GdbIndexSection>();
|
||||
Add(InX::GdbIndex);
|
||||
}
|
||||
|
||||
// We always need to add rel[a].plt to output if it has entries.
|
||||
@ -431,10 +430,10 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
false /*Sort*/);
|
||||
Add(In<ELFT>::RelaIplt);
|
||||
|
||||
In<ELFT>::Plt = make<PltSection>(Target->PltHeaderSize);
|
||||
Add(In<ELFT>::Plt);
|
||||
In<ELFT>::Iplt = make<PltSection>(0);
|
||||
Add(In<ELFT>::Iplt);
|
||||
InX::Plt = make<PltSection>(Target->PltHeaderSize);
|
||||
Add(InX::Plt);
|
||||
InX::Iplt = make<PltSection>(0);
|
||||
Add(InX::Iplt);
|
||||
|
||||
if (!Config->Relocatable) {
|
||||
if (Config->EhFrameHdr) {
|
||||
@ -445,11 +444,11 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
Add(In<ELFT>::EhFrame);
|
||||
}
|
||||
|
||||
if (In<ELFT>::SymTab)
|
||||
Add(In<ELFT>::SymTab);
|
||||
Add(In<ELFT>::ShStrTab);
|
||||
if (In<ELFT>::StrTab)
|
||||
Add(In<ELFT>::StrTab);
|
||||
if (InX::SymTab)
|
||||
Add(InX::SymTab);
|
||||
Add(InX::ShStrTab);
|
||||
if (InX::StrTab)
|
||||
Add(InX::StrTab);
|
||||
}
|
||||
|
||||
static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
|
||||
@ -504,7 +503,7 @@ static bool includeInSymtab(const SymbolBody &B) {
|
||||
// Local symbols are not in the linker's symbol table. This function scans
|
||||
// each object file's symbol table to copy local symbols to the output.
|
||||
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
|
||||
if (!In<ELFT>::SymTab)
|
||||
if (!InX::SymTab)
|
||||
return;
|
||||
for (elf::ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles()) {
|
||||
for (SymbolBody *B : F->getLocalSymbols()) {
|
||||
@ -522,7 +521,7 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
|
||||
SectionBase *Sec = DR->Section;
|
||||
if (!shouldKeepInSymtab(Sec, B->getName(), *B))
|
||||
continue;
|
||||
In<ELFT>::SymTab->addSymbol(B);
|
||||
InX::SymTab->addSymbol(B);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -542,43 +541,17 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
|
||||
auto *Sym =
|
||||
make<DefinedRegular>("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION,
|
||||
/*Value=*/0, /*Size=*/0, IS, nullptr);
|
||||
In<ELFT>::SymTab->addSymbol(Sym);
|
||||
InX::SymTab->addSymbol(Sym);
|
||||
}
|
||||
}
|
||||
|
||||
// PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections that
|
||||
// we would like to make sure appear is a specific order to maximize their
|
||||
// coverage by a single signed 16-bit offset from the TOC base pointer.
|
||||
// Conversely, the special .tocbss section should be first among all SHT_NOBITS
|
||||
// sections. This will put it next to the loaded special PPC64 sections (and,
|
||||
// thus, within reach of the TOC base pointer).
|
||||
static int getPPC64SectionRank(StringRef SectionName) {
|
||||
return StringSwitch<int>(SectionName)
|
||||
.Case(".tocbss", 0)
|
||||
.Case(".branch_lt", 2)
|
||||
.Case(".toc", 3)
|
||||
.Case(".toc1", 4)
|
||||
.Case(".opd", 5)
|
||||
.Default(1);
|
||||
}
|
||||
|
||||
// All sections with SHF_MIPS_GPREL flag should be grouped together
|
||||
// because data in these sections is addressable with a gp relative address.
|
||||
static int getMipsSectionRank(const OutputSection *S) {
|
||||
if ((S->Flags & SHF_MIPS_GPREL) == 0)
|
||||
return 0;
|
||||
if (S->Name == ".got")
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Today's loaders have a feature to make segments read-only after
|
||||
// processing dynamic relocations to enhance security. PT_GNU_RELRO
|
||||
// is defined for that.
|
||||
//
|
||||
// This function returns true if a section needs to be put into a
|
||||
// PT_GNU_RELRO segment.
|
||||
template <class ELFT> bool elf::isRelroSection(const OutputSection *Sec) {
|
||||
bool elf::isRelroSection(const OutputSection *Sec) {
|
||||
if (!Config->ZRelro)
|
||||
return false;
|
||||
|
||||
@ -613,27 +586,27 @@ template <class ELFT> bool elf::isRelroSection(const OutputSection *Sec) {
|
||||
// .got contains pointers to external symbols. They are resolved by
|
||||
// the dynamic linker when a module is loaded into memory, and after
|
||||
// that they are not expected to change. So, it can be in RELRO.
|
||||
if (In<ELFT>::Got && Sec == In<ELFT>::Got->OutSec)
|
||||
if (InX::Got && Sec == InX::Got->OutSec)
|
||||
return true;
|
||||
|
||||
// .got.plt contains pointers to external function symbols. They are
|
||||
// by default resolved lazily, so we usually cannot put it into RELRO.
|
||||
// However, if "-z now" is given, the lazy symbol resolution is
|
||||
// disabled, which enables us to put it into RELRO.
|
||||
if (Sec == In<ELFT>::GotPlt->OutSec)
|
||||
if (Sec == InX::GotPlt->OutSec)
|
||||
return Config->ZNow;
|
||||
|
||||
// .dynamic section contains data for the dynamic linker, and
|
||||
// there's no need to write to it at runtime, so it's better to put
|
||||
// it into RELRO.
|
||||
if (Sec == In<ELFT>::Dynamic->OutSec)
|
||||
if (Sec == InX::Dynamic->OutSec)
|
||||
return true;
|
||||
|
||||
// .bss.rel.ro is used for copy relocations for read-only symbols.
|
||||
// Since the dynamic linker needs to process copy relocations, the
|
||||
// section cannot be read-only, but once initialized, they shouldn't
|
||||
// change.
|
||||
if (Sec == In<ELFT>::BssRelRo->OutSec)
|
||||
if (Sec == InX::BssRelRo->OutSec)
|
||||
return true;
|
||||
|
||||
// Sections with some special names are put into RELRO. This is a
|
||||
@ -645,105 +618,149 @@ template <class ELFT> bool elf::isRelroSection(const OutputSection *Sec) {
|
||||
S == ".eh_frame" || S == ".openbsd.randomdata";
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static bool compareSectionsNonScript(const OutputSection *A,
|
||||
const OutputSection *B) {
|
||||
// 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 *);
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
@ -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
|
@ -12,7 +12,6 @@ add_lld_library(lldCore
|
||||
Resolver.cpp
|
||||
SymbolTable.cpp
|
||||
TargetOptionsCommandFlags.cpp
|
||||
TaskGroup.cpp
|
||||
Writer.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
...
|
||||
|
@ -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
|
||||
...
|
@ -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
|
@ -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
|
@ -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
|
@ -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
116
test/ELF/gdb-index-empty.s
Normal 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:
|
157
test/ELF/gdb-index-gc-sections.s
Normal file
157
test/ELF/gdb-index-gc-sections.s
Normal 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:
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
14
test/ELF/linkerscript/early-assign-symbol.s
Normal file
14
test/ELF/linkerscript/early-assign-symbol.s
Normal 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:
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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 { \
|
||||
|
33
test/ELF/linkerscript/symbol-memoryexpr.s
Normal file
33
test/ELF/linkerscript/symbol-memoryexpr.s
Normal 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
|
106
test/ELF/many-alloc-sections.s
Normal file
106
test/ELF/many-alloc-sections.s
Normal 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:
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
14
test/ELF/x86-64-reloc-tpoff32-fpic.s
Normal file
14
test/ELF/x86-64-reloc-tpoff32-fpic.s
Normal 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
|
@ -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)
|
||||
|
@ -1,7 +0,0 @@
|
||||
add_lld_unittest(CoreTests
|
||||
ParallelTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(CoreTests
|
||||
lldCore ${LLVM_PTHREAD_LIB}
|
||||
)
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user