mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-02 10:49:22 +00:00
ELF: Add basic partition data structures and behaviours.
This change causes us to read partition specifications from partition specification sections and split output sections into partitions according to their reachability from partition entry points. This is only the first step towards a full implementation of partitions. Later changes will add additional synthetic sections to each partition so that they can be loaded independently. Differential Revision: https://reviews.llvm.org/D60353 llvm-svn: 361925
This commit is contained in:
parent
e8698ead9d
commit
ba2816be82
@ -98,6 +98,8 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
|
||||
Tar = nullptr;
|
||||
memset(&In, 0, sizeof(In));
|
||||
|
||||
Partitions = {Partition()};
|
||||
|
||||
SharedFile::VernauxNum = 0;
|
||||
|
||||
Config->ProgName = Args[0];
|
||||
@ -1344,7 +1346,7 @@ static void replaceCommonSymbols() {
|
||||
|
||||
auto *Bss = make<BssSection>("COMMON", S->Size, S->Alignment);
|
||||
Bss->File = S->File;
|
||||
Bss->Live = !Config->GcSections;
|
||||
Bss->markDead();
|
||||
InputSections.push_back(Bss);
|
||||
S->replace(Defined{S->File, S->getName(), S->Binding, S->StOther, S->Type,
|
||||
/*Value=*/0, S->Size, Bss});
|
||||
@ -1432,6 +1434,55 @@ static void findKeepUniqueSections(opt::InputArgList &Args) {
|
||||
}
|
||||
}
|
||||
|
||||
// This function reads a symbol partition specification section. These sections
|
||||
// are used to control which partition a symbol is allocated to. See
|
||||
// https://lld.llvm.org/Partitions.html for more details on partitions.
|
||||
template <typename ELFT>
|
||||
static void readSymbolPartitionSection(InputSectionBase *S) {
|
||||
// Read the relocation that refers to the partition's entry point symbol.
|
||||
Symbol *Sym;
|
||||
if (S->AreRelocsRela)
|
||||
Sym = &S->getFile<ELFT>()->getRelocTargetSym(S->template relas<ELFT>()[0]);
|
||||
else
|
||||
Sym = &S->getFile<ELFT>()->getRelocTargetSym(S->template rels<ELFT>()[0]);
|
||||
if (!isa<Defined>(Sym) || !Sym->includeInDynsym())
|
||||
return;
|
||||
|
||||
StringRef PartName = reinterpret_cast<const char *>(S->data().data());
|
||||
for (Partition &Part : Partitions) {
|
||||
if (Part.Name == PartName) {
|
||||
Sym->Partition = Part.getNumber();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Forbid partitions from being used on incompatible targets, and forbid them
|
||||
// from being used together with various linker features that assume a single
|
||||
// set of output sections.
|
||||
if (Script->HasSectionsCommand)
|
||||
error(toString(S->File) +
|
||||
": partitions cannot be used with the SECTIONS command");
|
||||
if (Script->hasPhdrsCommands())
|
||||
error(toString(S->File) +
|
||||
": partitions cannot be used with the PHDRS command");
|
||||
if (!Config->SectionStartMap.empty())
|
||||
error(toString(S->File) + ": partitions cannot be used with "
|
||||
"--section-start, -Ttext, -Tdata or -Tbss");
|
||||
if (Config->EMachine == EM_MIPS)
|
||||
error(toString(S->File) + ": partitions cannot be used on this target");
|
||||
|
||||
// Impose a limit of no more than 254 partitions. This limit comes from the
|
||||
// sizes of the Partition fields in InputSectionBase and Symbol, as well as
|
||||
// the amount of space devoted to the partition number in RankFlags.
|
||||
if (Partitions.size() == 254)
|
||||
fatal("may not have more than 254 partitions");
|
||||
|
||||
Partitions.emplace_back();
|
||||
Partition &NewPart = Partitions.back();
|
||||
NewPart.Name = PartName;
|
||||
Sym->Partition = NewPart.getNumber();
|
||||
}
|
||||
|
||||
template <class ELFT> static Symbol *addUndefined(StringRef Name) {
|
||||
return Symtab->addSymbol(
|
||||
Undefined{nullptr, Name, STB_GLOBAL, STV_DEFAULT, 0});
|
||||
@ -1700,13 +1751,17 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
|
||||
for (InputSectionBase *S : F->getSections())
|
||||
InputSections.push_back(cast<InputSection>(S));
|
||||
|
||||
// We do not want to emit debug sections if --strip-all
|
||||
// or -strip-debug are given.
|
||||
if (Config->Strip != StripPolicy::None) {
|
||||
llvm::erase_if(InputSections, [](InputSectionBase *S) {
|
||||
return S->Name.startswith(".debug") || S->Name.startswith(".zdebug");
|
||||
});
|
||||
}
|
||||
llvm::erase_if(InputSections, [](InputSectionBase *S) {
|
||||
if (S->Type == SHT_LLVM_SYMPART) {
|
||||
readSymbolPartitionSection<ELFT>(S);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We do not want to emit debug sections if --strip-all
|
||||
// or -strip-debug are given.
|
||||
return Config->Strip != StripPolicy::None &&
|
||||
(S->Name.startswith(".debug") || S->Name.startswith(".zdebug"));
|
||||
});
|
||||
|
||||
Config->EFlags = Target->calcEFlags();
|
||||
// MaxPageSize (sometimes called abi page size) is the maximum page size that
|
||||
|
@ -157,7 +157,7 @@ private:
|
||||
|
||||
// Returns true if section S is subject of ICF.
|
||||
static bool isEligible(InputSection *S) {
|
||||
if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC))
|
||||
if (!S->isLive() || S->KeepUnique || !(S->Flags & SHF_ALLOC))
|
||||
return false;
|
||||
|
||||
// Don't merge writable sections. .data.rel.ro sections are marked as writable
|
||||
@ -496,7 +496,7 @@ template <class ELFT> void ICF<ELFT>::run() {
|
||||
// we want to remove duplicate implicit dependencies such as link order
|
||||
// and relocation sections.
|
||||
for (InputSection *IS : Sections[I]->DependentSections)
|
||||
IS->Live = false;
|
||||
IS->markDead();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -443,7 +443,7 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
||||
continue;
|
||||
}
|
||||
SectionBase *Section = D->Section->Repl;
|
||||
if (!Section->Live) {
|
||||
if (!Section->isLive()) {
|
||||
P->setSymbolAndType(0, 0, false);
|
||||
continue;
|
||||
}
|
||||
@ -1095,8 +1095,19 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
|
||||
|
||||
void InputSection::replace(InputSection *Other) {
|
||||
Alignment = std::max(Alignment, Other->Alignment);
|
||||
|
||||
// When a section is replaced with another section that was allocated to
|
||||
// another partition, the replacement section (and its associated sections)
|
||||
// need to be placed in the main partition so that both partitions will be
|
||||
// able to access it.
|
||||
if (Partition != Other->Partition) {
|
||||
Partition = 1;
|
||||
for (InputSection *IS : DependentSections)
|
||||
IS->Partition = 1;
|
||||
}
|
||||
|
||||
Other->Repl = Repl;
|
||||
Other->Live = false;
|
||||
Other->markDead();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
|
@ -54,10 +54,6 @@ public:
|
||||
// The next three bit fields are only used by InputSectionBase, but we
|
||||
// put them here so the struct packs better.
|
||||
|
||||
// The garbage collector sets sections' Live bits.
|
||||
// If GC is disabled, all sections are considered live by default.
|
||||
unsigned Live : 1;
|
||||
|
||||
// True if this section has already been placed to a linker script
|
||||
// output section. This is needed because, in a linker script, you
|
||||
// can refer to the same section more than once. For example, in
|
||||
@ -76,6 +72,11 @@ public:
|
||||
// Set for sections that should not be folded by ICF.
|
||||
unsigned KeepUnique : 1;
|
||||
|
||||
// The 1-indexed partition that this section is assigned to by the garbage
|
||||
// collector, or 0 if this section is dead. Normally there is only one
|
||||
// partition, so this will either be 0 or 1.
|
||||
uint8_t Partition;
|
||||
|
||||
// These corresponds to the fields in Elf_Shdr.
|
||||
uint32_t Alignment;
|
||||
uint64_t Flags;
|
||||
@ -95,12 +96,16 @@ public:
|
||||
|
||||
uint64_t getVA(uint64_t Offset = 0) const;
|
||||
|
||||
bool isLive() const { return Partition != 0; }
|
||||
void markLive() { Partition = 1; }
|
||||
void markDead() { Partition = 0; }
|
||||
|
||||
protected:
|
||||
SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags,
|
||||
uint64_t Entsize, uint64_t Alignment, uint32_t Type,
|
||||
uint32_t Info, uint32_t Link)
|
||||
: Name(Name), Repl(this), SectionKind(SectionKind), Live(false),
|
||||
Assigned(false), Bss(false), KeepUnique(false), Alignment(Alignment),
|
||||
: Name(Name), Repl(this), SectionKind(SectionKind), Assigned(false),
|
||||
Bss(false), KeepUnique(false), Partition(0), Alignment(Alignment),
|
||||
Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) {}
|
||||
};
|
||||
|
||||
|
@ -380,7 +380,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
|
||||
size_t SizeBefore = Ret.size();
|
||||
|
||||
for (InputSectionBase *Sec : InputSections) {
|
||||
if (!Sec->Live || Sec->Assigned)
|
||||
if (!Sec->isLive() || Sec->Assigned)
|
||||
continue;
|
||||
|
||||
// For -emit-relocs we have to ignore entries like
|
||||
@ -425,7 +425,7 @@ void LinkerScript::discard(ArrayRef<InputSection *> V) {
|
||||
In.HashTab = nullptr;
|
||||
|
||||
S->Assigned = false;
|
||||
S->Live = false;
|
||||
S->markDead();
|
||||
discard(S->DependentSections);
|
||||
}
|
||||
}
|
||||
@ -544,8 +544,9 @@ static OutputSection *createSection(InputSectionBase *IS,
|
||||
return Sec;
|
||||
}
|
||||
|
||||
static OutputSection *addInputSec(StringMap<OutputSection *> &Map,
|
||||
InputSectionBase *IS, StringRef OutsecName) {
|
||||
static OutputSection *
|
||||
addInputSec(StringMap<TinyPtrVector<OutputSection *>> &Map,
|
||||
InputSectionBase *IS, StringRef OutsecName) {
|
||||
// Sections with SHT_GROUP or SHF_GROUP attributes reach here only when the -r
|
||||
// option is given. A section with SHT_GROUP defines a "section group", and
|
||||
// its members have SHF_GROUP attribute. Usually these flags have already been
|
||||
@ -624,23 +625,26 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map,
|
||||
//
|
||||
// Given the above issues, we instead merge sections by name and error on
|
||||
// incompatible types and flags.
|
||||
OutputSection *&Sec = Map[OutsecName];
|
||||
if (Sec) {
|
||||
TinyPtrVector<OutputSection *> &V = Map[OutsecName];
|
||||
for (OutputSection *Sec : V) {
|
||||
if (Sec->Partition != IS->Partition)
|
||||
continue;
|
||||
Sec->addSection(cast<InputSection>(IS));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Sec = createSection(IS, OutsecName);
|
||||
OutputSection *Sec = createSection(IS, OutsecName);
|
||||
V.push_back(Sec);
|
||||
return Sec;
|
||||
}
|
||||
|
||||
// Add sections that didn't match any sections command.
|
||||
void LinkerScript::addOrphanSections() {
|
||||
StringMap<OutputSection *> Map;
|
||||
StringMap<TinyPtrVector<OutputSection *>> Map;
|
||||
std::vector<OutputSection *> V;
|
||||
|
||||
auto Add = [&](InputSectionBase *S) {
|
||||
if (!S->Live || S->Parent)
|
||||
if (!S->isLive() || S->Parent)
|
||||
return;
|
||||
|
||||
StringRef Name = getOutputSectionName(S);
|
||||
@ -886,7 +890,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
|
||||
// A live output section means that some input section was added to it. It
|
||||
// might have been removed (if it was empty synthetic section), but we at
|
||||
// least know the flags.
|
||||
if (Sec->Live)
|
||||
if (Sec->isLive())
|
||||
Flags = Sec->Flags;
|
||||
|
||||
// We do not want to keep any special flags for output section
|
||||
@ -897,7 +901,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
|
||||
SHF_WRITE | SHF_EXECINSTR);
|
||||
|
||||
if (IsEmpty && isDiscardable(*Sec)) {
|
||||
Sec->Live = false;
|
||||
Sec->markDead();
|
||||
Cmd = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ static std::vector<Defined *> getSymbols() {
|
||||
for (InputFile *File : ObjectFiles)
|
||||
for (Symbol *B : File->getSymbols())
|
||||
if (auto *DR = dyn_cast<Defined>(B))
|
||||
if (!DR->isSection() && DR->Section && DR->Section->Live &&
|
||||
if (!DR->isSection() && DR->Section && DR->Section->isLive() &&
|
||||
(DR->File == File || DR->NeedsPltAddr || DR->Section->Bss))
|
||||
V.push_back(DR);
|
||||
return V;
|
||||
@ -239,7 +239,7 @@ void elf::writeCrossReferenceTable() {
|
||||
if (isa<SharedSymbol>(Sym))
|
||||
Map[Sym].insert(File);
|
||||
if (auto *D = dyn_cast<Defined>(Sym))
|
||||
if (!D->isLocal() && (!D->Section || D->Section->Live))
|
||||
if (!D->isLocal() && (!D->Section || D->Section->isLive()))
|
||||
Map[D].insert(File);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "OutputSections.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "Symbols.h"
|
||||
#include "SyntheticSections.h"
|
||||
#include "Target.h"
|
||||
#include "lld/Common/Memory.h"
|
||||
#include "lld/Common/Strings.h"
|
||||
@ -44,11 +45,15 @@ using namespace lld::elf;
|
||||
namespace {
|
||||
template <class ELFT> class MarkLive {
|
||||
public:
|
||||
MarkLive(unsigned Partition) : Partition(Partition) {}
|
||||
|
||||
void run();
|
||||
void moveToMain();
|
||||
|
||||
private:
|
||||
void enqueue(InputSectionBase *Sec, uint64_t Offset);
|
||||
void markSymbol(Symbol *Sym);
|
||||
void mark();
|
||||
|
||||
template <class RelTy>
|
||||
void resolveReloc(InputSectionBase &Sec, RelTy &Rel, bool IsLSDA);
|
||||
@ -56,6 +61,9 @@ private:
|
||||
template <class RelTy>
|
||||
void scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels);
|
||||
|
||||
// The index of the partition that we are currently processing.
|
||||
unsigned Partition;
|
||||
|
||||
// A list of sections to visit.
|
||||
SmallVector<InputSection *, 256> Queue;
|
||||
|
||||
@ -183,9 +191,12 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *Sec, uint64_t Offset) {
|
||||
if (auto *MS = dyn_cast<MergeInputSection>(Sec))
|
||||
MS->getSectionPiece(Offset)->Live = true;
|
||||
|
||||
if (Sec->Live)
|
||||
// Set Sec->Partition to the meet (i.e. the "minimum") of Partition and
|
||||
// Sec->Partition in the following lattice: 1 < other < 0. If Sec->Partition
|
||||
// doesn't change, we don't need to do anything.
|
||||
if (Sec->Partition == 1 || Sec->Partition == Partition)
|
||||
return;
|
||||
Sec->Live = true;
|
||||
Sec->Partition = Sec->Partition ? 1 : Partition;
|
||||
|
||||
// Add input section to the queue.
|
||||
if (InputSection *S = dyn_cast<InputSection>(Sec))
|
||||
@ -203,6 +214,20 @@ template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *Sym) {
|
||||
// sections to set their "Live" bits.
|
||||
template <class ELFT> void MarkLive<ELFT>::run() {
|
||||
// Add GC root symbols.
|
||||
|
||||
// Preserve externally-visible symbols if the symbols defined by this
|
||||
// file can interrupt other ELF file's symbols at runtime.
|
||||
Symtab->forEachSymbol([&](Symbol *Sym) {
|
||||
if (Sym->includeInDynsym() && Sym->Partition == Partition)
|
||||
markSymbol(Sym);
|
||||
});
|
||||
|
||||
// If this isn't the main partition, that's all that we need to preserve.
|
||||
if (Partition != 1) {
|
||||
mark();
|
||||
return;
|
||||
}
|
||||
|
||||
markSymbol(Symtab->find(Config->Entry));
|
||||
markSymbol(Symtab->find(Config->Init));
|
||||
markSymbol(Symtab->find(Config->Fini));
|
||||
@ -211,13 +236,6 @@ template <class ELFT> void MarkLive<ELFT>::run() {
|
||||
for (StringRef S : Script->ReferencedSymbols)
|
||||
markSymbol(Symtab->find(S));
|
||||
|
||||
// Preserve externally-visible symbols if the symbols defined by this
|
||||
// file can interrupt other ELF file's symbols at runtime.
|
||||
Symtab->forEachSymbol([&](Symbol *Sym) {
|
||||
if (Sym->includeInDynsym())
|
||||
markSymbol(Sym);
|
||||
});
|
||||
|
||||
// Preserve special sections and those which are specified in linker
|
||||
// script KEEP command.
|
||||
for (InputSectionBase *Sec : InputSections) {
|
||||
@ -226,7 +244,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
|
||||
// all of them. We also want to preserve personality routines and LSDA
|
||||
// referenced by .eh_frame sections, so we scan them for that here.
|
||||
if (auto *EH = dyn_cast<EhInputSection>(Sec)) {
|
||||
EH->Live = true;
|
||||
EH->markLive();
|
||||
if (!EH->NumRelocations)
|
||||
continue;
|
||||
|
||||
@ -247,6 +265,10 @@ template <class ELFT> void MarkLive<ELFT>::run() {
|
||||
}
|
||||
}
|
||||
|
||||
mark();
|
||||
}
|
||||
|
||||
template <class ELFT> void MarkLive<ELFT>::mark() {
|
||||
// Mark all reachable sections.
|
||||
while (!Queue.empty()) {
|
||||
InputSectionBase &Sec = *Queue.pop_back_val();
|
||||
@ -264,6 +286,22 @@ template <class ELFT> void MarkLive<ELFT>::run() {
|
||||
}
|
||||
}
|
||||
|
||||
// Move the sections for some symbols to the main partition, specifically ifuncs
|
||||
// (because they can result in an IRELATIVE being added to the main partition's
|
||||
// GOT, which means that the ifunc must be available when the main partition is
|
||||
// loaded) and TLS symbols (because we only know how to correctly process TLS
|
||||
// relocations for the main partition).
|
||||
template <class ELFT> void MarkLive<ELFT>::moveToMain() {
|
||||
for (InputFile *File : ObjectFiles)
|
||||
for (Symbol *S : File->getSymbols())
|
||||
if (auto *D = dyn_cast<Defined>(S))
|
||||
if ((D->Type == STT_GNU_IFUNC || D->Type == STT_TLS) && D->Section &&
|
||||
D->Section->isLive())
|
||||
markSymbol(S);
|
||||
|
||||
mark();
|
||||
}
|
||||
|
||||
// Before calling this function, Live bits are off for all
|
||||
// input sections. This function make some or all of them on
|
||||
// so that they are emitted to the output file.
|
||||
@ -271,7 +309,7 @@ template <class ELFT> void elf::markLive() {
|
||||
// If -gc-sections is not given, no sections are removed.
|
||||
if (!Config->GcSections) {
|
||||
for (InputSectionBase *Sec : InputSections)
|
||||
Sec->Live = true;
|
||||
Sec->markLive();
|
||||
|
||||
// If a DSO defines a symbol referenced in a regular object, it is needed.
|
||||
Symtab->forEachSymbol([](Symbol *Sym) {
|
||||
@ -309,16 +347,23 @@ template <class ELFT> void elf::markLive() {
|
||||
bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA);
|
||||
|
||||
if (!IsAlloc && !IsLinkOrder && !IsRel)
|
||||
Sec->Live = true;
|
||||
Sec->markLive();
|
||||
}
|
||||
|
||||
// Follow the graph to mark all live sections.
|
||||
MarkLive<ELFT>().run();
|
||||
for (unsigned CurPart = 1; CurPart <= Partitions.size(); ++CurPart)
|
||||
MarkLive<ELFT>(CurPart).run();
|
||||
|
||||
// If we have multiple partitions, some sections need to live in the main
|
||||
// partition even if they were allocated to a loadable partition. Move them
|
||||
// there now.
|
||||
if (Partitions.size() != 1)
|
||||
MarkLive<ELFT>(1).moveToMain();
|
||||
|
||||
// Report garbage-collected sections.
|
||||
if (Config->PrintGcSections)
|
||||
for (InputSectionBase *Sec : InputSections)
|
||||
if (!Sec->Live)
|
||||
if (!Sec->isLive())
|
||||
message("removing unused section " + toString(Sec));
|
||||
}
|
||||
|
||||
|
@ -84,10 +84,10 @@ static bool canMergeToProgbits(unsigned Type) {
|
||||
}
|
||||
|
||||
void OutputSection::addSection(InputSection *IS) {
|
||||
if (!Live) {
|
||||
if (!isLive()) {
|
||||
// If IS is the first section to be added to this section,
|
||||
// initialize Type, Entsize and flags from IS.
|
||||
Live = true;
|
||||
// initialize Partition, Type, Entsize and flags from IS.
|
||||
Partition = IS->Partition;
|
||||
Type = IS->Type;
|
||||
Entsize = IS->Entsize;
|
||||
Flags = IS->Flags;
|
||||
@ -158,7 +158,7 @@ bool OutputSection::classof(const BaseCommand *C) {
|
||||
}
|
||||
|
||||
void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) {
|
||||
assert(Live);
|
||||
assert(isLive());
|
||||
for (BaseCommand *B : SectionCommands)
|
||||
if (auto *ISD = dyn_cast<InputSectionDescription>(B))
|
||||
sortByOrder(ISD->Sections, Order);
|
||||
|
@ -79,6 +79,7 @@ Symbol *SymbolTable::insert(StringRef Name) {
|
||||
Sym->ExportDynamic = false;
|
||||
Sym->CanInline = true;
|
||||
Sym->ScriptDefined = false;
|
||||
Sym->Partition = 1;
|
||||
return Sym;
|
||||
}
|
||||
|
||||
|
@ -333,7 +333,7 @@ void elf::maybeWarnUnorderableSymbol(const Symbol *Sym) {
|
||||
Warn(": unable to order absolute symbol: ");
|
||||
else if (D && isa<OutputSection>(D->Section))
|
||||
Warn(": unable to order synthetic symbol: ");
|
||||
else if (D && !D->Section->Repl->Live)
|
||||
else if (D && !D->Section->Repl->isLive())
|
||||
Warn(": unable to order discarded symbol: ");
|
||||
}
|
||||
|
||||
|
@ -255,6 +255,9 @@ public:
|
||||
// True if this symbol is defined by a linker script.
|
||||
unsigned ScriptDefined : 1;
|
||||
|
||||
// The partition whose dynamic symbol table contains this symbol's definition.
|
||||
uint8_t Partition = 1;
|
||||
|
||||
bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
|
||||
bool isTls() const { return Type == llvm::ELF::STT_TLS; }
|
||||
bool isFunc() const { return Type == llvm::ELF::STT_FUNC; }
|
||||
@ -516,6 +519,7 @@ void Symbol::replace(const Symbol &New) {
|
||||
Traced = Old.Traced;
|
||||
IsPreemptible = Old.IsPreemptible;
|
||||
ScriptDefined = Old.ScriptDefined;
|
||||
Partition = Old.Partition;
|
||||
|
||||
// Symbol length is computed lazily. If we already know a symbol length,
|
||||
// propagate it.
|
||||
|
@ -107,7 +107,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
|
||||
for (InputSectionBase *Sec : InputSections) {
|
||||
if (Sec->Type != SHT_MIPS_ABIFLAGS)
|
||||
continue;
|
||||
Sec->Live = false;
|
||||
Sec->markDead();
|
||||
Create = true;
|
||||
|
||||
std::string Filename = toString(Sec->File);
|
||||
@ -180,7 +180,7 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
|
||||
|
||||
Elf_Mips_RegInfo Reginfo = {};
|
||||
for (InputSectionBase *Sec : Sections) {
|
||||
Sec->Live = false;
|
||||
Sec->markDead();
|
||||
|
||||
std::string Filename = toString(Sec->File);
|
||||
ArrayRef<uint8_t> D = Sec->data();
|
||||
@ -237,7 +237,7 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
|
||||
|
||||
Elf_Mips_RegInfo Reginfo = {};
|
||||
for (InputSectionBase *Sec : Sections) {
|
||||
Sec->Live = false;
|
||||
Sec->markDead();
|
||||
|
||||
if (Sec->data().size() != sizeof(Elf_Mips_RegInfo)) {
|
||||
error(toString(Sec->File) + ": invalid size of .reginfo section");
|
||||
@ -259,7 +259,7 @@ InputSection *elf::createInterpSection() {
|
||||
|
||||
auto *Sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, Contents,
|
||||
".interp");
|
||||
Sec->Live = true;
|
||||
Sec->markLive();
|
||||
return Sec;
|
||||
}
|
||||
|
||||
@ -358,7 +358,7 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) {
|
||||
// FDEs for garbage-collected or merged-by-ICF sections are dead.
|
||||
if (auto *D = dyn_cast<Defined>(&B))
|
||||
if (SectionBase *Sec = D->Section)
|
||||
return Sec->Live;
|
||||
return Sec->isLive();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1290,7 +1290,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
||||
// as RelaIplt have. And we still want to emit proper dynamic tags for that
|
||||
// case, so here we always use RelaPlt as marker for the begining of
|
||||
// .rel[a].plt section.
|
||||
if (In.RelaPlt->getParent()->Live) {
|
||||
if (In.RelaPlt->getParent()->isLive()) {
|
||||
addInSec(DT_JMPREL, In.RelaPlt);
|
||||
Entries.push_back({DT_PLTRELSZ, addPltRelSz});
|
||||
switch (Config->EMachine) {
|
||||
@ -2370,7 +2370,7 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
|
||||
if (R.SectionIndex == -1ULL)
|
||||
continue;
|
||||
InputSectionBase *S = Sections[R.SectionIndex];
|
||||
if (!S || S == &InputSection::Discarded || !S->Live)
|
||||
if (!S || S == &InputSection::Discarded || !S->isLive())
|
||||
continue;
|
||||
// Range list with zero size has no effect.
|
||||
if (R.LowPC == R.HighPC)
|
||||
@ -2503,7 +2503,7 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
|
||||
// a .gdb_index. So we can remove them from the output.
|
||||
for (InputSectionBase *S : InputSections)
|
||||
if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes")
|
||||
S->Live = false;
|
||||
S->markDead();
|
||||
|
||||
std::vector<GdbChunk> Chunks(Sections.size());
|
||||
std::vector<std::vector<NameAttrEntry>> NameAttrs(Sections.size());
|
||||
@ -2945,7 +2945,7 @@ void elf::mergeSections() {
|
||||
|
||||
// We do not want to handle sections that are not alive, so just remove
|
||||
// them instead of trying to merge.
|
||||
if (!MS->Live) {
|
||||
if (!MS->isLive()) {
|
||||
S = nullptr;
|
||||
continue;
|
||||
}
|
||||
@ -3257,6 +3257,8 @@ bool PPC64LongBranchTargetSection::isNeeded() const {
|
||||
|
||||
InStruct elf::In;
|
||||
|
||||
std::vector<Partition> elf::Partitions;
|
||||
|
||||
template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
|
||||
template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
|
||||
template GdbIndexSection *GdbIndexSection::create<ELF64LE>();
|
||||
|
@ -31,6 +31,7 @@
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
class Defined;
|
||||
struct Partition;
|
||||
|
||||
class SyntheticSection : public InputSection {
|
||||
public:
|
||||
@ -38,7 +39,7 @@ public:
|
||||
StringRef Name)
|
||||
: InputSection(nullptr, Flags, Type, Alignment, {}, Name,
|
||||
InputSectionBase::Synthetic) {
|
||||
this->Live = true;
|
||||
markLive();
|
||||
}
|
||||
|
||||
virtual ~SyntheticSection() = default;
|
||||
@ -1062,6 +1063,14 @@ Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
|
||||
|
||||
void addVerneed(Symbol *SS);
|
||||
|
||||
extern std::vector<Partition> Partitions;
|
||||
|
||||
// Linker generated per-partition sections.
|
||||
struct Partition {
|
||||
StringRef Name;
|
||||
unsigned getNumber() const { return this - &Partitions[0] + 1; }
|
||||
};
|
||||
|
||||
// Linker generated sections which can be used as inputs.
|
||||
struct InStruct {
|
||||
InputSection *ARMAttributes;
|
||||
|
@ -157,7 +157,7 @@ template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
|
||||
|
||||
template <class ELFT> static void combineEhSections() {
|
||||
for (InputSectionBase *&S : InputSections) {
|
||||
if (!S->Live)
|
||||
if (!S->isLive())
|
||||
continue;
|
||||
|
||||
if (auto *ES = dyn_cast<EhInputSection>(S)) {
|
||||
@ -607,7 +607,7 @@ static bool includeInSymtab(const Symbol &B) {
|
||||
Sec = Sec->Repl;
|
||||
|
||||
// Exclude symbols pointing to garbage-collected sections.
|
||||
if (isa<InputSectionBase>(Sec) && !Sec->Live)
|
||||
if (isa<InputSectionBase>(Sec) && !Sec->isLive())
|
||||
return false;
|
||||
|
||||
if (auto *S = dyn_cast<MergeInputSection>(Sec))
|
||||
@ -761,8 +761,9 @@ static bool isRelroSection(const OutputSection *Sec) {
|
||||
// * 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 << 17,
|
||||
RF_NOT_ALLOC = 1 << 16,
|
||||
RF_NOT_ADDR_SET = 1 << 25,
|
||||
RF_NOT_ALLOC = 1 << 24,
|
||||
RF_PARTITION = 1 << 16, // Partition number (8 bits)
|
||||
RF_NOT_INTERP = 1 << 15,
|
||||
RF_NOT_NOTE = 1 << 14,
|
||||
RF_WRITE = 1 << 13,
|
||||
@ -782,7 +783,7 @@ enum RankFlags {
|
||||
};
|
||||
|
||||
static unsigned getSectionRank(const OutputSection *Sec) {
|
||||
unsigned Rank = 0;
|
||||
unsigned Rank = Sec->Partition * RF_PARTITION;
|
||||
|
||||
// We want to put section specified by -T option first, so we
|
||||
// can start assigning VA starting from them later.
|
||||
@ -953,11 +954,11 @@ void Writer<ELFT>::forEachRelSec(
|
||||
// Note that relocations for non-alloc sections are directly
|
||||
// processed by InputSection::relocateNonAlloc.
|
||||
for (InputSectionBase *IS : InputSections)
|
||||
if (IS->Live && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC))
|
||||
if (IS->isLive() && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC))
|
||||
Fn(*IS);
|
||||
for (EhInputSection *ES : In.EhFrame->Sections)
|
||||
Fn(*ES);
|
||||
if (In.ARMExidx && In.ARMExidx->Live)
|
||||
if (In.ARMExidx && In.ARMExidx->isLive())
|
||||
for (InputSection *Ex : In.ARMExidx->ExidxSections)
|
||||
Fn(*Ex);
|
||||
}
|
||||
@ -1054,7 +1055,7 @@ static int getRankProximityAux(OutputSection *A, OutputSection *B) {
|
||||
|
||||
static int getRankProximity(OutputSection *A, BaseCommand *B) {
|
||||
auto *Sec = dyn_cast<OutputSection>(B);
|
||||
return (Sec && Sec->Live) ? getRankProximityAux(A, Sec) : -1;
|
||||
return (Sec && Sec->isLive()) ? getRankProximityAux(A, Sec) : -1;
|
||||
}
|
||||
|
||||
// When placing orphan sections, we want to place them after symbol assignments
|
||||
@ -1096,7 +1097,7 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
|
||||
int Proximity = getRankProximity(Sec, *I);
|
||||
for (; I != E; ++I) {
|
||||
auto *CurSec = dyn_cast<OutputSection>(*I);
|
||||
if (!CurSec || !CurSec->Live)
|
||||
if (!CurSec || !CurSec->isLive())
|
||||
continue;
|
||||
if (getRankProximity(Sec, CurSec) != Proximity ||
|
||||
Sec->SortRank < CurSec->SortRank)
|
||||
@ -1105,7 +1106,7 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
|
||||
|
||||
auto IsLiveOutputSec = [](BaseCommand *Cmd) {
|
||||
auto *OS = dyn_cast<OutputSection>(Cmd);
|
||||
return OS && OS->Live;
|
||||
return OS && OS->isLive();
|
||||
};
|
||||
auto J = std::find_if(llvm::make_reverse_iterator(I),
|
||||
llvm::make_reverse_iterator(B), IsLiveOutputSec);
|
||||
|
23
lld/test/ELF/partition-errors.s
Normal file
23
lld/test/ELF/partition-errors.s
Normal file
@ -0,0 +1,23 @@
|
||||
// REQUIRES: x86, mips
|
||||
// RUN: llvm-mc -triple=x86_64-unknown-linux -filetype=obj -o %t.o %s
|
||||
// RUN: echo "SECTIONS {}" > %t.script
|
||||
// RUN: not ld.lld --export-dynamic %t.o %t.script 2>&1 | FileCheck %s
|
||||
// RUN: echo "PHDRS { text PT_LOAD; }" > %t2.script
|
||||
// RUN: not ld.lld --export-dynamic %t.o %t2.script 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld --export-dynamic %t.o --section-start .text=0 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld --export-dynamic %t.o -Ttext=0 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld --export-dynamic %t.o -Tdata=0 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld --export-dynamic %t.o -Tbss=0 2>&1 | FileCheck %s
|
||||
|
||||
// RUN: llvm-mc -triple=mipsel-unknown-linux -filetype=obj -o %t2.o %s
|
||||
// RUN: not ld.lld --export-dynamic %t2.o 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: error: {{.*}}.o: partitions cannot be used
|
||||
|
||||
.section .llvm_sympart.f1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad f1
|
||||
|
||||
.text
|
||||
.globl f1
|
||||
f1:
|
50
lld/test/ELF/partition-icf.s
Normal file
50
lld/test/ELF/partition-icf.s
Normal file
@ -0,0 +1,50 @@
|
||||
// REQUIRES: x86
|
||||
// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux
|
||||
// RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections --icf=all
|
||||
// RUN: llvm-readelf -S -s %t | FileCheck %s
|
||||
|
||||
// CHECK: [[MAIN:[0-9]+]]] .text
|
||||
// CHECK: [[P1:[0-9]+]]] .text
|
||||
// CHECK: [[P2:[0-9]+]]] .text
|
||||
|
||||
// CHECK: Symbol table '.symtab'
|
||||
// CHECK: [[P1]] f1
|
||||
// CHECK: [[P2]] f2
|
||||
// CHECK: [[MAIN]] g1
|
||||
// CHECK: [[MAIN]] g2
|
||||
|
||||
.section .llvm_sympart.f1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad f1
|
||||
|
||||
.section .llvm_sympart.f2,"",@llvm_sympart
|
||||
.asciz "part2"
|
||||
.quad f2
|
||||
|
||||
.section .llvm_sympart.g1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad g1
|
||||
|
||||
.section .llvm_sympart.g2,"",@llvm_sympart
|
||||
.asciz "part2"
|
||||
.quad g2
|
||||
|
||||
.section .text.f1,"ax",@progbits
|
||||
.globl f1
|
||||
f1:
|
||||
.byte 1
|
||||
|
||||
.section .text.f2,"ax",@progbits
|
||||
.globl f2
|
||||
f2:
|
||||
.byte 2
|
||||
|
||||
.section .text.g1,"ax",@progbits
|
||||
.globl g1
|
||||
g1:
|
||||
.byte 3
|
||||
|
||||
.section .text.g2,"ax",@progbits
|
||||
.globl g2
|
||||
g2:
|
||||
.byte 3
|
44
lld/test/ELF/partition-move-to-main.s
Normal file
44
lld/test/ELF/partition-move-to-main.s
Normal file
@ -0,0 +1,44 @@
|
||||
// REQUIRES: x86
|
||||
// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux
|
||||
// RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections
|
||||
// RUN: llvm-readelf -S -s %t | FileCheck %s
|
||||
|
||||
// Ordinarily, the TLS and IFUNC sections would be split into partitions.
|
||||
// Make sure that that didn't happen by checking that there is only one
|
||||
// of each section.
|
||||
|
||||
// CHECK: .ifunc
|
||||
// CHECK: .tdata
|
||||
|
||||
// CHECK-NOT: .ifunc
|
||||
// CHECK-NOT: .tdata
|
||||
|
||||
.section .llvm_sympart.f1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad f1
|
||||
|
||||
.section .text._start,"ax",@progbits
|
||||
.globl _start
|
||||
_start:
|
||||
call tls1
|
||||
call ifunc1
|
||||
|
||||
.section .text.f1,"ax",@progbits
|
||||
.globl f1
|
||||
f1:
|
||||
call tls2
|
||||
call ifunc2
|
||||
|
||||
.section .ifunc,"ax",@progbits,unique,1
|
||||
.type ifunc1 STT_GNU_IFUNC
|
||||
ifunc1:
|
||||
|
||||
.section .ifunc,"ax",@progbits,unique,2
|
||||
.type ifunc2 STT_GNU_IFUNC
|
||||
ifunc2:
|
||||
|
||||
.section .tdata,"awT",@progbits,unique,1
|
||||
tls1:
|
||||
|
||||
.section .tdata,"awT",@progbits,unique,2
|
||||
tls2:
|
63
lld/test/ELF/partitions.s
Normal file
63
lld/test/ELF/partitions.s
Normal file
@ -0,0 +1,63 @@
|
||||
// REQUIRES: x86
|
||||
// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux
|
||||
// RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections
|
||||
// RUN: llvm-readelf -S -s %t | FileCheck %s
|
||||
|
||||
// This is basically lld/docs/partitions.dot in object file form.
|
||||
// Test that the sections are correctly allocated to partitions.
|
||||
|
||||
// CHECK: [[MAIN:[0-9]+]]] .text
|
||||
// CHECK: [[P1:[0-9]+]]] .text
|
||||
// CHECK: [[P2:[0-9]+]]] .text
|
||||
|
||||
// CHECK: Symbol table '.symtab'
|
||||
// CHECK: [[MAIN]] f3
|
||||
// CHECK: [[P1]] f4
|
||||
// CHECK: [[MAIN]] f5
|
||||
// CHECK: [[P2]] f6
|
||||
// CHECK: [[MAIN]] _start
|
||||
// CHECK: [[P1]] f1
|
||||
// CHECK: [[P2]] f2
|
||||
|
||||
.section .llvm_sympart.f1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad f1
|
||||
|
||||
.section .llvm_sympart.f2,"",@llvm_sympart
|
||||
.asciz "part2"
|
||||
.quad f2
|
||||
|
||||
.section .text._start,"ax",@progbits
|
||||
.globl _start
|
||||
_start:
|
||||
call f3
|
||||
|
||||
.section .text.f1,"ax",@progbits
|
||||
.globl f1
|
||||
f1:
|
||||
call f3
|
||||
call f4
|
||||
call f5
|
||||
|
||||
.section .text.f2,"ax",@progbits
|
||||
.globl f2
|
||||
f2:
|
||||
call f3
|
||||
call f5
|
||||
call f6
|
||||
|
||||
.section .text.f3,"ax",@progbits
|
||||
f3:
|
||||
ret
|
||||
|
||||
.section .text.f4,"ax",@progbits
|
||||
f4:
|
||||
ret
|
||||
|
||||
.section .text.f5,"ax",@progbits
|
||||
f5:
|
||||
ret
|
||||
|
||||
.section .text.f6,"ax",@progbits
|
||||
f6:
|
||||
ret
|
Loading…
Reference in New Issue
Block a user