Merge OutputSectionCommand and OutputSection.

This is a bit of a hack, but it is *so* convenient.

Now that we create synthetic linker scripts when none is provided, we
always have to handle paired OutputSection and OutputsectionCommand and
keep a mapping from one to the other.

This patch simplifies things by merging them and creating what used to
be OutputSectionCommands really early.

llvm-svn: 309311
This commit is contained in:
Rafael Espindola
2017-07-27 19:22:43 +00:00
parent f0850e3ddb
commit 8c022ca783
11 changed files with 619 additions and 733 deletions

View File

@@ -27,7 +27,6 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
@@ -85,27 +84,26 @@ static SymbolBody *addRegular(SymbolAssignment *Cmd) {
return Sym->body();
}
OutputSectionCommand *
LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) {
OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
OutputSectionCommand *Cmd;
if (CmdRef && CmdRef->Location.empty()) {
OutputSection *LinkerScript::createOutputSection(StringRef Name,
StringRef Location) {
OutputSection *&SecRef = NameToOutputSection[Name];
OutputSection *Sec;
if (SecRef && SecRef->Location.empty()) {
// There was a forward reference.
Cmd = CmdRef;
Sec = SecRef;
} else {
Cmd = make<OutputSectionCommand>(Name);
if (!CmdRef)
CmdRef = Cmd;
Sec = make<OutputSection>(Name, SHT_PROGBITS, 0);
if (!SecRef)
SecRef = Sec;
}
Cmd->Location = Location;
return Cmd;
Sec->Location = Location;
return Sec;
}
OutputSectionCommand *
LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) {
OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) {
OutputSection *&CmdRef = NameToOutputSection[Name];
if (!CmdRef)
CmdRef = make<OutputSectionCommand>(Name);
CmdRef = make<OutputSection>(Name, SHT_PROGBITS, 0);
return CmdRef;
}
@@ -159,19 +157,6 @@ bool SymbolAssignment::classof(const BaseCommand *C) {
return C->Kind == AssignmentKind;
}
bool OutputSectionCommand::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind;
}
// Fill [Buf, Buf + Size) with Filler.
// This is used for linker script "=fillexp" command.
static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
size_t I = 0;
for (; I + 4 < Size; I += 4)
memcpy(Buf + I, &Filler, 4);
memcpy(Buf + I, &Filler, Size - I);
}
bool InputSectionDescription::classof(const BaseCommand *C) {
return C->Kind == InputSectionKind;
}
@@ -199,19 +184,6 @@ bool LinkerScript::shouldKeep(InputSectionBase *S) {
return false;
}
// If an input string is in the form of "foo.N" where N is a number,
// return N. Otherwise, returns 65536, which is one greater than the
// lowest priority.
static int getPriority(StringRef S) {
size_t Pos = S.rfind('.');
if (Pos == StringRef::npos)
return 65536;
int V;
if (!to_integer(S.substr(Pos + 1), V, 10))
return 65536;
return V;
}
// A helper function for the SORT() command.
static std::function<bool(InputSectionBase *, InputSectionBase *)>
getComparator(SortSectionPolicy K) {
@@ -325,7 +297,7 @@ void LinkerScript::discard(ArrayRef<InputSectionBase *> V) {
}
std::vector<InputSectionBase *>
LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) {
LinkerScript::createInputSectionList(OutputSection &OutCmd) {
std::vector<InputSectionBase *> Ret;
for (BaseCommand *Base : OutCmd.Commands) {
@@ -368,12 +340,12 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
continue;
}
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I])) {
std::vector<InputSectionBase *> V = createInputSectionList(*Cmd);
if (auto *Sec = dyn_cast<OutputSection>(Opt.Commands[I])) {
std::vector<InputSectionBase *> V = createInputSectionList(*Sec);
// The output section name `/DISCARD/' is special.
// Any input section assigned to it is discarded.
if (Cmd->Name == "/DISCARD/") {
if (Sec->Name == "/DISCARD/") {
discard(V);
continue;
}
@@ -385,7 +357,7 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
//
// Because we'll iterate over Commands many more times, the easiest
// way to "make it as if it wasn't present" is to just remove it.
if (!matchConstraints(V, Cmd->Constraint)) {
if (!matchConstraints(V, Sec->Constraint)) {
for (InputSectionBase *S : V)
S->Assigned = false;
Opt.Commands.erase(Opt.Commands.begin() + I);
@@ -395,37 +367,32 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
// A directive may contain symbol definitions like this:
// ".foo : { ...; bar = .; }". Handle them.
for (BaseCommand *Base : Cmd->Commands)
for (BaseCommand *Base : Sec->Commands)
if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base))
addSymbol(OutCmd);
// Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
// is given, input sections are aligned to that value, whether the
// given value is larger or smaller than the original section alignment.
if (Cmd->SubalignExpr) {
uint32_t Subalign = Cmd->SubalignExpr().getValue();
if (Sec->SubalignExpr) {
uint32_t Subalign = Sec->SubalignExpr().getValue();
for (InputSectionBase *S : V)
S->Alignment = Subalign;
}
// Add input sections to an output section.
for (InputSectionBase *S : V)
Factory.addInputSec(S, Cmd->Name, Cmd->Sec);
if (OutputSection *Sec = Cmd->Sec) {
assert(Sec->SectionIndex == INT_MAX);
Sec->SectionIndex = I;
if (Cmd->Noload)
Sec->Type = SHT_NOBITS;
SecToCommand[Sec] = Cmd;
}
Factory.addInputSec(S, Sec->Name, Sec);
assert(Sec->SectionIndex == INT_MAX);
Sec->SectionIndex = I;
if (Sec->Noload)
Sec->Type = SHT_NOBITS;
}
}
CurAddressState = nullptr;
}
void LinkerScript::fabricateDefaultCommands() {
std::vector<BaseCommand *> Commands;
// Define start address
uint64_t StartAddr = -1;
@@ -435,33 +402,15 @@ void LinkerScript::fabricateDefaultCommands() {
for (auto &KV : Config->SectionStartMap)
StartAddr = std::min(StartAddr, KV.second);
Commands.push_back(make<SymbolAssignment>(
".",
[=] {
return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize());
},
""));
// For each OutputSection that needs a VA fabricate an OutputSectionCommand
// with an InputSectionDescription describing the InputSections
for (OutputSection *Sec : OutputSections) {
auto *OSCmd = createOutputSectionCommand(Sec->Name, "<internal>");
OSCmd->Sec = Sec;
SecToCommand[Sec] = OSCmd;
Commands.push_back(OSCmd);
if (Sec->Sections.size()) {
auto *ISD = make<InputSectionDescription>("");
OSCmd->Commands.push_back(ISD);
for (InputSection *ISec : Sec->Sections) {
ISD->Sections.push_back(ISec);
ISec->Assigned = true;
}
}
}
// SECTIONS commands run before other non SECTIONS commands
Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end());
Opt.Commands = std::move(Commands);
Opt.Commands.insert(Opt.Commands.begin(),
make<SymbolAssignment>(".",
[=] {
return std::min(
StartAddr,
Config->ImageBase +
elf::getHeaderSize());
},
""));
}
// Add sections that didn't match any sections command.
@@ -473,35 +422,21 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
StringRef Name = getOutputSectionName(S->Name);
auto End = Opt.Commands.begin() + NumCommands;
auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) {
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
return Cmd->Name == Name;
if (auto *Sec = dyn_cast<OutputSection>(Base))
return Sec->Name == Name;
return false;
});
OutputSectionCommand *Cmd;
if (I == End) {
Factory.addInputSec(S, Name);
OutputSection *Sec = S->getOutputSection();
assert(Sec->SectionIndex == INT_MAX);
OutputSectionCommand *&CmdRef = SecToCommand[Sec];
if (!CmdRef) {
CmdRef = createOutputSectionCommand(Sec->Name, "<internal>");
CmdRef->Sec = Sec;
Opt.Commands.push_back(CmdRef);
}
Cmd = CmdRef;
} else {
Cmd = cast<OutputSectionCommand>(*I);
Factory.addInputSec(S, Name, Cmd->Sec);
if (OutputSection *Sec = Cmd->Sec) {
SecToCommand[Sec] = Cmd;
unsigned Index = std::distance(Opt.Commands.begin(), I);
assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index);
Sec->SectionIndex = Index;
}
OutputSection *Sec = cast<OutputSection>(*I);
Factory.addInputSec(S, Name, Sec);
unsigned Index = std::distance(Opt.Commands.begin(), I);
assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index);
Sec->SectionIndex = Index;
}
auto *ISD = make<InputSectionDescription>("");
ISD->Sections.push_back(cast<InputSection>(S));
Cmd->Commands.push_back(ISD);
}
}
@@ -605,14 +540,14 @@ void LinkerScript::process(BaseCommand &Base) {
// This function searches for a memory region to place the given output
// section in. If found, a pointer to the appropriate memory region is
// returned. Otherwise, a nullptr is returned.
MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) {
MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) {
// If a memory region name was specified in the output section command,
// then try to find that region first.
if (!Cmd->MemoryRegionName.empty()) {
auto It = Opt.MemoryRegions.find(Cmd->MemoryRegionName);
if (!Sec->MemoryRegionName.empty()) {
auto It = Opt.MemoryRegions.find(Sec->MemoryRegionName);
if (It != Opt.MemoryRegions.end())
return &It->second;
error("memory region '" + Cmd->MemoryRegionName + "' not declared");
error("memory region '" + Sec->MemoryRegionName + "' not declared");
return nullptr;
}
@@ -622,7 +557,6 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) {
if (Opt.MemoryRegions.empty())
return nullptr;
OutputSection *Sec = Cmd->Sec;
// See if a region can be found by matching section flags.
for (auto &Pair : Opt.MemoryRegions) {
MemoryRegion &M = Pair.second;
@@ -638,22 +572,18 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) {
// This function assigns offsets to input sections and an output section
// for a single sections command (e.g. ".text { *(.text); }").
void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) {
OutputSection *Sec = Cmd->Sec;
if (!Sec)
return;
void LinkerScript::assignOffsets(OutputSection *Sec) {
if (!(Sec->Flags & SHF_ALLOC))
Dot = 0;
else if (Cmd->AddrExpr)
setDot(Cmd->AddrExpr, Cmd->Location, false);
else if (Sec->AddrExpr)
setDot(Sec->AddrExpr, Sec->Location, false);
if (Cmd->LMAExpr) {
if (Sec->LMAExpr) {
uint64_t D = Dot;
CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; };
CurAddressState->LMAOffset = [=] { return Sec->LMAExpr().getValue() - D; };
}
CurAddressState->MemRegion = Cmd->MemRegion;
CurAddressState->MemRegion = Sec->MemRegion;
if (CurAddressState->MemRegion)
Dot = CurAddressState->MemRegionOffset[CurAddressState->MemRegion];
switchTo(Sec);
@@ -663,7 +593,7 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) {
if (CurAddressState->OutSec->Flags & SHF_COMPRESSED)
return;
for (BaseCommand *C : Cmd->Commands)
for (BaseCommand *C : Sec->Commands)
process(*C);
}
@@ -674,16 +604,16 @@ void LinkerScript::removeEmptyCommands() {
// clutter the output.
// We instead remove trivially empty sections. The bfd linker seems even
// more aggressive at removing them.
auto Pos = std::remove_if(
Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) {
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
return Cmd->Sec == nullptr;
return false;
});
auto Pos = std::remove_if(Opt.Commands.begin(), Opt.Commands.end(),
[&](BaseCommand *Base) {
if (auto *Sec = dyn_cast<OutputSection>(Base))
return !Sec->Live;
return false;
});
Opt.Commands.erase(Pos, Opt.Commands.end());
}
static bool isAllSectionDescription(const OutputSectionCommand &Cmd) {
static bool isAllSectionDescription(const OutputSection &Cmd) {
for (BaseCommand *Base : Cmd.Commands)
if (!isa<InputSectionDescription>(*Base))
return false;
@@ -698,32 +628,31 @@ void LinkerScript::adjustSectionsBeforeSorting() {
uint64_t Flags = SHF_ALLOC;
for (int I = 0, E = Opt.Commands.size(); I != E; ++I) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]);
if (!Cmd)
auto *Sec = dyn_cast<OutputSection>(Opt.Commands[I]);
if (!Sec)
continue;
if (OutputSection *Sec = Cmd->Sec) {
if (Sec->Live) {
Flags = Sec->Flags;
continue;
}
if (isAllSectionDescription(*Cmd))
if (isAllSectionDescription(*Sec))
continue;
auto *OutSec = make<OutputSection>(Cmd->Name, SHT_PROGBITS, Flags);
OutSec->SectionIndex = I;
Cmd->Sec = OutSec;
SecToCommand[OutSec] = Cmd;
Sec->Live = true;
Sec->SectionIndex = I;
Sec->Flags = Flags;
}
}
void LinkerScript::adjustSectionsAfterSorting() {
// Try and find an appropriate memory region to assign offsets in.
for (BaseCommand *Base : Opt.Commands) {
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) {
Cmd->MemRegion = findMemoryRegion(Cmd);
if (auto *Sec = dyn_cast<OutputSection>(Base)) {
Sec->MemRegion = findMemoryRegion(Sec);
// Handle align (e.g. ".foo : ALIGN(16) { ... }").
if (Cmd->AlignExpr && Cmd->Sec)
Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue());
if (Sec->AlignExpr)
Sec->updateAlignment(Sec->AlignExpr().getValue());
}
}
@@ -743,18 +672,17 @@ void LinkerScript::adjustSectionsAfterSorting() {
// Walk the commands and propagate the program headers to commands that don't
// explicitly specify them.
for (BaseCommand *Base : Opt.Commands) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd)
auto *Sec = dyn_cast<OutputSection>(Base);
if (!Sec)
continue;
if (Cmd->Phdrs.empty()) {
OutputSection *Sec = Cmd->Sec;
if (Sec->Phdrs.empty()) {
// To match the bfd linker script behaviour, only propagate program
// headers to sections that are allocated.
if (Sec && (Sec->Flags & SHF_ALLOC))
Cmd->Phdrs = DefPhdrs;
if (Sec->Flags & SHF_ALLOC)
Sec->Phdrs = DefPhdrs;
} else {
DefPhdrs = Cmd->Phdrs;
DefPhdrs = Sec->Phdrs;
}
}
@@ -763,11 +691,9 @@ void LinkerScript::adjustSectionsAfterSorting() {
void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) {
uint64_t Min = std::numeric_limits<uint64_t>::max();
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections)
if (Sec->Flags & SHF_ALLOC)
Min = std::min<uint64_t>(Min, Sec->Addr);
}
auto It = llvm::find_if(
Phdrs, [](const PhdrEntry *E) { return E->p_type == PT_LOAD; });
@@ -785,19 +711,16 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) {
assert(FirstPTLoad->First == Out::ElfHeader);
OutputSection *ActualFirst = nullptr;
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections) {
if (Sec->FirstInPtLoad == Out::ElfHeader) {
ActualFirst = Sec;
break;
}
}
if (ActualFirst) {
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections)
if (Sec->FirstInPtLoad == Out::ElfHeader)
Sec->FirstInPtLoad = ActualFirst;
}
FirstPTLoad->First = ActualFirst;
} else {
Phdrs.erase(It);
@@ -839,8 +762,7 @@ void LinkerScript::assignAddresses() {
continue;
}
auto *Cmd = cast<OutputSectionCommand>(Base);
assignOffsets(Cmd);
assignOffsets(cast<OutputSection>(Base));
}
CurAddressState = nullptr;
}
@@ -868,10 +790,9 @@ std::vector<PhdrEntry *> LinkerScript::createPhdrs() {
}
// Add output sections to program headers.
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
for (OutputSection *Sec : OutputSections) {
// Assign headers specified by linker script
for (size_t Id : getPhdrIndices(Cmd)) {
OutputSection *Sec = Cmd->Sec;
for (size_t Id : getPhdrIndices(Sec)) {
Ret[Id]->add(Sec);
if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
Ret[Id]->p_flags |= Sec->getPhdrFlags();
@@ -891,273 +812,6 @@ bool LinkerScript::ignoreInterpSection() {
return true;
}
OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {
auto I = SecToCommand.find(Sec);
if (I == SecToCommand.end())
return nullptr;
return I->second;
}
void OutputSectionCommand::sort(std::function<int(InputSectionBase *S)> Order) {
typedef std::pair<unsigned, InputSection *> Pair;
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
std::vector<Pair> V;
assert(Commands.size() == 1);
auto *ISD = cast<InputSectionDescription>(Commands[0]);
for (InputSection *S : ISD->Sections)
V.push_back({Order(S), S});
std::stable_sort(V.begin(), V.end(), Comp);
ISD->Sections.clear();
for (Pair &P : V)
ISD->Sections.push_back(P.second);
}
// Returns true if S matches /Filename.?\.o$/.
static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
if (!S.endswith(".o"))
return false;
S = S.drop_back(2);
if (S.endswith(Filename))
return true;
return !S.empty() && S.drop_back().endswith(Filename);
}
static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
// .ctors and .dtors are sorted by this priority from highest to lowest.
//
// 1. The section was contained in crtbegin (crtbegin contains
// some sentinel value in its .ctors and .dtors so that the runtime
// can find the beginning of the sections.)
//
// 2. The section has an optional priority value in the form of ".ctors.N"
// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
// they are compared as string rather than number.
//
// 3. The section is just ".ctors" or ".dtors".
//
// 4. The section was contained in crtend, which contains an end marker.
//
// In an ideal world, we don't need this function because .init_array and
// .ctors are duplicate features (and .init_array is newer.) However, there
// are too many real-world use cases of .ctors, so we had no choice to
// support that with this rather ad-hoc semantics.
static bool compCtors(const InputSection *A, const InputSection *B) {
bool BeginA = isCrtbegin(A->File->getName());
bool BeginB = isCrtbegin(B->File->getName());
if (BeginA != BeginB)
return BeginA;
bool EndA = isCrtend(A->File->getName());
bool EndB = isCrtend(B->File->getName());
if (EndA != EndB)
return EndB;
StringRef X = A->Name;
StringRef Y = B->Name;
assert(X.startswith(".ctors") || X.startswith(".dtors"));
assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
X = X.substr(6);
Y = Y.substr(6);
if (X.empty() && Y.empty())
return false;
return X < Y;
}
// Sorts input sections by the special rules for .ctors and .dtors.
// Unfortunately, the rules are different from the one for .{init,fini}_array.
// Read the comment above.
void OutputSectionCommand::sortCtorsDtors() {
assert(Commands.size() == 1);
auto *ISD = cast<InputSectionDescription>(Commands[0]);
std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors);
}
// Sorts input sections by section name suffixes, so that .foo.N comes
// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
// We want to keep the original order if the priorities are the same
// because the compiler keeps the original initialization order in a
// translation unit and we need to respect that.
// For more detail, read the section of the GCC's manual about init_priority.
void OutputSectionCommand::sortInitFini() {
// Sort sections by priority.
sort([](InputSectionBase *S) { return getPriority(S->Name); });
}
uint32_t OutputSectionCommand::getFiller() {
if (Filler)
return *Filler;
if (Sec->Flags & SHF_EXECINSTR)
return Target->TrapInstr;
return 0;
}
static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
if (Size == 1)
*Buf = Data;
else if (Size == 2)
write16(Buf, Data, Config->Endianness);
else if (Size == 4)
write32(Buf, Data, Config->Endianness);
else if (Size == 8)
write64(Buf, Data, Config->Endianness);
else
llvm_unreachable("unsupported Size argument");
}
static bool compareByFilePosition(InputSection *A, InputSection *B) {
// Synthetic doesn't have link order dependecy, stable_sort will keep it last
if (A->kind() == InputSectionBase::Synthetic ||
B->kind() == InputSectionBase::Synthetic)
return false;
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;
}
template <class ELFT>
static void finalizeShtGroup(OutputSection *OS,
ArrayRef<InputSection *> Sections) {
assert(Config->Relocatable && Sections.size() == 1);
// sh_link field for SHT_GROUP sections should contain the section index of
// the symbol table.
OS->Link = InX::SymTab->getParent()->SectionIndex;
// sh_info then contain index of an entry in symbol table section which
// provides signature of the section group.
ObjFile<ELFT> *Obj = Sections[0]->getFile<ELFT>();
ArrayRef<SymbolBody *> Symbols = Obj->getSymbols();
OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]);
}
template <class ELFT> void OutputSectionCommand::finalize() {
// Link order may be distributed across several InputSectionDescriptions
// but sort must consider them all at once.
std::vector<InputSection **> ScriptSections;
std::vector<InputSection *> Sections;
for (BaseCommand *Base : Commands)
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
for (InputSection *&IS : ISD->Sections) {
ScriptSections.push_back(&IS);
Sections.push_back(IS);
}
if ((Sec->Flags & SHF_LINK_ORDER)) {
std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition);
for (int I = 0, N = Sections.size(); I < N; ++I)
*ScriptSections[I] = Sections[I];
// We must preserve the link order dependency of sections with the
// SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
// need to translate the InputSection sh_link to the OutputSection sh_link,
// all InputSections in the OutputSection have the same dependency.
if (auto *D = Sections.front()->getLinkOrderDep())
Sec->Link = D->getParent()->SectionIndex;
}
uint32_t Type = Sec->Type;
if (Type == SHT_GROUP) {
finalizeShtGroup<ELFT>(Sec, Sections);
return;
}
if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
return;
InputSection *First = Sections[0];
if (isa<SyntheticSection>(First))
return;
Sec->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();
Sec->Info = S->getOutputSection()->SectionIndex;
Sec->Flags |= SHF_INFO_LINK;
}
// 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) {
if (Sec->Type == SHT_NOBITS)
return;
Sec->Loc = Buf;
// If -compress-debug-section is specified and if this is a debug seciton,
// we've already compressed section contents. If that's the case,
// just write it down.
if (!Sec->CompressedData.empty()) {
memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size());
memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(),
Sec->CompressedData.size());
return;
}
// Write leading padding.
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);
parallelForEachN(0, Sections.size(), [=](size_t I) {
InputSection *IS = Sections[I];
IS->writeTo<ELFT>(Buf);
// Fill gaps between sections.
if (Filler) {
uint8_t *Start = Buf + IS->OutSecOff + IS->getSize();
uint8_t *End;
if (I + 1 == Sections.size())
End = Buf + Sec->Size;
else
End = Buf + Sections[I + 1]->OutSecOff;
fill(Start, End - Start, Filler);
}
});
// Linker scripts may have BYTE()-family commands with which you
// can write arbitrary bytes to the output. Process them if any.
for (BaseCommand *Base : Commands)
if (auto *Data = dyn_cast<BytesDataCommand>(Base))
writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
}
ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
if (S == ".")
return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc};
@@ -1177,7 +831,7 @@ static const size_t NoPhdr = -1;
// Returns indices of ELF headers containing specific section. Each index is a
// zero based number of ELF header listed within PHDRS {} script block.
std::vector<size_t> LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) {
std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Cmd) {
std::vector<size_t> Ret;
for (StringRef PhdrName : Cmd->Phdrs) {
size_t Index = getPhdrIndex(Cmd->Location, PhdrName);
@@ -1202,18 +856,3 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
return NoPhdr;
}
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>();
template void OutputSectionCommand::finalize<ELF32LE>();
template void OutputSectionCommand::finalize<ELF32BE>();
template void OutputSectionCommand::finalize<ELF64LE>();
template void OutputSectionCommand::finalize<ELF64BE>();

View File

@@ -114,37 +114,6 @@ struct MemoryRegion {
uint32_t NegFlags;
};
struct OutputSectionCommand : BaseCommand {
OutputSectionCommand(StringRef Name)
: BaseCommand(OutputSectionKind), Name(Name) {}
static bool classof(const BaseCommand *C);
OutputSection *Sec = nullptr;
MemoryRegion *MemRegion = nullptr;
StringRef Name;
Expr AddrExpr;
Expr AlignExpr;
Expr LMAExpr;
Expr SubalignExpr;
std::vector<BaseCommand *> Commands;
std::vector<StringRef> Phdrs;
llvm::Optional<uint32_t> Filler;
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
bool Noload = false;
template <class ELFT> void finalize();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void maybeCompress();
uint32_t getFiller();
void sort(std::function<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
};
// This struct represents one section match pattern in SECTIONS() command.
// It can optionally have negative match pattern for EXCLUDED_FILE command.
// Also it may be surrounded with SORT() command, so contains sorting rules.
@@ -236,8 +205,7 @@ class LinkerScript final {
std::function<uint64_t()> LMAOffset;
AddressState(const ScriptConfiguration &Opt);
};
llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
llvm::DenseMap<StringRef, OutputSectionCommand *> NameToOutputSectionCommand;
llvm::DenseMap<StringRef, OutputSection *> NameToOutputSection;
void assignSymbol(SymbolAssignment *Cmd, bool InSec);
void setDot(Expr E, const Twine &Loc, bool InSec);
@@ -245,13 +213,12 @@ class LinkerScript final {
std::vector<InputSection *>
computeInputSections(const InputSectionDescription *);
std::vector<InputSectionBase *>
createInputSectionList(OutputSectionCommand &Cmd);
std::vector<InputSectionBase *> createInputSectionList(OutputSection &Cmd);
std::vector<size_t> getPhdrIndices(OutputSectionCommand *Cmd);
std::vector<size_t> getPhdrIndices(OutputSection *Sec);
size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
MemoryRegion *findMemoryRegion(OutputSection *Sec);
void switchTo(OutputSection *Sec);
uint64_t advance(uint64_t Size, unsigned Align);
@@ -265,11 +232,9 @@ class LinkerScript final {
public:
bool ErrorOnMissingSection = false;
OutputSectionCommand *createOutputSectionCommand(StringRef Name,
StringRef Location);
OutputSectionCommand *getOrCreateOutputSectionCommand(StringRef Name);
OutputSection *createOutputSection(StringRef Name, StringRef Location);
OutputSection *getOrCreateOutputSection(StringRef Name);
OutputSectionCommand *getCmd(OutputSection *Sec) const;
bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
uint64_t getDot() { return Dot; }
void discard(ArrayRef<InputSectionBase *> V);
@@ -287,7 +252,7 @@ public:
bool ignoreInterpSection();
bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd);
void assignOffsets(OutputSection *Sec);
void assignAddresses();
void allocateHeaders(std::vector<PhdrEntry *> &Phdrs);
void addSymbol(SymbolAssignment *Cmd);

View File

@@ -99,8 +99,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
return Ret;
}
template <class ELFT>
void elf::writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script) {
template <class ELFT> void elf::writeMapFile() {
if (Config->MapFile.empty())
return;
@@ -123,13 +122,12 @@ void elf::writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script) {
<< " Align Out In Symbol\n";
// Print out file contents.
for (OutputSectionCommand *Cmd : Script) {
OutputSection *OSec = Cmd->Sec;
for (OutputSection *OSec : OutputSections) {
writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment);
OS << OSec->Name << '\n';
// Dump symbols for each input section.
for (BaseCommand *Base : Cmd->Commands) {
for (BaseCommand *Base : OSec->Commands) {
auto *ISD = dyn_cast<InputSectionDescription>(Base);
if (!ISD)
continue;
@@ -144,7 +142,7 @@ void elf::writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script) {
}
}
template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSectionCommand *>);
template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSectionCommand *>);
template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSectionCommand *>);
template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSectionCommand *>);
template void elf::writeMapFile<ELF32LE>();
template void elf::writeMapFile<ELF32BE>();
template void elf::writeMapFile<ELF64LE>();
template void elf::writeMapFile<ELF64BE>();

