mirror of
https://github.com/intel/llvm.git
synced 2026-01-19 17:45:07 +08:00
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:
@@ -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>();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(); };
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user