summaryrefslogtreecommitdiff
path: root/ELF/LinkerScript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/LinkerScript.cpp')
-rw-r--r--ELF/LinkerScript.cpp132
1 files changed, 86 insertions, 46 deletions
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index 3f872c65897f..d7858e173c7b 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -406,27 +406,22 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
}
// Add input sections to an output section.
- unsigned Pos = 0;
- for (InputSectionBase *S : V) {
- // The actual offset will be computed during
- // assignAddresses. For now, use the index as a very crude
- // approximation so that it is at least easy for other code to
- // know the section order.
- cast<InputSection>(S)->OutSecOff = Pos++;
+ for (InputSectionBase *S : V)
Factory.addInputSec(S, Cmd->Name, Cmd->Sec);
+ if (OutputSection *Sec = Cmd->Sec) {
+ assert(Sec->SectionIndex == INT_MAX);
+ Sec->SectionIndex = I;
}
}
}
CurOutSec = nullptr;
}
-void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) {
+void LinkerScript::fabricateDefaultCommands() {
std::vector<BaseCommand *> Commands;
// Define start address
- uint64_t StartAddr = Config->ImageBase;
- if (AllocateHeader)
- StartAddr += elf::getHeaderSize();
+ uint64_t StartAddr = Config->ImageBase + elf::getHeaderSize();
// The Sections with -T<section> have been sorted in order of ascending
// address. We must lower StartAddr if the lowest -T<section address> as
@@ -488,6 +483,11 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
} else {
auto *Cmd = cast<OutputSectionCommand>(*I);
Factory.addInputSec(S, Name, Cmd->Sec);
+ if (OutputSection *Sec = Cmd->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(S);
Cmd->Commands.push_back(ISD);
@@ -495,17 +495,22 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
}
}
-static bool isTbss(OutputSection *Sec) {
- return (Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS;
+uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) {
+ bool IsTbss = (CurOutSec->Flags & SHF_TLS) && CurOutSec->Type == SHT_NOBITS;
+ uint64_t Start = IsTbss ? Dot + ThreadBssOffset : Dot;
+ Start = alignTo(Start, Align);
+ uint64_t End = Start + Size;
+
+ if (IsTbss)
+ ThreadBssOffset = End - Dot;
+ else
+ Dot = End;
+ return End;
}
void LinkerScript::output(InputSection *S) {
- bool IsTbss = isTbss(CurOutSec);
-
- uint64_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot;
- Pos = alignTo(Pos, S->Alignment);
- S->OutSecOff = Pos - CurOutSec->Addr;
- Pos += S->getSize();
+ uint64_t Pos = advance(S->getSize(), S->Alignment);
+ S->OutSecOff = Pos - S->getSize() - CurOutSec->Addr;
// Update output section size after adding each section. This is so that
// SIZEOF works correctly in the case below:
@@ -524,11 +529,6 @@ void LinkerScript::output(InputSection *S) {
" bytes");
}
}
-
- if (IsTbss)
- ThreadBssOffset = Pos - Dot;
- else
- Dot = Pos;
}
void LinkerScript::switchTo(OutputSection *Sec) {
@@ -536,9 +536,7 @@ void LinkerScript::switchTo(OutputSection *Sec) {
return;
CurOutSec = Sec;
-
- Dot = alignTo(Dot, CurOutSec->Alignment);
- CurOutSec->Addr = isTbss(CurOutSec) ? Dot + ThreadBssOffset : Dot;
+ CurOutSec->Addr = advance(0, CurOutSec->Alignment);
// If neither AT nor AT> is specified for an allocatable section, the linker
// will set the LMA such that the difference between VMA and LMA for the
@@ -643,6 +641,11 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) {
Dot = CurMemRegion->Offset;
switchTo(Sec);
+ // We do not support custom layout for compressed debug sectons.
+ // At this point we already know their size and have compressed content.
+ if (CurOutSec->Flags & SHF_COMPRESSED)
+ return;
+
for (BaseCommand *C : Cmd->Commands)
process(*C);
}
@@ -678,8 +681,9 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// consequeces and gives us a section to put the symbol in.
uint64_t Flags = SHF_ALLOC;
uint32_t Type = SHT_PROGBITS;
- for (BaseCommand *Base : Opt.Commands) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+
+ for (int I = 0, E = Opt.Commands.size(); I != E; ++I) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]);
if (!Cmd)
continue;
if (OutputSection *Sec = Cmd->Sec) {
@@ -692,6 +696,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
continue;
auto *OutSec = make<OutputSection>(Cmd->Name, Type, Flags);
+ OutSec->SectionIndex = I;
OutputSections->push_back(OutSec);
Cmd->Sec = OutSec;
}
@@ -894,6 +899,48 @@ void LinkerScript::synchronize() {
}
}
+static bool allocateHeaders(std::vector<PhdrEntry> &Phdrs,
+ ArrayRef<OutputSection *> OutputSections,
+ uint64_t Min) {
+ auto FirstPTLoad =
+ std::find_if(Phdrs.begin(), Phdrs.end(),
+ [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
+ if (FirstPTLoad == Phdrs.end())
+ return false;
+
+ uint64_t HeaderSize = getHeaderSize();
+ if (HeaderSize <= Min || Script->hasPhdrsCommands()) {
+ Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
+ Out::ElfHeader->Addr = Min;
+ Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
+ return true;
+ }
+
+ assert(FirstPTLoad->First == Out::ElfHeader);
+ OutputSection *ActualFirst = nullptr;
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->FirstInPtLoad == Out::ElfHeader) {
+ ActualFirst = Sec;
+ break;
+ }
+ }
+ if (ActualFirst) {
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->FirstInPtLoad == Out::ElfHeader)
+ Sec->FirstInPtLoad = ActualFirst;
+ FirstPTLoad->First = ActualFirst;
+ } else {
+ Phdrs.erase(FirstPTLoad);
+ }
+
+ auto PhdrI = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) {
+ return E.p_type == PT_PHDR;
+ });
+ if (PhdrI != Phdrs.end())
+ Phdrs.erase(PhdrI);
+ return false;
+}
+
void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
// Assign addresses as instructed by linker script SECTIONS sub-commands.
Dot = 0;
@@ -994,12 +1041,17 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
llvm_unreachable("unsupported Size argument");
}
-void LinkerScript::writeDataBytes(StringRef Name, uint8_t *Buf) {
- int I = getSectionIndex(Name);
- if (I == INT_MAX)
+void LinkerScript::writeDataBytes(OutputSection *Sec, uint8_t *Buf) {
+ auto I = std::find_if(Opt.Commands.begin(), Opt.Commands.end(),
+ [=](BaseCommand *Base) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ if (Cmd->Sec == Sec)
+ return true;
+ return false;
+ });
+ if (I == Opt.Commands.end())
return;
-
- auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]);
+ auto *Cmd = cast<OutputSectionCommand>(*I);
for (BaseCommand *Base : Cmd->Commands)
if (auto *Data = dyn_cast<BytesDataCommand>(Base))
writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
@@ -1013,18 +1065,6 @@ bool LinkerScript::hasLMA(StringRef Name) {
return false;
}
-// Returns the index of the given section name in linker script
-// SECTIONS commands. Sections are laid out as the same order as they
-// were in the script. If a given name did not appear in the script,
-// it returns INT_MAX, so that it will be laid out at end of file.
-int LinkerScript::getSectionIndex(StringRef Name) {
- for (int I = 0, E = Opt.Commands.size(); I != E; ++I)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]))
- if (Cmd->Name == Name)
- return I;
- return INT_MAX;
-}
-
ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
if (S == ".")
return {CurOutSec, Dot - CurOutSec->Addr};