View File

@@ -14,9 +14,8 @@
namespace lld {
namespace elf {
struct OutputSectionCommand;
template <class ELFT>
void writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script);
class OutputSection;
template <class ELFT> void writeMapFile();
} // namespace elf
} // namespace lld

View File

@@ -17,6 +17,7 @@
#include "Target.h"
#include "Threads.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SHA1.h"
@@ -42,7 +43,6 @@ OutputSection *Out::InitArray;
OutputSection *Out::FiniArray;
std::vector<OutputSection *> elf::OutputSections;
std::vector<OutputSectionCommand *> elf::OutputSectionCommands;
uint32_t OutputSection::getPhdrFlags() const {
uint32_t Ret = PF_R;
@@ -68,10 +68,13 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
}
OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
: SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
: BaseCommand(OutputSectionKind),
SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
/*Info*/ 0,
/*Link*/ 0),
SectionIndex(INT_MAX) {}
SectionIndex(INT_MAX) {
Live = false;
}
static uint64_t updateOffset(uint64_t Off, InputSection *S) {
Off = alignTo(Off, S->Alignment);
@@ -81,7 +84,7 @@ static uint64_t updateOffset(uint64_t Off, InputSection *S) {
void OutputSection::addSection(InputSection *S) {
assert(S->Live);
Sections.push_back(S);
Live = true;
S->Parent = this;
this->updateAlignment(S->Alignment);
@@ -99,6 +102,14 @@ void OutputSection::addSection(InputSection *S) {
// Probably we sholuld handle that as an error. But for now we just
// pick the largest sh_entsize.
this->Entsize = std::max(this->Entsize, S->Entsize);
if (!S->Assigned) {
S->Assigned = true;
if (Commands.empty() || !isa<InputSectionDescription>(Commands.back()))
Commands.push_back(make<InputSectionDescription>(""));
auto *ISD = cast<InputSectionDescription>(Commands.back());
ISD->Sections.push_back(S);
}
}
static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
@@ -220,7 +231,7 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS,
return;
}
if (Sec) {
if (Sec && Sec->Live) {
if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))
error("incompatible section flags for " + Sec->Name + "\n>>> " +
toString(IS) + ": 0x" + utohexstr(IS->Flags) +
@@ -238,8 +249,12 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS,
}
Sec->Flags |= IS->Flags;
} else {
Sec = make<OutputSection>(OutsecName, IS->Type, IS->Flags);
OutputSections.push_back(Sec);
if (!Sec) {
Sec = Script->createOutputSection(OutsecName, "<internal>");
Script->Opt.Commands.push_back(Sec);
}
Sec->Type = IS->Type;
Sec->Flags = IS->Flags;
}
Sec->addSection(cast<InputSection>(IS));
@@ -271,7 +286,307 @@ uint64_t elf::getHeaderSize() {
return Out::ElfHeader->Size + Out::ProgramHeaders->Size;
}
bool OutputSection::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind;
}
void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) {
typedef std::pair<unsigned, InputSection *> Pair;
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
std::vector<Pair> V;
assert(Commands.size() == 1);
auto *ISD = cast<InputSectionDescription>(Commands[0]);
for (InputSection *S : ISD->Sections)
V.push_back({Order(S), S});
std::stable_sort(V.begin(), V.end(), Comp);
ISD->Sections.clear();
for (Pair &P : V)
ISD->Sections.push_back(P.second);
}
// Fill [Buf, Buf + Size) with Filler.
// This is used for linker script "=fillexp" command.
static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
size_t I = 0;
for (; I + 4 < Size; I += 4)
memcpy(Buf + I, &Filler, 4);
memcpy(Buf + I, &Filler, Size - I);
}
// 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);
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;
}
static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
if (Size == 1)
*Buf = Data;
else if (Size == 2)
write16(Buf, Data, Config->Endianness);
else if (Size == 4)
write32(Buf, Data, Config->Endianness);
else if (Size == 8)
write64(Buf, Data, Config->Endianness);
else
llvm_unreachable("unsupported Size argument");
}
template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
if (Type == SHT_NOBITS)
return;
Loc = Buf;
// If -compress-debug-section is specified and if this is a debug seciton,
// we've already compressed section contents. If that's the case,
// just write it down.
if (!CompressedData.empty()) {
memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size());
memcpy(Buf + ZDebugHeader.size(), CompressedData.data(),
CompressedData.size());
return;
}
// Write leading padding.
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() ? Size : Sections[0]->OutSecOff, Filler);
parallelForEachN(0, Sections.size(), [=](size_t I) {
InputSection *IS = Sections[I];
IS->writeTo<ELFT>(Buf);
// Fill gaps between sections.
if (Filler) {
uint8_t *Start = Buf + IS->OutSecOff + IS->getSize();
uint8_t *End;
if (I + 1 == Sections.size())
End = Buf + Size;
else
End = Buf + Sections[I + 1]->OutSecOff;
fill(Start, End - Start, Filler);
}
});
// Linker scripts may have BYTE()-family commands with which you
// can write arbitrary bytes to the output. Process them if any.
for (BaseCommand *Base : Commands)
if (auto *Data = dyn_cast<BytesDataCommand>(Base))
writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
}
static bool compareByFilePosition(InputSection *A, InputSection *B) {
// Synthetic doesn't have link order dependecy, stable_sort will keep it last
if (A->kind() == InputSectionBase::Synthetic ||
B->kind() == InputSectionBase::Synthetic)
return false;
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;
}
template <class ELFT>
static void finalizeShtGroup(OutputSection *OS,
ArrayRef<InputSection *> Sections) {
assert(Config->Relocatable && Sections.size() == 1);
// sh_link field for SHT_GROUP sections should contain the section index of
// the symbol table.
OS->Link = InX::SymTab->getParent()->SectionIndex;
// sh_info then contain index of an entry in symbol table section which
// provides signature of the section group.
ObjFile<ELFT> *Obj = Sections[0]->getFile<ELFT>();
ArrayRef<SymbolBody *> Symbols = Obj->getSymbols();
OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]);
}
template <class ELFT> void OutputSection::finalize() {
// Link order may be distributed across several InputSectionDescriptions
// but sort must consider them all at once.
std::vector<InputSection **> ScriptSections;
std::vector<InputSection *> Sections;
for (BaseCommand *Base : Commands)
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
for (InputSection *&IS : ISD->Sections) {
ScriptSections.push_back(&IS);
Sections.push_back(IS);
}
if ((Flags & SHF_LINK_ORDER)) {
std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition);
for (int I = 0, N = Sections.size(); I < N; ++I)
*ScriptSections[I] = Sections[I];
// We must preserve the link order dependency of sections with the
// SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
// need to translate the InputSection sh_link to the OutputSection sh_link,
// all InputSections in the OutputSection have the same dependency.
if (auto *D = Sections.front()->getLinkOrderDep())
Link = D->getParent()->SectionIndex;
}
if (Type == SHT_GROUP) {
finalizeShtGroup<ELFT>(this, Sections);
return;
}
if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
return;
InputSection *First = Sections[0];
if (isa<SyntheticSection>(First))
return;
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();
Info = S->getOutputSection()->SectionIndex;
Flags |= SHF_INFO_LINK;
}
// Returns true if S matches /Filename.?\.o$/.
static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
if (!S.endswith(".o"))
return false;
S = S.drop_back(2);
if (S.endswith(Filename))
return true;
return !S.empty() && S.drop_back().endswith(Filename);
}
static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
// .ctors and .dtors are sorted by this priority from highest to lowest.
//
// 1. The section was contained in crtbegin (crtbegin contains
// some sentinel value in its .ctors and .dtors so that the runtime
// can find the beginning of the sections.)
//
// 2. The section has an optional priority value in the form of ".ctors.N"
// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
// they are compared as string rather than number.
//
// 3. The section is just ".ctors" or ".dtors".
//
// 4. The section was contained in crtend, which contains an end marker.
//
// In an ideal world, we don't need this function because .init_array and
// .ctors are duplicate features (and .init_array is newer.) However, there
// are too many real-world use cases of .ctors, so we had no choice to
// support that with this rather ad-hoc semantics.
static bool compCtors(const InputSection *A, const InputSection *B) {
bool BeginA = isCrtbegin(A->File->getName());
bool BeginB = isCrtbegin(B->File->getName());
if (BeginA != BeginB)
return BeginA;
bool EndA = isCrtend(A->File->getName());
bool EndB = isCrtend(B->File->getName());
if (EndA != EndB)
return EndB;
StringRef X = A->Name;
StringRef Y = B->Name;
assert(X.startswith(".ctors") || X.startswith(".dtors"));
assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
X = X.substr(6);
Y = Y.substr(6);
if (X.empty() && Y.empty())
return false;
return X < Y;
}
// Sorts input sections by the special rules for .ctors and .dtors.
// Unfortunately, the rules are different from the one for .{init,fini}_array.
// Read the comment above.
void OutputSection::sortCtorsDtors() {
assert(Commands.size() == 1);
auto *ISD = cast<InputSectionDescription>(Commands[0]);
std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors);
}
// If an input string is in the form of "foo.N" where N is a number,
// return N. Otherwise, returns 65536, which is one greater than the
// lowest priority.
int elf::getPriority(StringRef S) {
size_t Pos = S.rfind('.');
if (Pos == StringRef::npos)
return 65536;
int V;
if (!to_integer(S.substr(Pos + 1), V, 10))
return 65536;
return V;
}
// Sorts input sections by section name suffixes, so that .foo.N comes
// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
// We want to keep the original order if the priorities are the same
// because the compiler keeps the original initialization order in a
// translation unit and we need to respect that.
// For more detail, read the section of the GCC's manual about init_priority.
void OutputSection::sortInitFini() {
// Sort sections by priority.
sort([](InputSectionBase *S) { return getPriority(S->Name); });
}
uint32_t OutputSection::getFiller() {
if (Filler)
return *Filler;
if (Flags & SHF_EXECINSTR)
return Target->TrapInstr;
return 0;
}
template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf);
template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf);
template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf);
template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf);
template void OutputSection::maybeCompress<ELF32LE>();
template void OutputSection::maybeCompress<ELF32BE>();
template void OutputSection::maybeCompress<ELF64LE>();
template void OutputSection::maybeCompress<ELF64BE>();
template void OutputSection::finalize<ELF32LE>();
template void OutputSection::finalize<ELF32BE>();
template void OutputSection::finalize<ELF64LE>();
template void OutputSection::finalize<ELF64BE>();

