diff options
Diffstat (limited to 'ELF/LinkerScript.cpp')
-rw-r--r-- | ELF/LinkerScript.cpp | 132 |
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}; |