aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Leviant <evgeny.leviant@gmail.com>2016-07-19 09:25:43 +0000
committerEugene Leviant <evgeny.leviant@gmail.com>2016-07-19 09:25:43 +0000
commit7382f9dc5566cf08a8159ecc8e88eb9e1572bf82 (patch)
tree95242e56ef312e5f1397acfe0ac07ae93653ef57
parent843b055814a83a3b667064c4cca59ca13ee13ac5 (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.cpp186
-rw-r--r--ELF/LinkerScript.h17
-rw-r--r--ELF/Writer.cpp148
-rw-r--r--ELF/Writer.h22
-rw-r--r--test/ELF/linkerscript-phdrs.s36
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