View File

@@ -12,6 +12,7 @@
#include "Config.h"
#include "InputSection.h"
#include "LinkerScript.h"
#include "Relocations.h"
#include "lld/Core/LLVM.h"
@@ -38,13 +39,14 @@ class DefinedRegular;
// It is composed of multiple InputSections.
// The writer creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
class OutputSection final : public SectionBase {
class OutputSection final : public BaseCommand, public SectionBase {
public:
OutputSection(StringRef Name, uint32_t Type, uint64_t Flags);
static bool classof(const SectionBase *S) {
return S->kind() == SectionBase::Output;
}
static bool classof(const BaseCommand *C);
uint64_t getLMA() const { return Addr + LMAOffset; }
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
@@ -80,7 +82,6 @@ public:
uint32_t ShName = 0;
void addSection(InputSection *S);
std::vector<InputSection *> Sections;
// Used for implementation of --compress-debug-sections option.
std::vector<uint8_t> ZDebugHeader;
@@ -88,8 +89,33 @@ public:
// Location in the output buffer.
uint8_t *Loc = nullptr;
// The following members are normally only used in linker scripts.
MemoryRegion *MemRegion = nullptr;
Expr AddrExpr;
Expr AlignExpr;
Expr LMAExpr;
Expr SubalignExpr;
std::vector<BaseCommand *> Commands;
std::vector<StringRef> Phdrs;
llvm::Optional<uint32_t> Filler;
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
bool Noload = false;
template <class ELFT> void finalize();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void maybeCompress();
uint32_t getFiller();
void sort(std::function<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
};
int getPriority(StringRef S);
// All output sections that are handled by the linker specially are
// globally accessible. Writer initializes them, so don't use them
// until Writer is initialized.
@@ -146,7 +172,6 @@ uint64_t getHeaderSize();
void reportDiscarded(InputSectionBase *IS);
extern std::vector<OutputSection *> OutputSections;
extern std::vector<OutputSectionCommand *> OutputSectionCommands;
} // namespace elf
} // namespace lld

