diff options
Diffstat (limited to 'lib/ReaderWriter/LinkerScript.cpp')
-rw-r--r-- | lib/ReaderWriter/LinkerScript.cpp | 2895 |
1 files changed, 0 insertions, 2895 deletions
diff --git a/lib/ReaderWriter/LinkerScript.cpp b/lib/ReaderWriter/LinkerScript.cpp deleted file mode 100644 index 67822dc48fe6..000000000000 --- a/lib/ReaderWriter/LinkerScript.cpp +++ /dev/null @@ -1,2895 +0,0 @@ -//===- ReaderWriter/LinkerScript.cpp ----------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Linker script parser. -/// -//===----------------------------------------------------------------------===// - -#include "lld/ReaderWriter/LinkerScript.h" - -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/ELF.h" - -namespace lld { -namespace script { -void Token::dump(raw_ostream &os) const { - switch (_kind) { -#define CASE(name) \ - case Token::name: \ - os << #name ": "; \ - break; - CASE(unknown) - CASE(eof) - CASE(exclaim) - CASE(exclaimequal) - CASE(amp) - CASE(ampequal) - CASE(l_paren) - CASE(r_paren) - CASE(star) - CASE(starequal) - CASE(plus) - CASE(plusequal) - CASE(comma) - CASE(minus) - CASE(minusequal) - CASE(slash) - CASE(slashequal) - CASE(number) - CASE(colon) - CASE(semicolon) - CASE(less) - CASE(lessequal) - CASE(lessless) - CASE(lesslessequal) - CASE(equal) - CASE(equalequal) - CASE(greater) - CASE(greaterequal) - CASE(greatergreater) - CASE(greatergreaterequal) - CASE(question) - CASE(identifier) - CASE(libname) - CASE(kw_align) - CASE(kw_align_with_input) - CASE(kw_as_needed) - CASE(kw_at) - CASE(kw_discard) - CASE(kw_entry) - CASE(kw_exclude_file) - CASE(kw_extern) - CASE(kw_filehdr) - CASE(kw_fill) - CASE(kw_flags) - CASE(kw_group) - CASE(kw_hidden) - CASE(kw_input) - CASE(kw_keep) - CASE(kw_length) - CASE(kw_memory) - CASE(kw_origin) - CASE(kw_phdrs) - CASE(kw_provide) - CASE(kw_provide_hidden) - CASE(kw_only_if_ro) - CASE(kw_only_if_rw) - CASE(kw_output) - CASE(kw_output_arch) - CASE(kw_output_format) - CASE(kw_overlay) - CASE(kw_search_dir) - CASE(kw_sections) - CASE(kw_sort_by_alignment) - CASE(kw_sort_by_init_priority) - CASE(kw_sort_by_name) - CASE(kw_sort_none) - CASE(kw_subalign) - CASE(l_brace) - CASE(pipe) - CASE(pipeequal) - CASE(r_brace) - CASE(tilde) -#undef CASE - } - os << _range << "\n"; -} - -static llvm::ErrorOr<uint64_t> parseDecimal(StringRef str) { - uint64_t res = 0; - for (auto &c : str) { - res *= 10; - if (c < '0' || c > '9') - return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error)); - res += c - '0'; - } - return res; -} - -static llvm::ErrorOr<uint64_t> parseOctal(StringRef str) { - uint64_t res = 0; - for (auto &c : str) { - res <<= 3; - if (c < '0' || c > '7') - return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error)); - res += c - '0'; - } - return res; -} - -static llvm::ErrorOr<uint64_t> parseBinary(StringRef str) { - uint64_t res = 0; - for (auto &c : str) { - res <<= 1; - if (c != '0' && c != '1') - return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error)); - res += c - '0'; - } - return res; -} - -static llvm::ErrorOr<uint64_t> parseHex(StringRef str) { - uint64_t res = 0; - for (auto &c : str) { - res <<= 4; - if (c >= '0' && c <= '9') - res += c - '0'; - else if (c >= 'a' && c <= 'f') - res += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - res += c - 'A' + 10; - else - return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error)); - } - return res; -} - -static bool parseHexToByteStream(StringRef str, std::string &buf) { - unsigned char byte = 0; - bool dumpByte = str.size() % 2; - for (auto &c : str) { - byte <<= 4; - if (c >= '0' && c <= '9') - byte += c - '0'; - else if (c >= 'a' && c <= 'f') - byte += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - byte += c - 'A' + 10; - else - return false; - if (!dumpByte) { - dumpByte = true; - continue; - } - buf.push_back(byte); - byte = 0; - dumpByte = false; - } - return !dumpByte; -} - -static void dumpByteStream(raw_ostream &os, StringRef stream) { - os << "0x"; - for (auto &c : stream) { - unsigned char firstNibble = c >> 4 & 0xF; - if (firstNibble > 9) - os << (char) ('A' + firstNibble - 10); - else - os << (char) ('0' + firstNibble); - unsigned char secondNibble = c & 0xF; - if (secondNibble > 9) - os << (char) ('A' + secondNibble - 10); - else - os << (char) ('0' + secondNibble); - } -} - -static llvm::ErrorOr<uint64_t> parseNum(StringRef str) { - unsigned multiplier = 1; - enum NumKind { decimal, hex, octal, binary }; - NumKind kind = llvm::StringSwitch<NumKind>(str) - .StartsWith("0x", hex) - .StartsWith("0X", hex) - .StartsWith("0", octal) - .Default(decimal); - - // Parse scale - if (str.endswith("K")) { - multiplier = 1 << 10; - str = str.drop_back(); - } else if (str.endswith("M")) { - multiplier = 1 << 20; - str = str.drop_back(); - } - - // Parse type - if (str.endswith_lower("o")) { - kind = octal; - str = str.drop_back(); - } else if (str.endswith_lower("h")) { - kind = hex; - str = str.drop_back(); - } else if (str.endswith_lower("d")) { - kind = decimal; - str = str.drop_back(); - } else if (str.endswith_lower("b")) { - kind = binary; - str = str.drop_back(); - } - - llvm::ErrorOr<uint64_t> res(0); - switch (kind) { - case hex: - if (str.startswith_lower("0x")) - str = str.drop_front(2); - res = parseHex(str); - break; - case octal: - res = parseOctal(str); - break; - case decimal: - res = parseDecimal(str); - break; - case binary: - res = parseBinary(str); - break; - } - if (res.getError()) - return res; - - *res = *res * multiplier; - return res; -} - -bool Lexer::canStartNumber(char c) const { - return '0' <= c && c <= '9'; -} - -bool Lexer::canContinueNumber(char c) const { - // [xX] = hex marker, [hHoO] = type suffix, [MK] = scale suffix. - return strchr("0123456789ABCDEFabcdefxXhHoOMK", c); -} - -bool Lexer::canStartName(char c) const { - return strchr( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.$/\\*", c); -} - -bool Lexer::canContinueName(char c) const { - return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789_.$/\\~=+[]*?-:", c); -} - -/// Helper function to split a StringRef in two at the nth character. -/// The StringRef s is updated, while the function returns the n first -/// characters. -static StringRef drop(StringRef &s, int n) { - StringRef res = s.substr(0, n); - s = s.drop_front(n); - return res; -} - -void Lexer::lex(Token &tok) { - skipWhitespace(); - if (_buffer.empty()) { - tok = Token(_buffer, Token::eof); - return; - } - switch (_buffer[0]) { - case 0: - tok = Token(drop(_buffer, 1), Token::eof); - return; - case '(': - tok = Token(drop(_buffer, 1), Token::l_paren); - return; - case ')': - tok = Token(drop(_buffer, 1), Token::r_paren); - return; - case '{': - tok = Token(drop(_buffer, 1), Token::l_brace); - return; - case '}': - tok = Token(drop(_buffer, 1), Token::r_brace); - return; - case '=': - if (_buffer.startswith("==")) { - tok = Token(drop(_buffer, 2), Token::equalequal); - return; - } - tok = Token(drop(_buffer, 1), Token::equal); - return; - case '!': - if (_buffer.startswith("!=")) { - tok = Token(drop(_buffer, 2), Token::exclaimequal); - return; - } - tok = Token(drop(_buffer, 1), Token::exclaim); - return; - case ',': - tok = Token(drop(_buffer, 1), Token::comma); - return; - case ';': - tok = Token(drop(_buffer, 1), Token::semicolon); - return; - case ':': - tok = Token(drop(_buffer, 1), Token::colon); - return; - case '&': - if (_buffer.startswith("&=")) { - tok = Token(drop(_buffer, 2), Token::ampequal); - return; - } - tok = Token(drop(_buffer, 1), Token::amp); - return; - case '|': - if (_buffer.startswith("|=")) { - tok = Token(drop(_buffer, 2), Token::pipeequal); - return; - } - tok = Token(drop(_buffer, 1), Token::pipe); - return; - case '+': - if (_buffer.startswith("+=")) { - tok = Token(drop(_buffer, 2), Token::plusequal); - return; - } - tok = Token(drop(_buffer, 1), Token::plus); - return; - case '-': { - if (_buffer.startswith("-=")) { - tok = Token(drop(_buffer, 2), Token::minusequal); - return; - } - if (!_buffer.startswith("-l")) { - tok = Token(drop(_buffer, 1), Token::minus); - return; - } - // -l<lib name> - _buffer = _buffer.drop_front(2); - StringRef::size_type start = 0; - if (_buffer[start] == ':') - ++start; - if (!canStartName(_buffer[start])) - // Create 'unknown' token. - break; - auto libNameEnd = std::find_if(_buffer.begin() + start + 1, _buffer.end(), - [=](char c) { return !canContinueName(c); }); - StringRef::size_type libNameLen = - std::distance(_buffer.begin(), libNameEnd); - tok = Token(_buffer.substr(0, libNameLen), Token::libname); - _buffer = _buffer.drop_front(libNameLen); - return; - } - case '<': - if (_buffer.startswith("<<=")) { - tok = Token(drop(_buffer, 3), Token::lesslessequal); - return; - } - if (_buffer.startswith("<<")) { - tok = Token(drop(_buffer, 2), Token::lessless); - return; - } - if (_buffer.startswith("<=")) { - tok = Token(drop(_buffer, 2), Token::lessequal); - return; - } - tok = Token(drop(_buffer, 1), Token::less); - return; - case '>': - if (_buffer.startswith(">>=")) { - tok = Token(drop(_buffer, 3), Token::greatergreaterequal); - return; - } - if (_buffer.startswith(">>")) { - tok = Token(drop(_buffer, 2), Token::greatergreater); - return; - } - if (_buffer.startswith(">=")) { - tok = Token(drop(_buffer, 2), Token::greaterequal); - return; - } - tok = Token(drop(_buffer, 1), Token::greater); - return; - case '~': - tok = Token(drop(_buffer, 1), Token::tilde); - return; - case '\"': case '\'': { - // Handle quoted strings. They are treated as identifiers for - // simplicity. - char c = _buffer[0]; - _buffer = _buffer.drop_front(); - auto quotedStringEnd = _buffer.find(c); - if (quotedStringEnd == StringRef::npos || quotedStringEnd == 0) - break; - StringRef word = _buffer.substr(0, quotedStringEnd); - tok = Token(word, Token::identifier); - _buffer = _buffer.drop_front(quotedStringEnd + 1); - return; - } - default: - // Handle literal numbers - if (canStartNumber(_buffer[0])) { - auto endIter = std::find_if(_buffer.begin(), _buffer.end(), [=](char c) { - return !canContinueNumber(c); - }); - StringRef::size_type end = endIter == _buffer.end() - ? StringRef::npos - : std::distance(_buffer.begin(), endIter); - if (end == StringRef::npos || end == 0) - break; - StringRef word = _buffer.substr(0, end); - tok = Token(word, Token::number); - _buffer = _buffer.drop_front(end); - return; - } - // Handle slashes '/', which can be either an operator inside an expression - // or the beginning of an identifier - if (_buffer.startswith("/=")) { - tok = Token(drop(_buffer, 2), Token::slashequal); - return; - } - if (_buffer[0] == '/' && _buffer.size() > 1 && - !canContinueName(_buffer[1])) { - tok = Token(drop(_buffer, 1), Token::slash); - return; - } - // Handle stars '*' - if (_buffer.startswith("*=")) { - tok = Token(drop(_buffer, 2), Token::starequal); - return; - } - if (_buffer[0] == '*' && _buffer.size() > 1 && - !canContinueName(_buffer[1])) { - tok = Token(drop(_buffer, 1), Token::star); - return; - } - // Handle questions '?' - if (_buffer[0] == '?' && _buffer.size() > 1 && - !canContinueName(_buffer[1])) { - tok = Token(drop(_buffer, 1), Token::question); - return; - } - // keyword or identifier. - if (!canStartName(_buffer[0])) - break; - auto endIter = std::find_if(_buffer.begin() + 1, _buffer.end(), - [=](char c) { return !canContinueName(c); }); - StringRef::size_type end = endIter == _buffer.end() - ? StringRef::npos - : std::distance(_buffer.begin(), endIter); - if (end == StringRef::npos || end == 0) - break; - StringRef word = _buffer.substr(0, end); - Token::Kind kind = - llvm::StringSwitch<Token::Kind>(word) - .Case("ALIGN", Token::kw_align) - .Case("ALIGN_WITH_INPUT", Token::kw_align_with_input) - .Case("AS_NEEDED", Token::kw_as_needed) - .Case("AT", Token::kw_at) - .Case("ENTRY", Token::kw_entry) - .Case("EXCLUDE_FILE", Token::kw_exclude_file) - .Case("EXTERN", Token::kw_extern) - .Case("FILEHDR", Token::kw_filehdr) - .Case("FILL", Token::kw_fill) - .Case("FLAGS", Token::kw_flags) - .Case("GROUP", Token::kw_group) - .Case("HIDDEN", Token::kw_hidden) - .Case("INPUT", Token::kw_input) - .Case("KEEP", Token::kw_keep) - .Case("LENGTH", Token::kw_length) - .Case("l", Token::kw_length) - .Case("len", Token::kw_length) - .Case("MEMORY", Token::kw_memory) - .Case("ONLY_IF_RO", Token::kw_only_if_ro) - .Case("ONLY_IF_RW", Token::kw_only_if_rw) - .Case("ORIGIN", Token::kw_origin) - .Case("o", Token::kw_origin) - .Case("org", Token::kw_origin) - .Case("OUTPUT", Token::kw_output) - .Case("OUTPUT_ARCH", Token::kw_output_arch) - .Case("OUTPUT_FORMAT", Token::kw_output_format) - .Case("OVERLAY", Token::kw_overlay) - .Case("PHDRS", Token::kw_phdrs) - .Case("PROVIDE", Token::kw_provide) - .Case("PROVIDE_HIDDEN", Token::kw_provide_hidden) - .Case("SEARCH_DIR", Token::kw_search_dir) - .Case("SECTIONS", Token::kw_sections) - .Case("SORT", Token::kw_sort_by_name) - .Case("SORT_BY_ALIGNMENT", Token::kw_sort_by_alignment) - .Case("SORT_BY_INIT_PRIORITY", Token::kw_sort_by_init_priority) - .Case("SORT_BY_NAME", Token::kw_sort_by_name) - .Case("SORT_NONE", Token::kw_sort_none) - .Case("SUBALIGN", Token::kw_subalign) - .Case("/DISCARD/", Token::kw_discard) - .Default(Token::identifier); - tok = Token(word, kind); - _buffer = _buffer.drop_front(end); - return; - } - tok = Token(drop(_buffer, 1), Token::unknown); -} - -void Lexer::skipWhitespace() { - while (true) { - if (_buffer.empty()) - return; - switch (_buffer[0]) { - case ' ': - case '\r': - case '\n': - case '\t': - _buffer = _buffer.drop_front(); - break; - // Potential comment. - case '/': - if (_buffer.size() <= 1 || _buffer[1] != '*') - return; - // Skip starting /* - _buffer = _buffer.drop_front(2); - // If the next char is also a /, it's not the end. - if (!_buffer.empty() && _buffer[0] == '/') - _buffer = _buffer.drop_front(); - - // Scan for /'s. We're done if it is preceded by a *. - while (true) { - if (_buffer.empty()) - break; - _buffer = _buffer.drop_front(); - if (_buffer.data()[-1] == '/' && _buffer.data()[-2] == '*') - break; - } - break; - default: - return; - } - } -} - -// Constant functions -void Constant::dump(raw_ostream &os) const { os << _num; } - -ErrorOr<int64_t> Constant::evalExpr(const SymbolTableTy &symbolTable) const { - return _num; -} - -// Symbol functions -void Symbol::dump(raw_ostream &os) const { os << _name; } - -ErrorOr<int64_t> Symbol::evalExpr(const SymbolTableTy &symbolTable) const { - auto it = symbolTable.find(_name); - if (it == symbolTable.end()) - return LinkerScriptReaderError::unknown_symbol_in_expr; - return it->second; -} - -// FunctionCall functions -void FunctionCall::dump(raw_ostream &os) const { - os << _name << "("; - for (unsigned i = 0, e = _args.size(); i != e; ++i) { - if (i) - os << ", "; - _args[i]->dump(os); - } - os << ")"; -} - -ErrorOr<int64_t> -FunctionCall::evalExpr(const SymbolTableTy &symbolTable) const { - return LinkerScriptReaderError::unrecognized_function_in_expr; -} - -// Unary functions -void Unary::dump(raw_ostream &os) const { - os << "("; - if (_op == Unary::Minus) - os << "-"; - else - os << "~"; - _child->dump(os); - os << ")"; -} - -ErrorOr<int64_t> Unary::evalExpr(const SymbolTableTy &symbolTable) const { - auto child = _child->evalExpr(symbolTable); - if (child.getError()) - return child.getError(); - - int64_t childRes = *child; - switch (_op) { - case Unary::Minus: - return -childRes; - case Unary::Not: - return ~childRes; - } - - llvm_unreachable(""); -} - -// BinOp functions -void BinOp::dump(raw_ostream &os) const { - os << "("; - _lhs->dump(os); - os << " "; - switch (_op) { - case Sum: - os << "+"; - break; - case Sub: - os << "-"; - break; - case Mul: - os << "*"; - break; - case Div: - os << "/"; - break; - case Shl: - os << "<<"; - break; - case Shr: - os << ">>"; - break; - case And: - os << "&"; - break; - case Or: - os << "|"; - break; - case CompareEqual: - os << "=="; - break; - case CompareDifferent: - os << "!="; - break; - case CompareLess: - os << "<"; - break; - case CompareGreater: - os << ">"; - break; - case CompareLessEqual: - os << "<="; - break; - case CompareGreaterEqual: - os << ">="; - break; - } - os << " "; - _rhs->dump(os); - os << ")"; -} - -ErrorOr<int64_t> BinOp::evalExpr(const SymbolTableTy &symbolTable) const { - auto lhs = _lhs->evalExpr(symbolTable); - if (lhs.getError()) - return lhs.getError(); - auto rhs = _rhs->evalExpr(symbolTable); - if (rhs.getError()) - return rhs.getError(); - - int64_t lhsRes = *lhs; - int64_t rhsRes = *rhs; - - switch(_op) { - case And: return lhsRes & rhsRes; - case CompareDifferent: return lhsRes != rhsRes; - case CompareEqual: return lhsRes == rhsRes; - case CompareGreater: return lhsRes > rhsRes; - case CompareGreaterEqual: return lhsRes >= rhsRes; - case CompareLess: return lhsRes < rhsRes; - case CompareLessEqual: return lhsRes <= rhsRes; - case Div: return lhsRes / rhsRes; - case Mul: return lhsRes * rhsRes; - case Or: return lhsRes | rhsRes; - case Shl: return lhsRes << rhsRes; - case Shr: return lhsRes >> rhsRes; - case Sub: return lhsRes - rhsRes; - case Sum: return lhsRes + rhsRes; - } - - llvm_unreachable(""); -} - -// TernaryConditional functions -void TernaryConditional::dump(raw_ostream &os) const { - _conditional->dump(os); - os << " ? "; - _trueExpr->dump(os); - os << " : "; - _falseExpr->dump(os); -} - -ErrorOr<int64_t> -TernaryConditional::evalExpr(const SymbolTableTy &symbolTable) const { - auto conditional = _conditional->evalExpr(symbolTable); - if (conditional.getError()) - return conditional.getError(); - if (*conditional) - return _trueExpr->evalExpr(symbolTable); - return _falseExpr->evalExpr(symbolTable); -} - -// SymbolAssignment functions -void SymbolAssignment::dump(raw_ostream &os) const { - int numParen = 0; - - if (_assignmentVisibility != Default) { - switch (_assignmentVisibility) { - case Hidden: - os << "HIDDEN("; - break; - case Provide: - os << "PROVIDE("; - break; - case ProvideHidden: - os << "PROVIDE_HIDDEN("; - break; - default: - llvm_unreachable("Unknown visibility"); - } - ++numParen; - } - - os << _symbol << " "; - switch (_assignmentKind) { - case Simple: - os << "="; - break; - case Sum: - os << "+="; - break; - case Sub: - os << "-="; - break; - case Mul: - os << "*="; - break; - case Div: - os << "/="; - break; - case Shl: - os << "<<="; - break; - case Shr: - os << ">>="; - break; - case And: - os << "&="; - break; - case Or: - os << "|="; - break; - } - - os << " "; - _expression->dump(os); - if (numParen) - os << ")"; - os << ";"; -} - -static int dumpSortDirectives(raw_ostream &os, WildcardSortMode sortMode) { - switch (sortMode) { - case WildcardSortMode::NA: - return 0; - case WildcardSortMode::ByName: - os << "SORT_BY_NAME("; - return 1; - case WildcardSortMode::ByAlignment: - os << "SORT_BY_ALIGNMENT("; - return 1; - case WildcardSortMode::ByInitPriority: - os << "SORT_BY_INIT_PRIORITY("; - return 1; - case WildcardSortMode::ByNameAndAlignment: - os << "SORT_BY_NAME(SORT_BY_ALIGNMENT("; - return 2; - case WildcardSortMode::ByAlignmentAndName: - os << "SORT_BY_ALIGNMENT(SORT_BY_NAME("; - return 2; - case WildcardSortMode::None: - os << "SORT_NONE("; - return 1; - } - return 0; -} - -// InputSectionName functions -void InputSectionName::dump(raw_ostream &os) const { - os << _name; -} - -// InputSectionSortedGroup functions -static void dumpInputSections(raw_ostream &os, - llvm::ArrayRef<const InputSection *> secs) { - bool excludeFile = false; - bool first = true; - - for (auto &secName : secs) { - if (!first) - os << " "; - first = false; - // Coalesce multiple input sections marked with EXCLUDE_FILE in the same - // EXCLUDE_FILE() group - if (auto inputSec = dyn_cast<InputSectionName>(secName)) { - if (!excludeFile && inputSec->hasExcludeFile()) { - excludeFile = true; - os << "EXCLUDE_FILE("; - } else if (excludeFile && !inputSec->hasExcludeFile()) { - excludeFile = false; - os << ") "; - } - } - secName->dump(os); - } - - if (excludeFile) - os << ")"; -} - -void InputSectionSortedGroup::dump(raw_ostream &os) const { - int numParen = dumpSortDirectives(os, _sortMode); - dumpInputSections(os, _sections); - for (int i = 0; i < numParen; ++i) - os << ")"; -} - -// InputSectionsCmd functions -void InputSectionsCmd::dump(raw_ostream &os) const { - if (_keep) - os << "KEEP("; - - int numParen = dumpSortDirectives(os, _fileSortMode); - os << _memberName; - for (int i = 0; i < numParen; ++i) - os << ")"; - - if (_archiveName.size() > 0) { - os << ":"; - numParen = dumpSortDirectives(os, _archiveSortMode); - os << _archiveName; - for (int i = 0; i < numParen; ++i) - os << ")"; - } - - if (_sections.size() > 0) { - os << "("; - dumpInputSections(os, _sections); - os << ")"; - } - - if (_keep) - os << ")"; -} - -void FillCmd::dump(raw_ostream &os) const { - os << "FILL("; - dumpByteStream(os, StringRef((const char *)_bytes.begin(), _bytes.size())); - os << ")"; -} - -// OutputSectionDescription functions -void OutputSectionDescription::dump(raw_ostream &os) const { - if (_discard) - os << "/DISCARD/"; - else - os << _sectionName; - - if (_address) { - os << " "; - _address->dump(os); - } - os << " :\n"; - - if (_at) { - os << " AT("; - _at->dump(os); - os << ")\n"; - } - - if (_align) { - os << " ALIGN("; - _align->dump(os); - os << ")\n"; - } else if (_alignWithInput) { - os << " ALIGN_WITH_INPUT\n"; - } - - if (_subAlign) { - os << " SUBALIGN("; - _subAlign->dump(os); - os << ")\n"; - } - - switch (_constraint) { - case C_None: - break; - case C_OnlyIfRO: - os << "ONLY_IF_RO"; - break; - case C_OnlyIfRW: - os << "ONLY_IF_RW"; - break; - } - - os << " {\n"; - for (auto &command : _outputSectionCommands) { - os << " "; - command->dump(os); - os << "\n"; - } - os << " }"; - - for (auto && phdr : _phdrs) - os << " : " << phdr; - - if (_fillStream.size() > 0) { - os << " ="; - dumpByteStream(os, _fillStream); - } else if (_fillExpr) { - os << " ="; - _fillExpr->dump(os); - } -} - -// Special header that discards output sections assigned to it. -static const PHDR PHDR_NONE("NONE", 0, false, false, nullptr, 0); - -bool PHDR::isNone() const { - return this == &PHDR_NONE; -} - -void PHDR::dump(raw_ostream &os) const { - os << _name << " " << _type; - if (_includeFileHdr) - os << " FILEHDR"; - if (_includePHDRs) - os << " PHDRS"; - if (_at) { - os << " AT ("; - _at->dump(os); - os << ")"; - } - if (_flags) - os << " FLAGS (" << _flags << ")"; - os << ";\n"; -} - -void PHDRS::dump(raw_ostream &os) const { - os << "PHDRS\n{\n"; - for (auto &&phdr : _phdrs) { - phdr->dump(os); - } - os << "}\n"; -} - -// Sections functions -void Sections::dump(raw_ostream &os) const { - os << "SECTIONS\n{\n"; - for (auto &command : _sectionsCommands) { - command->dump(os); - os << "\n"; - } - os << "}\n"; -} - -// Memory functions -void MemoryBlock::dump(raw_ostream &os) const { - os << _name; - - if (!_attr.empty()) - os << " (" << _attr << ")"; - - os << " : "; - - os << "ORIGIN = "; - _origin->dump(os); - os << ", "; - - os << "LENGTH = "; - _length->dump(os); -} - -void Memory::dump(raw_ostream &os) const { - os << "MEMORY\n{\n"; - for (auto &block : _blocks) { - block->dump(os); - os << "\n"; - } - os << "}\n"; -} - -// Extern functions -void Extern::dump(raw_ostream &os) const { - os << "EXTERN("; - for (unsigned i = 0, e = _symbols.size(); i != e; ++i) { - if (i) - os << " "; - os << _symbols[i]; - } - os << ")\n"; -} - -// Parser functions -std::error_code Parser::parse() { - // Get the first token. - _lex.lex(_tok); - // Parse top level commands. - while (true) { - switch (_tok._kind) { - case Token::eof: - return std::error_code(); - case Token::semicolon: - consumeToken(); - break; - case Token::kw_output: { - auto output = parseOutput(); - if (!output) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(output); - break; - } - case Token::kw_output_format: { - auto outputFormat = parseOutputFormat(); - if (!outputFormat) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(outputFormat); - break; - } - case Token::kw_output_arch: { - auto outputArch = parseOutputArch(); - if (!outputArch) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(outputArch); - break; - } - case Token::kw_input: { - Input *input = parsePathList<Input>(); - if (!input) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(input); - break; - } - case Token::kw_group: { - Group *group = parsePathList<Group>(); - if (!group) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(group); - break; - } - case Token::kw_as_needed: - // Not allowed at top level. - error(_tok, "AS_NEEDED not allowed at top level."); - return LinkerScriptReaderError::parse_error; - case Token::kw_entry: { - Entry *entry = parseEntry(); - if (!entry) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(entry); - break; - } - case Token::kw_phdrs: { - PHDRS *phdrs = parsePHDRS(); - if (!phdrs) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(phdrs); - break; - } - case Token::kw_search_dir: { - SearchDir *searchDir = parseSearchDir(); - if (!searchDir) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(searchDir); - break; - } - case Token::kw_sections: { - Sections *sections = parseSections(); - if (!sections) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(sections); - break; - } - case Token::identifier: - case Token::kw_hidden: - case Token::kw_provide: - case Token::kw_provide_hidden: { - const Command *cmd = parseSymbolAssignment(); - if (!cmd) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(cmd); - break; - } - case Token::kw_memory: { - const Command *cmd = parseMemory(); - if (!cmd) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(cmd); - break; - } - case Token::kw_extern: { - const Command *cmd = parseExtern(); - if (!cmd) - return LinkerScriptReaderError::parse_error; - _script._commands.push_back(cmd); - break; - } - default: - // Unexpected. - error(_tok, "expected linker script command"); - return LinkerScriptReaderError::parse_error; - } - } - return LinkerScriptReaderError::parse_error; -} - -const Expression *Parser::parseFunctionCall() { - assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_align) && - "expected function call first tokens"); - SmallVector<const Expression *, 8> params; - StringRef name = _tok._range; - - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - if (_tok._kind == Token::r_paren) { - consumeToken(); - return new (_alloc) FunctionCall(*this, _tok._range, params); - } - - if (const Expression *firstParam = parseExpression()) - params.push_back(firstParam); - else - return nullptr; - - while (_tok._kind == Token::comma) { - consumeToken(); - if (const Expression *param = parseExpression()) - params.push_back(param); - else - return nullptr; - } - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) FunctionCall(*this, name, params); -} - -bool Parser::expectExprOperand() { - if (!(_tok._kind == Token::identifier || _tok._kind == Token::number || - _tok._kind == Token::kw_align || _tok._kind == Token::l_paren || - _tok._kind == Token::minus || _tok._kind == Token::tilde)) { - error(_tok, "expected symbol, number, minus, tilde or left parenthesis."); - return false; - } - return true; -} - -const Expression *Parser::parseExprOperand() { - if (!expectExprOperand()) - return nullptr; - - switch (_tok._kind) { - case Token::identifier: { - if (peek()._kind== Token::l_paren) - return parseFunctionCall(); - auto *sym = new (_alloc) Symbol(*this, _tok._range); - consumeToken(); - return sym; - } - case Token::kw_align: - return parseFunctionCall(); - case Token::minus: - consumeToken(); - return new (_alloc) Unary(*this, Unary::Minus, parseExprOperand()); - case Token::tilde: - consumeToken(); - return new (_alloc) Unary(*this, Unary::Not, parseExprOperand()); - case Token::number: { - auto val = parseNum(_tok._range); - if (val.getError()) { - error(_tok, "Unrecognized number constant"); - return nullptr; - } - auto *c = new (_alloc) Constant(*this, *val); - consumeToken(); - return c; - } - case Token::l_paren: { - consumeToken(); - const Expression *expr = parseExpression(); - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return expr; - } - default: - llvm_unreachable("Unknown token"); - } -} - -static bool TokenToBinOp(const Token &tok, BinOp::Operation &op, - unsigned &precedence) { - switch (tok._kind) { - case Token::star: - op = BinOp::Mul; - precedence = 3; - return true; - case Token::slash: - op = BinOp::Div; - precedence = 3; - return true; - case Token::plus: - op = BinOp::Sum; - precedence = 4; - return true; - case Token::minus: - op = BinOp::Sub; - precedence = 4; - return true; - case Token::lessless: - op = BinOp::Shl; - precedence = 5; - return true; - case Token::greatergreater: - op = BinOp::Shr; - precedence = 5; - return true; - case Token::less: - op = BinOp::CompareLess; - precedence = 6; - return true; - case Token::greater: - op = BinOp::CompareGreater; - precedence = 6; - return true; - case Token::lessequal: - op = BinOp::CompareLessEqual; - precedence = 6; - return true; - case Token::greaterequal: - op = BinOp::CompareGreaterEqual; - precedence = 6; - return true; - case Token::equalequal: - op = BinOp::CompareEqual; - precedence = 7; - return true; - case Token::exclaimequal: - op = BinOp::CompareDifferent; - precedence = 7; - return true; - case Token::amp: - op = BinOp::And; - precedence = 8; - return true; - case Token::pipe: - op = BinOp::Or; - precedence = 10; - return true; - default: - break; - } - return false; -} - -static bool isExpressionOperator(Token tok) { - switch (tok._kind) { - case Token::star: - case Token::slash: - case Token::plus: - case Token::minus: - case Token::lessless: - case Token::greatergreater: - case Token::less: - case Token::greater: - case Token::lessequal: - case Token::greaterequal: - case Token::equalequal: - case Token::exclaimequal: - case Token::amp: - case Token::pipe: - case Token::question: - return true; - default: - return false; - } -} - -const Expression *Parser::parseExpression(unsigned precedence) { - assert(precedence <= 13 && "Invalid precedence value"); - if (!expectExprOperand()) - return nullptr; - - const Expression *expr = parseExprOperand(); - if (!expr) - return nullptr; - - BinOp::Operation op; - unsigned binOpPrecedence = 0; - if (TokenToBinOp(_tok, op, binOpPrecedence)) { - if (precedence >= binOpPrecedence) - return parseOperatorOperandLoop(expr, precedence); - return expr; - } - - // Non-binary operators - if (_tok._kind == Token::question && precedence >= 13) - return parseOperatorOperandLoop(expr, precedence); - return expr; -} - -const Expression *Parser::parseOperatorOperandLoop(const Expression *lhs, - unsigned highestPrecedence) { - assert(highestPrecedence <= 13 && "Invalid precedence value"); - unsigned precedence = 0; - const Expression *binOp = nullptr; - - while (1) { - BinOp::Operation op; - if (!TokenToBinOp(_tok, op, precedence)) { - if (_tok._kind == Token::question && highestPrecedence >= 13) - return parseTernaryCondOp(lhs); - return binOp; - } - - if (precedence > highestPrecedence) - return binOp; - - consumeToken(); - const Expression *rhs = parseExpression(precedence - 1); - if (!rhs) - return nullptr; - binOp = new (_alloc) BinOp(*this, lhs, op, rhs); - lhs = binOp; - } -} - -const Expression *Parser::parseTernaryCondOp(const Expression *lhs) { - assert(_tok._kind == Token::question && "Expected question mark"); - - consumeToken(); - - // The ternary conditional operator has right-to-left associativity. - // To implement this, we allow our children to contain ternary conditional - // operators themselves (precedence 13). - const Expression *trueExpr = parseExpression(13); - if (!trueExpr) - return nullptr; - - if (!expectAndConsume(Token::colon, "expected :")) - return nullptr; - - const Expression *falseExpr = parseExpression(13); - if (!falseExpr) - return nullptr; - - return new (_alloc) TernaryConditional(*this, lhs, trueExpr, falseExpr); -} - -// Parse OUTPUT(ident) -Output *Parser::parseOutput() { - assert(_tok._kind == Token::kw_output && "Expected OUTPUT"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - if (_tok._kind != Token::identifier) { - error(_tok, "Expected identifier in OUTPUT."); - return nullptr; - } - - auto ret = new (_alloc) Output(*this, _tok._range); - consumeToken(); - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return ret; -} - -// Parse OUTPUT_FORMAT(ident) -OutputFormat *Parser::parseOutputFormat() { - assert(_tok._kind == Token::kw_output_format && "Expected OUTPUT_FORMAT!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - if (_tok._kind != Token::identifier) { - error(_tok, "Expected identifier in OUTPUT_FORMAT."); - return nullptr; - } - - SmallVector<StringRef, 8> formats; - formats.push_back(_tok._range); - - consumeToken(); - - do { - if (isNextToken(Token::comma)) - consumeToken(); - else - break; - if (_tok._kind != Token::identifier) { - error(_tok, "Expected identifier in OUTPUT_FORMAT."); - return nullptr; - } - formats.push_back(_tok._range); - consumeToken(); - } while (isNextToken(Token::comma)); - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return new (_alloc) OutputFormat(*this, formats); -} - -// Parse OUTPUT_ARCH(ident) -OutputArch *Parser::parseOutputArch() { - assert(_tok._kind == Token::kw_output_arch && "Expected OUTPUT_ARCH!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - if (_tok._kind != Token::identifier) { - error(_tok, "Expected identifier in OUTPUT_ARCH."); - return nullptr; - } - - auto ret = new (_alloc) OutputArch(*this, _tok._range); - consumeToken(); - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return ret; -} - -// Parse file list for INPUT or GROUP -template<class T> T *Parser::parsePathList() { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - SmallVector<Path, 8> paths; - while (_tok._kind == Token::identifier || _tok._kind == Token::libname || - _tok._kind == Token::kw_as_needed) { - switch (_tok._kind) { - case Token::identifier: - paths.push_back(Path(_tok._range)); - consumeToken(); - break; - case Token::libname: - paths.push_back(Path(_tok._range, false, true)); - consumeToken(); - break; - case Token::kw_as_needed: - if (!parseAsNeeded(paths)) - return nullptr; - break; - default: - llvm_unreachable("Invalid token."); - } - } - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) T(*this, paths); -} - -// Parse AS_NEEDED(file ...) -bool Parser::parseAsNeeded(SmallVectorImpl<Path> &paths) { - assert(_tok._kind == Token::kw_as_needed && "Expected AS_NEEDED!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return false; - - while (_tok._kind == Token::identifier || _tok._kind == Token::libname) { - switch (_tok._kind) { - case Token::identifier: - paths.push_back(Path(_tok._range, true, false)); - consumeToken(); - break; - case Token::libname: - paths.push_back(Path(_tok._range, true, true)); - consumeToken(); - break; - default: - llvm_unreachable("Invalid token."); - } - } - - if (!expectAndConsume(Token::r_paren, "expected )")) - return false; - return true; -} - -// Parse ENTRY(ident) -Entry *Parser::parseEntry() { - assert(_tok._kind == Token::kw_entry && "Expected ENTRY!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - if (_tok._kind != Token::identifier) { - error(_tok, "expected identifier in ENTRY"); - return nullptr; - } - StringRef entryName(_tok._range); - consumeToken(); - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) Entry(*this, entryName); -} - -// Parse SEARCH_DIR(ident) -SearchDir *Parser::parseSearchDir() { - assert(_tok._kind == Token::kw_search_dir && "Expected SEARCH_DIR!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - if (_tok._kind != Token::identifier) { - error(_tok, "expected identifier in SEARCH_DIR"); - return nullptr; - } - StringRef searchPath(_tok._range); - consumeToken(); - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) SearchDir(*this, searchPath); -} - -const SymbolAssignment *Parser::parseSymbolAssignment() { - assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_hidden || - _tok._kind == Token::kw_provide || - _tok._kind == Token::kw_provide_hidden) && - "Expected identifier!"); - SymbolAssignment::AssignmentVisibility visibility = SymbolAssignment::Default; - SymbolAssignment::AssignmentKind kind; - int numParen = 0; - - switch (_tok._kind) { - case Token::kw_hidden: - visibility = SymbolAssignment::Hidden; - ++numParen; - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - break; - case Token::kw_provide: - visibility = SymbolAssignment::Provide; - ++numParen; - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - break; - case Token::kw_provide_hidden: - visibility = SymbolAssignment::ProvideHidden; - ++numParen; - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - break; - default: - break; - } - - StringRef name = _tok._range; - consumeToken(); - - // Parse assignment operator (=, +=, -= etc.) - switch (_tok._kind) { - case Token::equal: - kind = SymbolAssignment::Simple; - break; - case Token::plusequal: - kind = SymbolAssignment::Sum; - break; - case Token::minusequal: - kind = SymbolAssignment::Sub; - break; - case Token::starequal: - kind = SymbolAssignment::Mul; - break; - case Token::slashequal: - kind = SymbolAssignment::Div; - break; - case Token::ampequal: - kind = SymbolAssignment::And; - break; - case Token::pipeequal: - kind = SymbolAssignment::Or; - break; - case Token::lesslessequal: - kind = SymbolAssignment::Shl; - break; - case Token::greatergreaterequal: - kind = SymbolAssignment::Shr; - break; - default: - error(_tok, "unexpected token"); - return nullptr; - } - - consumeToken(); - - const Expression *expr = nullptr; - switch (_tok._kind) { - case Token::number: - case Token::kw_align: - case Token::identifier: - case Token::l_paren: - expr = parseExpression(); - if (!expr) - return nullptr; - break; - default: - error(_tok, "unexpected token while parsing assignment value."); - return nullptr; - } - - for (int i = 0; i < numParen; ++i) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return new (_alloc) SymbolAssignment(*this, name, expr, kind, visibility); -} - -llvm::ErrorOr<InputSectionsCmd::VectorTy> Parser::parseExcludeFile() { - assert(_tok._kind == Token::kw_exclude_file && "Expected EXCLUDE_FILE!"); - InputSectionsCmd::VectorTy res; - consumeToken(); - - if (!expectAndConsume(Token::l_paren, "expected (")) - return llvm::ErrorOr<InputSectionsCmd::VectorTy>( - make_error_code(llvm::errc::io_error)); - - while (_tok._kind == Token::identifier) { - res.push_back(new (_alloc) InputSectionName(*this, _tok._range, true)); - consumeToken(); - } - - if (!expectAndConsume(Token::r_paren, "expected )")) - return llvm::ErrorOr<InputSectionsCmd::VectorTy>( - make_error_code(llvm::errc::io_error)); - return llvm::ErrorOr<InputSectionsCmd::VectorTy>(std::move(res)); -} - -int Parser::parseSortDirectives(WildcardSortMode &sortMode) { - int numParsedDirectives = 0; - sortMode = WildcardSortMode::NA; - - if (_tok._kind == Token::kw_sort_by_name) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - sortMode = WildcardSortMode::ByName; - } - - if (_tok._kind == Token::kw_sort_by_init_priority) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - sortMode = WildcardSortMode::ByInitPriority; - } - - if (_tok._kind == Token::kw_sort_by_alignment) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - if (sortMode != WildcardSortMode::ByName) - sortMode = WildcardSortMode::ByAlignment; - else - sortMode = WildcardSortMode::ByNameAndAlignment; - } - - if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_name) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - if (sortMode == WildcardSortMode::ByAlignment) - sortMode = WildcardSortMode::ByAlignmentAndName; - } - - if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_alignment) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - } - - if (numParsedDirectives == 0 && _tok._kind == Token::kw_sort_none) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return -1; - ++numParsedDirectives; - sortMode = WildcardSortMode::None; - } - - return numParsedDirectives; -} - -const InputSection *Parser::parseSortedInputSections() { - assert((_tok._kind == Token::kw_sort_by_name || - _tok._kind == Token::kw_sort_by_alignment || - _tok._kind == Token::kw_sort_by_init_priority || - _tok._kind == Token::kw_sort_none) && - "Expected SORT directives!"); - - WildcardSortMode sortMode = WildcardSortMode::NA; - int numParen = parseSortDirectives(sortMode); - if (numParen == -1) - return nullptr; - - SmallVector<const InputSection *, 8> inputSections; - - while (_tok._kind == Token::identifier) { - inputSections.push_back(new (_alloc) - InputSectionName(*this, _tok._range, false)); - consumeToken(); - } - - // Eat "numParen" rparens - for (int i = 0, e = numParen; i != e; ++i) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return new (_alloc) InputSectionSortedGroup(*this, sortMode, inputSections); -} - -const InputSectionsCmd *Parser::parseInputSectionsCmd() { - assert((_tok._kind == Token::identifier || _tok._kind == Token::colon || - _tok._kind == Token::star || _tok._kind == Token::kw_keep || - _tok._kind == Token::kw_sort_by_name || - _tok._kind == Token::kw_sort_by_alignment || - _tok._kind == Token::kw_sort_by_init_priority || - _tok._kind == Token::kw_sort_none) && - "Expected input section first tokens!"); - int numParen = 1; - bool keep = false; - WildcardSortMode fileSortMode = WildcardSortMode::NA; - WildcardSortMode archiveSortMode = WildcardSortMode::NA; - StringRef memberName; - StringRef archiveName; - - if (_tok._kind == Token::kw_keep) { - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - ++numParen; - keep = true; - } - - // Input name - if (_tok._kind != Token::colon) { - int numParen = parseSortDirectives(fileSortMode); - if (numParen == -1) - return nullptr; - memberName = _tok._range; - consumeToken(); - if (numParen) { - while (numParen--) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - } - } - if (_tok._kind == Token::colon) { - consumeToken(); - if (_tok._kind == Token::identifier || - _tok._kind == Token::kw_sort_by_name || - _tok._kind == Token::kw_sort_by_alignment || - _tok._kind == Token::kw_sort_by_init_priority || - _tok._kind == Token::kw_sort_none) { - int numParen = parseSortDirectives(archiveSortMode); - if (numParen == -1) - return nullptr; - archiveName = _tok._range; - consumeToken(); - for (int i = 0; i != numParen; ++i) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - } - } - - SmallVector<const InputSection *, 8> inputSections; - - if (_tok._kind != Token::l_paren) - return new (_alloc) - InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode, - archiveSortMode, inputSections); - consumeToken(); - - while (_tok._kind == Token::identifier || - _tok._kind == Token::kw_exclude_file || - _tok._kind == Token::kw_sort_by_name || - _tok._kind == Token::kw_sort_by_alignment || - _tok._kind == Token::kw_sort_by_init_priority || - _tok._kind == Token::kw_sort_none) { - switch (_tok._kind) { - case Token::kw_exclude_file: { - auto vec = parseExcludeFile(); - if (vec.getError()) - return nullptr; - inputSections.insert(inputSections.end(), vec->begin(), vec->end()); - break; - } - case Token::star: - case Token::identifier: { - inputSections.push_back(new (_alloc) - InputSectionName(*this, _tok._range, false)); - consumeToken(); - break; - } - case Token::kw_sort_by_name: - case Token::kw_sort_by_alignment: - case Token::kw_sort_by_init_priority: - case Token::kw_sort_none: { - const InputSection *group = parseSortedInputSections(); - if (!group) - return nullptr; - inputSections.push_back(group); - break; - } - default: - llvm_unreachable("Unknown token"); - } - } - - for (int i = 0; i < numParen; ++i) - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - return new (_alloc) - InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode, - archiveSortMode, inputSections); -} - -const FillCmd *Parser::parseFillCmd() { - assert(_tok._kind == Token::kw_fill && "Expected FILL!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - SmallVector<uint8_t, 8> storage; - - // If the expression is just a number, it's arbitrary length. - if (_tok._kind == Token::number && peek()._kind == Token::r_paren) { - if (_tok._range.size() > 2 && _tok._range.startswith("0x")) { - StringRef num = _tok._range.substr(2); - for (char c : num) { - unsigned nibble = llvm::hexDigitValue(c); - if (nibble == -1u) - goto not_simple_hex; - storage.push_back(nibble); - } - - if (storage.size() % 2 != 0) - storage.insert(storage.begin(), 0); - - // Collapse nibbles. - for (std::size_t i = 0, e = storage.size() / 2; i != e; ++i) - storage[i] = (storage[i * 2] << 4) + storage[(i * 2) + 1]; - - storage.resize(storage.size() / 2); - } - } -not_simple_hex: - - const Expression *expr = parseExpression(); - if (!expr) - return nullptr; - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - - return new(getAllocator()) FillCmd(*this, storage); -} - -const OutputSectionDescription *Parser::parseOutputSectionDescription() { - assert((_tok._kind == Token::kw_discard || _tok._kind == Token::identifier) && - "Expected /DISCARD/ or identifier!"); - StringRef sectionName; - const Expression *address = nullptr; - const Expression *align = nullptr; - const Expression *subAlign = nullptr; - const Expression *at = nullptr; - const Expression *fillExpr = nullptr; - StringRef fillStream; - bool alignWithInput = false; - bool discard = false; - OutputSectionDescription::Constraint constraint = - OutputSectionDescription::C_None; - SmallVector<const Command *, 8> outputSectionCommands; - - if (_tok._kind == Token::kw_discard) - discard = true; - else - sectionName = _tok._range; - consumeToken(); - - if (_tok._kind == Token::number || _tok._kind == Token::identifier || - _tok._kind == Token::kw_align || _tok._kind == Token::l_paren) { - address = parseExpression(); - if (!address) - return nullptr; - } - - if (!expectAndConsume(Token::colon, "expected :")) - return nullptr; - - if (_tok._kind == Token::kw_at) { - consumeToken(); - at = parseExpression(); - if (!at) - return nullptr; - } - - if (_tok._kind == Token::kw_align) { - consumeToken(); - align = parseExpression(); - if (!align) - return nullptr; - } - - if (_tok._kind == Token::kw_align_with_input) { - consumeToken(); - alignWithInput = true; - } - - if (_tok._kind == Token::kw_subalign) { - consumeToken(); - subAlign = parseExpression(); - if (!subAlign) - return nullptr; - } - - if (_tok._kind == Token::kw_only_if_ro) { - consumeToken(); - constraint = OutputSectionDescription::C_OnlyIfRO; - } else if (_tok._kind == Token::kw_only_if_rw) { - consumeToken(); - constraint = OutputSectionDescription::C_OnlyIfRW; - } - - if (!expectAndConsume(Token::l_brace, "expected {")) - return nullptr; - - // Parse zero or more output-section-commands - while (_tok._kind != Token::r_brace) { - switch (_tok._kind) { - case Token::semicolon: - consumeToken(); - break; - case Token::identifier: - switch (peek()._kind) { - case Token::equal: - case Token::plusequal: - case Token::minusequal: - case Token::starequal: - case Token::slashequal: - case Token::ampequal: - case Token::pipeequal: - case Token::lesslessequal: - case Token::greatergreaterequal: - if (const Command *cmd = parseSymbolAssignment()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - default: - if (const Command *cmd = parseInputSectionsCmd()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - } - break; - case Token::kw_fill: - if (const Command *cmd = parseFillCmd()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - case Token::kw_keep: - case Token::star: - case Token::colon: - case Token::kw_sort_by_name: - case Token::kw_sort_by_alignment: - case Token::kw_sort_by_init_priority: - case Token::kw_sort_none: - if (const Command *cmd = parseInputSectionsCmd()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - case Token::kw_hidden: - case Token::kw_provide: - case Token::kw_provide_hidden: - if (const Command *cmd = parseSymbolAssignment()) - outputSectionCommands.push_back(cmd); - else - return nullptr; - break; - default: - error(_tok, "expected symbol assignment or input file name."); - return nullptr; - } - } - - if (!expectAndConsume(Token::r_brace, "expected }")) - return nullptr; - - SmallVector<StringRef, 2> phdrs; - while (_tok._kind == Token::colon) { - consumeToken(); - if (_tok._kind != Token::identifier) { - error(_tok, "expected program header name"); - return nullptr; - } - phdrs.push_back(_tok._range); - consumeToken(); - } - - if (_tok._kind == Token::equal) { - consumeToken(); - if (_tok._kind != Token::number || !_tok._range.startswith_lower("0x")) { - fillExpr = parseExpression(); - if (!fillExpr) - return nullptr; - } else { - std::string strBuf; - if (isExpressionOperator(peek()) || - !parseHexToByteStream(_tok._range.drop_front(2), strBuf)) { - fillExpr = parseExpression(); - if(!fillExpr) - return nullptr; - } else { - char *rawBuf = (char *) _alloc.Allocate(strBuf.size(), 1); - memcpy(rawBuf, strBuf.c_str(), strBuf.size()); - fillStream = StringRef(rawBuf, strBuf.size()); - consumeToken(); - } - } - } - - return new (_alloc) OutputSectionDescription( - *this, sectionName, address, align, subAlign, at, fillExpr, fillStream, - alignWithInput, discard, constraint, outputSectionCommands, phdrs); -} - -const Overlay *Parser::parseOverlay() { - assert(_tok._kind == Token::kw_overlay && "Expected OVERLAY!"); - error(_tok, "Overlay description is not yet supported."); - return nullptr; -} - -const PHDR *Parser::parsePHDR() { - assert(_tok._kind == Token::identifier && "Expected identifier!"); - - StringRef name = _tok._range; - consumeToken(); - - uint64_t type; - - switch (_tok._kind) { - case Token::identifier: - case Token::number: - case Token::l_paren: { - const Expression *expr = parseExpression(); - if (!expr) - return nullptr; - Expression::SymbolTableTy PHDRTypes; -#define PHDR_INSERT(x) PHDRTypes.insert(std::make_pair(#x, llvm::ELF::x)) - PHDR_INSERT(PT_NULL); - PHDR_INSERT(PT_LOAD); - PHDR_INSERT(PT_DYNAMIC); - PHDR_INSERT(PT_INTERP); - PHDR_INSERT(PT_NOTE); - PHDR_INSERT(PT_SHLIB); - PHDR_INSERT(PT_PHDR); - PHDR_INSERT(PT_TLS); - PHDR_INSERT(PT_LOOS); - PHDR_INSERT(PT_GNU_EH_FRAME); - PHDR_INSERT(PT_GNU_STACK); - PHDR_INSERT(PT_GNU_RELRO); - PHDR_INSERT(PT_SUNW_EH_FRAME); - PHDR_INSERT(PT_SUNW_UNWIND); - PHDR_INSERT(PT_HIOS); - PHDR_INSERT(PT_LOPROC); - PHDR_INSERT(PT_ARM_ARCHEXT); - PHDR_INSERT(PT_ARM_EXIDX); - PHDR_INSERT(PT_ARM_UNWIND); - PHDR_INSERT(PT_MIPS_REGINFO); - PHDR_INSERT(PT_MIPS_RTPROC); - PHDR_INSERT(PT_MIPS_OPTIONS); - PHDR_INSERT(PT_MIPS_ABIFLAGS); - PHDR_INSERT(PT_HIPROC); -#undef PHDR_INSERT - auto t = expr->evalExpr(PHDRTypes); - if (t == LinkerScriptReaderError::unknown_symbol_in_expr) { - error(_tok, "Unknown type"); - return nullptr; - } - if (!t) - return nullptr; - type = *t; - break; - } - default: - error(_tok, "expected identifier or expression"); - return nullptr; - } - - uint64_t flags = 0; - const Expression *flagsExpr = nullptr; - bool includeFileHdr = false; - bool includePHDRs = false; - - while (_tok._kind != Token::semicolon) { - switch (_tok._kind) { - case Token::kw_filehdr: - if (includeFileHdr) { - error(_tok, "Duplicate FILEHDR attribute"); - return nullptr; - } - includeFileHdr = true; - consumeToken(); - break; - case Token::kw_phdrs: - if (includePHDRs) { - error(_tok, "Duplicate PHDRS attribute"); - return nullptr; - } - includePHDRs = true; - consumeToken(); - break; - case Token::kw_flags: { - if (flagsExpr) { - error(_tok, "Duplicate FLAGS attribute"); - return nullptr; - } - consumeToken(); - if (!expectAndConsume(Token::l_paren, "Expected (")) - return nullptr; - flagsExpr = parseExpression(); - if (!flagsExpr) - return nullptr; - auto f = flagsExpr->evalExpr(); - if (!f) - return nullptr; - flags = *f; - if (!expectAndConsume(Token::r_paren, "Expected )")) - return nullptr; - } break; - default: - error(_tok, "Unexpected token"); - return nullptr; - } - } - - if (!expectAndConsume(Token::semicolon, "Expected ;")) - return nullptr; - - return new (getAllocator()) - PHDR(name, type, includeFileHdr, includePHDRs, nullptr, flags); -} - -PHDRS *Parser::parsePHDRS() { - assert(_tok._kind == Token::kw_phdrs && "Expected PHDRS!"); - consumeToken(); - if (!expectAndConsume(Token::l_brace, "expected {")) - return nullptr; - - SmallVector<const PHDR *, 8> phdrs; - - while (true) { - if (_tok._kind == Token::identifier) { - const PHDR *phdr = parsePHDR(); - if (!phdr) - return nullptr; - phdrs.push_back(phdr); - } else - break; - } - - if (!expectAndConsume(Token::r_brace, "expected }")) - return nullptr; - - return new (getAllocator()) PHDRS(*this, phdrs); -} - -Sections *Parser::parseSections() { - assert(_tok._kind == Token::kw_sections && "Expected SECTIONS!"); - consumeToken(); - if (!expectAndConsume(Token::l_brace, "expected {")) - return nullptr; - SmallVector<const Command *, 8> sectionsCommands; - - bool unrecognizedToken = false; - // Parse zero or more sections-commands - while (!unrecognizedToken) { - switch (_tok._kind) { - case Token::semicolon: - consumeToken(); - break; - - case Token::identifier: - switch (peek()._kind) { - case Token::equal: - case Token::plusequal: - case Token::minusequal: - case Token::starequal: - case Token::slashequal: - case Token::ampequal: - case Token::pipeequal: - case Token::lesslessequal: - case Token::greatergreaterequal: - if (const Command *cmd = parseSymbolAssignment()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - default: - if (const Command *cmd = parseOutputSectionDescription()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - } - break; - - case Token::kw_discard: - case Token::star: - if (const Command *cmd = parseOutputSectionDescription()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - - case Token::kw_entry: - if (const Command *cmd = parseEntry()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - - case Token::kw_hidden: - case Token::kw_provide: - case Token::kw_provide_hidden: - if (const Command *cmd = parseSymbolAssignment()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - - case Token::kw_overlay: - if (const Command *cmd = parseOverlay()) - sectionsCommands.push_back(cmd); - else - return nullptr; - break; - - default: - unrecognizedToken = true; - break; - } - } - - if (!expectAndConsume( - Token::r_brace, - "expected symbol assignment, entry, overlay or output section name.")) - return nullptr; - - return new (_alloc) Sections(*this, sectionsCommands); -} - -Memory *Parser::parseMemory() { - assert(_tok._kind == Token::kw_memory && "Expected MEMORY!"); - consumeToken(); - if (!expectAndConsume(Token::l_brace, "expected {")) - return nullptr; - SmallVector<const MemoryBlock *, 8> blocks; - - bool unrecognizedToken = false; - // Parse zero or more memory block descriptors. - while (!unrecognizedToken) { - if (_tok._kind == Token::identifier) { - StringRef name; - StringRef attrs; - const Expression *origin = nullptr; - const Expression *length = nullptr; - - name = _tok._range; - consumeToken(); - - // Parse optional memory region attributes. - if (_tok._kind == Token::l_paren) { - consumeToken(); - - if (_tok._kind != Token::identifier) { - error(_tok, "Expected memory attribute string."); - return nullptr; - } - attrs = _tok._range; - consumeToken(); - - if (!expectAndConsume(Token::r_paren, "expected )")) - return nullptr; - } - - if (!expectAndConsume(Token::colon, "expected :")) - return nullptr; - - // Parse the ORIGIN (base address of memory block). - if (!expectAndConsume(Token::kw_origin, "expected ORIGIN")) - return nullptr; - - if (!expectAndConsume(Token::equal, "expected =")) - return nullptr; - - origin = parseExpression(); - if (!origin) - return nullptr; - - if (!expectAndConsume(Token::comma, "expected ,")) - return nullptr; - - // Parse the LENGTH (length of memory block). - if (!expectAndConsume(Token::kw_length, "expected LENGTH")) - return nullptr; - - if (!expectAndConsume(Token::equal, "expected =")) - return nullptr; - - length = parseExpression(); - if (!length) - return nullptr; - - auto *block = new (_alloc) MemoryBlock(name, attrs, origin, length); - blocks.push_back(block); - } else { - unrecognizedToken = true; - } - } - if (!expectAndConsume( - Token::r_brace, - "expected memory block definition.")) - return nullptr; - - return new (_alloc) Memory(*this, blocks); -} - -Extern *Parser::parseExtern() { - assert(_tok._kind == Token::kw_extern && "Expected EXTERN!"); - consumeToken(); - if (!expectAndConsume(Token::l_paren, "expected (")) - return nullptr; - - // Parse one or more symbols. - SmallVector<StringRef, 8> symbols; - if (_tok._kind != Token::identifier) { - error(_tok, "expected one or more symbols in EXTERN."); - return nullptr; - } - symbols.push_back(_tok._range); - consumeToken(); - while (_tok._kind == Token::identifier) { - symbols.push_back(_tok._range); - consumeToken(); - } - - if (!expectAndConsume(Token::r_paren, "expected symbol in EXTERN.")) - return nullptr; - - return new (_alloc) Extern(*this, symbols); -} - -// Sema member functions -Sema::Sema() : _programPHDR(nullptr) {} - -std::error_code Sema::perform() { - llvm::StringMap<const PHDR *> phdrs; - - for (auto &parser : _scripts) { - for (const Command *c : parser->get()->_commands) { - if (const auto *sec = dyn_cast<Sections>(c)) { - linearizeAST(sec); - } else if (const auto *ph = dyn_cast<PHDRS>(c)) { - if (auto ec = collectPHDRs(ph, phdrs)) - return ec; - } - } - } - return buildSectionToPHDR(phdrs); -} - -bool Sema::less(const SectionKey &lhs, const SectionKey &rhs) const { - int a = getLayoutOrder(lhs, true); - int b = getLayoutOrder(rhs, true); - - if (a != b) { - if (a < 0) - return false; - if (b < 0) - return true; - return a < b; - } - - // If both sections are not mapped anywhere, they have the same order - if (a < 0) - return false; - - // If both sections fall into the same layout order, we need to find their - // relative position as written in the (InputSectionsCmd). - return localCompare(a, lhs, rhs); -} - -StringRef Sema::getOutputSection(const SectionKey &key) const { - int layoutOrder = getLayoutOrder(key, true); - if (layoutOrder < 0) - return StringRef(); - - for (int i = layoutOrder - 1; i >= 0; --i) { - if (!isa<OutputSectionDescription>(_layoutCommands[i])) - continue; - - const OutputSectionDescription *out = - dyn_cast<OutputSectionDescription>(_layoutCommands[i]); - return out->name(); - } - - return StringRef(); -} - -std::vector<const SymbolAssignment *> -Sema::getExprs(const SectionKey &key) { - int layoutOrder = getLayoutOrder(key, false); - auto ans = std::vector<const SymbolAssignment *>(); - - if (layoutOrder < 0 || _deliveredExprs.count(layoutOrder) > 0) - return ans; - - for (int i = layoutOrder - 1; i >= 0; --i) { - if (isa<InputSection>(_layoutCommands[i])) - break; - if (auto assgn = dyn_cast<SymbolAssignment>(_layoutCommands[i])) - ans.push_back(assgn); - } - - // Reverse this order so we evaluate the expressions in the original order - // of the linker script - std::reverse(ans.begin(), ans.end()); - - // Mark this layout number as delivered - _deliveredExprs.insert(layoutOrder); - return ans; -} - -std::error_code Sema::evalExpr(const SymbolAssignment *assgn, - uint64_t &curPos) { - _symbolTable[StringRef(".")] = curPos; - - auto ans = assgn->expr()->evalExpr(_symbolTable); - if (ans.getError()) - return ans.getError(); - uint64_t result = *ans; - - if (assgn->symbol() == ".") { - curPos = result; - return std::error_code(); - } - - _symbolTable[assgn->symbol()] = result; - return std::error_code(); -} - -const llvm::StringSet<> &Sema::getScriptDefinedSymbols() const { - // Do we have cached results? - if (!_definedSymbols.empty()) - return _definedSymbols; - - // Populate our defined set and return it - for (auto cmd : _layoutCommands) - if (auto sa = dyn_cast<SymbolAssignment>(cmd)) { - StringRef symbol = sa->symbol(); - if (!symbol.empty() && symbol != ".") - _definedSymbols.insert(symbol); - } - - return _definedSymbols; -} - -uint64_t Sema::getLinkerScriptExprValue(StringRef name) const { - auto it = _symbolTable.find(name); - assert (it != _symbolTable.end() && "Invalid symbol name!"); - return it->second; -} - -bool Sema::hasPHDRs() const { return !_sectionToPHDR.empty(); } - -std::vector<const PHDR *> Sema::getPHDRsForOutputSection(StringRef name) const { - auto vec = _sectionToPHDR.lookup(name); - return std::vector<const PHDR *>(std::begin(vec), std::end(vec)); -} - -const PHDR *Sema::getProgramPHDR() const { return _programPHDR; } - -void Sema::dump() const { - raw_ostream &os = llvm::outs(); - os << "Linker script semantics dump\n"; - int num = 0; - for (auto &parser : _scripts) { - os << "Dumping script #" << ++num << ":\n"; - parser->get()->dump(os); - os << "\n"; - } - os << "Dumping rule ids:\n"; - for (unsigned i = 0; i < _layoutCommands.size(); ++i) { - os << "LayoutOrder " << i << ":\n"; - _layoutCommands[i]->dump(os); - os << "\n\n"; - } -} - -/// Given a string "pattern" with wildcard characters, return true if it -/// matches "name". This function is useful when checking if a given name -/// pattern written in the linker script, i.e. ".text*", should match -/// ".text.anytext". -static bool wildcardMatch(StringRef pattern, StringRef name) { - auto i = name.begin(); - - // Check if each char in pattern also appears in our input name, handling - // special wildcard characters. - for (auto j = pattern.begin(), e = pattern.end(); j != e; ++j) { - if (i == name.end()) - return false; - - switch (*j) { - case '*': - while (!wildcardMatch(pattern.drop_front(j - pattern.begin() + 1), - name.drop_front(i - name.begin()))) { - if (i == name.end()) - return false; - ++i; - } - break; - case '?': - // Matches any character - ++i; - break; - case '[': { - // Matches a range of characters specified between brackets - size_t end = pattern.find(']', j - pattern.begin()); - if (end == pattern.size()) - return false; - - StringRef chars = pattern.slice(j - pattern.begin(), end); - if (chars.find(i) == StringRef::npos) - return false; - - j = pattern.begin() + end; - ++i; - break; - } - case '\\': - ++j; - if (*j != *i) - return false; - ++i; - break; - default: - // No wildcard character means we must match exactly the same char - if (*j != *i) - return false; - ++i; - break; - } - } - - // If our pattern has't consumed the entire string, it is not a match - return i == name.end(); -} - -int Sema::matchSectionName(int id, const SectionKey &key) const { - const InputSectionsCmd *cmd = dyn_cast<InputSectionsCmd>(_layoutCommands[id]); - - if (!cmd || !wildcardMatch(cmd->archiveName(), key.archivePath)) - return -1; - - while ((size_t)++id < _layoutCommands.size() && - (isa<InputSection>(_layoutCommands[id]))) { - if (isa<InputSectionSortedGroup>(_layoutCommands[id])) - continue; - - const InputSectionName *in = - dyn_cast<InputSectionName>(_layoutCommands[id]); - if (wildcardMatch(in->name(), key.sectionName)) - return id; - } - return -1; -} - -int Sema::getLayoutOrder(const SectionKey &key, bool coarse) const { - // First check if we already answered this layout question - if (coarse) { - auto entry = _cacheSectionOrder.find(key); - if (entry != _cacheSectionOrder.end()) - return entry->second; - } else { - auto entry = _cacheExpressionOrder.find(key); - if (entry != _cacheExpressionOrder.end()) - return entry->second; - } - - // Try to match exact file name - auto range = _memberToLayoutOrder.equal_range(key.memberPath); - for (auto I = range.first, E = range.second; I != E; ++I) { - int order = I->second; - int exprOrder = -1; - - if ((exprOrder = matchSectionName(order, key)) >= 0) { - if (coarse) { - _cacheSectionOrder.insert(std::make_pair(key, order)); - return order; - } - _cacheExpressionOrder.insert(std::make_pair(key, exprOrder)); - return exprOrder; - } - } - - // If we still couldn't find a rule for this input section, try to match - // wildcards - for (const auto &I : _memberNameWildcards) { - if (!wildcardMatch(I.first, key.memberPath)) - continue; - int order = I.second; - int exprOrder = -1; - - if ((exprOrder = matchSectionName(order, key)) >= 0) { - if (coarse) { - _cacheSectionOrder.insert(std::make_pair(key, order)); - return order; - } - _cacheExpressionOrder.insert(std::make_pair(key, exprOrder)); - return exprOrder; - } - } - - _cacheSectionOrder.insert(std::make_pair(key, -1)); - _cacheExpressionOrder.insert(std::make_pair(key, -1)); - return -1; -} - -static bool compareSortedNames(WildcardSortMode sortMode, StringRef lhs, - StringRef rhs) { - switch (sortMode) { - case WildcardSortMode::None: - case WildcardSortMode::NA: - return false; - case WildcardSortMode::ByAlignment: - case WildcardSortMode::ByInitPriority: - case WildcardSortMode::ByAlignmentAndName: - assert(false && "Unimplemented sort order"); - break; - case WildcardSortMode::ByName: - return lhs.compare(rhs) < 0; - case WildcardSortMode::ByNameAndAlignment: - int compare = lhs.compare(rhs); - if (compare != 0) - return compare < 0; - return compareSortedNames(WildcardSortMode::ByAlignment, lhs, rhs); - } - return false; -} - -static bool sortedGroupContains(const InputSectionSortedGroup *cmd, - const Sema::SectionKey &key) { - for (const InputSection *child : *cmd) { - if (auto i = dyn_cast<InputSectionName>(child)) { - if (wildcardMatch(i->name(), key.sectionName)) - return true; - continue; - } - - auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(child); - assert(sortedGroup && "Expected InputSectionSortedGroup object"); - - if (sortedGroupContains(sortedGroup, key)) - return true; - } - - return false; -} - -bool Sema::localCompare(int order, const SectionKey &lhs, - const SectionKey &rhs) const { - const InputSectionsCmd *cmd = - dyn_cast<InputSectionsCmd>(_layoutCommands[order]); - - assert(cmd && "Invalid InputSectionsCmd index"); - - if (lhs.archivePath != rhs.archivePath) - return compareSortedNames(cmd->archiveSortMode(), lhs.archivePath, - rhs.archivePath); - - if (lhs.memberPath != rhs.memberPath) - return compareSortedNames(cmd->fileSortMode(), lhs.memberPath, - rhs.memberPath); - - // Both sections come from the same exact same file and rule. Start walking - // through input section names as written in the linker script and the - // first one to match will have higher priority. - for (const InputSection *inputSection : *cmd) { - if (auto i = dyn_cast<InputSectionName>(inputSection)) { - // If both match, return false (both have equal priority) - // If rhs match, return false (rhs has higher priority) - if (wildcardMatch(i->name(), rhs.sectionName)) - return false; - // If lhs matches first, it has priority over rhs - if (wildcardMatch(i->name(), lhs.sectionName)) - return true; - continue; - } - - // Handle sorted subgroups specially - auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection); - assert(sortedGroup && "Expected InputSectionSortedGroup object"); - - bool a = sortedGroupContains(sortedGroup, lhs); - bool b = sortedGroupContains(sortedGroup, rhs); - if (a && !b) - return false; - if (b && !a) - return true; - if (!a && !a) - continue; - - return compareSortedNames(sortedGroup->sortMode(), lhs.sectionName, - rhs.sectionName); - } - - llvm_unreachable(""); - return false; -} - -std::error_code Sema::collectPHDRs(const PHDRS *ph, - llvm::StringMap<const PHDR *> &phdrs) { - bool loadFound = false; - for (auto *p : *ph) { - phdrs[p->name()] = p; - - switch (p->type()) { - case llvm::ELF::PT_PHDR: - if (_programPHDR != nullptr) - return LinkerScriptReaderError::extra_program_phdr; - if (loadFound) - return LinkerScriptReaderError::misplaced_program_phdr; - if (!p->hasPHDRs()) - return LinkerScriptReaderError::program_phdr_wrong_phdrs; - _programPHDR = p; - break; - case llvm::ELF::PT_LOAD: - // Program header, if available, should have program header table - // mapped in the first loadable segment. - if (!loadFound && _programPHDR && !p->hasPHDRs()) - return LinkerScriptReaderError::program_phdr_wrong_phdrs; - loadFound = true; - break; - } - } - return std::error_code(); -} - -std::error_code Sema::buildSectionToPHDR(llvm::StringMap<const PHDR *> &phdrs) { - const bool noPhdrs = phdrs.empty(); - - // Add NONE header to the map provided there's no user-defined - // header with the same name. - if (!phdrs.count(PHDR_NONE.name())) - phdrs[PHDR_NONE.name()] = &PHDR_NONE; - - // Match output sections to available headers. - llvm::SmallVector<const PHDR *, 2> phdrsCur, phdrsLast { &PHDR_NONE }; - for (const Command *cmd : _layoutCommands) { - auto osd = dyn_cast<OutputSectionDescription>(cmd); - if (!osd || osd->isDiscarded()) - continue; - - phdrsCur.clear(); - for (StringRef name : osd->PHDRs()) { - auto it = phdrs.find(name); - if (it == phdrs.end()) { - return LinkerScriptReaderError::unknown_phdr_ids; - } - phdrsCur.push_back(it->second); - } - - // If no headers and no errors - insert empty headers set. - // If the current set of headers is empty, then use the last non-empty - // set. Otherwise mark the current set to be the last non-empty set for - // successors. - if (noPhdrs) - phdrsCur.clear(); - else if (phdrsCur.empty()) - phdrsCur = phdrsLast; - else - phdrsLast = phdrsCur; - - _sectionToPHDR[osd->name()] = phdrsCur; - } - return std::error_code(); -} - -static bool hasWildcard(StringRef name) { - for (auto ch : name) - if (ch == '*' || ch == '?' || ch == '[' || ch == '\\') - return true; - return false; -} - -void Sema::linearizeAST(const InputSection *inputSection) { - if (isa<InputSectionName>(inputSection)) { - _layoutCommands.push_back(inputSection); - return; - } - - auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection); - assert(sortedGroup && "Expected InputSectionSortedGroup object"); - - for (const InputSection *child : *sortedGroup) { - linearizeAST(child); - } -} - -void Sema::linearizeAST(const InputSectionsCmd *inputSections) { - StringRef memberName = inputSections->memberName(); - // Populate our maps for fast lookup of InputSectionsCmd - if (hasWildcard(memberName)) - _memberNameWildcards.push_back( - std::make_pair(memberName, (int)_layoutCommands.size())); - else if (!memberName.empty()) - _memberToLayoutOrder.insert( - std::make_pair(memberName.str(), (int)_layoutCommands.size())); - - _layoutCommands.push_back(inputSections); - for (const InputSection *inputSection : *inputSections) - linearizeAST(inputSection); -} - -void Sema::linearizeAST(const Sections *sections) { - for (const Command *sectionCommand : *sections) { - if (isa<SymbolAssignment>(sectionCommand)) { - _layoutCommands.push_back(sectionCommand); - continue; - } - - if (!isa<OutputSectionDescription>(sectionCommand)) - continue; - - _layoutCommands.push_back(sectionCommand); - auto *outSection = dyn_cast<OutputSectionDescription>(sectionCommand); - - for (const Command *outSecCommand : *outSection) { - if (isa<SymbolAssignment>(outSecCommand)) { - _layoutCommands.push_back(outSecCommand); - continue; - } - - if (!isa<InputSectionsCmd>(outSecCommand)) - continue; - - linearizeAST(dyn_cast<InputSectionsCmd>(outSecCommand)); - } - } -} - -} // end namespace script -} // end namespace lld |