diff options
Diffstat (limited to 'lld/ELF/ScriptParser.cpp')
| -rw-r--r-- | lld/ELF/ScriptParser.cpp | 252 |
1 files changed, 173 insertions, 79 deletions
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 7331d1156f27..4d73541b3d42 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -14,10 +14,11 @@ #include "ScriptParser.h" #include "Config.h" #include "Driver.h" -#include "InputSection.h" +#include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" #include "ScriptLexer.h" +#include "SymbolTable.h" #include "Symbols.h" #include "Target.h" #include "lld/Common/CommonLinkerContext.h" @@ -31,7 +32,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" -#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/TimeProfiler.h" #include <cassert> #include <limits> @@ -91,8 +92,8 @@ private: std::array<uint8_t, 4> readFill(); bool readSectionDirective(OutputSection *cmd, StringRef tok1, StringRef tok2); void readSectionAddressType(OutputSection *cmd); - OutputSection *readOverlaySectionDescription(); - OutputSection *readOutputSectionDescription(StringRef outSec); + OutputDesc *readOverlaySectionDescription(); + OutputDesc *readOutputSectionDescription(StringRef outSec); SmallVector<SectionCommand *, 0> readOverlay(); SmallVector<StringRef, 0> readOutputSectionPhdrs(); std::pair<uint64_t, uint64_t> readInputSectionFlags(); @@ -135,6 +136,9 @@ private: // True if a script being read is in the --sysroot directory. bool isUnderSysroot = false; + bool seenDataAlign = false; + bool seenRelroEnd = false; + // A set to detect an INCLUDE() cycle. StringSet<> seen; }; @@ -348,7 +352,7 @@ void ScriptParser::readEntry() { expect("("); StringRef tok = next(); if (config->entry.empty()) - config->entry = tok; + config->entry = unquote(tok); expect(")"); } @@ -412,6 +416,7 @@ void ScriptParser::readOutputArch() { static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) { return StringSwitch<std::pair<ELFKind, uint16_t>>(s) .Case("elf32-i386", {ELF32LEKind, EM_386}) + .Case("elf32-avr", {ELF32LEKind, EM_AVR}) .Case("elf32-iamcu", {ELF32LEKind, EM_IAMCU}) .Case("elf32-littlearm", {ELF32LEKind, EM_ARM}) .Case("elf32-x86-64", {ELF32LEKind, EM_X86_64}) @@ -534,14 +539,14 @@ SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() { while (!errorCount() && !consume("}")) { // VA is the same for all sections. The LMAs are consecutive in memory // starting from the base load address specified. - OutputSection *os = readOverlaySectionDescription(); - os->addrExpr = addrExpr; + OutputDesc *osd = readOverlaySectionDescription(); + osd->osec.addrExpr = addrExpr; if (prev) - os->lmaExpr = [=] { return prev->getLMA() + prev->size; }; + osd->osec.lmaExpr = [=] { return prev->getLMA() + prev->size; }; else - os->lmaExpr = lmaExpr; - v.push_back(os); - prev = os; + osd->osec.lmaExpr = lmaExpr; + v.push_back(osd); + prev = &osd->osec; } // According to the specification, at the end of the overlay, the location @@ -551,7 +556,7 @@ SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() { Expr moveDot = [=] { uint64_t max = 0; for (SectionCommand *cmd : v) - max = std::max(max, cast<OutputSection>(cmd)->size); + max = std::max(max, cast<OutputDesc>(cmd)->osec.size); return addrExpr().getValue() + max; }; v.push_back(make<SymbolAssignment>(".", moveDot, getCurrentLocation())); @@ -583,6 +588,14 @@ void ScriptParser::readSections() { else v.push_back(readOutputSectionDescription(tok)); } + + // If DATA_SEGMENT_RELRO_END is absent, for sections after DATA_SEGMENT_ALIGN, + // the relro fields should be cleared. + if (!seenRelroEnd) + for (SectionCommand *cmd : v) + if (auto *osd = dyn_cast<OutputDesc>(cmd)) + osd->osec.relro = false; + script->sectionCommands.insert(script->sectionCommands.end(), v.begin(), v.end()); @@ -599,8 +612,8 @@ void ScriptParser::readSections() { StringRef where = next(); SmallVector<StringRef, 0> names; for (SectionCommand *cmd : v) - if (auto *os = dyn_cast<OutputSection>(cmd)) - names.push_back(os->name); + if (auto *os = dyn_cast<OutputDesc>(cmd)) + names.push_back(os->osec.name); if (!names.empty()) script->insertCommands.push_back({std::move(names), isAfter, where}); } @@ -611,7 +624,7 @@ void ScriptParser::readTarget() { // for --format. We recognize only /^elf/ and "binary" in the linker // script as well. expect("("); - StringRef tok = next(); + StringRef tok = unquote(next()); expect(")"); if (tok.startswith("elf")) @@ -624,14 +637,16 @@ void ScriptParser::readTarget() { static int precedence(StringRef op) { return StringSwitch<int>(op) - .Cases("*", "/", "%", 8) - .Cases("+", "-", 7) - .Cases("<<", ">>", 6) - .Cases("<", "<=", ">", ">=", "==", "!=", 5) - .Case("&", 4) - .Case("|", 3) - .Case("&&", 2) - .Case("||", 1) + .Cases("*", "/", "%", 10) + .Cases("+", "-", 9) + .Cases("<<", ">>", 8) + .Cases("<", "<=", ">", ">=", 7) + .Cases("==", "!=", 6) + .Case("&", 5) + .Case("|", 4) + .Case("&&", 3) + .Case("||", 2) + .Case("?", 1) .Default(-1); } @@ -787,19 +802,45 @@ Expr ScriptParser::readAssert() { }; } +#define ECase(X) \ + { #X, X } +constexpr std::pair<const char *, unsigned> typeMap[] = { + ECase(SHT_PROGBITS), ECase(SHT_NOTE), ECase(SHT_NOBITS), + ECase(SHT_INIT_ARRAY), ECase(SHT_FINI_ARRAY), ECase(SHT_PREINIT_ARRAY), +}; +#undef ECase + // 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. +// can be one of following: "(NOLOAD)", "(COPY)", "(INFO)", "(OVERLAY)", and +// "(TYPE=<value>)". +// 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") + if (tok2 != "NOLOAD" && tok2 != "COPY" && tok2 != "INFO" && + tok2 != "OVERLAY" && tok2 != "TYPE") return false; expect("("); if (consume("NOLOAD")) { - cmd->noload = true; cmd->type = SHT_NOBITS; + cmd->typeIsSet = true; + } else if (consume("TYPE")) { + expect("="); + StringRef value = peek(); + auto it = llvm::find_if(typeMap, [=](auto e) { return e.first == value; }); + if (it != std::end(typeMap)) { + // The value is a recognized literal SHT_*. + cmd->type = it->second; + skip(); + } else if (value.startswith("SHT_")) { + setError("unknown section type " + value); + } else { + // Otherwise, read an expression. + cmd->type = readExpr()().getValue(); + } + cmd->typeIsSet = true; } else { skip(); // This is "COPY", "INFO" or "OVERLAY". cmd->nonAlloc = true; @@ -820,7 +861,11 @@ bool ScriptParser::readSectionDirective(OutputSection *cmd, StringRef tok1, Stri // 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 (readSectionDirective(cmd, peek(), peek2())) + // Temporarily set inExpr to support TYPE=<value> without spaces. + bool saved = std::exchange(inExpr, true); + bool isDirective = readSectionDirective(cmd, peek(), peek2()); + inExpr = saved; + if (isDirective) return; cmd->addrExpr = readExpr(); @@ -839,45 +884,46 @@ static Expr checkAlignment(Expr e, std::string &loc) { }; } -OutputSection *ScriptParser::readOverlaySectionDescription() { - OutputSection *cmd = - script->createOutputSection(next(), getCurrentLocation()); - cmd->inOverlay = true; +OutputDesc *ScriptParser::readOverlaySectionDescription() { + OutputDesc *osd = script->createOutputSection(next(), getCurrentLocation()); + osd->osec.inOverlay = true; expect("{"); while (!errorCount() && !consume("}")) { uint64_t withFlags = 0; uint64_t withoutFlags = 0; if (consume("INPUT_SECTION_FLAGS")) std::tie(withFlags, withoutFlags) = readInputSectionFlags(); - cmd->commands.push_back( + osd->osec.commands.push_back( readInputSectionRules(next(), withFlags, withoutFlags)); } - return cmd; + return osd; } -OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) { - OutputSection *cmd = - script->createOutputSection(outSec, getCurrentLocation()); +OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) { + OutputDesc *cmd = script->createOutputSection(outSec, getCurrentLocation()); + OutputSection *osec = &cmd->osec; + // Maybe relro. Will reset to false if DATA_SEGMENT_RELRO_END is absent. + osec->relro = seenDataAlign && !seenRelroEnd; size_t symbolsReferenced = script->referencedSymbols.size(); if (peek() != ":") - readSectionAddressType(cmd); + readSectionAddressType(osec); expect(":"); std::string location = getCurrentLocation(); if (consume("AT")) - cmd->lmaExpr = readParenExpr(); + osec->lmaExpr = readParenExpr(); if (consume("ALIGN")) - cmd->alignExpr = checkAlignment(readParenExpr(), location); + osec->alignExpr = checkAlignment(readParenExpr(), location); if (consume("SUBALIGN")) - cmd->subalignExpr = checkAlignment(readParenExpr(), location); + osec->subalignExpr = checkAlignment(readParenExpr(), location); // Parse constraints. if (consume("ONLY_IF_RO")) - cmd->constraint = ConstraintKind::ReadOnly; + osec->constraint = ConstraintKind::ReadOnly; if (consume("ONLY_IF_RW")) - cmd->constraint = ConstraintKind::ReadWrite; + osec->constraint = ConstraintKind::ReadWrite; expect("{"); while (!errorCount() && !consume("}")) { @@ -885,9 +931,9 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) { if (tok == ";") { // Empty commands are allowed. Do nothing here. } else if (SymbolAssignment *assign = readAssignment(tok)) { - cmd->commands.push_back(assign); + osec->commands.push_back(assign); } else if (ByteCommand *data = readByteCommand(tok)) { - cmd->commands.push_back(data); + osec->commands.push_back(data); } else if (tok == "CONSTRUCTORS") { // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors // by name. This is for very old file formats such as ECOFF/XCOFF. @@ -898,13 +944,15 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) { // https://sourceware.org/binutils/docs/ld/Output-Section-Data.html if (peek() != "(") setError("( expected, but got " + peek()); - cmd->filler = readFill(); + osec->filler = readFill(); } else if (tok == "SORT") { readSort(); } else if (tok == "INCLUDE") { readInclude(); + } else if (tok == "(" || tok == ")") { + setError("expected filename pattern"); } else if (peek() == "(") { - cmd->commands.push_back(readInputSectionDescription(tok)); + osec->commands.push_back(readInputSectionDescription(tok)); } else { // 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 @@ -914,27 +962,27 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) { // case above. auto *isd = make<InputSectionDescription>(tok); isd->sectionPatterns.push_back({{}, StringMatcher("*")}); - cmd->commands.push_back(isd); + osec->commands.push_back(isd); } } if (consume(">")) - cmd->memoryRegionName = std::string(next()); + osec->memoryRegionName = std::string(next()); if (consume("AT")) { expect(">"); - cmd->lmaRegionName = std::string(next()); + osec->lmaRegionName = std::string(next()); } - if (cmd->lmaExpr && !cmd->lmaRegionName.empty()) + if (osec->lmaExpr && !osec->lmaRegionName.empty()) error("section can't have both LMA and a load region"); - cmd->phdrs = readOutputSectionPhdrs(); + osec->phdrs = readOutputSectionPhdrs(); if (peek() == "=" || peek().startswith("=")) { inExpr = true; consume("="); - cmd->filler = readFill(); + osec->filler = readFill(); inExpr = false; } @@ -942,7 +990,7 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) { consume(","); if (script->referencedSymbols.size() > symbolsReferenced) - cmd->expressionsUseSymbols = true; + osec->expressionsUseSymbols = true; return cmd; } @@ -969,7 +1017,14 @@ std::array<uint8_t, 4> ScriptParser::readFill() { SymbolAssignment *ScriptParser::readProvideHidden(bool provide, bool hidden) { expect("("); - SymbolAssignment *cmd = readSymbolAssignment(next()); + StringRef name = next(), eq = peek(); + if (eq != "=") { + setError("= expected, but got " + next()); + while (!atEOF() && next() != ")") + ; + return nullptr; + } + SymbolAssignment *cmd = readSymbolAssignment(name); cmd->provide = provide; cmd->hidden = hidden; expect(")"); @@ -983,14 +1038,24 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) { size_t oldPos = pos; SymbolAssignment *cmd = nullptr; - if (peek() == "=" || peek() == "+=") + const StringRef op = peek(); + if (op.startswith("=")) { + // Support = followed by an expression without whitespace. + SaveAndRestore<bool> saved(inExpr, true); + cmd = readSymbolAssignment(tok); + } else if ((op.size() == 2 && op[1] == '=' && strchr("*/+-&|", op[0])) || + op == "<<=" || op == ">>=") { cmd = readSymbolAssignment(tok); - else if (tok == "PROVIDE") + } else if (tok == "PROVIDE") { + SaveAndRestore<bool> saved(inExpr, true); cmd = readProvideHidden(true, false); - else if (tok == "HIDDEN") + } else if (tok == "HIDDEN") { + SaveAndRestore<bool> saved(inExpr, true); cmd = readProvideHidden(false, true); - else if (tok == "PROVIDE_HIDDEN") + } else if (tok == "PROVIDE_HIDDEN") { + SaveAndRestore<bool> saved(inExpr, true); cmd = readProvideHidden(true, true); + } if (cmd) { cmd->commandString = @@ -1004,11 +1069,38 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) { SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef name) { name = unquote(name); StringRef op = next(); - assert(op == "=" || op == "+="); + assert(op == "=" || op == "*=" || op == "/=" || op == "+=" || op == "-=" || + op == "&=" || op == "|=" || op == "<<=" || op == ">>="); + // Note: GNU ld does not support %= or ^=. Expr e = readExpr(); - if (op == "+=") { + if (op != "=") { std::string loc = getCurrentLocation(); - e = [=] { return add(script->getSymbolValue(name, loc), e()); }; + e = [=, c = op[0]]() -> ExprValue { + ExprValue lhs = script->getSymbolValue(name, loc); + switch (c) { + case '*': + return lhs.getValue() * e().getValue(); + case '/': + if (uint64_t rv = e().getValue()) + return lhs.getValue() / rv; + error(loc + ": division by zero"); + return 0; + case '+': + return add(lhs, e()); + case '-': + return sub(lhs, e()); + case '<': + return lhs.getValue() << e().getValue(); + case '>': + return lhs.getValue() >> e().getValue(); + case '&': + return lhs.getValue() & e().getValue(); + case '|': + return lhs.getValue() | e().getValue(); + default: + llvm_unreachable(""); + } + }; } return make<SymbolAssignment>(name, e, getCurrentLocation()); } @@ -1082,11 +1174,11 @@ Expr ScriptParser::combine(StringRef op, Expr l, Expr r) { Expr ScriptParser::readExpr1(Expr lhs, int minPrec) { while (!atEOF() && !errorCount()) { // Read an operator and an expression. - if (consume("?")) - return readTernary(lhs); StringRef op1 = peek(); if (precedence(op1) < minPrec) break; + if (consume("?")) + return readTernary(lhs); skip(); Expr rhs = readPrimary(); @@ -1244,9 +1336,9 @@ StringRef ScriptParser::readParenLiteral() { return tok; } -static void checkIfExists(OutputSection *cmd, StringRef location) { - if (cmd->location.empty() && script->errorOnMissingSection) - error(location + ": undefined section " + cmd->name); +static void checkIfExists(const OutputSection &osec, StringRef location) { + if (osec.location.empty() && script->errorOnMissingSection) + error(location + ": undefined section " + osec.name); } static bool isValidSymbolName(StringRef s) { @@ -1288,11 +1380,11 @@ Expr ScriptParser::readPrimary() { } if (tok == "ADDR") { StringRef name = readParenLiteral(); - OutputSection *sec = script->getOrCreateOutputSection(name); - sec->usedInExpression = true; + OutputSection *osec = &script->getOrCreateOutputSection(name)->osec; + osec->usedInExpression = true; return [=]() -> ExprValue { - checkIfExists(sec, location); - return {sec, false, 0, location}; + checkIfExists(*osec, location); + return {osec, false, 0, location}; }; } if (tok == "ALIGN") { @@ -1313,10 +1405,10 @@ Expr ScriptParser::readPrimary() { } if (tok == "ALIGNOF") { StringRef name = readParenLiteral(); - OutputSection *cmd = script->getOrCreateOutputSection(name); + OutputSection *osec = &script->getOrCreateOutputSection(name)->osec; return [=] { - checkIfExists(cmd, location); - return cmd->alignment; + checkIfExists(*osec, location); + return osec->alignment; }; } if (tok == "ASSERT") @@ -1329,6 +1421,7 @@ Expr ScriptParser::readPrimary() { expect(","); readExpr(); expect(")"); + seenDataAlign = true; return [=] { return alignTo(script->getDot(), std::max((uint64_t)1, e().getValue())); }; @@ -1348,6 +1441,7 @@ Expr ScriptParser::readPrimary() { expect(","); readExpr(); expect(")"); + seenRelroEnd = true; Expr e = getPageSize(); return [=] { return alignTo(script->getDot(), e().getValue()); }; } @@ -1368,11 +1462,11 @@ Expr ScriptParser::readPrimary() { } if (tok == "LOADADDR") { StringRef name = readParenLiteral(); - OutputSection *cmd = script->getOrCreateOutputSection(name); - cmd->usedInExpression = true; + OutputSection *osec = &script->getOrCreateOutputSection(name)->osec; + osec->usedInExpression = true; return [=] { - checkIfExists(cmd, location); - return cmd->getLMA(); + checkIfExists(*osec, location); + return osec->getLMA(); }; } if (tok == "LOG2CEIL") { @@ -1412,7 +1506,7 @@ Expr ScriptParser::readPrimary() { } if (tok == "SIZEOF") { StringRef name = readParenLiteral(); - OutputSection *cmd = script->getOrCreateOutputSection(name); + OutputSection *cmd = &script->getOrCreateOutputSection(name)->osec; // Linker script does not create an output section if its content is empty. // We want to allow SIZEOF(.foo) where .foo is a section which happened to // be empty. |