View File

@@ -1006,7 +1006,7 @@ void ThunkCreator::mergeThunks() {
}
}
static uint32_t findEndOfFirstNonExec(OutputSectionCommand &Cmd) {
static uint32_t findEndOfFirstNonExec(OutputSection &Cmd) {
for (BaseCommand *Base : Cmd.Commands)
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
for (auto *IS : ISD->Sections)
@@ -1015,11 +1015,11 @@ static uint32_t findEndOfFirstNonExec(OutputSectionCommand &Cmd) {
return 0;
}
ThunkSection *ThunkCreator::getOSThunkSec(OutputSectionCommand *Cmd,
ThunkSection *ThunkCreator::getOSThunkSec(OutputSection *Cmd,
std::vector<InputSection *> *ISR) {
if (CurTS == nullptr) {
uint32_t Off = findEndOfFirstNonExec(*Cmd);
CurTS = addThunkSection(Cmd->Sec, ISR, Off);
CurTS = addThunkSection(Cmd, ISR, Off);
}
return CurTS;
}
@@ -1028,10 +1028,9 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) {
ThunkSection *TS = ThunkedSections.lookup(IS);
if (TS)
return TS;
auto *TOS = IS->getParent();
// Find InputSectionRange within TOS that IS is in
OutputSectionCommand *C = Script->getCmd(TOS);
OutputSection *C = IS->getParent();
std::vector<InputSection *> *Range = nullptr;
for (BaseCommand *BC : C->Commands)
if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
@@ -1043,15 +1042,15 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) {
break;
}
}
TS = addThunkSection(TOS, Range, IS->OutSecOff);
TS = addThunkSection(C, Range, IS->OutSecOff);
ThunkedSections[IS] = TS;
return TS;
}
ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
ThunkSection *ThunkCreator::addThunkSection(OutputSection *Cmd,
std::vector<InputSection *> *ISR,
uint64_t Off) {
auto *TS = make<ThunkSection>(OS, Off);
auto *TS = make<ThunkSection>(Cmd, Off);
ThunkSections[ISR].push_back(TS);
return TS;
}
@@ -1074,19 +1073,18 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body,
// Call Fn on every executable InputSection accessed via the linker script
// InputSectionDescription::Sections.
void ThunkCreator::forEachExecInputSection(
ArrayRef<OutputSectionCommand *> OutputSections,
std::function<void(OutputSectionCommand *, std::vector<InputSection *> *,
ArrayRef<OutputSection *> OutputSections,
std::function<void(OutputSection *, std::vector<InputSection *> *,
InputSection *)>
Fn) {
for (OutputSectionCommand *Cmd : OutputSections) {
OutputSection *OS = Cmd->Sec;
for (OutputSection *OS : OutputSections) {
if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
continue;
for (BaseCommand *BC : Cmd->Commands)
for (BaseCommand *BC : OS->Commands)
if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
CurTS = nullptr;
for (InputSection *IS : ISD->Sections)
Fn(Cmd, &ISD->Sections, IS);
Fn(OS, &ISD->Sections, IS);
}
}
}
@@ -1101,8 +1099,7 @@ void ThunkCreator::forEachExecInputSection(
//
// FIXME: All Thunks are assumed to be in range of the relocation. Range
// extension Thunks are not yet supported.
bool ThunkCreator::createThunks(
ArrayRef<OutputSectionCommand *> OutputSections) {
bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
if (Pass > 0)
ThunkSections.clear();
@@ -1112,7 +1109,7 @@ bool ThunkCreator::createThunks(
// We separate the creation of ThunkSections from the insertion of the
// ThunkSections back into the OutputSection as ThunkSections are not always
// inserted into the same OutputSection as the caller.
forEachExecInputSection(OutputSections, [&](OutputSectionCommand *Cmd,
forEachExecInputSection(OutputSections, [&](OutputSection *Cmd,
std::vector<InputSection *> *ISR,
InputSection *IS) {
for (Relocation &Rel : IS->Relocations) {
@@ -1127,7 +1124,7 @@ bool ThunkCreator::createThunks(
// Find or create a ThunkSection for the new Thunk
ThunkSection *TS;
if (auto *TIS = T->getTargetInputSection())
TS = getISThunkSec(TIS, Cmd->Sec);
TS = getISThunkSec(TIS, Cmd);
else
TS = getOSThunkSec(Cmd, ISR);
TS->addThunk(T);

View File

@@ -21,7 +21,7 @@ class SymbolBody;
class InputSection;
class InputSectionBase;
class OutputSection;
struct OutputSectionCommand;
class OutputSection;
// List of target-independent relocation types. Relocations read
// from files are converted to these types so that the main code
@@ -125,7 +125,7 @@ class Thunk;
class ThunkCreator {
public:
// Return true if Thunks have been added to OutputSections
bool createThunks(ArrayRef<OutputSectionCommand *> OutputSections);
bool createThunks(ArrayRef<OutputSection *> OutputSections);
// The number of completed passes of createThunks this permits us
// to do one time initialization on Pass 0 and put a limit on the
@@ -134,16 +134,16 @@ public:
private:
void mergeThunks();
ThunkSection *getOSThunkSec(OutputSectionCommand *Cmd,
ThunkSection *getOSThunkSec(OutputSection *Cmd,
std::vector<InputSection *> *ISR);
ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS);
void forEachExecInputSection(
ArrayRef<OutputSectionCommand *> OutputSections,
std::function<void(OutputSectionCommand *, std::vector<InputSection *> *,
ArrayRef<OutputSection *> OutputSections,
std::function<void(OutputSection *, std::vector<InputSection *> *,
InputSection *)>
Fn);
std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type);
ThunkSection *addThunkSection(OutputSection *OS,
ThunkSection *addThunkSection(OutputSection *Cmd,
std::vector<InputSection *> *, uint64_t Off);
// Record all the available Thunks for a Symbol
llvm::DenseMap<SymbolBody *, std::vector<Thunk *>> ThunkedSymbols;

View File

@@ -55,7 +55,7 @@ public:
private:
void addFile(StringRef Path);
OutputSection *checkSection(OutputSectionCommand *Cmd, StringRef Loccation);
OutputSection *checkSection(OutputSection *Cmd, StringRef Loccation);
void readAsNeeded();
void readEntry();
@@ -76,8 +76,8 @@ private:
BytesDataCommand *readBytesDataCommand(StringRef Tok);
uint32_t readFill();
uint32_t parseFill(StringRef Tok);
void readSectionAddressType(OutputSectionCommand *Cmd);
OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
void readSectionAddressType(OutputSection *Cmd);
OutputSection *readOutputSectionDescription(StringRef OutSec);
std::vector<StringRef> readOutputSectionPhdrs();
InputSectionDescription *readInputSectionDescription(StringRef Tok);
StringMatcher readFilePatterns();
@@ -581,7 +581,7 @@ uint32_t ScriptParser::readFill() {
//
// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
void ScriptParser::readSectionAddressType(OutputSectionCommand *Cmd) {
void ScriptParser::readSectionAddressType(OutputSection *Cmd) {
if (consume("(")) {
if (consume("NOLOAD")) {
expect(")");
@@ -601,10 +601,9 @@ void ScriptParser::readSectionAddressType(OutputSectionCommand *Cmd) {
}
}
OutputSectionCommand *
ScriptParser::readOutputSectionDescription(StringRef OutSec) {
OutputSectionCommand *Cmd =
Script->createOutputSectionCommand(OutSec, getCurrentLocation());
OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
OutputSection *Cmd =
Script->createOutputSection(OutSec, getCurrentLocation());
if (peek() != ":")
readSectionAddressType(Cmd);
@@ -857,14 +856,11 @@ StringRef ScriptParser::readParenLiteral() {
return Tok;
}
OutputSection *ScriptParser::checkSection(OutputSectionCommand *Cmd,
OutputSection *ScriptParser::checkSection(OutputSection *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;
return Cmd;
}
Expr ScriptParser::readPrimary() {
@@ -895,7 +891,7 @@ Expr ScriptParser::readPrimary() {
}
if (Tok == "ADDR") {
StringRef Name = readParenLiteral();
OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
OutputSection *Cmd = Script->getOrCreateOutputSection(Name);
return [=]() -> ExprValue {
return {checkSection(Cmd, Location), 0, Location};
};
@@ -916,7 +912,7 @@ Expr ScriptParser::readPrimary() {
}
if (Tok == "ALIGNOF") {
StringRef Name = readParenLiteral();
OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
OutputSection *Cmd = Script->getOrCreateOutputSection(Name);
return [=] { return checkSection(Cmd, Location)->Alignment; };
}
if (Tok == "ASSERT")
@@ -962,7 +958,7 @@ Expr ScriptParser::readPrimary() {
}
if (Tok == "LOADADDR") {
StringRef Name = readParenLiteral();
OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
OutputSection *Cmd = Script->getOrCreateOutputSection(Name);
return [=] { return checkSection(Cmd, Location)->getLMA(); };
}
if (Tok == "ORIGIN") {
@@ -981,11 +977,11 @@ Expr ScriptParser::readPrimary() {
}
if (Tok == "SIZEOF") {
StringRef Name = readParenLiteral();
OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
OutputSection *Cmd = Script->getOrCreateOutputSection(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; };
return [=] { return Cmd->Size; };
}
if (Tok == "SIZEOF_HEADERS")
return [=] { return elf::getHeaderSize(); };

View File

@@ -2282,7 +2282,7 @@ void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
// 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());
OutputSection *C = getParent();
auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(),
[](const BaseCommand *Base) {
return isa<InputSectionDescription>(Base);

View File

@@ -46,7 +46,6 @@ public:
void run();
private:
void clearOutputSections();
void createSyntheticSections();
void copyLocalSymbols();
void addSectionSymbols();
@@ -79,8 +78,7 @@ private:
void addStartEndSymbols();
void addStartStopSymbols(OutputSection *Sec);
uint64_t getEntryAddr();
OutputSection *findSectionInScript(StringRef Name);
OutputSectionCommand *findSectionCommand(StringRef Name);
OutputSection *findSection(StringRef Name);
std::vector<PhdrEntry *> Phdrs;
@@ -150,15 +148,6 @@ template <class ELFT> static void combineEhFrameSections() {
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
}
template <class ELFT> void Writer<ELFT>::clearOutputSections() {
// Clear the OutputSections to make sure it is not used anymore. Any
// code from this point on should be using the linker script
// commands.
for (OutputSection *Sec : OutputSections)
Sec->Sections.clear();
OutputSections.clear();
}
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
// Create linker-synthesized sections such as .got or .plt.
@@ -188,7 +177,6 @@ template <class ELFT> void Writer<ELFT>::run() {
Script->processCommands(Factory);
createSections();
}
clearOutputSections();
if (Config->Discard != DiscardPolicy::All)
copyLocalSymbols();
@@ -210,9 +198,8 @@ template <class ELFT> void Writer<ELFT>::run() {
// 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(
OutputSectionCommands.begin(), OutputSectionCommands.end(),
[](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); });
parallelForEach(OutputSections.begin(), OutputSections.end(),
[](OutputSection *Sec) { Sec->maybeCompress<ELFT>(); });
Script->assignAddresses();
Script->allocateHeaders(Phdrs);
@@ -230,8 +217,8 @@ template <class ELFT> void Writer<ELFT>::run() {
setPhdrs();
if (Config->Relocatable) {
for (OutputSectionCommand *Cmd : OutputSectionCommands)
Cmd->Sec->Addr = 0;
for (OutputSection *Sec : OutputSections)
Sec->Addr = 0;
} else {
fixPredefinedSymbols();
}
@@ -258,7 +245,7 @@ template <class ELFT> void Writer<ELFT>::run() {
return;
// Handle -Map option.
writeMapFile<ELFT>(OutputSectionCommands);
writeMapFile<ELFT>();
if (ErrorCount)
return;
@@ -496,15 +483,15 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
// Create one STT_SECTION symbol for each output section we might
// have a relocation with.
for (BaseCommand *Base : Script->Opt.Commands) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd)
auto *Sec = dyn_cast<OutputSection>(Base);
if (!Sec)
continue;
auto I = llvm::find_if(Cmd->Commands, [](BaseCommand *Base) {
auto I = llvm::find_if(Sec->Commands, [](BaseCommand *Base) {
if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
return !ISD->Sections.empty();
return false;
});
if (I == Cmd->Commands.end())
if (I == Sec->Commands.end())
continue;
InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0];
if (isa<SyntheticSection>(IS) || IS->Type == SHT_REL ||
@@ -735,8 +722,8 @@ static unsigned getSectionRank(const OutputSection *Sec) {
}
static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) {
const OutputSection *A = cast<OutputSectionCommand>(ACmd)->Sec;
const OutputSection *B = cast<OutputSectionCommand>(BCmd)->Sec;
const OutputSection *A = cast<OutputSection>(ACmd);
const OutputSection *B = cast<OutputSection>(BCmd);
if (A->SortRank != B->SortRank)
return A->SortRank < B->SortRank;
if (!(A->SortRank & RF_NOT_ADDR_SET))
@@ -867,13 +854,13 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
static void sortInitFini(OutputSectionCommand *Cmd) {
static void sortInitFini(OutputSection *Cmd) {
if (Cmd)
Cmd->sortInitFini();
}
// Sort input sections by the special rule for .ctors and .dtors.
static void sortCtorsDtors(OutputSectionCommand *Cmd) {
static void sortCtorsDtors(OutputSection *Cmd) {
if (Cmd)
Cmd->sortCtorsDtors();
}
@@ -905,8 +892,8 @@ template <class ELFT> static void sortBySymbolsOrder() {
// Sort sections by priority.
for (BaseCommand *Base : Script->Opt.Commands)
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); });
if (auto *Sec = dyn_cast<OutputSection>(Base))
Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); });
}
template <class ELFT>
@@ -932,30 +919,34 @@ void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) {
}
template <class ELFT> void Writer<ELFT>::createSections() {
std::vector<BaseCommand *> Old = Script->Opt.Commands;
Script->Opt.Commands.clear();
for (InputSectionBase *IS : InputSections)
if (IS)
Factory.addInputSec(IS, getOutputSectionName(IS->Name));
Script->Opt.Commands.insert(Script->Opt.Commands.end(), Old.begin(),
Old.end());
Script->fabricateDefaultCommands();
sortBySymbolsOrder<ELFT>();
sortInitFini(findSectionCommand(".init_array"));
sortInitFini(findSectionCommand(".fini_array"));
sortCtorsDtors(findSectionCommand(".ctors"));
sortCtorsDtors(findSectionCommand(".dtors"));
sortInitFini(findSection(".init_array"));
sortInitFini(findSection(".fini_array"));
sortCtorsDtors(findSection(".ctors"));
sortCtorsDtors(findSection(".dtors"));
}
// We want to find how similar two ranks are.
// The more branches in getSectionRank that match, the more similar they are.
// Since each branch corresponds to a bit flag, we can just use
// countLeadingZeros.
static int getRankProximity(OutputSection *A, OutputSection *B) {
static int getRankProximityAux(OutputSection *A, OutputSection *B) {
return countLeadingZeros(A->SortRank ^ B->SortRank);
}
static int getRankProximity(OutputSection *A, BaseCommand *B) {
if (auto *Cmd = dyn_cast<OutputSectionCommand>(B))
if (Cmd->Sec)
return getRankProximity(A, Cmd->Sec);
if (auto *Sec = dyn_cast<OutputSection>(B))
if (Sec->Live)
return getRankProximityAux(A, Sec);
return -1;
}
@@ -974,7 +965,7 @@ static int getRankProximity(OutputSection *A, BaseCommand *B) {
// rw_sec : { *(rw_sec) }
// would mean that the RW PT_LOAD would become unaligned.
static bool shouldSkip(BaseCommand *Cmd) {
if (isa<OutputSectionCommand>(Cmd))
if (isa<OutputSection>(Cmd))
return false;
if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd))
return Assign->Name != ".";
@@ -988,7 +979,7 @@ template <typename ELFT>
static std::vector<BaseCommand *>::iterator
findOrphanPos(std::vector<BaseCommand *>::iterator B,
std::vector<BaseCommand *>::iterator E) {
OutputSection *Sec = cast<OutputSectionCommand>(*E)->Sec;
OutputSection *Sec = cast<OutputSection>(*E);
// Find the first element that has as close a rank as possible.
auto I = std::max_element(B, E, [=](BaseCommand *A, BaseCommand *B) {
@@ -1000,16 +991,16 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B,
// Consider all existing sections with the same proximity.
int Proximity = getRankProximity(Sec, *I);
for (; I != E; ++I) {
auto *Cmd = dyn_cast<OutputSectionCommand>(*I);
if (!Cmd || !Cmd->Sec)
auto *CurSec = dyn_cast<OutputSection>(*I);
if (!CurSec || !CurSec->Live)
continue;
if (getRankProximity(Sec, Cmd->Sec) != Proximity ||
Sec->SortRank < Cmd->Sec->SortRank)
if (getRankProximity(Sec, CurSec) != Proximity ||
Sec->SortRank < CurSec->SortRank)
break;
}
auto J = std::find_if(
llvm::make_reverse_iterator(I), llvm::make_reverse_iterator(B),
[](BaseCommand *Cmd) { return isa<OutputSectionCommand>(Cmd); });
[](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); });
I = J.base();
while (I != E && shouldSkip(*I))
++I;
@@ -1026,18 +1017,15 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
return;
for (BaseCommand *Base : Script->Opt.Commands)
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
if (OutputSection *Sec = Cmd->Sec)
Sec->SortRank = getSectionRank(Sec);
if (auto *Sec = dyn_cast<OutputSection>(Base))
Sec->SortRank = getSectionRank(Sec);
if (!Script->Opt.HasSections) {
// We know that all the OutputSectionCommands are contiguous in
// We know that all the OutputSections are contiguous in
// this case.
auto E = Script->Opt.Commands.end();
auto I = Script->Opt.Commands.begin();
auto IsSection = [](BaseCommand *Base) {
return isa<OutputSectionCommand>(Base);
};
auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); };
I = std::find_if(I, E, IsSection);
E = std::find_if(llvm::make_reverse_iterator(E),
llvm::make_reverse_iterator(I), IsSection)
@@ -1088,8 +1076,8 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
auto I = Script->Opt.Commands.begin();
auto E = Script->Opt.Commands.end();
auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) {
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
return Cmd->Sec && Cmd->Sec->SectionIndex == INT_MAX;
if (auto *Sec = dyn_cast<OutputSection>(Base))
return Sec->Live && Sec->SectionIndex == INT_MAX;
return false;
});
@@ -1109,13 +1097,13 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
while (NonScriptI != E) {
auto Pos = findOrphanPos<ELFT>(I, NonScriptI);
OutputSection *Orphan = cast<OutputSectionCommand>(*NonScriptI)->Sec;
OutputSection *Orphan = cast<OutputSection>(*NonScriptI);
// As an optimization, find all sections with the same sort rank
// and insert them with one rotate.
unsigned Rank = Orphan->SortRank;
auto End = std::find_if(NonScriptI + 1, E, [=](BaseCommand *Cmd) {
return cast<OutputSectionCommand>(Cmd)->Sec->SortRank != Rank;
return cast<OutputSection>(Cmd)->SortRank != Rank;
});
std::rotate(Pos, NonScriptI, End);
NonScriptI = End;
@@ -1149,9 +1137,8 @@ static void removeUnusedSyntheticSections() {
if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable)
continue;
OutputSectionCommand *Cmd = Script->getCmd(OS);
std::vector<BaseCommand *>::iterator Empty = Cmd->Commands.end();
for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) {
std::vector<BaseCommand *>::iterator Empty = OS->Commands.end();
for (auto I = OS->Commands.begin(), E = OS->Commands.end(); I != E; ++I) {
BaseCommand *B = *I;
if (auto *ISD = dyn_cast<InputSectionDescription>(B)) {
auto P = std::find(ISD->Sections.begin(), ISD->Sections.end(), SS);
@@ -1161,17 +1148,17 @@ static void removeUnusedSyntheticSections() {
Empty = I;
}
}
if (Empty != Cmd->Commands.end())
Cmd->Commands.erase(Empty);
if (Empty != OS->Commands.end())
OS->Commands.erase(Empty);
// If there are no other sections in the output section, remove it from the
// output.
if (Cmd->Commands.empty()) {
if (OS->Commands.empty()) {
// Also remove script commands matching the output section.
auto &Cmds = Script->Opt.Commands;
auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd) {
if (auto *OSCmd = dyn_cast<OutputSectionCommand>(Cmd))
return OSCmd->Sec == OS;
auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd2) {
if (auto *Sec = dyn_cast<OutputSection>(Cmd2))
return Sec == OS;
return false;
});
Cmds.erase(I, Cmds.end());
@@ -1181,10 +1168,10 @@ static void removeUnusedSyntheticSections() {
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::finalizeSections() {
Out::DebugInfo = findSectionInScript(".debug_info");
Out::PreinitArray = findSectionInScript(".preinit_array");
Out::InitArray = findSectionInScript(".init_array");
Out::FiniArray = findSectionInScript(".fini_array");
Out::DebugInfo = findSection(".debug_info");
Out::PreinitArray = findSection(".preinit_array");
Out::InitArray = findSection(".init_array");
Out::FiniArray = findSection(".fini_array");
// The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
// symbols for sections, so that the runtime can get the start and end
@@ -1192,9 +1179,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (!Config->Relocatable) {
addStartEndSymbols();
for (BaseCommand *Base : Script->Opt.Commands)
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
if (Cmd->Sec)
addStartStopSymbols(Cmd->Sec);
if (auto *Sec = dyn_cast<OutputSection>(Base))
addStartStopSymbols(Sec);
}
// Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
@@ -1250,16 +1236,16 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
sortSections();
// Now that we have the final list, create a list of all the
// OutputSectionCommands for convenience.
// OutputSections for convenience.
for (BaseCommand *Base : Script->Opt.Commands)
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
OutputSectionCommands.push_back(Cmd);
if (auto *Sec = dyn_cast<OutputSection>(Base))
OutputSections.push_back(Sec);
// Prefer command line supplied address over other constraints.
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
auto I = Config->SectionStartMap.find(Cmd->Name);
for (OutputSection *Sec : OutputSections) {
auto I = Config->SectionStartMap.find(Sec->Name);
if (I != Config->SectionStartMap.end())
Cmd->AddrExpr = [=] { return I->second; };
Sec->AddrExpr = [=] { return I->second; };
}
// This is a bit of a hack. A value of 0 means undef, so we set it
@@ -1268,8 +1254,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
Out::ElfHeader->SectionIndex = 1;
unsigned I = 1;
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections) {
Sec->SectionIndex = I++;
Sec->ShName = InX::ShStrTab->addString(Sec->Name);
}
@@ -1307,10 +1292,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// when no more Thunks are added
ThunkCreator TC;
Script->assignAddresses();
if (TC.createThunks(OutputSectionCommands)) {
if (TC.createThunks(OutputSections)) {
applySynthetic({InX::MipsGot},
[](SyntheticSection *SS) { SS->updateAllocSize(); });
if (TC.createThunks(OutputSectionCommands))
if (TC.createThunks(OutputSections))
fatal("All non-range thunks should be created in first call");
}
}
@@ -1318,8 +1303,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
for (OutputSectionCommand *Cmd : OutputSectionCommands)
Cmd->finalize<ELFT>();
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();
// createThunks may have added local symbols to the static symbol table
applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},
@@ -1329,18 +1314,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
// ARM ABI requires .ARM.exidx to be terminated by some piece of data.
// We have the terminater synthetic section class. Add that at the end.
OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx");
if (!Cmd || !Cmd->Sec || Config->Relocatable)
OutputSection *Cmd = findSection(".ARM.exidx");
if (!Cmd || !Cmd->Live || Config->Relocatable)
return;
auto *Sentinel = make<ARMExidxSentinelSection>();
Cmd->Sec->addSection(Sentinel);
// Add the sentinel to the last of these too.
auto ISD = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
[](const BaseCommand *Base) {
return isa<InputSectionDescription>(Base);
});
cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel);
Cmd->addSection(Sentinel);
}
// The linker is expected to define SECNAME_start and SECNAME_end
@@ -1364,7 +1343,7 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
Define("__init_array_start", "__init_array_end", Out::InitArray);
Define("__fini_array_start", "__fini_array_end", Out::FiniArray);
if (OutputSection *Sec = findSectionInScript(".ARM.exidx"))
if (OutputSection *Sec = findSection(".ARM.exidx"))
Define("__exidx_start", "__exidx_end", Sec);
}
@@ -1382,19 +1361,11 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
}
template <class ELFT>
OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) {
template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) {
for (BaseCommand *Base : Script->Opt.Commands)
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
if (Cmd->Name == Name)
return Cmd;
return nullptr;
}
template <class ELFT>
OutputSection *Writer<ELFT>::findSectionInScript(StringRef Name) {
if (OutputSectionCommand *Cmd = findSectionCommand(Name))
return Cmd->Sec;
if (auto *Sec = dyn_cast<OutputSection>(Base))
if (Sec->Name == Name)
return Sec;
return nullptr;
}
@@ -1435,8 +1406,8 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders);
// PT_INTERP must be the second entry if exists.
if (OutputSection *Sec = findSectionInScript(".interp"))
AddHdr(PT_INTERP, Sec->getPhdrFlags())->add(Sec);
if (OutputSection *Cmd = findSection(".interp"))
AddHdr(PT_INTERP, Cmd->getPhdrFlags())->add(Cmd);
// Add the first PT_LOAD segment for regular output sections.
uint64_t Flags = computeFlags(PF_R);
@@ -1446,8 +1417,7 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
Load->add(Out::ElfHeader);
Load->add(Out::ProgramHeaders);
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections) {
if (!(Sec->Flags & SHF_ALLOC))
break;
if (!needsPtLoad(Sec))
@@ -1459,7 +1429,7 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// different flags or is loaded at a discontiguous address using AT linker
// script command.
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
if (Cmd->LMAExpr || Flags != NewFlags) {
if (Sec->LMAExpr || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
Flags = NewFlags;
}
@@ -1469,11 +1439,9 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// Add a TLS segment if any.
PhdrEntry *TlsHdr = make<PhdrEntry>(PT_TLS, PF_R);
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections)
if (Sec->Flags & SHF_TLS)
TlsHdr->add(Sec);
}
if (TlsHdr->First)
Ret.push_back(TlsHdr);
@@ -1485,11 +1453,9 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// PT_GNU_RELRO includes all sections that should be marked as
// read-only by dynamic linker after proccessing relocations.
PhdrEntry *RelRo = make<PhdrEntry>(PT_GNU_RELRO, PF_R);
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections)
if (needsPtLoad(Sec) && isRelroSection(Sec))
RelRo->add(Sec);
}
if (RelRo->First)
Ret.push_back(RelRo);
@@ -1501,8 +1467,8 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes
// the dynamic linker fill the segment with random data.
if (OutputSection *Sec = findSectionInScript(".openbsd.randomdata"))
AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags())->add(Sec);
if (OutputSection *Cmd = findSection(".openbsd.randomdata"))
AddHdr(PT_OPENBSD_RANDOMIZE, Cmd->getPhdrFlags())->add(Cmd);
// PT_GNU_STACK is a special section to tell the loader to make the
// pages for the stack non-executable. If you really want an executable
@@ -1524,10 +1490,9 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// Create one PT_NOTE per a group of contiguous .note sections.
PhdrEntry *Note = nullptr;
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections) {
if (Sec->Type == SHT_NOTE) {
if (!Note || Cmd->LMAExpr)
if (!Note || Sec->LMAExpr)
Note = AddHdr(PT_NOTE, PF_R);
Note->add(Sec);
} else {
@@ -1541,15 +1506,15 @@ template <class ELFT>
void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry *> &Phdrs) {
if (Config->EMachine != EM_ARM)
return;
auto I = llvm::find_if(OutputSectionCommands, [](OutputSectionCommand *Cmd) {
return Cmd->Sec->Type == SHT_ARM_EXIDX;
auto I = llvm::find_if(OutputSections, [](OutputSection *Cmd) {
return Cmd->Type == SHT_ARM_EXIDX;
});
if (I == OutputSectionCommands.end())
if (I == OutputSections.end())
return;
// PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME
PhdrEntry *ARMExidx = make<PhdrEntry>(PT_ARM_EXIDX, PF_R);
ARMExidx->add((*I)->Sec);
ARMExidx->add(*I);
Phdrs.push_back(ARMExidx);
}
@@ -1557,8 +1522,7 @@ void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry *> &Phdrs) {
// first section after PT_GNU_RELRO have to be page aligned so that the dynamic
// linker can set the permissions.
template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
auto PageAlign = [](OutputSection *Sec) {
OutputSectionCommand *Cmd = Script->getCmd(Sec);
auto PageAlign = [](OutputSection *Cmd) {
if (Cmd && !Cmd->AddrExpr)
Cmd->AddrExpr = [=] {
return alignTo(Script->getDot(), Config->MaxPageSize);
@@ -1576,14 +1540,13 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
PageAlign(P->First);
// Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
// have to align it to a page.
auto End = OutputSectionCommands.end();
auto I =
std::find(OutputSectionCommands.begin(), End, Script->getCmd(P->Last));
auto End = OutputSections.end();
auto I = std::find(OutputSections.begin(), End, P->Last);
if (I == End || (I + 1) == End)
continue;
OutputSection *Sec = (*(I + 1))->Sec;
if (needsPtLoad(Sec))
PageAlign(Sec);
OutputSection *Cmd = (*(I + 1));
if (needsPtLoad(Cmd))
PageAlign(Cmd);
}
}
@@ -1591,41 +1554,39 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
// its new file offset. The file offset must be the same with its
// virtual address (modulo the page size) so that the loader can load
// executables without any address adjustment.
static uint64_t getFileAlignment(uint64_t Off, OutputSection *Sec) {
OutputSection *First = Sec->FirstInPtLoad;
static uint64_t getFileAlignment(uint64_t Off, OutputSection *Cmd) {
OutputSection *First = Cmd->FirstInPtLoad;
// If the section is not in a PT_LOAD, we just have to align it.
if (!First)
return alignTo(Off, Sec->Alignment);
return alignTo(Off, Cmd->Alignment);
// The first section in a PT_LOAD has to have congruent offset and address
// module the page size.
if (Sec == First)
return alignTo(Off, std::max<uint64_t>(Sec->Alignment, Config->MaxPageSize),
Sec->Addr);
if (Cmd == First)
return alignTo(Off, std::max<uint64_t>(Cmd->Alignment, Config->MaxPageSize),
Cmd->Addr);
// If two sections share the same PT_LOAD the file offset is calculated
// using this formula: Off2 = Off1 + (VA2 - VA1).
return First->Offset + Sec->Addr - First->Addr;
return First->Offset + Cmd->Addr - First->Addr;
}
static uint64_t setOffset(OutputSection *Sec, uint64_t Off) {
if (Sec->Type == SHT_NOBITS) {
Sec->Offset = Off;
static uint64_t setOffset(OutputSection *Cmd, uint64_t Off) {
if (Cmd->Type == SHT_NOBITS) {
Cmd->Offset = Off;
return Off;
}
Off = getFileAlignment(Off, Sec);
Sec->Offset = Off;
return Off + Sec->Size;
Off = getFileAlignment(Off, Cmd);
Cmd->Offset = Off;
return Off + Cmd->Size;
}
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
uint64_t Off = 0;
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections)
if (Sec->Flags & SHF_ALLOC)
Off = setOffset(Sec, Off);
}
FileSize = alignTo(Off, Config->Wordsize);
}
@@ -1635,12 +1596,11 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
Off = setOffset(Out::ElfHeader, Off);
Off = setOffset(Out::ProgramHeaders, Off);
for (OutputSectionCommand *Cmd : OutputSectionCommands)
Off = setOffset(Cmd->Sec, Off);
for (OutputSection *Sec : OutputSections)
Off = setOffset(Sec, Off);
SectionHeaderOff = alignTo(Off, Config->Wordsize);
FileSize =
SectionHeaderOff + (OutputSectionCommands.size() + 1) * sizeof(Elf_Shdr);
FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
}
// Finalize the program headers. We call this function after we assign
@@ -1696,7 +1656,7 @@ template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() {
return Addr;
// Case 4
if (OutputSection *Sec = findSectionInScript(".text")) {
if (OutputSection *Sec = findSection(".text")) {
if (Config->WarnMissingEntry)
warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" +
utohexstr(Sec->Addr));
@@ -1738,9 +1698,9 @@ template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
LastRO = P;
}
auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) {
auto Set = [](DefinedRegular *S, OutputSection *Cmd, uint64_t Value) {
if (S) {
S->Section = Sec;
S->Section = Cmd;
S->Value = Value;
}
};
@@ -1759,15 +1719,15 @@ template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
}
if (ElfSym::Bss)
ElfSym::Bss->Section = findSectionInScript(".bss");
ElfSym::Bss->Section = findSection(".bss");
// Setup MIPS _gp_disp/__gnu_local_gp symbols which should
// be equal to the _gp symbol's value.
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;
for (const OutputSection *Cmd : OutputSections) {
const OutputSection *OS = Cmd;
if (OS->Flags & SHF_MIPS_GPREL) {
ElfSym::MipsGp->Value = OS->Addr + 0x7ff0;
break;
@@ -1794,7 +1754,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
EHdr->e_ehsize = sizeof(Elf_Ehdr);
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
EHdr->e_shnum = OutputSectionCommands.size() + 1;
EHdr->e_shnum = OutputSections.size() + 1;
EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex;
if (Config->EMachine == EM_ARM)
@@ -1826,8 +1786,8 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
// Write the section header table. Note that the first table entry is null.
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
for (OutputSectionCommand *Cmd : OutputSectionCommands)
Cmd->Sec->writeHeaderTo<ELFT>(++SHdrs);
for (OutputSection *Sec : OutputSections)
Sec->writeHeaderTo<ELFT>(++SHdrs);
}
// Open a result file.
@@ -1850,11 +1810,9 @@ template <class ELFT> void Writer<ELFT>::openFile() {
template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
uint8_t *Buf = Buffer->getBufferStart();
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections)
if (Sec->Flags & SHF_ALLOC)
Cmd->writeTo<ELFT>(Buf + Sec->Offset);
}
Sec->writeTo<ELFT>(Buf + Sec->Offset);
}
// Write section contents to a mmap'ed file.
@@ -1863,8 +1821,8 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
// PPC64 needs to process relocations in the .opd section
// before processing relocations in code-containing sections.
if (auto *OpdCmd = findSectionCommand(".opd")) {
Out::Opd = OpdCmd->Sec;
if (auto *OpdCmd = findSection(".opd")) {
Out::Opd = OpdCmd;
Out::OpdBuf = Buf + Out::Opd->Offset;
OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
}
@@ -1877,25 +1835,19 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
// In -r or -emit-relocs mode, write the relocation sections first as in
// ELf_Rel targets we might find out that we need to modify the relocated
// section while doing it.
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections)
if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
Cmd->writeTo<ELFT>(Buf + Sec->Offset);
}
Sec->writeTo<ELFT>(Buf + Sec->Offset);
for (OutputSectionCommand *Cmd : OutputSectionCommands) {
OutputSection *Sec = Cmd->Sec;
for (OutputSection *Sec : OutputSections)
if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
Sec->Type != SHT_RELA)
Cmd->writeTo<ELFT>(Buf + Sec->Offset);
}
Sec->writeTo<ELFT>(Buf + Sec->Offset);
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
// it should be written after .eh_frame is written.
if (EhFrameHdr) {
OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr);
Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
}
if (EhFrameHdr)
EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {