From: Rafael Espindola Date: Thu, 27 Jul 2017 19:22:43 +0000 (+0000) Subject: Merge OutputSectionCommand and OutputSection. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8c022ca783ea3eff96fd11993664198c35cd7fc1;p=platform%2Fupstream%2Fllvm.git 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 --- diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 8bf968f..48ad826 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -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(Name); - if (!CmdRef) - CmdRef = Cmd; + Sec = make(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(Name); + CmdRef = make(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 getComparator(SortSectionPolicy K) { @@ -325,7 +297,7 @@ void LinkerScript::discard(ArrayRef V) { } std::vector -LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) { +LinkerScript::createInputSectionList(OutputSection &OutCmd) { std::vector Ret; for (BaseCommand *Base : OutCmd.Commands) { @@ -368,12 +340,12 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { continue; } - if (auto *Cmd = dyn_cast(Opt.Commands[I])) { - std::vector V = createInputSectionList(*Cmd); + if (auto *Sec = dyn_cast(Opt.Commands[I])) { + std::vector 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(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 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( - ".", - [=] { - 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, ""); - OSCmd->Sec = Sec; - SecToCommand[Sec] = OSCmd; - - Commands.push_back(OSCmd); - if (Sec->Sections.size()) { - auto *ISD = make(""); - 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(".", + [=] { + 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(Base)) - return Cmd->Name == Name; + if (auto *Sec = dyn_cast(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, ""); - CmdRef->Sec = Sec; - Opt.Commands.push_back(CmdRef); - } - Cmd = CmdRef; } else { - Cmd = cast(*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(*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(""); - ISD->Sections.push_back(cast(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(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(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(*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(Opt.Commands[I]); - if (!Cmd) + auto *Sec = dyn_cast(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(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(Base)) { - Cmd->MemRegion = findMemoryRegion(Cmd); + if (auto *Sec = dyn_cast(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(Base); - if (!Cmd) + auto *Sec = dyn_cast(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 &Phdrs) { uint64_t Min = std::numeric_limits::max(); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) Min = std::min(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 &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(Base); - assignOffsets(Cmd); + assignOffsets(cast(Base)); } CurAddressState = nullptr; } @@ -868,10 +790,9 @@ std::vector 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 Order) { - typedef std::pair Pair; - auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; - - std::vector V; - assert(Commands.size() == 1); - auto *ISD = cast(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(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 -static void finalizeShtGroup(OutputSection *OS, - ArrayRef 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 *Obj = Sections[0]->getFile(); - ArrayRef Symbols = Obj->getSymbols(); - OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]); -} - -template void OutputSectionCommand::finalize() { - // Link order may be distributed across several InputSectionDescriptions - // but sort must consider them all at once. - std::vector ScriptSections; - std::vector Sections; - for (BaseCommand *Base : Commands) - if (auto *ISD = dyn_cast(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(Sec, Sections); - return; - } - - if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) - return; - - InputSection *First = Sections[0]; - if (isa(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 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(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 Buf(Sec->Size); - writeTo(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 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 Sections; - for (BaseCommand *Cmd : Commands) - if (auto *ISD = dyn_cast(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(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(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 LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) { +std::vector LinkerScript::getPhdrIndices(OutputSection *Cmd) { std::vector 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(uint8_t *Buf); -template void OutputSectionCommand::writeTo(uint8_t *Buf); -template void OutputSectionCommand::writeTo(uint8_t *Buf); -template void OutputSectionCommand::writeTo(uint8_t *Buf); - -template void OutputSectionCommand::maybeCompress(); -template void OutputSectionCommand::maybeCompress(); -template void OutputSectionCommand::maybeCompress(); -template void OutputSectionCommand::maybeCompress(); - -template void OutputSectionCommand::finalize(); -template void OutputSectionCommand::finalize(); -template void OutputSectionCommand::finalize(); -template void OutputSectionCommand::finalize(); diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 1603c59..735acc3 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -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 Commands; - std::vector Phdrs; - llvm::Optional Filler; - ConstraintKind Constraint = ConstraintKind::NoConstraint; - std::string Location; - std::string MemoryRegionName; - bool Noload = false; - - template void finalize(); - template void writeTo(uint8_t *Buf); - template void maybeCompress(); - uint32_t getFiller(); - - void sort(std::function 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 LMAOffset; AddressState(const ScriptConfiguration &Opt); }; - llvm::DenseMap SecToCommand; - llvm::DenseMap NameToOutputSectionCommand; + llvm::DenseMap 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 computeInputSections(const InputSectionDescription *); - std::vector - createInputSectionList(OutputSectionCommand &Cmd); + std::vector createInputSectionList(OutputSection &Cmd); - std::vector getPhdrIndices(OutputSectionCommand *Cmd); + std::vector 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 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 &Phdrs); void addSymbol(SymbolAssignment *Cmd); diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp index e221b6d..8a92714 100644 --- a/lld/ELF/MapFile.cpp +++ b/lld/ELF/MapFile.cpp @@ -99,8 +99,7 @@ getSymbolStrings(ArrayRef Syms) { return Ret; } -template -void elf::writeMapFile(llvm::ArrayRef Script) { +template void elf::writeMapFile() { if (Config->MapFile.empty()) return; @@ -123,13 +122,12 @@ void elf::writeMapFile(llvm::ArrayRef Script) { << " Align Out In Symbol\n"; // Print out file contents. - for (OutputSectionCommand *Cmd : Script) { - OutputSection *OSec = Cmd->Sec; + for (OutputSection *OSec : OutputSections) { writeHeader(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(Base); if (!ISD) continue; @@ -144,7 +142,7 @@ void elf::writeMapFile(llvm::ArrayRef Script) { } } -template void elf::writeMapFile(ArrayRef); -template void elf::writeMapFile(ArrayRef); -template void elf::writeMapFile(ArrayRef); -template void elf::writeMapFile(ArrayRef); +template void elf::writeMapFile(); +template void elf::writeMapFile(); +template void elf::writeMapFile(); +template void elf::writeMapFile(); diff --git a/lld/ELF/MapFile.h b/lld/ELF/MapFile.h index 460848f..1c63644 100644 --- a/lld/ELF/MapFile.h +++ b/lld/ELF/MapFile.h @@ -14,9 +14,8 @@ namespace lld { namespace elf { -struct OutputSectionCommand; -template -void writeMapFile(llvm::ArrayRef Script); +class OutputSection; +template void writeMapFile(); } // namespace elf } // namespace lld diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index abe5481..c33f547 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -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 elf::OutputSections; -std::vector 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(Commands.back())) + Commands.push_back(make("")); + auto *ISD = cast(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(OutsecName, IS->Type, IS->Flags); - OutputSections.push_back(Sec); + if (!Sec) { + Sec = Script->createOutputSection(OutsecName, ""); + Script->Opt.Commands.push_back(Sec); + } + Sec->Type = IS->Type; + Sec->Flags = IS->Flags; } Sec->addSection(cast(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 Order) { + typedef std::pair Pair; + auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; + + std::vector V; + assert(Commands.size() == 1); + auto *ISD = cast(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 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(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 Buf(Size); + writeTo(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 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 Sections; + for (BaseCommand *Cmd : Commands) + if (auto *ISD = dyn_cast(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(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(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 +static void finalizeShtGroup(OutputSection *OS, + ArrayRef 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 *Obj = Sections[0]->getFile(); + ArrayRef Symbols = Obj->getSymbols(); + OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]); +} + +template void OutputSection::finalize() { + // Link order may be distributed across several InputSectionDescriptions + // but sort must consider them all at once. + std::vector ScriptSections; + std::vector Sections; + for (BaseCommand *Base : Commands) + if (auto *ISD = dyn_cast(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(this, Sections); + return; + } + + if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) + return; + + InputSection *First = Sections[0]; + if (isa(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(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::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF32BE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF64LE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF64BE::Shdr *Shdr); + +template void OutputSection::writeTo(uint8_t *Buf); +template void OutputSection::writeTo(uint8_t *Buf); +template void OutputSection::writeTo(uint8_t *Buf); +template void OutputSection::writeTo(uint8_t *Buf); + +template void OutputSection::maybeCompress(); +template void OutputSection::maybeCompress(); +template void OutputSection::maybeCompress(); +template void OutputSection::maybeCompress(); + +template void OutputSection::finalize(); +template void OutputSection::finalize(); +template void OutputSection::finalize(); +template void OutputSection::finalize(); diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 6c583be..817c943 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -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 void writeHeaderTo(typename ELFT::Shdr *SHdr); @@ -80,7 +82,6 @@ public: uint32_t ShName = 0; void addSection(InputSection *S); - std::vector Sections; // Used for implementation of --compress-debug-sections option. std::vector 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 Commands; + std::vector Phdrs; + llvm::Optional Filler; + ConstraintKind Constraint = ConstraintKind::NoConstraint; + std::string Location; + std::string MemoryRegionName; + bool Noload = false; + + template void finalize(); + template void writeTo(uint8_t *Buf); + template void maybeCompress(); + uint32_t getFiller(); + + void sort(std::function 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 OutputSections; -extern std::vector OutputSectionCommands; } // namespace elf } // namespace lld diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index fe9efe9..efbebc0 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -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(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 *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 *Range = nullptr; for (BaseCommand *BC : C->Commands) if (auto *ISD = dyn_cast(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 *ISR, uint64_t Off) { - auto *TS = make(OS, Off); + auto *TS = make(Cmd, Off); ThunkSections[ISR].push_back(TS); return TS; } @@ -1074,19 +1073,18 @@ std::pair ThunkCreator::getThunk(SymbolBody &Body, // Call Fn on every executable InputSection accessed via the linker script // InputSectionDescription::Sections. void ThunkCreator::forEachExecInputSection( - ArrayRef OutputSections, - std::function *, + ArrayRef OutputSections, + std::function *, 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(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 OutputSections) { +bool ThunkCreator::createThunks(ArrayRef 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 *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); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index ea046d2..2a9b895 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -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 OutputSections); + bool createThunks(ArrayRef 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 *ISR); ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS); void forEachExecInputSection( - ArrayRef OutputSections, - std::function *, + ArrayRef OutputSections, + std::function *, InputSection *)> Fn); std::pair getThunk(SymbolBody &Body, uint32_t Type); - ThunkSection *addThunkSection(OutputSection *OS, + ThunkSection *addThunkSection(OutputSection *Cmd, std::vector *, uint64_t Off); // Record all the available Thunks for a Symbol llvm::DenseMap> ThunkedSymbols; diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index b5fd76b..8c96505 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -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 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(); }; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 19e0e4c..8d04025 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -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(Base); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index f3e580c..a9e3856 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -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 Phdrs; @@ -150,15 +148,6 @@ template static void combineEhFrameSections() { V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } -template void Writer::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 void Writer::run() { // Create linker-synthesized sections such as .got or .plt. @@ -188,7 +177,6 @@ template void Writer::run() { Script->processCommands(Factory); createSections(); } - clearOutputSections(); if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); @@ -210,9 +198,8 @@ template void Writer::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(); }); + parallelForEach(OutputSections.begin(), OutputSections.end(), + [](OutputSection *Sec) { Sec->maybeCompress(); }); Script->assignAddresses(); Script->allocateHeaders(Phdrs); @@ -230,8 +217,8 @@ template void Writer::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 void Writer::run() { return; // Handle -Map option. - writeMapFile(OutputSectionCommands); + writeMapFile(); if (ErrorCount) return; @@ -496,15 +483,15 @@ template void Writer::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(Base); - if (!Cmd) + auto *Sec = dyn_cast(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(Base)) return !ISD->Sections.empty(); return false; }); - if (I == Cmd->Commands.end()) + if (I == Sec->Commands.end()) continue; InputSection *IS = cast(*I)->Sections[0]; if (isa(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(ACmd)->Sec; - const OutputSection *B = cast(BCmd)->Sec; + const OutputSection *A = cast(ACmd); + const OutputSection *B = cast(BCmd); if (A->SortRank != B->SortRank) return A->SortRank < B->SortRank; if (!(A->SortRank & RF_NOT_ADDR_SET)) @@ -867,13 +854,13 @@ template void Writer::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 static void sortBySymbolsOrder() { // Sort sections by priority. for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast(Base)) - Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); + if (auto *Sec = dyn_cast(Base)) + Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); } template @@ -932,30 +919,34 @@ void Writer::forEachRelSec(std::function Fn) { } template void Writer::createSections() { + std::vector 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(); - 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(B)) - if (Cmd->Sec) - return getRankProximity(A, Cmd->Sec); + if (auto *Sec = dyn_cast(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(Cmd)) + if (isa(Cmd)) return false; if (auto *Assign = dyn_cast(Cmd)) return Assign->Name != "."; @@ -988,7 +979,7 @@ template static std::vector::iterator findOrphanPos(std::vector::iterator B, std::vector::iterator E) { - OutputSection *Sec = cast(*E)->Sec; + OutputSection *Sec = cast(*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::iterator B, // Consider all existing sections with the same proximity. int Proximity = getRankProximity(Sec, *I); for (; I != E; ++I) { - auto *Cmd = dyn_cast(*I); - if (!Cmd || !Cmd->Sec) + auto *CurSec = dyn_cast(*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(Cmd); }); + [](BaseCommand *Cmd) { return isa(Cmd); }); I = J.base(); while (I != E && shouldSkip(*I)) ++I; @@ -1026,18 +1017,15 @@ template void Writer::sortSections() { return; for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast(Base)) - if (OutputSection *Sec = Cmd->Sec) - Sec->SortRank = getSectionRank(Sec); + if (auto *Sec = dyn_cast(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(Base); - }; + auto IsSection = [](BaseCommand *Base) { return isa(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 void Writer::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(Base)) - return Cmd->Sec && Cmd->Sec->SectionIndex == INT_MAX; + if (auto *Sec = dyn_cast(Base)) + return Sec->Live && Sec->SectionIndex == INT_MAX; return false; }); @@ -1109,13 +1097,13 @@ template void Writer::sortSections() { while (NonScriptI != E) { auto Pos = findOrphanPos(I, NonScriptI); - OutputSection *Orphan = cast(*NonScriptI)->Sec; + OutputSection *Orphan = cast(*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(Cmd)->Sec->SortRank != Rank; + return cast(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::iterator Empty = Cmd->Commands.end(); - for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) { + std::vector::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(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(Cmd)) - return OSCmd->Sec == OS; + auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd2) { + if (auto *Sec = dyn_cast(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 void Writer::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 void Writer::finalizeSections() { if (!Config->Relocatable) { addStartEndSymbols(); for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast(Base)) - if (Cmd->Sec) - addStartStopSymbols(Cmd->Sec); + if (auto *Sec = dyn_cast(Base)) + addStartStopSymbols(Sec); } // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. @@ -1250,16 +1236,16 @@ template void Writer::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(Base)) - OutputSectionCommands.push_back(Cmd); + if (auto *Sec = dyn_cast(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 void Writer::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 void Writer::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 void Writer::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(); + for (OutputSection *Sec : OutputSections) + Sec->finalize(); // createThunks may have added local symbols to the static symbol table applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, @@ -1329,18 +1314,12 @@ template void Writer::finalizeSections() { template void Writer::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(); - 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(Base); - }); - cast(*ISD)->Sections.push_back(Sentinel); + Cmd->addSection(Sentinel); } // The linker is expected to define SECNAME_start and SECNAME_end @@ -1364,7 +1343,7 @@ template void Writer::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::addStartStopSymbols(OutputSection *Sec) { addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } -template -OutputSectionCommand *Writer::findSectionCommand(StringRef Name) { +template OutputSection *Writer::findSection(StringRef Name) { for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast(Base)) - if (Cmd->Name == Name) - return Cmd; - return nullptr; -} - -template -OutputSection *Writer::findSectionInScript(StringRef Name) { - if (OutputSectionCommand *Cmd = findSectionCommand(Name)) - return Cmd->Sec; + if (auto *Sec = dyn_cast(Base)) + if (Sec->Name == Name) + return Sec; return nullptr; } @@ -1435,8 +1406,8 @@ template std::vector Writer::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 std::vector Writer::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 std::vector Writer::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 std::vector Writer::createPhdrs() { // Add a TLS segment if any. PhdrEntry *TlsHdr = make(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 std::vector Writer::createPhdrs() { // PT_GNU_RELRO includes all sections that should be marked as // read-only by dynamic linker after proccessing relocations. PhdrEntry *RelRo = make(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 std::vector Writer::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 std::vector Writer::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 void Writer::addPtArmExid(std::vector &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(PT_ARM_EXIDX, PF_R); - ARMExidx->add((*I)->Sec); + ARMExidx->add(*I); Phdrs.push_back(ARMExidx); } @@ -1557,8 +1522,7 @@ void Writer::addPtArmExid(std::vector &Phdrs) { // first section after PT_GNU_RELRO have to be page aligned so that the dynamic // linker can set the permissions. template void Writer::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 void Writer::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 void Writer::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(Sec->Alignment, Config->MaxPageSize), - Sec->Addr); + if (Cmd == First) + return alignTo(Off, std::max(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 void Writer::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 void Writer::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 uint64_t Writer::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 void Writer::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 void Writer::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 void Writer::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 void Writer::writeHeader() { // Write the section header table. Note that the first table entry is null. auto *SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); - for (OutputSectionCommand *Cmd : OutputSectionCommands) - Cmd->Sec->writeHeaderTo(++SHdrs); + for (OutputSection *Sec : OutputSections) + Sec->writeHeaderTo(++SHdrs); } // Open a result file. @@ -1850,11 +1810,9 @@ template void Writer::openFile() { template void Writer::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(Buf + Sec->Offset); - } + Sec->writeTo(Buf + Sec->Offset); } // Write section contents to a mmap'ed file. @@ -1863,8 +1821,8 @@ template void Writer::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(Buf + Out::Opd->Offset); } @@ -1877,25 +1835,19 @@ template void Writer::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(Buf + Sec->Offset); - } + Sec->writeTo(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(Buf + Sec->Offset); - } + Sec->writeTo(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(Buf + EhFrameHdr->Offset); - } + if (EhFrameHdr) + EhFrameHdr->writeTo(Buf + EhFrameHdr->Offset); } template void Writer::writeBuildId() {