summaryrefslogtreecommitdiffstats
path: root/lld/ELF/LinkerScript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/LinkerScript.cpp')
-rw-r--r--lld/ELF/LinkerScript.cpp186
1 files changed, 182 insertions, 4 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index dc4333f0fde..28f60ca1acc 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/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;
OpenPOWER on IntegriCloud