diff options
Diffstat (limited to 'ELF/ScriptParser.cpp')
-rw-r--r-- | ELF/ScriptParser.cpp | 153 |
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"); } } |