[ELF] Minimal PHDRS parser and section to segment assignment support
authorEugene Leviant <evgeny.leviant@gmail.com>
Tue, 19 Jul 2016 09:25:43 +0000 (09:25 +0000)
committerEugene Leviant <evgeny.leviant@gmail.com>
Tue, 19 Jul 2016 09:25:43 +0000 (09:25 +0000)
llvm-svn: 275965

lld/ELF/LinkerScript.cpp
lld/ELF/LinkerScript.h
lld/ELF/Writer.cpp
lld/ELF/Writer.h
lld/test/ELF/linkerscript-phdrs.s [new file with mode: 0644]

index dc4333f..28f60ca 100644 (file)
@@ -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;
index 768f78a..4ff7150 100644 (file)
@@ -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;
 };
index 387bec3..784e182 100644 (file)
@@ -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> *);
index df25d8e..ec7a2eb 100644 (file)
@@ -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/lld/test/ELF/linkerscript-phdrs.s b/lld/test/ELF/linkerscript-phdrs.s
new file mode 100644 (file)
index 0000000..ca9703f
--- /dev/null
@@ -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