2899 lines
		
	
	
		
			77 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			2899 lines
		
	
	
		
			77 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- ReaderWriter/LinkerScript.cpp --------------------------------------===//
 | 
						|
//
 | 
						|
//                             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();
 | 
						|
    Symbol *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;
 | 
						|
    }
 | 
						|
    Constant *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;
 | 
						|
 | 
						|
      MemoryBlock *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 (auto I = _memberNameWildcards.begin(), E = _memberNameWildcards.end();
 | 
						|
       I != E; ++I) {
 | 
						|
    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
 |