diff options
author | Eugene Leviant <evgeny.leviant@gmail.com> | 2016-07-19 09:25:43 +0000 |
---|---|---|
committer | Eugene Leviant <evgeny.leviant@gmail.com> | 2016-07-19 09:25:43 +0000 |
commit | 7382f9dc5566cf08a8159ecc8e88eb9e1572bf82 (patch) | |
tree | 95242e56ef312e5f1397acfe0ac07ae93653ef57 | |
parent | 843b055814a83a3b667064c4cca59ca13ee13ac5 (diff) |
[ELF] Minimal PHDRS parser and section to segment assignment support
git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@275965 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | ELF/LinkerScript.cpp | 186 | ||||
-rw-r--r-- | ELF/LinkerScript.h | 17 | ||||
-rw-r--r-- | ELF/Writer.cpp | 148 | ||||
-rw-r--r-- | ELF/Writer.h | 22 | ||||
-rw-r--r-- | test/ELF/linkerscript-phdrs.s | 36 |
5 files changed, 343 insertions, 66 deletions
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index dc4333f0f..28f60ca1a 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -23,6 +23,7 @@ #include "Symbols.h" #include "SymbolTable.h" #include "Target.h" +#include "Writer.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ELF.h" #include "llvm/Support/FileSystem.h" @@ -217,7 +218,7 @@ void LinkerScript<ELFT>::assignAddresses( for (OutputSectionBase<ELFT> *Sec : Sections) { StringRef Name = Sec->getName(); if (getSectionIndex(Name) == INT_MAX) - Opt.Commands.push_back({SectionKind, {}, Name}); + Opt.Commands.push_back({SectionKind, {}, Name, {}}); } // Assign addresses as instructed by linker script SECTIONS sub-commands. @@ -274,6 +275,91 @@ void LinkerScript<ELFT>::assignAddresses( } template <class ELFT> +std::vector<Phdr<ELFT>> +LinkerScript<ELFT>::createPhdrs(ArrayRef<OutputSectionBase<ELFT> *> Sections) { + int TlsNum = -1; + int NoteNum = -1; + int RelroNum = -1; + Phdr *Load = nullptr; + uintX_t Flags = PF_R; + std::vector<Phdr> Phdrs; + + for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) { + Phdrs.emplace_back(Cmd.Type, PF_R); + Phdr &Added = Phdrs.back(); + + if (Cmd.HasFilehdr) + Added.AddSec(Out<ELFT>::ElfHeader); + if (Cmd.HasPhdrs) + Added.AddSec(Out<ELFT>::ProgramHeaders); + + switch (Cmd.Type) { + case PT_INTERP: + if (needsInterpSection<ELFT>()) + Added.AddSec(Out<ELFT>::Interp); + break; + case PT_DYNAMIC: + if (isOutputDynamic<ELFT>()) { + Added.H.p_flags = toPhdrFlags(Out<ELFT>::Dynamic->getFlags()); + Added.AddSec(Out<ELFT>::Dynamic); + } + break; + case PT_TLS: + TlsNum = Phdrs.size() - 1; + break; + case PT_NOTE: + NoteNum = Phdrs.size() - 1; + break; + case PT_GNU_RELRO: + RelroNum = Phdrs.size() - 1; + break; + case PT_GNU_EH_FRAME: + if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr) { + Added.H.p_flags = toPhdrFlags(Out<ELFT>::EhFrameHdr->getFlags()); + Added.AddSec(Out<ELFT>::EhFrameHdr); + } + break; + } + } + + for (OutputSectionBase<ELFT> *Sec : Sections) { + if (!(Sec->getFlags() & SHF_ALLOC)) + break; + + if (TlsNum != -1 && (Sec->getFlags() & SHF_TLS)) + Phdrs[TlsNum].AddSec(Sec); + + if (!needsPtLoad<ELFT>(Sec)) + continue; + + const std::vector<size_t> &PhdrIds = + getPhdrIndicesForSection(Sec->getName()); + if (!PhdrIds.empty()) { + // Assign headers specified by linker script + for (size_t Id : PhdrIds) { + Phdrs[Id].AddSec(Sec); + Phdrs[Id].H.p_flags |= toPhdrFlags(Sec->getFlags()); + } + } else { + // If we have no load segment or flags've changed then we want new load + // segment. + uintX_t NewFlags = toPhdrFlags(Sec->getFlags()); + if (Load == nullptr || Flags != NewFlags) { + Load = &*Phdrs.emplace(Phdrs.end(), PT_LOAD, NewFlags); + Flags = NewFlags; + } + Load->AddSec(Sec); + } + + if (RelroNum != -1 && isRelroSection(Sec)) + Phdrs[RelroNum].AddSec(Sec); + if (NoteNum != -1 && Sec->getType() == SHT_NOTE) + Phdrs[NoteNum].AddSec(Sec); + } + return Phdrs; +} + +template <class ELFT> ArrayRef<uint8_t> LinkerScript<ELFT>::getFiller(StringRef Name) { auto I = Opt.Filler.find(Name); if (I == Opt.Filler.end()) @@ -314,6 +400,35 @@ void LinkerScript<ELFT>::addScriptedSymbols() { Symtab<ELFT>::X->addAbsolute(Cmd.Name, STV_DEFAULT); } +template <class ELFT> bool LinkerScript<ELFT>::hasPhdrsCommands() { + return !Opt.PhdrsCommands.empty(); +} + +// Returns indices of ELF headers containing specific section, identified +// by Name. Each index is a zero based number of ELF header listed within +// PHDRS {} script block. +template <class ELFT> +std::vector<size_t> +LinkerScript<ELFT>::getPhdrIndicesForSection(StringRef Name) { + std::vector<size_t> Indices; + auto ItSect = std::find_if( + Opt.Commands.begin(), Opt.Commands.end(), + [Name](const SectionsCommand &Cmd) { return Cmd.Name == Name; }); + if (ItSect != Opt.Commands.end()) { + SectionsCommand &SecCmd = (*ItSect); + for (StringRef PhdrName : SecCmd.Phdrs) { + auto ItPhdr = std::find_if( + Opt.PhdrsCommands.rbegin(), Opt.PhdrsCommands.rend(), + [PhdrName](PhdrsCommand &Cmd) { return Cmd.Name == PhdrName; }); + if (ItPhdr == Opt.PhdrsCommands.rend()) + error("section header '" + PhdrName + "' is not listed in PHDRS"); + else + Indices.push_back(std::distance(ItPhdr, Opt.PhdrsCommands.rend()) - 1); + } + } + return Indices; +} + class elf::ScriptParser : public ScriptParserBase { typedef void (ScriptParser::*Handler)(); @@ -334,11 +449,14 @@ private: void readOutput(); void readOutputArch(); void readOutputFormat(); + void readPhdrs(); void readSearchDir(); void readSections(); void readLocationCounterValue(); void readOutputSectionDescription(StringRef OutSec); + std::vector<StringRef> readOutputSectionPhdrs(); + unsigned readPhdrType(); void readSymbolAssignment(StringRef Name); std::vector<StringRef> readSectionsCommandExpr(); @@ -357,6 +475,7 @@ const StringMap<elf::ScriptParser::Handler> elf::ScriptParser::Cmd = { {"OUTPUT", &ScriptParser::readOutput}, {"OUTPUT_ARCH", &ScriptParser::readOutputArch}, {"OUTPUT_FORMAT", &ScriptParser::readOutputFormat}, + {"PHDRS", &ScriptParser::readPhdrs}, {"SEARCH_DIR", &ScriptParser::readSearchDir}, {"SECTIONS", &ScriptParser::readSections}, {";", &ScriptParser::readNothing}}; @@ -493,6 +612,28 @@ void ScriptParser::readOutputFormat() { expect(")"); } +void ScriptParser::readPhdrs() { + expect("{"); + while (!Error && !skip("}")) { + StringRef Tok = next(); + Opt.PhdrsCommands.push_back({Tok, PT_NULL, false, false}); + PhdrsCommand &PhdrCmd = Opt.PhdrsCommands.back(); + + PhdrCmd.Type = readPhdrType(); + do { + Tok = next(); + if (Tok == ";") + break; + if (Tok == "FILEHDR") + PhdrCmd.HasFilehdr = true; + else if (Tok == "PHDRS") + PhdrCmd.HasPhdrs = true; + else + setError("unexpected header attribute: " + Tok); + } while (!Error); + } +} + void ScriptParser::readSearchDir() { expect("("); Config->SearchPaths.push_back(next()); @@ -523,11 +664,12 @@ void ScriptParser::readLocationCounterValue() { if (Expr.empty()) error("error in location counter expression"); else - Opt.Commands.push_back({AssignmentKind, std::move(Expr), "."}); + Opt.Commands.push_back({AssignmentKind, std::move(Expr), ".", {}}); } void ScriptParser::readOutputSectionDescription(StringRef OutSec) { - Opt.Commands.push_back({SectionKind, {}, OutSec}); + Opt.Commands.push_back({SectionKind, {}, OutSec, {}}); + SectionsCommand &Cmd = Opt.Commands.back(); expect(":"); expect("{"); @@ -551,6 +693,7 @@ void ScriptParser::readOutputSectionDescription(StringRef OutSec) { setError("unknown command " + Tok); } } + Cmd.Phdrs = readOutputSectionPhdrs(); StringRef Tok = peek(); if (Tok.startswith("=")) { @@ -570,7 +713,7 @@ void ScriptParser::readSymbolAssignment(StringRef Name) { if (Expr.empty()) error("error in symbol assignment expression"); else - Opt.Commands.push_back({AssignmentKind, std::move(Expr), Name}); + Opt.Commands.push_back({AssignmentKind, std::move(Expr), Name, {}}); } std::vector<StringRef> ScriptParser::readSectionsCommandExpr() { @@ -584,6 +727,41 @@ std::vector<StringRef> ScriptParser::readSectionsCommandExpr() { return Expr; } +std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() { + std::vector<StringRef> Phdrs; + while (!Error && peek().startswith(":")) { + StringRef Tok = next(); + Tok = (Tok.size() == 1) ? next() : Tok.substr(1); + if (Tok.empty()) { + setError("section header name is empty"); + break; + } + else + Phdrs.push_back(Tok); + } + return Phdrs; +} + +unsigned ScriptParser::readPhdrType() { + static const char *typeNames[] = { + "PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", + "PT_NOTE", "PT_SHLIB", "PT_PHDR", "PT_TLS", + "PT_GNU_EH_FRAME", "PT_GNU_STACK", "PT_GNU_RELRO"}; + static unsigned typeCodes[] = { + PT_NULL, PT_LOAD, PT_DYNAMIC, PT_INTERP, PT_NOTE, PT_SHLIB, + PT_PHDR, PT_TLS, PT_GNU_EH_FRAME, PT_GNU_STACK, PT_GNU_RELRO}; + + unsigned PhdrType = PT_NULL; + StringRef Tok = next(); + auto It = std::find(std::begin(typeNames), std::end(typeNames), Tok); + if (It != std::end(typeNames)) + PhdrType = typeCodes[std::distance(std::begin(typeNames), It)]; + else + setError("invalid program header type"); + + return PhdrType; +} + static bool isUnderSysroot(StringRef Path) { if (Config->Sysroot == "") return false; diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index 768f78a66..4ff71508d 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_LINKER_SCRIPT_H #define LLD_ELF_LINKER_SCRIPT_H +#include "Writer.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" @@ -46,6 +47,14 @@ struct SectionsCommand { SectionsCommandKind Kind; std::vector<StringRef> Expr; StringRef Name; + std::vector<StringRef> Phdrs; +}; + +struct PhdrsCommand { + StringRef Name; + unsigned Type; + bool HasFilehdr; + bool HasPhdrs; }; // ScriptConfiguration holds linker script parse results. @@ -59,6 +68,9 @@ struct ScriptConfiguration { // Used to assign addresses to sections. std::vector<SectionsCommand> Commands; + // Used to assign sections to headers. + std::vector<PhdrsCommand> PhdrsCommands; + bool DoLayout = false; llvm::BumpPtrAllocator Alloc; @@ -75,6 +87,8 @@ template <class ELFT> class LinkerScript { typedef typename ELFT::uint uintX_t; public: + typedef Phdr<ELFT> Phdr; + StringRef getOutputSection(InputSectionBase<ELFT> *S); ArrayRef<uint8_t> getFiller(StringRef Name); bool isDiscarded(InputSectionBase<ELFT> *S); @@ -82,12 +96,15 @@ public: void assignAddresses(ArrayRef<OutputSectionBase<ELFT> *> S); int compareSections(StringRef A, StringRef B); void addScriptedSymbols(); + std::vector<Phdr> createPhdrs(ArrayRef<OutputSectionBase<ELFT> *> S); + bool hasPhdrsCommands(); private: // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; int getSectionIndex(StringRef Name); + std::vector<size_t> getPhdrIndicesForSection(StringRef Name); uintX_t Dot; }; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 387bec3d8..784e18286 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -44,18 +44,7 @@ public: void run(); private: - // This describes a program header entry. - // Each contains type, access flags and range of output sections that will be - // placed in it. - struct Phdr { - Phdr(unsigned Type, unsigned Flags) { - H.p_type = Type; - H.p_flags = Flags; - } - Elf_Phdr H = {}; - OutputSectionBase<ELFT> *First = nullptr; - OutputSectionBase<ELFT> *Last = nullptr; - }; + typedef Phdr<ELFT> Phdr; void copyLocalSymbols(); void addReservedSymbols(); @@ -74,12 +63,6 @@ private: void writeHeader(); void writeSections(); void writeBuildId(); - bool needsInterpSection() const { - return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty(); - } - bool isOutputDynamic() const { - return !Symtab.getSharedFiles().empty() || Config->Pic; - } void addCommonSymbols(std::vector<DefinedCommon *> &Syms); @@ -240,7 +223,10 @@ template <class ELFT> void Writer<ELFT>::run() { if (Config->Relocatable) { assignFileOffsets(); } else { - createPhdrs(); + if (Script<ELFT>::X->hasPhdrsCommands()) + Phdrs = Script<ELFT>::X->createPhdrs(OutputSections); + else + createPhdrs(); fixHeaders(); if (ScriptConfig->DoLayout) { Script<ELFT>::X->assignAddresses(OutputSections); @@ -376,7 +362,7 @@ static int getPPC64SectionRank(StringRef SectionName) { .Default(1); } -template <class ELFT> static bool isRelroSection(OutputSectionBase<ELFT> *Sec) { +template <class ELFT> bool elf::isRelroSection(OutputSectionBase<ELFT> *Sec) { if (!Config->ZRelro) return false; typename ELFT::uint Flags = Sec->getFlags(); @@ -472,6 +458,40 @@ static bool compareSections(OutputSectionBase<ELFT> *A, return false; } +uint32_t elf::toPhdrFlags(uint64_t Flags) { + uint32_t Ret = PF_R; + if (Flags & SHF_WRITE) + Ret |= PF_W; + if (Flags & SHF_EXECINSTR) + Ret |= PF_X; + return Ret; +} + +// Various helper functions +template <class ELFT> bool elf::needsInterpSection() { + return !Symtab<ELFT>::X->getSharedFiles().empty() && + !Config->DynamicLinker.empty(); +} + +template <class ELFT> bool elf::isOutputDynamic() { + return !Symtab<ELFT>::X->getSharedFiles().empty() || Config->Pic; +} + +// Program header entry +template<class ELFT> +Phdr<ELFT>::Phdr(unsigned Type, unsigned Flags) { + H.p_type = Type; + H.p_flags = Flags; +} + +template<class ELFT> +void Phdr<ELFT>::AddSec(OutputSectionBase<ELFT> *Sec) { + Last = Sec; + if (!First) + First = Sec; + H.p_align = std::max<typename ELFT::uint>(H.p_align, Sec->getAlignment()); +} + // Until this function is called, common symbols do not belong to any section. // This function adds them to end of BSS section. template <class ELFT> @@ -515,7 +535,7 @@ static Symbol *addOptionalSynthetic(SymbolTable<ELFT> &Table, StringRef Name, // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { - if (isOutputDynamic() || !Out<ELFT>::RelaPlt) + if (isOutputDynamic<ELFT>() || !Out<ELFT>::RelaPlt) return; StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start"; addOptionalSynthetic(Symtab, S, Out<ELFT>::RelaPlt, 0); @@ -569,7 +589,7 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { // static linking the linker is required to optimize away any references to // __tls_get_addr, so it's not defined anywhere. Create a hidden definition // to avoid the undefined symbol error. - if (!isOutputDynamic()) + if (!isOutputDynamic<ELFT>()) Symtab.addIgnored("__tls_get_addr"); auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1, @@ -658,7 +678,7 @@ template <class ELFT> void Writer<ELFT>::createSections() { // It should be okay as no one seems to care about the type. // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html - if (isOutputDynamic()) + if (isOutputDynamic<ELFT>()) Symtab.addSynthetic("_DYNAMIC", Out<ELFT>::Dynamic, 0); // Define __rel[a]_iplt_{start,end} symbols if needed. @@ -712,7 +732,7 @@ template <class ELFT> void Writer<ELFT>::createSections() { if (Out<ELFT>::SymTab) Out<ELFT>::SymTab->addSymbol(Body); - if (isOutputDynamic() && S->includeInDynsym()) { + if (isOutputDynamic<ELFT>() && S->includeInDynsym()) { Out<ELFT>::DynSymTab->addSymbol(Body); if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body)) if (SS->file()->isNeeded()) @@ -741,7 +761,7 @@ template <class ELFT> void Writer<ELFT>::createSections() { // Finalizers fix each section's size. // .dynsym is finalized early since that may fill up .gnu.hash. - if (isOutputDynamic()) + if (isOutputDynamic<ELFT>()) Out<ELFT>::DynSymTab->finalize(); // Fill other section headers. The dynamic table is finalized @@ -753,7 +773,7 @@ template <class ELFT> void Writer<ELFT>::createSections() { if (Sec != Out<ELFT>::DynStrTab && Sec != Out<ELFT>::Dynamic) Sec->finalize(); - if (isOutputDynamic()) + if (isOutputDynamic<ELFT>()) Out<ELFT>::Dynamic->finalize(); // Now that all output offsets are fixed. Finalize mergeable sections @@ -791,7 +811,7 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { // Add .interp at first because some loaders want to see that section // on the first page of the executable file when loaded into memory. - if (needsInterpSection()) + if (needsInterpSection<ELFT>()) OutputSections.insert(OutputSections.begin(), Out<ELFT>::Interp); // This order is not the same as the final output order @@ -799,7 +819,7 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { Add(Out<ELFT>::SymTab); Add(Out<ELFT>::ShStrTab); Add(Out<ELFT>::StrTab); - if (isOutputDynamic()) { + if (isOutputDynamic<ELFT>()) { Add(Out<ELFT>::DynSymTab); bool HasVerNeed = Out<ELFT>::VerNeed->getNeedNum() != 0; @@ -822,7 +842,7 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { // Even during static linking it can contain R_[*]_IRELATIVE relocations. if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) { Add(Out<ELFT>::RelaPlt); - Out<ELFT>::RelaPlt->Static = !isOutputDynamic(); + Out<ELFT>::RelaPlt->Static = !isOutputDynamic<ELFT>(); } if (needsGot()) @@ -882,7 +902,7 @@ void Writer<ELFT>::addStartStopSymbols(OutputSectionBase<ELFT> *Sec) { Symtab.addSynthetic(Stop, Sec, DefinedSynthetic<ELFT>::SectionEnd); } -template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) { +template <class ELFT> bool elf::needsPtLoad(OutputSectionBase<ELFT> *Sec) { if (!(Sec->getFlags() & SHF_ALLOC)) return false; @@ -894,15 +914,6 @@ template <class ELFT> static bool needsPtLoad(OutputSectionBase<ELFT> *Sec) { return true; } -static uint32_t toPhdrFlags(uint64_t Flags) { - uint32_t Ret = PF_R; - if (Flags & SHF_WRITE) - Ret |= PF_W; - if (Flags & SHF_EXECINSTR) - Ret |= PF_X; - return Ret; -} - // Decide which program headers to create and which sections to include in each // one. template <class ELFT> void Writer<ELFT>::createPhdrs() { @@ -910,28 +921,21 @@ template <class ELFT> void Writer<ELFT>::createPhdrs() { return &*Phdrs.emplace(Phdrs.end(), Type, Flags); }; - auto AddSec = [](Phdr &Hdr, OutputSectionBase<ELFT> *Sec) { - Hdr.Last = Sec; - if (!Hdr.First) - Hdr.First = Sec; - Hdr.H.p_align = std::max<uintX_t>(Hdr.H.p_align, Sec->getAlignment()); - }; - // The first phdr entry is PT_PHDR which describes the program header itself. Phdr &Hdr = *AddHdr(PT_PHDR, PF_R); - AddSec(Hdr, Out<ELFT>::ProgramHeaders); + Hdr.AddSec(Out<ELFT>::ProgramHeaders); // PT_INTERP must be the second entry if exists. - if (needsInterpSection()) { + if (needsInterpSection<ELFT>()) { Phdr &Hdr = *AddHdr(PT_INTERP, toPhdrFlags(Out<ELFT>::Interp->getFlags())); - AddSec(Hdr, Out<ELFT>::Interp); + Hdr.AddSec(Out<ELFT>::Interp); } // Add the first PT_LOAD segment for regular output sections. uintX_t Flags = PF_R; Phdr *Load = AddHdr(PT_LOAD, Flags); - AddSec(*Load, Out<ELFT>::ElfHeader); - AddSec(*Load, Out<ELFT>::ProgramHeaders); + Load->AddSec(Out<ELFT>::ElfHeader); + Load->AddSec(Out<ELFT>::ProgramHeaders); Phdr TlsHdr(PT_TLS, PF_R); Phdr RelRo(PT_GNU_RELRO, PF_R); @@ -944,7 +948,7 @@ template <class ELFT> void Writer<ELFT>::createPhdrs() { // and put all TLS sections inside for futher use when // assign addresses. if (Sec->getFlags() & SHF_TLS) - AddSec(TlsHdr, Sec); + TlsHdr.AddSec(Sec); if (!needsPtLoad<ELFT>(Sec)) continue; @@ -956,12 +960,12 @@ template <class ELFT> void Writer<ELFT>::createPhdrs() { Flags = NewFlags; } - AddSec(*Load, Sec); + Load->AddSec(Sec); if (isRelroSection(Sec)) - AddSec(RelRo, Sec); + RelRo.AddSec(Sec); if (Sec->getType() == SHT_NOTE) - AddSec(Note, Sec); + Note.AddSec(Sec); } // Add the TLS segment unless it's empty. @@ -969,9 +973,9 @@ template <class ELFT> void Writer<ELFT>::createPhdrs() { Phdrs.push_back(std::move(TlsHdr)); // Add an entry for .dynamic. - if (isOutputDynamic()) { + if (isOutputDynamic<ELFT>()) { Phdr &H = *AddHdr(PT_DYNAMIC, toPhdrFlags(Out<ELFT>::Dynamic->getFlags())); - AddSec(H, Out<ELFT>::Dynamic); + H.AddSec(Out<ELFT>::Dynamic); } // PT_GNU_RELRO includes all sections that should be marked as @@ -983,7 +987,7 @@ template <class ELFT> void Writer<ELFT>::createPhdrs() { if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr) { Phdr &Hdr = *AddHdr(PT_GNU_EH_FRAME, toPhdrFlags(Out<ELFT>::EhFrameHdr->getFlags())); - AddSec(Hdr, Out<ELFT>::EhFrameHdr); + Hdr.AddSec(Out<ELFT>::EhFrameHdr); } // PT_GNU_STACK is a special section to tell the loader to make the @@ -993,8 +997,6 @@ template <class ELFT> void Writer<ELFT>::createPhdrs() { if (Note.First) Phdrs.push_back(std::move(Note)); - - Out<ELFT>::ProgramHeaders->setSize(sizeof(Elf_Phdr) * Phdrs.size()); } // The first section of each PT_LOAD and the first section after PT_GNU_RELRO @@ -1027,6 +1029,7 @@ template <class ELFT> void Writer<ELFT>::fixHeaders() { Out<ELFT>::ElfHeader->setVA(BaseVA); uintX_t Off = Out<ELFT>::ElfHeader->getSize(); Out<ELFT>::ProgramHeaders->setVA(Off + BaseVA); + Out<ELFT>::ProgramHeaders->setSize(sizeof(Elf_Phdr) * Phdrs.size()); } // Assign VAs (addresses at run-time) to output sections. @@ -1281,3 +1284,28 @@ template void elf::writeResult<ELF32LE>(SymbolTable<ELF32LE> *Symtab); template void elf::writeResult<ELF32BE>(SymbolTable<ELF32BE> *Symtab); template void elf::writeResult<ELF64LE>(SymbolTable<ELF64LE> *Symtab); template void elf::writeResult<ELF64BE>(SymbolTable<ELF64BE> *Symtab); + +template struct elf::Phdr<ELF32LE>; +template struct elf::Phdr<ELF32BE>; +template struct elf::Phdr<ELF64LE>; +template struct elf::Phdr<ELF64BE>; + +template bool elf::needsInterpSection<ELF32LE>(); +template bool elf::needsInterpSection<ELF32BE>(); +template bool elf::needsInterpSection<ELF64LE>(); +template bool elf::needsInterpSection<ELF64BE>(); + +template bool elf::isOutputDynamic<ELF32LE>(); +template bool elf::isOutputDynamic<ELF32BE>(); +template bool elf::isOutputDynamic<ELF64LE>(); +template bool elf::isOutputDynamic<ELF64BE>(); + +template bool elf::isRelroSection<ELF32LE>(OutputSectionBase<ELF32LE> *); +template bool elf::isRelroSection<ELF32BE>(OutputSectionBase<ELF32BE> *); +template bool elf::isRelroSection<ELF64LE>(OutputSectionBase<ELF64LE> *); +template bool elf::isRelroSection<ELF64BE>(OutputSectionBase<ELF64BE> *); + +template bool elf::needsPtLoad<ELF32LE>(OutputSectionBase<ELF32LE> *); +template bool elf::needsPtLoad<ELF32BE>(OutputSectionBase<ELF32BE> *); +template bool elf::needsPtLoad<ELF64LE>(OutputSectionBase<ELF64LE> *); +template bool elf::needsPtLoad<ELF64BE>(OutputSectionBase<ELF64BE> *); diff --git a/ELF/Writer.h b/ELF/Writer.h index df25d8e40..ec7a2eb6d 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_WRITER_H #define LLD_ELF_WRITER_H +#include <cstdint> #include <memory> namespace llvm { @@ -18,13 +19,30 @@ namespace llvm { namespace lld { namespace elf { +template <class ELFT> class OutputSectionBase; template <class ELFT> class InputSectionBase; template <class ELFT> class ObjectFile; template <class ELFT> class SymbolTable; - template <class ELFT> void writeResult(SymbolTable<ELFT> *Symtab); - template <class ELFT> void markLive(); +template <class ELFT> bool needsInterpSection(); +template <class ELFT> bool isOutputDynamic(); +template <class ELFT> bool isRelroSection(OutputSectionBase<ELFT> *Sec); +template <class ELFT> bool needsPtLoad(OutputSectionBase<ELFT> *Sec); +uint32_t toPhdrFlags(uint64_t Flags); + +// This describes a program header entry. +// Each contains type, access flags and range of output sections that will be +// placed in it. +template<class ELFT> +struct Phdr { + Phdr(unsigned Type, unsigned Flags); + void AddSec(OutputSectionBase<ELFT> *Sec); + + typename ELFT::Phdr H = {}; + OutputSectionBase<ELFT> *First = nullptr; + OutputSectionBase<ELFT> *Last = nullptr; +}; template <class ELFT> llvm::StringRef getOutputSectionName(InputSectionBase<ELFT> *S); diff --git a/test/ELF/linkerscript-phdrs.s b/test/ELF/linkerscript-phdrs.s new file mode 100644 index 000000000..ca9703f58 --- /dev/null +++ b/test/ELF/linkerscript-phdrs.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS ;} \ +# RUN: SECTIONS { \ +# RUN: . = 0x10000200; \ +# RUN: .text : {*(.text.*)} :all \ +# RUN: .foo : {*(.foo.*)} :all \ +# RUN: .data : {*(.data.*)} :all}" > %t.script + +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-readobj -program-headers %t1 | FileCheck %s +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x10000000 +# CHECK-NEXT: PhysicalAddress: 0x10000000 +# CHECK-NEXT: FileSize: 521 +# CHECK-NEXT: MemSize: 521 +# CHECK-NEXT: Flags [ (0x7) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_W (0x2) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] + +.global _start +_start: + nop + +.section .foo.1,"a" +foo1: + .long 0 + +.section .foo.2,"aw" +foo2: + .long 0 |