summaryrefslogtreecommitdiff
path: root/ELF/ScriptParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/ScriptParser.cpp')
-rw-r--r--ELF/ScriptParser.cpp153
1 files changed, 117 insertions, 36 deletions
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index ddb4a49a3e5e6..eee3f0e330cc3 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -72,13 +72,15 @@ private:
void readRegionAlias();
void readSearchDir();
void readSections();
+ void readTarget();
void readVersion();
void readVersionScriptCommand();
SymbolAssignment *readSymbolAssignment(StringRef Name);
ByteCommand *readByteCommand(StringRef Tok);
- uint32_t readFill();
- uint32_t parseFill(StringRef Tok);
+ std::array<uint8_t, 4> readFill();
+ std::array<uint8_t, 4> parseFill(StringRef Tok);
+ bool readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2);
void readSectionAddressType(OutputSection *Cmd);
OutputSection *readOverlaySectionDescription();
OutputSection *readOutputSectionDescription(StringRef OutSec);
@@ -92,6 +94,7 @@ private:
SortSectionPolicy readSortKind();
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
SymbolAssignment *readAssignment(StringRef Tok);
+ std::tuple<ELFKind, uint16_t, bool> readBfdName();
void readSort();
Expr readAssert();
Expr readConstant();
@@ -255,6 +258,8 @@ void ScriptParser::readLinkerScript() {
readSearchDir();
} else if (Tok == "SECTIONS") {
readSections();
+ } else if (Tok == "TARGET") {
+ readTarget();
} else if (Tok == "VERSION") {
readVersion();
} else if (SymbolAssignment *Cmd = readAssignment(Tok)) {
@@ -266,6 +271,8 @@ void ScriptParser::readLinkerScript() {
}
void ScriptParser::readDefsym(StringRef Name) {
+ if (errorCount())
+ return;
Expr E = readExpr();
if (!atEOF())
setError("EOF expected, but got " + next());
@@ -378,10 +385,50 @@ void ScriptParser::readOutputArch() {
skip();
}
+std::tuple<ELFKind, uint16_t, bool> ScriptParser::readBfdName() {
+ StringRef S = unquote(next());
+ if (S == "elf32-i386")
+ return std::make_tuple(ELF32LEKind, EM_386, false);
+ if (S == "elf32-iamcu")
+ return std::make_tuple(ELF32LEKind, EM_IAMCU, false);
+ if (S == "elf32-littlearm")
+ return std::make_tuple(ELF32LEKind, EM_ARM, false);
+ if (S == "elf32-x86-64")
+ return std::make_tuple(ELF32LEKind, EM_X86_64, false);
+ if (S == "elf64-littleaarch64")
+ return std::make_tuple(ELF64LEKind, EM_AARCH64, false);
+ if (S == "elf64-powerpc")
+ return std::make_tuple(ELF64BEKind, EM_PPC64, false);
+ if (S == "elf64-powerpcle")
+ return std::make_tuple(ELF64LEKind, EM_PPC64, false);
+ if (S == "elf64-x86-64")
+ return std::make_tuple(ELF64LEKind, EM_X86_64, false);
+ if (S == "elf32-tradbigmips")
+ return std::make_tuple(ELF32BEKind, EM_MIPS, false);
+ if (S == "elf32-ntradbigmips")
+ return std::make_tuple(ELF32BEKind, EM_MIPS, true);
+ if (S == "elf32-tradlittlemips")
+ return std::make_tuple(ELF32LEKind, EM_MIPS, false);
+ if (S == "elf32-ntradlittlemips")
+ return std::make_tuple(ELF32LEKind, EM_MIPS, true);
+ if (S == "elf64-tradbigmips")
+ return std::make_tuple(ELF64BEKind, EM_MIPS, false);
+ if (S == "elf64-tradlittlemips")
+ return std::make_tuple(ELF64LEKind, EM_MIPS, false);
+
+ setError("unknown output format name: " + S);
+ return std::make_tuple(ELFNoneKind, EM_NONE, false);
+}
+
+// Parse OUTPUT_FORMAT(bfdname) or OUTPUT_FORMAT(bfdname, big, little).
+// Currently we ignore big and little parameters.
void ScriptParser::readOutputFormat() {
- // Error checking only for now.
expect("(");
- skip();
+
+ std::tuple<ELFKind, uint16_t, bool> BfdTuple = readBfdName();
+ if (Config->EKind == ELFNoneKind)
+ std::tie(Config->EKind, Config->EMachine, Config->MipsN32Abi) = BfdTuple;
+
if (consume(")"))
return;
expect(",");
@@ -497,6 +544,9 @@ void ScriptParser::readSections() {
for (BaseCommand *Cmd : readOverlay())
V.push_back(Cmd);
continue;
+ } else if (Tok == "INCLUDE") {
+ readInclude();
+ continue;
}
if (BaseCommand *Cmd = readAssignment(Tok))
@@ -522,6 +572,23 @@ void ScriptParser::readSections() {
V.end());
}
+void ScriptParser::readTarget() {
+ // TARGET(foo) is an alias for "--format foo". Unlike GNU linkers,
+ // we accept only a limited set of BFD names (i.e. "elf" or "binary")
+ // for --format. We recognize only /^elf/ and "binary" in the linker
+ // script as well.
+ expect("(");
+ StringRef Tok = next();
+ expect(")");
+
+ if (Tok.startswith("elf"))
+ Config->FormatBinary = false;
+ else if (Tok == "binary")
+ Config->FormatBinary = true;
+ else
+ setError("unknown target: " + Tok);
+}
+
static int precedence(StringRef Op) {
return StringSwitch<int>(Op)
.Cases("*", "/", "%", 8)
@@ -672,13 +739,33 @@ Expr ScriptParser::readAssert() {
// alias for =fillexp section attribute, which is different from
// what GNU linkers do.
// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
-uint32_t ScriptParser::readFill() {
+std::array<uint8_t, 4> ScriptParser::readFill() {
expect("(");
- uint32_t V = parseFill(next());
+ std::array<uint8_t, 4> V = parseFill(next());
expect(")");
return V;
}
+// Tries to read the special directive for an output section definition which
+// can be one of following: "(NOLOAD)", "(COPY)", "(INFO)" or "(OVERLAY)".
+// Tok1 and Tok2 are next 2 tokens peeked. See comment for readSectionAddressType below.
+bool ScriptParser::readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2) {
+ if (Tok1 != "(")
+ return false;
+ if (Tok2 != "NOLOAD" && Tok2 != "COPY" && Tok2 != "INFO" && Tok2 != "OVERLAY")
+ return false;
+
+ expect("(");
+ if (consume("NOLOAD")) {
+ Cmd->Noload = true;
+ } else {
+ skip(); // This is "COPY", "INFO" or "OVERLAY".
+ Cmd->NonAlloc = true;
+ }
+ expect(")");
+ return true;
+}
+
// Reads an expression and/or the special directive for an output
// section definition. Directive is one of following: "(NOLOAD)",
// "(COPY)", "(INFO)" or "(OVERLAY)".
@@ -691,28 +778,12 @@ 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(OutputSection *Cmd) {
- if (consume("(")) {
- if (consume("NOLOAD")) {
- expect(")");
- Cmd->Noload = true;
- return;
- }
- if (consume("COPY") || consume("INFO") || consume("OVERLAY")) {
- expect(")");
- Cmd->NonAlloc = true;
- return;
- }
- Cmd->AddrExpr = readExpr();
- expect(")");
- } else {
- Cmd->AddrExpr = readExpr();
- }
+ if (readSectionDirective(Cmd, peek(), peek2()))
+ return;
- if (consume("(")) {
- expect("NOLOAD");
- expect(")");
- Cmd->Noload = true;
- }
+ Cmd->AddrExpr = readExpr();
+ if (peek() == "(" && !readSectionDirective(Cmd, "(", peek2()))
+ setError("unknown section directive: " + peek2());
}
static Expr checkAlignment(Expr E, std::string &Loc) {
@@ -778,10 +849,17 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
Cmd->Filler = readFill();
} else if (Tok == "SORT") {
readSort();
+ } else if (Tok == "INCLUDE") {
+ readInclude();
} else if (peek() == "(") {
Cmd->SectionCommands.push_back(readInputSectionDescription(Tok));
} else {
- setError("unknown command " + Tok);
+ // We have a file name and no input sections description. It is not a
+ // commonly used syntax, but still acceptable. In that case, all sections
+ // from the file will be included.
+ auto *ISD = make<InputSectionDescription>(Tok);
+ ISD->SectionPatterns.push_back({{}, StringMatcher({"*"})});
+ Cmd->SectionCommands.push_back(ISD);
}
}
@@ -818,13 +896,13 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
// When reading a hexstring, ld.bfd handles it as a blob of arbitrary
// size, while ld.gold always handles it as a 32-bit big-endian number.
// We are compatible with ld.gold because it's easier to implement.
-uint32_t ScriptParser::parseFill(StringRef Tok) {
+std::array<uint8_t, 4> ScriptParser::parseFill(StringRef Tok) {
uint32_t V = 0;
if (!to_integer(Tok, V))
setError("invalid filler expression: " + Tok);
- uint32_t Buf;
- write32be(&Buf, V);
+ std::array<uint8_t, 4> Buf;
+ write32be(Buf.data(), V);
return Buf;
}
@@ -1404,7 +1482,11 @@ uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2,
void ScriptParser::readMemory() {
expect("{");
while (!errorCount() && !consume("}")) {
- StringRef Name = next();
+ StringRef Tok = next();
+ if (Tok == "INCLUDE") {
+ readInclude();
+ continue;
+ }
uint32_t Flags = 0;
uint32_t NegFlags = 0;
@@ -1419,10 +1501,9 @@ void ScriptParser::readMemory() {
uint64_t Length = readMemoryAssignment("LENGTH", "len", "l");
// Add the memory region to the region map.
- MemoryRegion *MR =
- make<MemoryRegion>(Name, Origin, Length, Flags, NegFlags);
- if (!Script->MemoryRegions.insert({Name, MR}).second)
- setError("region '" + Name + "' already defined");
+ MemoryRegion *MR = make<MemoryRegion>(Tok, Origin, Length, Flags, NegFlags);
+ if (!Script->MemoryRegions.insert({Tok, MR}).second)
+ setError("region '" + Tok + "' already defined");
}
}