Vendor import of lld trunk r304460:
https://llvm.org/svn/llvm-project/lld/trunk@304460
This commit is contained in:
parent
cbb560c9ba
commit
80350c116f
@ -139,21 +139,24 @@ uint64_t SectionBase::getOffset(uint64_t Offset) const {
|
||||
return Offset;
|
||||
case Merge:
|
||||
const MergeInputSection *MS = cast<MergeInputSection>(this);
|
||||
if (MS->MergeSec)
|
||||
return MS->MergeSec->OutSecOff + MS->getOffset(Offset);
|
||||
if (InputSection *IS = MS->getParent())
|
||||
return IS->OutSecOff + MS->getOffset(Offset);
|
||||
return MS->getOffset(Offset);
|
||||
}
|
||||
llvm_unreachable("invalid section kind");
|
||||
}
|
||||
|
||||
OutputSection *SectionBase::getOutputSection() {
|
||||
InputSection *Sec;
|
||||
if (auto *IS = dyn_cast<InputSection>(this))
|
||||
return IS->OutSec;
|
||||
if (auto *MS = dyn_cast<MergeInputSection>(this))
|
||||
return MS->MergeSec ? MS->MergeSec->OutSec : nullptr;
|
||||
if (auto *EH = dyn_cast<EhInputSection>(this))
|
||||
return EH->EHSec->OutSec;
|
||||
return cast<OutputSection>(this);
|
||||
Sec = IS;
|
||||
else if (auto *MS = dyn_cast<MergeInputSection>(this))
|
||||
Sec = MS->getParent();
|
||||
else if (auto *EH = dyn_cast<EhInputSection>(this))
|
||||
Sec = EH->getParent();
|
||||
else
|
||||
return cast<OutputSection>(this);
|
||||
return Sec ? Sec->getParent() : nullptr;
|
||||
}
|
||||
|
||||
// Uncompress section contents. Note that this function is called
|
||||
@ -181,9 +184,15 @@ uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const {
|
||||
return getOffset(Sym.Value);
|
||||
}
|
||||
|
||||
InputSectionBase *InputSectionBase::getLinkOrderDep() const {
|
||||
if ((Flags & SHF_LINK_ORDER) && Link != 0)
|
||||
return File->getSections()[Link];
|
||||
InputSection *InputSectionBase::getLinkOrderDep() const {
|
||||
if ((Flags & SHF_LINK_ORDER) && Link != 0) {
|
||||
InputSectionBase *L = File->getSections()[Link];
|
||||
if (auto *IS = dyn_cast<InputSection>(L))
|
||||
return IS;
|
||||
error(
|
||||
"Merge and .eh_frame sections are not supported with SHF_LINK_ORDER " +
|
||||
toString(L));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -295,6 +304,10 @@ bool InputSectionBase::classof(const SectionBase *S) {
|
||||
return S->kind() != Output;
|
||||
}
|
||||
|
||||
OutputSection *InputSection::getParent() const {
|
||||
return cast_or_null<OutputSection>(Parent);
|
||||
}
|
||||
|
||||
void InputSection::copyShtGroup(uint8_t *Buf) {
|
||||
assert(this->Type == SHT_GROUP);
|
||||
|
||||
@ -309,7 +322,8 @@ void InputSection::copyShtGroup(uint8_t *Buf) {
|
||||
ArrayRef<InputSectionBase *> Sections = this->File->getSections();
|
||||
for (uint32_t Val : From.slice(1)) {
|
||||
uint32_t Index = read32(&Val, Config->Endianness);
|
||||
write32(To++, Sections[Index]->OutSec->SectionIndex, Config->Endianness);
|
||||
write32(To++, Sections[Index]->getOutputSection()->SectionIndex,
|
||||
Config->Endianness);
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,7 +356,7 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
||||
|
||||
// Output section VA is zero for -r, so r_offset is an offset within the
|
||||
// section, but for --emit-relocs it is an virtual address.
|
||||
P->r_offset = RelocatedSection->OutSec->Addr +
|
||||
P->r_offset = RelocatedSection->getOutputSection()->Addr +
|
||||
RelocatedSection->getOffset(Rel.r_offset);
|
||||
P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Body), Type,
|
||||
Config->IsMips64EL);
|
||||
@ -596,7 +610,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t AddrLoc = this->OutSec->Addr + Offset;
|
||||
uint64_t AddrLoc = getParent()->Addr + Offset;
|
||||
uint64_t SymVA = 0;
|
||||
if (!Sym.isTls() || Out::TlsPhdr)
|
||||
SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>(
|
||||
@ -729,6 +743,10 @@ EhInputSection::EhInputSection(elf::ObjectFile<ELFT> *F,
|
||||
this->Live = true;
|
||||
}
|
||||
|
||||
SyntheticSection *EhInputSection::getParent() const {
|
||||
return cast_or_null<SyntheticSection>(Parent);
|
||||
}
|
||||
|
||||
bool EhInputSection::classof(const SectionBase *S) {
|
||||
return S->kind() == InputSectionBase::EHFrame;
|
||||
}
|
||||
@ -797,6 +815,10 @@ static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) {
|
||||
return StringRef::npos;
|
||||
}
|
||||
|
||||
SyntheticSection *MergeInputSection::getParent() const {
|
||||
return cast_or_null<SyntheticSection>(Parent);
|
||||
}
|
||||
|
||||
// Split SHF_STRINGS section. Such section is a sequence of
|
||||
// null-terminated strings.
|
||||
void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) {
|
||||
|
@ -120,7 +120,12 @@ public:
|
||||
uint64_t Entsize, uint32_t Link, uint32_t Info,
|
||||
uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name,
|
||||
Kind SectionKind);
|
||||
OutputSection *OutSec = nullptr;
|
||||
|
||||
// Input sections are part of an output section. Special sections
|
||||
// like .eh_frame and merge sections are first combined into a
|
||||
// synthetic section that is then added to an output section. In all
|
||||
// cases this points one level up.
|
||||
SectionBase *Parent = nullptr;
|
||||
|
||||
// Relocations that refer to this section.
|
||||
const void *FirstRelocation = nullptr;
|
||||
@ -158,7 +163,7 @@ public:
|
||||
return getFile<ELFT>()->getObj();
|
||||
}
|
||||
|
||||
InputSectionBase *getLinkOrderDep() const;
|
||||
InputSection *getLinkOrderDep() const;
|
||||
|
||||
void uncompress();
|
||||
|
||||
@ -237,10 +242,7 @@ public:
|
||||
SectionPiece *getSectionPiece(uint64_t Offset);
|
||||
const SectionPiece *getSectionPiece(uint64_t Offset) const;
|
||||
|
||||
// MergeInputSections are aggregated to a synthetic input sections,
|
||||
// and then added to an OutputSection. This pointer points to a
|
||||
// synthetic MergeSyntheticSection which this section belongs to.
|
||||
MergeSyntheticSection *MergeSec = nullptr;
|
||||
SyntheticSection *getParent() const;
|
||||
|
||||
private:
|
||||
void splitStrings(ArrayRef<uint8_t> A, size_t Size);
|
||||
@ -280,7 +282,8 @@ public:
|
||||
// Splittable sections are handled as a sequence of data
|
||||
// rather than a single large blob of data.
|
||||
std::vector<EhSectionPiece> Pieces;
|
||||
SyntheticSection *EHSec = nullptr;
|
||||
|
||||
SyntheticSection *getParent() const;
|
||||
};
|
||||
|
||||
// This is a section that is added directly to an output section
|
||||
@ -299,6 +302,8 @@ public:
|
||||
// beginning of the output section.
|
||||
template <class ELFT> void writeTo(uint8_t *Buf);
|
||||
|
||||
OutputSection *getParent() const;
|
||||
|
||||
// The offset from beginning of the output sections this section was assigned
|
||||
// to. The writer sets a value.
|
||||
uint64_t OutSecOff = 0;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Compression.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
@ -51,9 +52,8 @@ LinkerScript *elf::Script;
|
||||
|
||||
uint64_t ExprValue::getValue() const {
|
||||
if (Sec) {
|
||||
if (Sec->getOutputSection())
|
||||
return alignTo(Sec->getOffset(Val) + Sec->getOutputSection()->Addr,
|
||||
Alignment);
|
||||
if (OutputSection *OS = Sec->getOutputSection())
|
||||
return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment);
|
||||
error("unable to evaluate expression: input section " + Sec->Name +
|
||||
" has no output section assigned");
|
||||
}
|
||||
@ -85,29 +85,28 @@ template <class ELFT> static SymbolBody *addRegular(SymbolAssignment *Cmd) {
|
||||
return Sym->body();
|
||||
}
|
||||
|
||||
OutputSection *LinkerScript::getOutputSection(const Twine &Loc,
|
||||
StringRef Name) {
|
||||
for (OutputSection *Sec : *OutputSections)
|
||||
if (Sec->Name == Name)
|
||||
return Sec;
|
||||
|
||||
static OutputSection Dummy("", 0, 0);
|
||||
if (ErrorOnMissingSection)
|
||||
error(Loc + ": undefined section " + Name);
|
||||
return &Dummy;
|
||||
OutputSectionCommand *
|
||||
LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) {
|
||||
OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
|
||||
OutputSectionCommand *Cmd;
|
||||
if (CmdRef && CmdRef->Location.empty()) {
|
||||
// There was a forward reference.
|
||||
Cmd = CmdRef;
|
||||
} else {
|
||||
Cmd = make<OutputSectionCommand>(Name);
|
||||
if (!CmdRef)
|
||||
CmdRef = Cmd;
|
||||
}
|
||||
Cmd->Location = Location;
|
||||
return Cmd;
|
||||
}
|
||||
|
||||
// This function is essentially the same as getOutputSection(Name)->Size,
|
||||
// but it won't print out an error message if a given section is not found.
|
||||
//
|
||||
// Linker script does not create an output section if its content is empty.
|
||||
// We want to allow SIZEOF(.foo) where .foo is a section which happened to
|
||||
// be empty. That is why this function is different from getOutputSection().
|
||||
uint64_t LinkerScript::getOutputSectionSize(StringRef Name) {
|
||||
for (OutputSection *Sec : *OutputSections)
|
||||
if (Sec->Name == Name)
|
||||
return Sec->Size;
|
||||
return 0;
|
||||
OutputSectionCommand *
|
||||
LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) {
|
||||
OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
|
||||
if (!CmdRef)
|
||||
CmdRef = make<OutputSectionCommand>(Name);
|
||||
return CmdRef;
|
||||
}
|
||||
|
||||
void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
|
||||
@ -291,12 +290,14 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
|
||||
size_t SizeBefore = Ret.size();
|
||||
|
||||
for (InputSectionBase *Sec : InputSections) {
|
||||
if (!isa<InputSection>(Sec))
|
||||
continue;
|
||||
|
||||
if (Sec->Assigned)
|
||||
continue;
|
||||
|
||||
if (!Sec->Live) {
|
||||
reportDiscarded(Sec);
|
||||
continue;
|
||||
}
|
||||
|
||||
// For -emit-relocs we have to ignore entries like
|
||||
// .rela.dyn : { *(.rela.data) }
|
||||
// which are common because they are in the default bfd script.
|
||||
@ -455,7 +456,7 @@ void LinkerScript::fabricateDefaultCommands() {
|
||||
// For each OutputSection that needs a VA fabricate an OutputSectionCommand
|
||||
// with an InputSectionDescription describing the InputSections
|
||||
for (OutputSection *Sec : *OutputSections) {
|
||||
auto *OSCmd = make<OutputSectionCommand>(Sec->Name);
|
||||
auto *OSCmd = createOutputSectionCommand(Sec->Name, "<internal>");
|
||||
OSCmd->Sec = Sec;
|
||||
SecToCommand[Sec] = OSCmd;
|
||||
|
||||
@ -487,7 +488,7 @@ void LinkerScript::fabricateDefaultCommands() {
|
||||
// Add sections that didn't match any sections command.
|
||||
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
|
||||
for (InputSectionBase *S : InputSections) {
|
||||
if (!S->Live || S->OutSec)
|
||||
if (!S->Live || S->Parent)
|
||||
continue;
|
||||
StringRef Name = getOutputSectionName(S->Name);
|
||||
auto I = std::find_if(
|
||||
@ -590,7 +591,7 @@ void LinkerScript::process(BaseCommand &Base) {
|
||||
// It calculates and assigns the offsets for each section and also
|
||||
// updates the output section size.
|
||||
auto &Cmd = cast<InputSectionDescription>(Base);
|
||||
for (InputSectionBase *Sec : Cmd.Sections) {
|
||||
for (InputSection *Sec : Cmd.Sections) {
|
||||
// We tentatively added all synthetic sections at the beginning and removed
|
||||
// empty ones afterwards (because there is no way to know whether they were
|
||||
// going be empty or not other than actually running linker scripts.)
|
||||
@ -601,8 +602,8 @@ void LinkerScript::process(BaseCommand &Base) {
|
||||
|
||||
if (!Sec->Live)
|
||||
continue;
|
||||
assert(CurOutSec == Sec->OutSec);
|
||||
output(cast<InputSection>(Sec));
|
||||
assert(CurOutSec == Sec->getParent());
|
||||
output(Sec);
|
||||
}
|
||||
}
|
||||
|
||||
@ -842,7 +843,7 @@ void LinkerScript::placeOrphanSections() {
|
||||
// representations agree on which input sections to use.
|
||||
OutputSectionCommand *Cmd = getCmd(Sec);
|
||||
if (!Cmd) {
|
||||
Cmd = make<OutputSectionCommand>(Name);
|
||||
Cmd = createOutputSectionCommand(Name, "<internal>");
|
||||
Opt.Commands.insert(CmdIter, Cmd);
|
||||
++CmdIndex;
|
||||
|
||||
@ -919,9 +920,10 @@ void LinkerScript::synchronize() {
|
||||
}
|
||||
}
|
||||
|
||||
static bool allocateHeaders(std::vector<PhdrEntry> &Phdrs,
|
||||
ArrayRef<OutputSection *> OutputSections,
|
||||
uint64_t Min) {
|
||||
static bool
|
||||
allocateHeaders(std::vector<PhdrEntry> &Phdrs,
|
||||
ArrayRef<OutputSectionCommand *> OutputSectionCommands,
|
||||
uint64_t Min) {
|
||||
auto FirstPTLoad =
|
||||
std::find_if(Phdrs.begin(), Phdrs.end(),
|
||||
[](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
|
||||
@ -938,16 +940,19 @@ static bool allocateHeaders(std::vector<PhdrEntry> &Phdrs,
|
||||
|
||||
assert(FirstPTLoad->First == Out::ElfHeader);
|
||||
OutputSection *ActualFirst = nullptr;
|
||||
for (OutputSection *Sec : OutputSections) {
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
if (Sec->FirstInPtLoad == Out::ElfHeader) {
|
||||
ActualFirst = Sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ActualFirst) {
|
||||
for (OutputSection *Sec : OutputSections)
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
if (Sec->FirstInPtLoad == Out::ElfHeader)
|
||||
Sec->FirstInPtLoad = ActualFirst;
|
||||
}
|
||||
FirstPTLoad->First = ActualFirst;
|
||||
} else {
|
||||
Phdrs.erase(FirstPTLoad);
|
||||
@ -961,7 +966,9 @@ static bool allocateHeaders(std::vector<PhdrEntry> &Phdrs,
|
||||
return false;
|
||||
}
|
||||
|
||||
void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
|
||||
void LinkerScript::assignAddresses(
|
||||
std::vector<PhdrEntry> &Phdrs,
|
||||
ArrayRef<OutputSectionCommand *> OutputSectionCommands) {
|
||||
// Assign addresses as instructed by linker script SECTIONS sub-commands.
|
||||
Dot = 0;
|
||||
ErrorOnMissingSection = true;
|
||||
@ -983,14 +990,15 @@ void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
|
||||
}
|
||||
|
||||
uint64_t MinVA = std::numeric_limits<uint64_t>::max();
|
||||
for (OutputSection *Sec : *OutputSections) {
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
if (Sec->Flags & SHF_ALLOC)
|
||||
MinVA = std::min<uint64_t>(MinVA, Sec->Addr);
|
||||
else
|
||||
Sec->Addr = 0;
|
||||
}
|
||||
|
||||
allocateHeaders(Phdrs, *OutputSections, MinVA);
|
||||
allocateHeaders(Phdrs, OutputSectionCommands, MinVA);
|
||||
}
|
||||
|
||||
// Creates program headers as instructed by PHDRS linker script command.
|
||||
@ -1068,6 +1076,33 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
|
||||
llvm_unreachable("unsupported Size argument");
|
||||
}
|
||||
|
||||
// Compress section contents if this section contains debug info.
|
||||
template <class ELFT> void OutputSectionCommand::maybeCompress() {
|
||||
typedef typename ELFT::Chdr Elf_Chdr;
|
||||
|
||||
// Compress only DWARF debug sections.
|
||||
if (!Config->CompressDebugSections || (Sec->Flags & SHF_ALLOC) ||
|
||||
!Name.startswith(".debug_"))
|
||||
return;
|
||||
|
||||
// Create a section header.
|
||||
Sec->ZDebugHeader.resize(sizeof(Elf_Chdr));
|
||||
auto *Hdr = reinterpret_cast<Elf_Chdr *>(Sec->ZDebugHeader.data());
|
||||
Hdr->ch_type = ELFCOMPRESS_ZLIB;
|
||||
Hdr->ch_size = Sec->Size;
|
||||
Hdr->ch_addralign = Sec->Alignment;
|
||||
|
||||
// Write section contents to a temporary buffer and compress it.
|
||||
std::vector<uint8_t> Buf(Sec->Size);
|
||||
writeTo<ELFT>(Buf.data());
|
||||
if (Error E = zlib::compress(toStringRef(Buf), Sec->CompressedData))
|
||||
fatal("compress failed: " + llvm::toString(std::move(E)));
|
||||
|
||||
// Update section headers.
|
||||
Sec->Size = sizeof(Elf_Chdr) + Sec->CompressedData.size();
|
||||
Sec->Flags |= SHF_COMPRESSED;
|
||||
}
|
||||
|
||||
template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
|
||||
Sec->Loc = Buf;
|
||||
|
||||
@ -1084,7 +1119,12 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
|
||||
return;
|
||||
|
||||
// Write leading padding.
|
||||
ArrayRef<InputSection *> Sections = Sec->Sections;
|
||||
std::vector<InputSection *> Sections;
|
||||
for (BaseCommand *Cmd : Commands)
|
||||
if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
|
||||
for (InputSection *IS : ISD->Sections)
|
||||
if (IS->Live)
|
||||
Sections.push_back(IS);
|
||||
uint32_t Filler = getFiller();
|
||||
if (Filler)
|
||||
fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler);
|
||||
@ -1161,3 +1201,8 @@ template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf);
|
||||
template void OutputSectionCommand::writeTo<ELF32BE>(uint8_t *Buf);
|
||||
template void OutputSectionCommand::writeTo<ELF64LE>(uint8_t *Buf);
|
||||
template void OutputSectionCommand::writeTo<ELF64BE>(uint8_t *Buf);
|
||||
|
||||
template void OutputSectionCommand::maybeCompress<ELF32LE>();
|
||||
template void OutputSectionCommand::maybeCompress<ELF32BE>();
|
||||
template void OutputSectionCommand::maybeCompress<ELF64LE>();
|
||||
template void OutputSectionCommand::maybeCompress<ELF64BE>();
|
||||
|
@ -137,6 +137,7 @@ struct OutputSectionCommand : BaseCommand {
|
||||
std::string MemoryRegionName;
|
||||
|
||||
template <class ELFT> void writeTo(uint8_t *Buf);
|
||||
template <class ELFT> void maybeCompress();
|
||||
uint32_t getFiller();
|
||||
};
|
||||
|
||||
@ -221,6 +222,8 @@ struct ScriptConfiguration {
|
||||
|
||||
class LinkerScript final {
|
||||
llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
|
||||
llvm::DenseMap<StringRef, OutputSectionCommand *> NameToOutputSectionCommand;
|
||||
|
||||
void assignSymbol(SymbolAssignment *Cmd, bool InSec);
|
||||
void setDot(Expr E, const Twine &Loc, bool InSec);
|
||||
|
||||
@ -241,7 +244,6 @@ class LinkerScript final {
|
||||
void process(BaseCommand &Base);
|
||||
|
||||
OutputSection *Aether;
|
||||
bool ErrorOnMissingSection = false;
|
||||
|
||||
uint64_t Dot;
|
||||
uint64_t ThreadBssOffset = 0;
|
||||
@ -251,11 +253,14 @@ class LinkerScript final {
|
||||
MemoryRegion *CurMemRegion = nullptr;
|
||||
|
||||
public:
|
||||
bool ErrorOnMissingSection = false;
|
||||
OutputSectionCommand *createOutputSectionCommand(StringRef Name,
|
||||
StringRef Location);
|
||||
OutputSectionCommand *getOrCreateOutputSectionCommand(StringRef Name);
|
||||
|
||||
OutputSectionCommand *getCmd(OutputSection *Sec) const;
|
||||
bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
|
||||
uint64_t getDot() { return Dot; }
|
||||
OutputSection *getOutputSection(const Twine &Loc, StringRef S);
|
||||
uint64_t getOutputSectionSize(StringRef S);
|
||||
void discard(ArrayRef<InputSectionBase *> V);
|
||||
|
||||
ExprValue getSymbolValue(const Twine &Loc, StringRef S);
|
||||
@ -277,7 +282,8 @@ public:
|
||||
void placeOrphanSections();
|
||||
void processNonSectionCommands();
|
||||
void synchronize();
|
||||
void assignAddresses(std::vector<PhdrEntry> &Phdrs);
|
||||
void assignAddresses(std::vector<PhdrEntry> &Phdrs,
|
||||
ArrayRef<OutputSectionCommand *> OutputSectionCommands);
|
||||
|
||||
void addSymbol(SymbolAssignment *Cmd);
|
||||
void processCommands(OutputSectionFactory &Factory);
|
||||
|
@ -220,7 +220,8 @@ template <class ELFT> void elf::markLive() {
|
||||
|
||||
auto MarkSymbol = [&](const SymbolBody *Sym) {
|
||||
if (auto *D = dyn_cast_or_null<DefinedRegular>(Sym))
|
||||
Enqueue({cast<InputSectionBase>(D->Section), D->Value});
|
||||
if (auto *IS = cast_or_null<InputSectionBase>(D->Section))
|
||||
Enqueue({IS, D->Value});
|
||||
};
|
||||
|
||||
// Add GC root symbols.
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "SyntheticSections.h"
|
||||
#include "Target.h"
|
||||
#include "Threads.h"
|
||||
#include "llvm/Support/Compression.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/MD5.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
@ -76,46 +75,19 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) {
|
||||
if (A->kind() == InputSectionBase::Synthetic ||
|
||||
B->kind() == InputSectionBase::Synthetic)
|
||||
return false;
|
||||
auto *LA = cast<InputSection>(A->getLinkOrderDep());
|
||||
auto *LB = cast<InputSection>(B->getLinkOrderDep());
|
||||
OutputSection *AOut = LA->OutSec;
|
||||
OutputSection *BOut = LB->OutSec;
|
||||
InputSection *LA = A->getLinkOrderDep();
|
||||
InputSection *LB = B->getLinkOrderDep();
|
||||
OutputSection *AOut = LA->getParent();
|
||||
OutputSection *BOut = LB->getParent();
|
||||
if (AOut != BOut)
|
||||
return AOut->SectionIndex < BOut->SectionIndex;
|
||||
return LA->OutSecOff < LB->OutSecOff;
|
||||
}
|
||||
|
||||
// Compress section contents if this section contains debug info.
|
||||
template <class ELFT> void OutputSection::maybeCompress() {
|
||||
typedef typename ELFT::Chdr Elf_Chdr;
|
||||
|
||||
// Compress only DWARF debug sections.
|
||||
if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) ||
|
||||
!Name.startswith(".debug_"))
|
||||
return;
|
||||
|
||||
// Create a section header.
|
||||
ZDebugHeader.resize(sizeof(Elf_Chdr));
|
||||
auto *Hdr = reinterpret_cast<Elf_Chdr *>(ZDebugHeader.data());
|
||||
Hdr->ch_type = ELFCOMPRESS_ZLIB;
|
||||
Hdr->ch_size = Size;
|
||||
Hdr->ch_addralign = Alignment;
|
||||
|
||||
// Write section contents to a temporary buffer and compress it.
|
||||
std::vector<uint8_t> Buf(Size);
|
||||
Script->getCmd(this)->writeTo<ELFT>(Buf.data());
|
||||
if (Error E = zlib::compress(toStringRef(Buf), CompressedData))
|
||||
fatal("compress failed: " + llvm::toString(std::move(E)));
|
||||
|
||||
// Update section headers.
|
||||
Size = sizeof(Elf_Chdr) + CompressedData.size();
|
||||
Flags |= SHF_COMPRESSED;
|
||||
}
|
||||
|
||||
template <class ELFT> static void finalizeShtGroup(OutputSection *Sec) {
|
||||
// sh_link field for SHT_GROUP sections should contain the section index of
|
||||
// the symbol table.
|
||||
Sec->Link = InX::SymTab->OutSec->SectionIndex;
|
||||
Sec->Link = InX::SymTab->getParent()->SectionIndex;
|
||||
|
||||
// sh_info then contain index of an entry in symbol table section which
|
||||
// provides signature of the section group.
|
||||
@ -135,7 +107,7 @@ template <class ELFT> void OutputSection::finalize() {
|
||||
// need to translate the InputSection sh_link to the OutputSection sh_link,
|
||||
// all InputSections in the OutputSection have the same dependency.
|
||||
if (auto *D = this->Sections.front()->getLinkOrderDep())
|
||||
this->Link = D->OutSec->SectionIndex;
|
||||
this->Link = D->getParent()->SectionIndex;
|
||||
}
|
||||
|
||||
uint32_t Type = this->Type;
|
||||
@ -151,11 +123,11 @@ template <class ELFT> void OutputSection::finalize() {
|
||||
if (isa<SyntheticSection>(First))
|
||||
return;
|
||||
|
||||
this->Link = InX::SymTab->OutSec->SectionIndex;
|
||||
this->Link = InX::SymTab->getParent()->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();
|
||||
this->Info = S->OutSec->SectionIndex;
|
||||
Info = S->getOutputSection()->SectionIndex;
|
||||
}
|
||||
|
||||
static uint64_t updateOffset(uint64_t Off, InputSection *S) {
|
||||
@ -167,7 +139,7 @@ static uint64_t updateOffset(uint64_t Off, InputSection *S) {
|
||||
void OutputSection::addSection(InputSection *S) {
|
||||
assert(S->Live);
|
||||
Sections.push_back(S);
|
||||
S->OutSec = this;
|
||||
S->Parent = this;
|
||||
this->updateAlignment(S->Alignment);
|
||||
|
||||
// The actual offsets will be computed by assignAddresses. For now, use
|
||||
@ -351,7 +323,7 @@ static bool canMergeToProgbits(unsigned Type) {
|
||||
Type == SHT_NOTE;
|
||||
}
|
||||
|
||||
static void reportDiscarded(InputSectionBase *IS) {
|
||||
void elf::reportDiscarded(InputSectionBase *IS) {
|
||||
if (!Config->PrintGcSections)
|
||||
return;
|
||||
message("removing unused section from '" + IS->Name + "' in file '" +
|
||||
@ -437,8 +409,3 @@ template void OutputSection::finalize<ELF32LE>();
|
||||
template void OutputSection::finalize<ELF32BE>();
|
||||
template void OutputSection::finalize<ELF64LE>();
|
||||
template void OutputSection::finalize<ELF64BE>();
|
||||
|
||||
template void OutputSection::maybeCompress<ELF32LE>();
|
||||
template void OutputSection::maybeCompress<ELF32BE>();
|
||||
template void OutputSection::maybeCompress<ELF64LE>();
|
||||
template void OutputSection::maybeCompress<ELF64BE>();
|
||||
|
@ -83,7 +83,6 @@ public:
|
||||
void sortInitFini();
|
||||
void sortCtorsDtors();
|
||||
template <class ELFT> void finalize();
|
||||
template <class ELFT> void maybeCompress();
|
||||
void assignOffsets();
|
||||
std::vector<InputSection *> Sections;
|
||||
|
||||
@ -149,6 +148,7 @@ private:
|
||||
};
|
||||
|
||||
uint64_t getHeaderSize();
|
||||
void reportDiscarded(InputSectionBase *IS);
|
||||
|
||||
} // namespace elf
|
||||
} // namespace lld
|
||||
|
@ -360,9 +360,9 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
|
||||
// These expressions always compute a constant
|
||||
if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
|
||||
R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
|
||||
R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_PLT_PC,
|
||||
R_TLSGD_PC, R_TLSGD, R_PPC_PLT_OPD, R_TLSDESC_CALL,
|
||||
R_TLSDESC_PAGE, R_HINT>(E))
|
||||
R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC,
|
||||
R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
|
||||
R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
|
||||
return true;
|
||||
|
||||
// These never do, except if the entire file is position dependent or if
|
||||
@ -1015,7 +1015,7 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) {
|
||||
ThunkSection *TS = ThunkedSections.lookup(IS);
|
||||
if (TS)
|
||||
return TS;
|
||||
auto *TOS = cast<OutputSection>(IS->OutSec);
|
||||
auto *TOS = IS->getParent();
|
||||
TS = make<ThunkSection>(TOS, IS->OutSecOff);
|
||||
ThunkSections[TOS].push_back(TS);
|
||||
ThunkedSections[IS] = TS;
|
||||
|
@ -55,6 +55,7 @@ public:
|
||||
|
||||
private:
|
||||
void addFile(StringRef Path);
|
||||
OutputSection *checkSection(OutputSectionCommand *Cmd, StringRef Loccation);
|
||||
|
||||
void readAsNeeded();
|
||||
void readEntry();
|
||||
@ -564,8 +565,8 @@ uint32_t ScriptParser::readFill() {
|
||||
|
||||
OutputSectionCommand *
|
||||
ScriptParser::readOutputSectionDescription(StringRef OutSec) {
|
||||
OutputSectionCommand *Cmd = make<OutputSectionCommand>(OutSec);
|
||||
Cmd->Location = getCurrentLocation();
|
||||
OutputSectionCommand *Cmd =
|
||||
Script->createOutputSectionCommand(OutSec, getCurrentLocation());
|
||||
|
||||
// Read an address expression.
|
||||
// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
|
||||
@ -819,6 +820,16 @@ StringRef ScriptParser::readParenLiteral() {
|
||||
return Tok;
|
||||
}
|
||||
|
||||
OutputSection *ScriptParser::checkSection(OutputSectionCommand *Cmd,
|
||||
StringRef Location) {
|
||||
if (Cmd->Location.empty() && Script->ErrorOnMissingSection)
|
||||
error(Location + ": undefined section " + Cmd->Name);
|
||||
if (Cmd->Sec)
|
||||
return Cmd->Sec;
|
||||
static OutputSection Dummy("", 0, 0);
|
||||
return &Dummy;
|
||||
}
|
||||
|
||||
Expr ScriptParser::readPrimary() {
|
||||
if (peek() == "(")
|
||||
return readParenExpr();
|
||||
@ -847,9 +858,8 @@ Expr ScriptParser::readPrimary() {
|
||||
}
|
||||
if (Tok == "ADDR") {
|
||||
StringRef Name = readParenLiteral();
|
||||
return [=]() -> ExprValue {
|
||||
return {Script->getOutputSection(Location, Name), 0};
|
||||
};
|
||||
OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
|
||||
return [=]() -> ExprValue { return {checkSection(Cmd, Location), 0}; };
|
||||
}
|
||||
if (Tok == "ALIGN") {
|
||||
expect("(");
|
||||
@ -867,7 +877,8 @@ Expr ScriptParser::readPrimary() {
|
||||
}
|
||||
if (Tok == "ALIGNOF") {
|
||||
StringRef Name = readParenLiteral();
|
||||
return [=] { return Script->getOutputSection(Location, Name)->Alignment; };
|
||||
OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
|
||||
return [=] { return checkSection(Cmd, Location)->Alignment; };
|
||||
}
|
||||
if (Tok == "ASSERT")
|
||||
return readAssertExpr();
|
||||
@ -912,7 +923,8 @@ Expr ScriptParser::readPrimary() {
|
||||
}
|
||||
if (Tok == "LOADADDR") {
|
||||
StringRef Name = readParenLiteral();
|
||||
return [=] { return Script->getOutputSection(Location, Name)->getLMA(); };
|
||||
OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
|
||||
return [=] { return checkSection(Cmd, Location)->getLMA(); };
|
||||
}
|
||||
if (Tok == "ORIGIN") {
|
||||
StringRef Name = readParenLiteral();
|
||||
@ -930,7 +942,11 @@ Expr ScriptParser::readPrimary() {
|
||||
}
|
||||
if (Tok == "SIZEOF") {
|
||||
StringRef Name = readParenLiteral();
|
||||
return [=] { return Script->getOutputSectionSize(Name); };
|
||||
OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
|
||||
// Linker script does not create an output section if its content is empty.
|
||||
// We want to allow SIZEOF(.foo) where .foo is a section which happened to
|
||||
// be empty.
|
||||
return [=] { return Cmd->Sec ? Cmd->Sec->Size : 0; };
|
||||
}
|
||||
if (Tok == "SIZEOF_HEADERS")
|
||||
return [=] { return elf::getHeaderSize(); };
|
||||
|
@ -101,12 +101,12 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) {
|
||||
case SymbolBody::DefinedCommonKind:
|
||||
if (!Config->DefineCommon)
|
||||
return 0;
|
||||
return InX::Common->OutSec->Addr + InX::Common->OutSecOff +
|
||||
return InX::Common->getParent()->Addr + InX::Common->OutSecOff +
|
||||
cast<DefinedCommon>(Body).Offset;
|
||||
case SymbolBody::SharedKind: {
|
||||
auto &SS = cast<SharedSymbol>(Body);
|
||||
if (SS.NeedsCopy)
|
||||
return SS.CopyRelSec->OutSec->Addr + SS.CopyRelSec->OutSecOff +
|
||||
return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff +
|
||||
SS.CopyRelSecOff;
|
||||
if (SS.NeedsPltAddr)
|
||||
return Body.getPltVA();
|
||||
@ -207,13 +207,13 @@ OutputSection *SymbolBody::getOutputSection() const {
|
||||
|
||||
if (auto *S = dyn_cast<SharedSymbol>(this)) {
|
||||
if (S->NeedsCopy)
|
||||
return S->CopyRelSec->OutSec;
|
||||
return S->CopyRelSec->getParent();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (isa<DefinedCommon>(this)) {
|
||||
if (Config->DefineCommon)
|
||||
return InX::Common->OutSec;
|
||||
return InX::Common->getParent();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,8 @@ using namespace lld;
|
||||
using namespace lld::elf;
|
||||
|
||||
uint64_t SyntheticSection::getVA() const {
|
||||
if (this->OutSec)
|
||||
return this->OutSec->Addr + this->OutSecOff;
|
||||
if (OutputSection *Sec = getParent())
|
||||
return Sec->Addr + OutSecOff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -367,8 +367,8 @@ BssSection::BssSection(StringRef Name)
|
||||
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 0, Name) {}
|
||||
|
||||
size_t BssSection::reserveSpace(uint64_t Size, uint32_t Alignment) {
|
||||
if (OutSec)
|
||||
OutSec->updateAlignment(Alignment);
|
||||
if (OutputSection *Sec = getParent())
|
||||
Sec->updateAlignment(Alignment);
|
||||
this->Size = alignTo(this->Size, Alignment) + Size;
|
||||
this->Alignment = std::max(this->Alignment, Alignment);
|
||||
return this->Size - Size;
|
||||
@ -494,7 +494,7 @@ void EhFrameSection<ELFT>::addSectionAux(EhInputSection *Sec,
|
||||
template <class ELFT>
|
||||
void EhFrameSection<ELFT>::addSection(InputSectionBase *C) {
|
||||
auto *Sec = cast<EhInputSection>(C);
|
||||
Sec->EHSec = this;
|
||||
Sec->Parent = this;
|
||||
updateAlignment(Sec->Alignment);
|
||||
Sections.push_back(Sec);
|
||||
for (auto *DS : Sec->DependentSections)
|
||||
@ -579,7 +579,7 @@ uint64_t EhFrameSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
|
||||
if ((Enc & 0x70) == DW_EH_PE_absptr)
|
||||
return Addr;
|
||||
if ((Enc & 0x70) == DW_EH_PE_pcrel)
|
||||
return Addr + this->OutSec->Addr + Off;
|
||||
return Addr + getParent()->Addr + Off;
|
||||
fatal("unknown FDE size relative encoding");
|
||||
}
|
||||
|
||||
@ -610,7 +610,7 @@ template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
|
||||
for (SectionPiece *Fde : Cie->FdePieces) {
|
||||
uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
|
||||
uint64_t FdeVA = this->OutSec->Addr + Fde->OutputOff;
|
||||
uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
|
||||
In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
|
||||
}
|
||||
}
|
||||
@ -698,8 +698,7 @@ void MipsGotSection::addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr) {
|
||||
// sections referenced by GOT relocations. Then later in the `finalize`
|
||||
// method calculate number of "pages" required to cover all saved output
|
||||
// section and allocate appropriate number of GOT entries.
|
||||
auto *DefSym = cast<DefinedRegular>(&Sym);
|
||||
PageIndexMap.insert({DefSym->Section->getOutputSection(), 0});
|
||||
PageIndexMap.insert({Sym.getOutputSection(), 0});
|
||||
return;
|
||||
}
|
||||
if (Sym.isTls()) {
|
||||
@ -766,8 +765,7 @@ static uint64_t getMipsPageCount(uint64_t Size) {
|
||||
|
||||
uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &B,
|
||||
int64_t Addend) const {
|
||||
const OutputSection *OutSec =
|
||||
cast<DefinedRegular>(&B)->Section->getOutputSection();
|
||||
const OutputSection *OutSec = B.getOutputSection();
|
||||
uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
|
||||
uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend));
|
||||
uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
|
||||
@ -1071,11 +1069,11 @@ 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) {
|
||||
this->Link = InX::DynStrTab->getParent()->SectionIndex;
|
||||
if (In<ELFT>::RelaDyn->getParent()->Size > 0) {
|
||||
bool IsRela = Config->IsRela;
|
||||
add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
|
||||
add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->OutSec->Size});
|
||||
add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent()->Size});
|
||||
add({IsRela ? DT_RELAENT : DT_RELENT,
|
||||
uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
|
||||
|
||||
@ -1088,9 +1086,9 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
||||
add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels});
|
||||
}
|
||||
}
|
||||
if (In<ELFT>::RelaPlt->OutSec->Size > 0) {
|
||||
if (In<ELFT>::RelaPlt->getParent()->Size > 0) {
|
||||
add({DT_JMPREL, In<ELFT>::RelaPlt});
|
||||
add({DT_PLTRELSZ, In<ELFT>::RelaPlt->OutSec->Size});
|
||||
add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent()->Size});
|
||||
add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
|
||||
InX::GotPlt});
|
||||
add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)});
|
||||
@ -1152,7 +1150,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
||||
add({DT_MIPS_RLD_MAP, InX::MipsRldMap});
|
||||
}
|
||||
|
||||
this->OutSec->Link = this->Link;
|
||||
getParent()->Link = this->Link;
|
||||
|
||||
// +1 for DT_NULL
|
||||
this->Size = (Entries.size() + 1) * this->Entsize;
|
||||
@ -1168,7 +1166,7 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
P->d_un.d_ptr = E.OutSec->Addr;
|
||||
break;
|
||||
case Entry::InSecAddr:
|
||||
P->d_un.d_ptr = E.InSec->OutSec->Addr + E.InSec->OutSecOff;
|
||||
P->d_un.d_ptr = E.InSec->getParent()->Addr + E.InSec->OutSecOff;
|
||||
break;
|
||||
case Entry::SecSize:
|
||||
P->d_un.d_val = E.OutSec->Size;
|
||||
@ -1185,7 +1183,7 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
}
|
||||
|
||||
uint64_t DynamicReloc::getOffset() const {
|
||||
return InputSec->OutSec->Addr + InputSec->getOffset(OffsetInSec);
|
||||
return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec);
|
||||
}
|
||||
|
||||
int64_t DynamicReloc::getAddend() const {
|
||||
@ -1258,11 +1256,11 @@ template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
|
||||
}
|
||||
|
||||
template <class ELFT> void RelocationSection<ELFT>::finalizeContents() {
|
||||
this->Link = InX::DynSymTab ? InX::DynSymTab->OutSec->SectionIndex
|
||||
: InX::SymTab->OutSec->SectionIndex;
|
||||
this->Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex
|
||||
: InX::SymTab->getParent()->SectionIndex;
|
||||
|
||||
// Set required output section properties.
|
||||
this->OutSec->Link = this->Link;
|
||||
getParent()->Link = this->Link;
|
||||
}
|
||||
|
||||
SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
|
||||
@ -1293,14 +1291,14 @@ static bool sortMipsSymbols(const SymbolTableEntry &L,
|
||||
// function. (For .dynsym, we don't do that because symbols for
|
||||
// dynamic linking are inherently all globals.)
|
||||
void SymbolTableBaseSection::finalizeContents() {
|
||||
this->OutSec->Link = StrTabSec.OutSec->SectionIndex;
|
||||
getParent()->Link = StrTabSec.getParent()->SectionIndex;
|
||||
|
||||
// If it is a .dynsym, there should be no local symbols, but we need
|
||||
// to do a few things for the dynamic linker.
|
||||
if (this->Type == SHT_DYNSYM) {
|
||||
// Section's Info field has the index of the first non-local symbol.
|
||||
// Because the first symbol entry is a null entry, 1 is the first.
|
||||
this->OutSec->Info = 1;
|
||||
getParent()->Info = 1;
|
||||
|
||||
if (InX::GnuHashTab) {
|
||||
// NB: It also sorts Symbols to meet the GNU hash table requirements.
|
||||
@ -1326,7 +1324,7 @@ void SymbolTableBaseSection::postThunkContents() {
|
||||
S.Symbol->symbol()->computeBinding() == STB_LOCAL;
|
||||
});
|
||||
size_t NumLocals = It - Symbols.begin();
|
||||
this->OutSec->Info = NumLocals + 1;
|
||||
getParent()->Info = NumLocals + 1;
|
||||
}
|
||||
|
||||
void SymbolTableBaseSection::addSymbol(SymbolBody *B) {
|
||||
@ -1344,8 +1342,7 @@ size_t SymbolTableBaseSection::getSymbolIndex(SymbolBody *Body) {
|
||||
// This is used for -r, so we have to handle multiple section
|
||||
// symbols being combined.
|
||||
if (Body->Type == STT_SECTION && E.Symbol->Type == STT_SECTION)
|
||||
return cast<DefinedRegular>(Body)->Section->getOutputSection() ==
|
||||
cast<DefinedRegular>(E.Symbol)->Section->getOutputSection();
|
||||
return Body->getOutputSection() == E.Symbol->getOutputSection();
|
||||
return false;
|
||||
});
|
||||
if (I == Symbols.end())
|
||||
@ -1456,7 +1453,7 @@ GnuHashTableSection::GnuHashTableSection()
|
||||
}
|
||||
|
||||
void GnuHashTableSection::finalizeContents() {
|
||||
this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex;
|
||||
getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
|
||||
|
||||
// Computes bloom filter size in word size. We want to allocate 8
|
||||
// bits for each symbol. It must be a power of two.
|
||||
@ -1590,7 +1587,7 @@ HashTableSection<ELFT>::HashTableSection()
|
||||
}
|
||||
|
||||
template <class ELFT> void HashTableSection<ELFT>::finalizeContents() {
|
||||
this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex;
|
||||
getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
|
||||
|
||||
unsigned NumEntries = 2; // nbucket and nchain.
|
||||
NumEntries += InX::DynSymTab->getNumSymbols(); // The chain entries.
|
||||
@ -1801,7 +1798,7 @@ void GdbIndexSection::finalizeContents() {
|
||||
|
||||
for (InputSectionBase *S : InputSections)
|
||||
if (InputSection *IS = dyn_cast<InputSection>(S))
|
||||
if (IS->OutSec && IS->Name == ".debug_info")
|
||||
if (IS->getParent() && IS->Name == ".debug_info")
|
||||
readDwarf(IS);
|
||||
|
||||
SymbolTable.finalizeContents();
|
||||
@ -1846,7 +1843,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
|
||||
|
||||
// Write the address area.
|
||||
for (AddressEntry &E : AddressArea) {
|
||||
uint64_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0);
|
||||
uint64_t BaseAddr = E.Section->getParent()->Addr + E.Section->getOffset(0);
|
||||
write64le(Buf, BaseAddr + E.LowAddress);
|
||||
write64le(Buf + 8, BaseAddr + E.HighAddress);
|
||||
write32le(Buf + 16, E.CuIndex);
|
||||
@ -1906,7 +1903,7 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
|
||||
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
|
||||
Buf[2] = DW_EH_PE_udata4;
|
||||
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
|
||||
write32<E>(Buf + 4, In<ELFT>::EhFrame->OutSec->Addr - this->getVA() - 4);
|
||||
write32<E>(Buf + 4, In<ELFT>::EhFrame->getParent()->Addr - this->getVA() - 4);
|
||||
write32<E>(Buf + 8, Fdes.size());
|
||||
Buf += 12;
|
||||
|
||||
@ -1948,12 +1945,12 @@ template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() {
|
||||
for (VersionDefinition &V : Config->VersionDefinitions)
|
||||
V.NameOff = InX::DynStrTab->addString(V.Name);
|
||||
|
||||
this->OutSec->Link = InX::DynStrTab->OutSec->SectionIndex;
|
||||
getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
|
||||
|
||||
// sh_info should be set to the number of definitions. This fact is missed in
|
||||
// documentation, but confirmed by binutils community:
|
||||
// https://sourceware.org/ml/binutils/2014-11/msg00355.html
|
||||
this->OutSec->Info = getVerDefNum();
|
||||
getParent()->Info = getVerDefNum();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
@ -2001,7 +1998,7 @@ 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 = InX::DynSymTab->OutSec->SectionIndex;
|
||||
getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
|
||||
}
|
||||
|
||||
template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
|
||||
@ -2093,8 +2090,8 @@ template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
}
|
||||
|
||||
template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
|
||||
this->OutSec->Link = InX::DynStrTab->OutSec->SectionIndex;
|
||||
this->OutSec->Info = Needed.size();
|
||||
getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
|
||||
getParent()->Info = Needed.size();
|
||||
}
|
||||
|
||||
template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const {
|
||||
@ -2115,7 +2112,7 @@ MergeSyntheticSection::MergeSyntheticSection(StringRef Name, uint32_t Type,
|
||||
|
||||
void MergeSyntheticSection::addSection(MergeInputSection *MS) {
|
||||
assert(!Finalized);
|
||||
MS->MergeSec = this;
|
||||
MS->Parent = this;
|
||||
Sections.push_back(MS);
|
||||
}
|
||||
|
||||
@ -2186,13 +2183,23 @@ ARMExidxSentinelSection::ARMExidxSentinelSection()
|
||||
// This section will have been sorted last in the .ARM.exidx table.
|
||||
// This table entry will have the form:
|
||||
// | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND |
|
||||
// The sentinel must have the PREL31 value of an address higher than any
|
||||
// address described by any other table entry.
|
||||
void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
|
||||
// Get the InputSection before us, we are by definition last
|
||||
auto RI = this->OutSec->Sections.rbegin();
|
||||
InputSection *LE = *(++RI);
|
||||
InputSection *LC = cast<InputSection>(LE->getLinkOrderDep());
|
||||
uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize());
|
||||
uint64_t P = this->getVA();
|
||||
// The Sections are sorted in order of ascending PREL31 address with the
|
||||
// sentinel last. We need to find the InputSection that precedes the
|
||||
// sentinel. By construction the Sentinel is in the last
|
||||
// InputSectionDescription as the InputSection that precedes it.
|
||||
OutputSectionCommand *C = Script->getCmd(getParent());
|
||||
auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(),
|
||||
[](const BaseCommand *Base) {
|
||||
return isa<InputSectionDescription>(Base);
|
||||
});
|
||||
auto L = cast<InputSectionDescription>(*ISD);
|
||||
InputSection *Highest = L->Sections[L->Sections.size() - 2];
|
||||
InputSection *LS = Highest->getLinkOrderDep();
|
||||
uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize());
|
||||
uint64_t P = getVA();
|
||||
Target->relocateOne(Buf, R_ARM_PREL31, S - P);
|
||||
write32le(Buf + 4, 0x1);
|
||||
}
|
||||
@ -2200,7 +2207,7 @@ void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
|
||||
ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
|
||||
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
|
||||
Config->Wordsize, ".text.thunk") {
|
||||
this->OutSec = OS;
|
||||
this->Parent = OS;
|
||||
this->OutSecOff = Off;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
virtual bool empty() const { return false; }
|
||||
uint64_t getVA() const;
|
||||
|
||||
static bool classof(const InputSectionBase *D) {
|
||||
static bool classof(const SectionBase *D) {
|
||||
return D->kind() == InputSectionBase::Synthetic;
|
||||
}
|
||||
};
|
||||
|
@ -62,10 +62,10 @@ static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); }
|
||||
template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) {
|
||||
for (InputSectionBase *D : InputSections) {
|
||||
auto *IS = dyn_cast_or_null<InputSection>(D);
|
||||
if (!IS || !IS->OutSec)
|
||||
if (!IS || !IS->getParent())
|
||||
continue;
|
||||
|
||||
uint8_t *ISLoc = cast<OutputSection>(IS->OutSec)->Loc + IS->OutSecOff;
|
||||
uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff;
|
||||
if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
|
||||
return IS->template getLocation<ELFT>(Loc - ISLoc) + ": ";
|
||||
}
|
||||
|
@ -261,23 +261,26 @@ template <class ELFT> void Writer<ELFT>::run() {
|
||||
if (!Config->Relocatable)
|
||||
fixSectionAlignments();
|
||||
Script->fabricateDefaultCommands();
|
||||
} else {
|
||||
Script->synchronize();
|
||||
}
|
||||
|
||||
for (BaseCommand *Base : Script->Opt.Commands)
|
||||
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
|
||||
OutputSectionCommands.push_back(Cmd);
|
||||
|
||||
clearOutputSections();
|
||||
// If -compressed-debug-sections is specified, we need to compress
|
||||
// .debug_* sections. Do it right now because it changes the size of
|
||||
// output sections.
|
||||
parallelForEach(OutputSections.begin(), OutputSections.end(),
|
||||
[](OutputSection *S) { S->maybeCompress<ELFT>(); });
|
||||
parallelForEach(
|
||||
OutputSectionCommands.begin(), OutputSectionCommands.end(),
|
||||
[](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); });
|
||||
|
||||
if (Config->Relocatable) {
|
||||
assignFileOffsets();
|
||||
} else {
|
||||
Script->synchronize();
|
||||
Script->assignAddresses(Phdrs);
|
||||
Script->assignAddresses(Phdrs, OutputSectionCommands);
|
||||
|
||||
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
|
||||
// 0 sized region. This has to be done late since only after assignAddresses
|
||||
@ -300,13 +303,13 @@ template <class ELFT> void Writer<ELFT>::run() {
|
||||
openFile();
|
||||
if (ErrorCount)
|
||||
return;
|
||||
|
||||
if (!Config->OFormatBinary) {
|
||||
writeHeader();
|
||||
writeSections();
|
||||
} else {
|
||||
writeSectionsBinary();
|
||||
}
|
||||
clearOutputSections();
|
||||
|
||||
// Backfill .note.gnu.build-id section content. This is done at last
|
||||
// because the content is usually a hash value of the entire output file.
|
||||
@ -613,27 +616,27 @@ 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 (InX::Got && Sec == InX::Got->OutSec)
|
||||
if (InX::Got && Sec == InX::Got->getParent())
|
||||
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 == InX::GotPlt->OutSec)
|
||||
if (Sec == InX::GotPlt->getParent())
|
||||
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 == InX::Dynamic->OutSec)
|
||||
if (Sec == InX::Dynamic->getParent())
|
||||
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 == InX::BssRelRo->OutSec)
|
||||
if (Sec == InX::BssRelRo->getParent())
|
||||
return true;
|
||||
|
||||
// Sections with some special names are put into RELRO. This is a
|
||||
@ -1112,9 +1115,9 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
|
||||
static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
|
||||
std::function<void(SyntheticSection *)> Fn) {
|
||||
for (SyntheticSection *SS : Sections)
|
||||
if (SS && SS->OutSec && !SS->empty()) {
|
||||
if (SS && SS->getParent() && !SS->empty()) {
|
||||
Fn(SS);
|
||||
SS->OutSec->assignOffsets();
|
||||
SS->getParent()->assignOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1130,16 +1133,15 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
|
||||
SyntheticSection *SS = dyn_cast<SyntheticSection>(S);
|
||||
if (!SS)
|
||||
return;
|
||||
if (!SS->empty() || !SS->OutSec)
|
||||
OutputSection *OS = SS->getParent();
|
||||
if (!SS->empty() || !OS)
|
||||
continue;
|
||||
|
||||
SS->OutSec->Sections.erase(std::find(SS->OutSec->Sections.begin(),
|
||||
SS->OutSec->Sections.end(), SS));
|
||||
OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS));
|
||||
SS->Live = false;
|
||||
// If there are no other sections in the output section, remove it from the
|
||||
// output.
|
||||
if (SS->OutSec->Sections.empty())
|
||||
V.erase(std::find(V.begin(), V.end(), SS->OutSec));
|
||||
if (OS->Sections.empty())
|
||||
V.erase(std::find(V.begin(), V.end(), OS));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1427,8 +1429,8 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
|
||||
|
||||
// Add an entry for .dynamic.
|
||||
if (InX::DynSymTab)
|
||||
AddHdr(PT_DYNAMIC, InX::Dynamic->OutSec->getPhdrFlags())
|
||||
->add(InX::Dynamic->OutSec);
|
||||
AddHdr(PT_DYNAMIC, InX::Dynamic->getParent()->getPhdrFlags())
|
||||
->add(InX::Dynamic->getParent());
|
||||
|
||||
// PT_GNU_RELRO includes all sections that should be marked as
|
||||
// read-only by dynamic linker after proccessing relocations.
|
||||
@ -1441,9 +1443,9 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
|
||||
|
||||
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
|
||||
if (!In<ELFT>::EhFrame->empty() && In<ELFT>::EhFrameHdr &&
|
||||
In<ELFT>::EhFrame->OutSec && In<ELFT>::EhFrameHdr->OutSec)
|
||||
AddHdr(PT_GNU_EH_FRAME, In<ELFT>::EhFrameHdr->OutSec->getPhdrFlags())
|
||||
->add(In<ELFT>::EhFrameHdr->OutSec);
|
||||
In<ELFT>::EhFrame->getParent() && In<ELFT>::EhFrameHdr->getParent())
|
||||
AddHdr(PT_GNU_EH_FRAME, In<ELFT>::EhFrameHdr->getParent()->getPhdrFlags())
|
||||
->add(In<ELFT>::EhFrameHdr->getParent());
|
||||
|
||||
// PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes
|
||||
// the dynamic linker fill the segment with random data.
|
||||
@ -1556,9 +1558,11 @@ static uint64_t setOffset(OutputSection *Sec, uint64_t Off) {
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
|
||||
uint64_t Off = 0;
|
||||
for (OutputSection *Sec : OutputSections)
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
|
||||
OutputSection *Sec = Cmd->Sec;
|
||||
if (Sec->Flags & SHF_ALLOC)
|
||||
Off = setOffset(Sec, Off);
|
||||
}
|
||||
FileSize = alignTo(Off, Config->Wordsize);
|
||||
}
|
||||
|
||||
@ -1568,11 +1572,12 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
|
||||
Off = setOffset(Out::ElfHeader, Off);
|
||||
Off = setOffset(Out::ProgramHeaders, Off);
|
||||
|
||||
for (OutputSection *Sec : OutputSections)
|
||||
Off = setOffset(Sec, Off);
|
||||
for (OutputSectionCommand *Cmd : OutputSectionCommands)
|
||||
Off = setOffset(Cmd->Sec, Off);
|
||||
|
||||
SectionHeaderOff = alignTo(Off, Config->Wordsize);
|
||||
FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
|
||||
FileSize =
|
||||
SectionHeaderOff + (OutputSectionCommands.size() + 1) * sizeof(Elf_Shdr);
|
||||
}
|
||||
|
||||
// Finalize the program headers. We call this function after we assign
|
||||
@ -1695,16 +1700,15 @@ template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
|
||||
|
||||
// Setup MIPS _gp_disp/__gnu_local_gp symbols which should
|
||||
// be equal to the _gp symbol's value.
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
if (!ElfSym::MipsGp->Value) {
|
||||
// Find GP-relative section with the lowest address
|
||||
// and use this address to calculate default _gp value.
|
||||
uint64_t Gp = -1;
|
||||
for (const OutputSection *OS : OutputSections)
|
||||
if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp)
|
||||
Gp = OS->Addr;
|
||||
if (Gp != (uint64_t)-1)
|
||||
ElfSym::MipsGp->Value = Gp + 0x7ff0;
|
||||
if (Config->EMachine == EM_MIPS && !ElfSym::MipsGp->Value) {
|
||||
// Find GP-relative section with the lowest address
|
||||
// and use this address to calculate default _gp value.
|
||||
for (const OutputSectionCommand *Cmd : OutputSectionCommands) {
|
||||
OutputSection *OS = Cmd->Sec;
|
||||
if (OS->Flags & SHF_MIPS_GPREL) {
|
||||
ElfSym::MipsGp->Value = OS->Addr + 0x7ff0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1728,7 +1732,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||
EHdr->e_phnum = Phdrs.size();
|
||||
EHdr->e_shentsize = sizeof(Elf_Shdr);
|
||||
EHdr->e_shnum = OutputSectionCommands.size() + 1;
|
||||
EHdr->e_shstrndx = InX::ShStrTab->OutSec->SectionIndex;
|
||||
EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex;
|
||||
|
||||
if (Config->EMachine == EM_ARM)
|
||||
// We don't currently use any features incompatible with EF_ARM_EABI_VER5,
|
||||
@ -1804,7 +1808,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
|
||||
|
||||
OutputSection *EhFrameHdr =
|
||||
(In<ELFT>::EhFrameHdr && !In<ELFT>::EhFrameHdr->empty())
|
||||
? In<ELFT>::EhFrameHdr->OutSec
|
||||
? In<ELFT>::EhFrameHdr->getParent()
|
||||
: nullptr;
|
||||
|
||||
// In -r or -emit-relocs mode, write the relocation sections first as in
|
||||
@ -1832,7 +1836,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
|
||||
}
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::writeBuildId() {
|
||||
if (!InX::BuildId || !InX::BuildId->OutSec)
|
||||
if (!InX::BuildId || !InX::BuildId->getParent())
|
||||
return;
|
||||
|
||||
// Compute a hash of all sections of the output file.
|
||||
|
7
test/ELF/gc-absolute.s
Normal file
7
test/ELF/gc-absolute.s
Normal file
@ -0,0 +1,7 @@
|
||||
# REQUIRES: x86
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
||||
# RUN: ld.lld %t -o %t2 -shared --gc-sections
|
||||
|
||||
.global foo
|
||||
foo = 0x123
|
32
test/ELF/i386-gotpc-dynamic.s
Normal file
32
test/ELF/i386-gotpc-dynamic.s
Normal file
@ -0,0 +1,32 @@
|
||||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
|
||||
# RUN: ld.lld %t.o -o %t.so -shared
|
||||
# RUN: llvm-readobj -s %t.so | FileCheck %s
|
||||
# RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s
|
||||
|
||||
# CHECK: Section {
|
||||
# CHECK: Index: 7
|
||||
# CHECK-NEXT: Name: .got
|
||||
# CHECK-NEXT: Type: SHT_PROGBITS
|
||||
# CHECK-NEXT: Flags [
|
||||
# CHECK-NEXT: SHF_ALLOC
|
||||
# CHECK-NEXT: SHF_WRITE
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Address: 0x2030
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Link:
|
||||
# CHECK-NEXT: Info:
|
||||
# CHECK-NEXT: AddressAlignment:
|
||||
# CHECK-NEXT: EntrySize:
|
||||
# CHECK-NEXT: }
|
||||
|
||||
## 0x1000 + 4144 = 0x2030
|
||||
# DISASM: 1000: {{.*}} movl $4144, %eax
|
||||
|
||||
.section .foo,"ax",@progbits
|
||||
foo:
|
||||
movl $bar@got-., %eax # R_386_GOTPC
|
||||
|
||||
.local bar
|
||||
bar:
|
38
test/ELF/mips64-eh-abs-reloc.s
Normal file
38
test/ELF/mips64-eh-abs-reloc.s
Normal file
@ -0,0 +1,38 @@
|
||||
# Having an R_MIPS_64 relocation in eh_frame would previously crash LLD
|
||||
# REQUIRES: mips
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
|
||||
# RUN: llvm-readobj -r %t.o | FileCheck %s -check-prefix OBJ
|
||||
# RUN: ld.lld --eh-frame-hdr -shared -z notext -o %t.so %t.o
|
||||
# RUN: llvm-readobj -r %t.so | FileCheck %s -check-prefix PIC-RELOCS
|
||||
|
||||
# Linking this as a PIE executable would also previously crash
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %S/Inputs/archive2.s -o %t-foo.o
|
||||
# -pie needs -z notext because of the R_MIPS_64 relocation
|
||||
# RUN: ld.lld --eh-frame-hdr -Bdynamic -pie -z notext -o %t-pie-dynamic.exe %t.o %t-foo.o
|
||||
# RUN: llvm-readobj -r %t-pie-dynamic.exe | FileCheck %s -check-prefix PIC-RELOCS
|
||||
|
||||
|
||||
# OBJ: Section ({{.*}}) .rela.text {
|
||||
# OBJ-NEXT: 0x0 R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 foo 0x0
|
||||
# OBJ-NEXT: }
|
||||
# OBJ-NEXT: Section ({{.*}}) .rela.eh_frame {
|
||||
# OBJ-NEXT: 0x1C R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text 0x0
|
||||
# OBJ-NEXT: }
|
||||
|
||||
# PIC-RELOCS: Relocations [
|
||||
# PIC-RELOCS-NEXT: Section (7) .rela.dyn {
|
||||
# PIC-RELOCS-NEXT: {{0x.+}} R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x10000
|
||||
# PIC-RELOCS-NEXT: }
|
||||
# PIC-RELOCS-NEXT:]
|
||||
|
||||
|
||||
.globl foo
|
||||
|
||||
bar:
|
||||
.cfi_startproc
|
||||
lui $11, %hi(%neg(%gp_rel(foo)))
|
||||
.cfi_endproc
|
||||
|
||||
.globl __start
|
||||
__start:
|
||||
b bar
|
15
test/ELF/section-metadata-err.s
Normal file
15
test/ELF/section-metadata-err.s
Normal file
@ -0,0 +1,15 @@
|
||||
# REQUIRES: x86
|
||||
|
||||
# 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: Merge and .eh_frame sections are not supported with SHF_LINK_ORDER {{.*}}section-metadata-err.s.tmp.o:(.foo)
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
.quad .foo
|
||||
|
||||
.section .foo,"aM",@progbits,8
|
||||
.quad 0
|
||||
|
||||
.section bar,"ao",@progbits,.foo
|
Loading…
x
Reference in New Issue
Block a user