diff options
Diffstat (limited to 'lld/ELF/ScriptParser.cpp')
-rw-r--r-- | lld/ELF/ScriptParser.cpp | 242 |
1 files changed, 168 insertions, 74 deletions
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index fd8de3b54bd7..fea6b7a274e7 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/ScopedPrinter.h" #include <cassert> #include <limits> #include <vector> @@ -37,9 +38,9 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::support::endian; +using namespace lld; +using namespace lld::elf; -namespace lld { -namespace elf { namespace { class ScriptParser final : ScriptLexer { public: @@ -91,10 +92,13 @@ private: OutputSection *readOutputSectionDescription(StringRef outSec); std::vector<BaseCommand *> readOverlay(); std::vector<StringRef> readOutputSectionPhdrs(); + std::pair<uint64_t, uint64_t> readInputSectionFlags(); InputSectionDescription *readInputSectionDescription(StringRef tok); StringMatcher readFilePatterns(); std::vector<SectionPattern> readInputSectionsList(); - InputSectionDescription *readInputSectionRules(StringRef filePattern); + InputSectionDescription *readInputSectionRules(StringRef filePattern, + uint64_t withFlags, + uint64_t withoutFlags); unsigned readPhdrType(); SortSectionPolicy readSortKind(); SymbolAssignment *readProvideHidden(bool provide, bool hidden); @@ -104,7 +108,7 @@ private: Expr readConstant(); Expr getPageSize(); - uint64_t readMemoryAssignment(StringRef, StringRef, StringRef); + Expr readMemoryAssignment(StringRef, StringRef, StringRef); std::pair<uint32_t, uint32_t> readMemoryAttributes(); Expr combine(StringRef op, Expr l, Expr r); @@ -171,7 +175,6 @@ static ExprValue bitOr(ExprValue a, ExprValue b) { } void ScriptParser::readDynamicList() { - config->hasDynamicList = true; expect("{"); std::vector<SymbolVersion> locals; std::vector<SymbolVersion> globals; @@ -286,22 +289,40 @@ void ScriptParser::addFile(StringRef s) { } if (s.startswith("/")) { + // Case 1: s is an absolute path. Just open it. driver->addFile(s, /*withLOption=*/false); } else if (s.startswith("=")) { + // Case 2: relative to the sysroot. if (config->sysroot.empty()) driver->addFile(s.substr(1), /*withLOption=*/false); else driver->addFile(saver.save(config->sysroot + "/" + s.substr(1)), /*withLOption=*/false); } else if (s.startswith("-l")) { + // Case 3: search in the list of library paths. driver->addLibrary(s.substr(2)); - } else if (sys::fs::exists(s)) { - driver->addFile(s, /*withLOption=*/false); } else { - if (Optional<std::string> path = findFromSearchPaths(s)) - driver->addFile(saver.save(*path), /*withLOption=*/true); - else - setError("unable to find " + s); + // Case 4: s is a relative path. Search in the directory of the script file. + std::string filename = std::string(getCurrentMB().getBufferIdentifier()); + StringRef directory = sys::path::parent_path(filename); + if (!directory.empty()) { + SmallString<0> path(directory); + sys::path::append(path, s); + if (sys::fs::exists(path)) { + driver->addFile(path, /*withLOption=*/false); + return; + } + } + // Then search in the current working directory. + if (sys::fs::exists(s)) { + driver->addFile(s, /*withLOption=*/false); + } else { + // Finally, search in the list of library paths. + if (Optional<std::string> path = findFromSearchPaths(s)) + driver->addFile(saver.save(*path), /*withLOption=*/true); + else + setError("unable to find " + s); + } } } @@ -400,6 +421,7 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) { .Case("elf64-tradlittlemips", {ELF64LEKind, EM_MIPS}) .Case("elf32-littleriscv", {ELF32LEKind, EM_RISCV}) .Case("elf64-littleriscv", {ELF64LEKind, EM_RISCV}) + .Case("elf64-sparc", {ELF64BEKind, EM_SPARCV9}) .Default({ELFNoneKind, EM_NONE}); } @@ -408,14 +430,14 @@ static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) { void ScriptParser::readOutputFormat() { expect("("); - StringRef name = unquote(next()); - StringRef s = name; + config->bfdname = unquote(next()); + StringRef s = config->bfdname; if (s.consume_back("-freebsd")) config->osabi = ELFOSABI_FREEBSD; std::tie(config->ekind, config->emachine) = parseBfdName(s); if (config->emachine == EM_NONE) - setError("unknown output format name: " + name); + setError("unknown output format name: " + config->bfdname); if (s == "elf32-ntradlittlemips" || s == "elf32-ntradbigmips") config->mipsN32Abi = true; @@ -519,13 +541,6 @@ std::vector<BaseCommand *> ScriptParser::readOverlay() { } void ScriptParser::readSections() { - script->hasSectionsCommand = true; - - // -no-rosegment is used to avoid placing read only non-executable sections in - // their own segment. We do the same if SECTIONS command is present in linker - // script. See comment for computeFlags(). - config->singleRoRx = true; - expect("{"); std::vector<BaseCommand *> v; while (!errorCount() && !consume("}")) { @@ -544,22 +559,23 @@ void ScriptParser::readSections() { else v.push_back(readOutputSectionDescription(tok)); } + script->sectionCommands.insert(script->sectionCommands.end(), v.begin(), + v.end()); - if (!atEOF() && consume("INSERT")) { - std::vector<BaseCommand *> *dest = nullptr; - if (consume("AFTER")) - dest = &script->insertAfterCommands[next()]; - else if (consume("BEFORE")) - dest = &script->insertBeforeCommands[next()]; - else - setError("expected AFTER/BEFORE, but got '" + next() + "'"); - if (dest) - dest->insert(dest->end(), v.begin(), v.end()); + if (atEOF() || !consume("INSERT")) { + script->hasSectionsCommand = true; return; } - script->sectionCommands.insert(script->sectionCommands.end(), v.begin(), - v.end()); + bool isAfter = false; + if (consume("AFTER")) + isAfter = true; + else if (!consume("BEFORE")) + setError("expected AFTER/BEFORE, but got '" + next() + "'"); + StringRef where = next(); + for (BaseCommand *cmd : v) + if (auto *os = dyn_cast<OutputSection>(cmd)) + script->insertCommands.push_back({os, isAfter, where}); } void ScriptParser::readTarget() { @@ -593,10 +609,11 @@ static int precedence(StringRef op) { } StringMatcher ScriptParser::readFilePatterns() { - std::vector<StringRef> v; + StringMatcher Matcher; + while (!errorCount() && !consume(")")) - v.push_back(next()); - return StringMatcher(v); + Matcher.addPattern(SingleStringMatcher(next())); + return Matcher; } SortSectionPolicy ScriptParser::readSortKind() { @@ -633,12 +650,12 @@ std::vector<SectionPattern> ScriptParser::readInputSectionsList() { excludeFilePat = readFilePatterns(); } - std::vector<StringRef> v; + StringMatcher SectionMatcher; while (!errorCount() && peek() != ")" && peek() != "EXCLUDE_FILE") - v.push_back(unquote(next())); + SectionMatcher.addPattern(unquote(next())); - if (!v.empty()) - ret.push_back({std::move(excludeFilePat), StringMatcher(v)}); + if (!SectionMatcher.empty()) + ret.push_back({std::move(excludeFilePat), std::move(SectionMatcher)}); else setError("section pattern is expected"); } @@ -657,8 +674,10 @@ std::vector<SectionPattern> ScriptParser::readInputSectionsList() { // // <section-list> is parsed by readInputSectionsList(). InputSectionDescription * -ScriptParser::readInputSectionRules(StringRef filePattern) { - auto *cmd = make<InputSectionDescription>(filePattern); +ScriptParser::readInputSectionRules(StringRef filePattern, uint64_t withFlags, + uint64_t withoutFlags) { + auto *cmd = + make<InputSectionDescription>(filePattern, withFlags, withoutFlags); expect("("); while (!errorCount() && !consume(")")) { @@ -694,15 +713,23 @@ InputSectionDescription * ScriptParser::readInputSectionDescription(StringRef tok) { // Input section wildcard can be surrounded by KEEP. // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep + uint64_t withFlags = 0; + uint64_t withoutFlags = 0; if (tok == "KEEP") { expect("("); - StringRef filePattern = next(); - InputSectionDescription *cmd = readInputSectionRules(filePattern); + if (consume("INPUT_SECTION_FLAGS")) + std::tie(withFlags, withoutFlags) = readInputSectionFlags(); + InputSectionDescription *cmd = + readInputSectionRules(next(), withFlags, withoutFlags); expect(")"); script->keptSections.push_back(cmd); return cmd; } - return readInputSectionRules(tok); + if (tok == "INPUT_SECTION_FLAGS") { + std::tie(withFlags, withoutFlags) = readInputSectionFlags(); + tok = next(); + } + return readInputSectionRules(tok, withFlags, withoutFlags); } void ScriptParser::readSort() { @@ -737,6 +764,7 @@ bool ScriptParser::readSectionDirective(OutputSection *cmd, StringRef tok1, Stri expect("("); if (consume("NOLOAD")) { cmd->noload = true; + cmd->type = SHT_NOBITS; } else { skip(); // This is "COPY", "INFO" or "OVERLAY". cmd->nonAlloc = true; @@ -781,9 +809,14 @@ OutputSection *ScriptParser::readOverlaySectionDescription() { script->createOutputSection(next(), getCurrentLocation()); cmd->inOverlay = true; expect("{"); - while (!errorCount() && !consume("}")) - cmd->sectionCommands.push_back(readInputSectionRules(next())); - cmd->phdrs = readOutputSectionPhdrs(); + while (!errorCount() && !consume("}")) { + uint64_t withFlags = 0; + uint64_t withoutFlags = 0; + if (consume("INPUT_SECTION_FLAGS")) + std::tie(withFlags, withoutFlags) = readInputSectionFlags(); + cmd->sectionCommands.push_back( + readInputSectionRules(next(), withFlags, withoutFlags)); + } return cmd; } @@ -828,9 +861,9 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) { // We handle the FILL command as an alias for =fillexp section attribute, // which is different from what GNU linkers do. // https://sourceware.org/binutils/docs/ld/Output-Section-Data.html - expect("("); + if (peek() != "(") + setError("( expected, but got " + peek()); cmd->filler = readFill(); - expect(")"); } else if (tok == "SORT") { readSort(); } else if (tok == "INCLUDE") { @@ -841,18 +874,21 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) { // 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. + // FIXME: GNU ld permits INPUT_SECTION_FLAGS to be used here. We do not + // handle this case here as it will already have been matched by the + // case above. auto *isd = make<InputSectionDescription>(tok); - isd->sectionPatterns.push_back({{}, StringMatcher({"*"})}); + isd->sectionPatterns.push_back({{}, StringMatcher("*")}); cmd->sectionCommands.push_back(isd); } } if (consume(">")) - cmd->memoryRegionName = next(); + cmd->memoryRegionName = std::string(next()); if (consume("AT")) { expect(">"); - cmd->lmaRegionName = next(); + cmd->lmaRegionName = std::string(next()); } if (cmd->lmaExpr && !cmd->lmaRegionName.empty()) @@ -882,8 +918,11 @@ 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. +// Also, we require that expressions with operators must be wrapped into +// round brackets. We did it to resolve the ambiguity when parsing scripts like: +// SECTIONS { .foo : { ... } =120+3 /DISCARD/ : { ... } } std::array<uint8_t, 4> ScriptParser::readFill() { - uint64_t value = readExpr()().val; + uint64_t value = readPrimary()().val; if (value > UINT32_MAX) setError("filler expression result does not fit 32-bit: 0x" + Twine::utohexstr(value)); @@ -1102,6 +1141,63 @@ ByteCommand *ScriptParser::readByteCommand(StringRef tok) { return make<ByteCommand>(e, size, commandString); } +static llvm::Optional<uint64_t> parseFlag(StringRef tok) { + if (llvm::Optional<uint64_t> asInt = parseInt(tok)) + return asInt; +#define CASE_ENT(enum) #enum, ELF::enum + return StringSwitch<llvm::Optional<uint64_t>>(tok) + .Case(CASE_ENT(SHF_WRITE)) + .Case(CASE_ENT(SHF_ALLOC)) + .Case(CASE_ENT(SHF_EXECINSTR)) + .Case(CASE_ENT(SHF_MERGE)) + .Case(CASE_ENT(SHF_STRINGS)) + .Case(CASE_ENT(SHF_INFO_LINK)) + .Case(CASE_ENT(SHF_LINK_ORDER)) + .Case(CASE_ENT(SHF_OS_NONCONFORMING)) + .Case(CASE_ENT(SHF_GROUP)) + .Case(CASE_ENT(SHF_TLS)) + .Case(CASE_ENT(SHF_COMPRESSED)) + .Case(CASE_ENT(SHF_EXCLUDE)) + .Case(CASE_ENT(SHF_ARM_PURECODE)) + .Default(None); +#undef CASE_ENT +} + +// Reads the '(' <flags> ')' list of section flags in +// INPUT_SECTION_FLAGS '(' <flags> ')' in the +// following form: +// <flags> ::= <flag> +// | <flags> & flag +// <flag> ::= Recognized Flag Name, or Integer value of flag. +// If the first character of <flag> is a ! then this means without flag, +// otherwise with flag. +// Example: SHF_EXECINSTR & !SHF_WRITE means with flag SHF_EXECINSTR and +// without flag SHF_WRITE. +std::pair<uint64_t, uint64_t> ScriptParser::readInputSectionFlags() { + uint64_t withFlags = 0; + uint64_t withoutFlags = 0; + expect("("); + while (!errorCount()) { + StringRef tok = unquote(next()); + bool without = tok.consume_front("!"); + if (llvm::Optional<uint64_t> flag = parseFlag(tok)) { + if (without) + withoutFlags |= *flag; + else + withFlags |= *flag; + } else { + setError("unrecognised flag: " + tok); + } + if (consume(")")) + break; + if (!consume("&")) { + next(); + setError("expected & or )"); + } + } + return std::make_pair(withFlags, withoutFlags); +} + StringRef ScriptParser::readParenLiteral() { expect("("); bool orig = inExpr; @@ -1222,7 +1318,7 @@ Expr ScriptParser::readPrimary() { setError("memory region not defined: " + name); return [] { return 0; }; } - return [=] { return script->memoryRegions[name]->length; }; + return script->memoryRegions[name]->length; } if (tok == "LOADADDR") { StringRef name = readParenLiteral(); @@ -1249,7 +1345,7 @@ Expr ScriptParser::readPrimary() { setError("memory region not defined: " + name); return [] { return 0; }; } - return [=] { return script->memoryRegions[name]->origin; }; + return script->memoryRegions[name]->origin; } if (tok == "SEGMENT_START") { expect("("); @@ -1268,7 +1364,7 @@ Expr ScriptParser::readPrimary() { return [=] { return cmd->size; }; } if (tok == "SIZEOF_HEADERS") - return [=] { return getHeaderSize(); }; + return [=] { return elf::getHeaderSize(); }; // Tok is the dot. if (tok == ".") @@ -1374,12 +1470,11 @@ void ScriptParser::readVersionDeclaration(StringRef verStr) { // as a parent. This version hierarchy is, probably against your // instinct, purely for hint; the runtime doesn't care about it // at all. In LLD, we simply ignore it. - if (peek() != ";") - skip(); - expect(";"); + if (next() != ";") + expect(";"); } -static bool hasWildcard(StringRef s) { +bool elf::hasWildcard(StringRef s) { return s.find_first_of("?*[") != StringRef::npos; } @@ -1440,14 +1535,14 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() { return ret; } -uint64_t ScriptParser::readMemoryAssignment(StringRef s1, StringRef s2, - StringRef s3) { +Expr ScriptParser::readMemoryAssignment(StringRef s1, StringRef s2, + StringRef s3) { if (!consume(s1) && !consume(s2) && !consume(s3)) { setError("expected one of: " + s1 + ", " + s2 + ", or " + s3); - return 0; + return [] { return 0; }; } expect("="); - return readExpr()().getValue(); + return readExpr(); } // Parse the MEMORY command as specified in: @@ -1471,9 +1566,9 @@ void ScriptParser::readMemory() { } expect(":"); - uint64_t origin = readMemoryAssignment("ORIGIN", "org", "o"); + Expr origin = readMemoryAssignment("ORIGIN", "org", "o"); expect(","); - uint64_t length = readMemoryAssignment("LENGTH", "len", "l"); + Expr length = readMemoryAssignment("LENGTH", "len", "l"); // Add the memory region to the region map. MemoryRegion *mr = make<MemoryRegion>(tok, origin, length, flags, negFlags); @@ -1511,19 +1606,18 @@ std::pair<uint32_t, uint32_t> ScriptParser::readMemoryAttributes() { return {flags, negFlags}; } -void readLinkerScript(MemoryBufferRef mb) { +void elf::readLinkerScript(MemoryBufferRef mb) { ScriptParser(mb).readLinkerScript(); } -void readVersionScript(MemoryBufferRef mb) { +void elf::readVersionScript(MemoryBufferRef mb) { ScriptParser(mb).readVersionScript(); } -void readDynamicList(MemoryBufferRef mb) { ScriptParser(mb).readDynamicList(); } +void elf::readDynamicList(MemoryBufferRef mb) { + ScriptParser(mb).readDynamicList(); +} -void readDefsym(StringRef name, MemoryBufferRef mb) { +void elf::readDefsym(StringRef name, MemoryBufferRef mb) { ScriptParser(mb).readDefsym(name); } - -} // namespace elf -} // namespace lld |