parent
95a192a3ab
commit
cc0554d057
|
|
@ -78,6 +78,7 @@ public:
|
|||
kw_entry,
|
||||
kw_exclude_file,
|
||||
kw_extern,
|
||||
kw_fill,
|
||||
kw_group,
|
||||
kw_hidden,
|
||||
kw_input,
|
||||
|
|
@ -85,6 +86,7 @@ public:
|
|||
kw_length,
|
||||
kw_memory,
|
||||
kw_origin,
|
||||
kw_phdrs,
|
||||
kw_provide,
|
||||
kw_provide_hidden,
|
||||
kw_only_if_ro,
|
||||
|
|
@ -160,6 +162,7 @@ public:
|
|||
enum class Kind {
|
||||
Entry,
|
||||
Extern,
|
||||
Fill,
|
||||
Group,
|
||||
Input,
|
||||
InputSectionsCmd,
|
||||
|
|
@ -170,6 +173,7 @@ public:
|
|||
OutputFormat,
|
||||
OutputSectionDescription,
|
||||
Overlay,
|
||||
PHDRS,
|
||||
SearchDir,
|
||||
Sections,
|
||||
SortedGroup,
|
||||
|
|
@ -191,6 +195,14 @@ private:
|
|||
Kind _kind;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ArrayRef<T> save_array(llvm::BumpPtrAllocator &alloc, ArrayRef<T> array) {
|
||||
size_t num = array.size();
|
||||
T *start = alloc.Allocate<T>(num);
|
||||
std::uninitialized_copy(std::begin(array), std::end(array), start);
|
||||
return llvm::makeArrayRef(start, num);
|
||||
}
|
||||
|
||||
class Output : public Command {
|
||||
public:
|
||||
Output(Parser &ctx, StringRef outputFileName)
|
||||
|
|
@ -212,10 +224,7 @@ class OutputFormat : public Command {
|
|||
public:
|
||||
OutputFormat(Parser &ctx, const SmallVectorImpl<StringRef> &formats)
|
||||
: Command(ctx, Kind::OutputFormat) {
|
||||
size_t numFormats = formats.size();
|
||||
StringRef *formatsStart = getAllocator().Allocate<StringRef>(numFormats);
|
||||
std::copy(std::begin(formats), std::end(formats), formatsStart);
|
||||
_formats = llvm::makeArrayRef(formatsStart, numFormats);
|
||||
_formats = save_array<StringRef>(getAllocator(), formats);
|
||||
}
|
||||
|
||||
static bool classof(const Command *c) {
|
||||
|
|
@ -274,10 +283,7 @@ class PathList : public Command {
|
|||
public:
|
||||
PathList(Parser &ctx, StringRef name, const SmallVectorImpl<Path> &paths)
|
||||
: Command(ctx, K), _name(name) {
|
||||
size_t numPaths = paths.size();
|
||||
Path *pathsStart = getAllocator().template Allocate<Path>(numPaths);
|
||||
std::copy(std::begin(paths), std::end(paths), pathsStart);
|
||||
_paths = llvm::makeArrayRef(pathsStart, numPaths);
|
||||
_paths = save_array<Path>(getAllocator(), paths);
|
||||
}
|
||||
|
||||
static bool classof(const Command *c) { return c->getKind() == K; }
|
||||
|
|
@ -382,7 +388,8 @@ public:
|
|||
Kind getKind() const { return _kind; }
|
||||
inline llvm::BumpPtrAllocator &getAllocator() const;
|
||||
virtual void dump(raw_ostream &os) const = 0;
|
||||
virtual ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const = 0;
|
||||
virtual ErrorOr<int64_t>
|
||||
evalExpr(const SymbolTableTy &symbolTable = SymbolTableTy()) const = 0;
|
||||
virtual ~Expression() {}
|
||||
|
||||
protected:
|
||||
|
|
@ -406,7 +413,7 @@ public:
|
|||
return c->getKind() == Kind::Constant;
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
|
||||
ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override;
|
||||
|
||||
private:
|
||||
uint64_t _num;
|
||||
|
|
@ -422,7 +429,7 @@ public:
|
|||
return c->getKind() == Kind::Symbol;
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
|
||||
ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override;
|
||||
|
||||
private:
|
||||
StringRef _name;
|
||||
|
|
@ -433,11 +440,7 @@ public:
|
|||
FunctionCall(Parser &ctx, StringRef name,
|
||||
const SmallVectorImpl<const Expression *> &args)
|
||||
: Expression(ctx, Kind::FunctionCall), _name(name) {
|
||||
size_t numArgs = args.size();
|
||||
const Expression **argsStart =
|
||||
getAllocator().Allocate<const Expression *>(numArgs);
|
||||
std::copy(std::begin(args), std::end(args), argsStart);
|
||||
_args = llvm::makeArrayRef(argsStart, numArgs);
|
||||
_args = save_array<const Expression *>(getAllocator(), args);
|
||||
}
|
||||
|
||||
void dump(raw_ostream &os) const override;
|
||||
|
|
@ -446,7 +449,7 @@ public:
|
|||
return c->getKind() == Kind::FunctionCall;
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
|
||||
ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override;
|
||||
|
||||
private:
|
||||
StringRef _name;
|
||||
|
|
@ -468,7 +471,7 @@ public:
|
|||
return c->getKind() == Kind::Unary;
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
|
||||
ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override;
|
||||
|
||||
private:
|
||||
Operation _op;
|
||||
|
|
@ -503,7 +506,7 @@ public:
|
|||
return c->getKind() == Kind::BinOp;
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
|
||||
ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override;
|
||||
|
||||
private:
|
||||
Operation _op;
|
||||
|
|
@ -538,7 +541,7 @@ public:
|
|||
return c->getKind() == Kind::TernaryConditional;
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> evalExpr(SymbolTableTy &symbolTable) const override;
|
||||
ErrorOr<int64_t> evalExpr(const SymbolTableTy &symbolTable) const override;
|
||||
|
||||
private:
|
||||
const Expression *_conditional;
|
||||
|
|
@ -647,11 +650,7 @@ public:
|
|||
InputSectionSortedGroup(Parser &ctx, WildcardSortMode sort,
|
||||
const SmallVectorImpl<const InputSection *> §ions)
|
||||
: InputSection(ctx, Kind::SortedGroup), _sortMode(sort) {
|
||||
size_t numSections = sections.size();
|
||||
const InputSection **sectionsStart =
|
||||
getAllocator().Allocate<const InputSection *>(numSections);
|
||||
std::copy(std::begin(sections), std::end(sections), sectionsStart);
|
||||
_sections = llvm::makeArrayRef(sectionsStart, numSections);
|
||||
_sections = save_array<const InputSection *>(getAllocator(), sections);
|
||||
}
|
||||
|
||||
void dump(raw_ostream &os) const override;
|
||||
|
|
@ -691,11 +690,7 @@ public:
|
|||
: Command(ctx, Kind::InputSectionsCmd), _memberName(memberName),
|
||||
_archiveName(archiveName), _keep(keep), _fileSortMode(fileSortMode),
|
||||
_archiveSortMode(archiveSortMode) {
|
||||
size_t numSections = sections.size();
|
||||
const InputSection **sectionsStart =
|
||||
getAllocator().Allocate<const InputSection *>(numSections);
|
||||
std::copy(std::begin(sections), std::end(sections), sectionsStart);
|
||||
_sections = llvm::makeArrayRef(sectionsStart, numSections);
|
||||
_sections = save_array<const InputSection *>(getAllocator(), sections);
|
||||
}
|
||||
|
||||
void dump(raw_ostream &os) const override;
|
||||
|
|
@ -720,6 +715,24 @@ private:
|
|||
llvm::ArrayRef<const InputSection *> _sections;
|
||||
};
|
||||
|
||||
class FillCmd : public Command {
|
||||
public:
|
||||
FillCmd(Parser &ctx, ArrayRef<uint8_t> bytes) : Command(ctx, Kind::Fill) {
|
||||
_bytes = save_array<uint8_t>(getAllocator(), bytes);
|
||||
}
|
||||
|
||||
void dump(raw_ostream &os) const override;
|
||||
|
||||
static bool classof(const Command *c) {
|
||||
return c->getKind() == Kind::Fill;
|
||||
}
|
||||
|
||||
ArrayRef<uint8_t> bytes() { return _bytes; }
|
||||
|
||||
private:
|
||||
ArrayRef<uint8_t> _bytes;
|
||||
};
|
||||
|
||||
/// A sections-command to specify which input sections and symbols compose a
|
||||
/// given output section.
|
||||
/// Example:
|
||||
|
|
@ -743,18 +756,16 @@ public:
|
|||
const Expression *align, const Expression *subAlign, const Expression *at,
|
||||
const Expression *fillExpr, StringRef fillStream, bool alignWithInput,
|
||||
bool discard, Constraint constraint,
|
||||
const SmallVectorImpl<const Command *> &outputSectionCommands)
|
||||
const SmallVectorImpl<const Command *> &outputSectionCommands,
|
||||
ArrayRef<StringRef> phdrs)
|
||||
: Command(ctx, Kind::OutputSectionDescription), _sectionName(sectionName),
|
||||
_address(address), _align(align), _subAlign(subAlign), _at(at),
|
||||
_fillExpr(fillExpr), _fillStream(fillStream),
|
||||
_alignWithInput(alignWithInput), _discard(discard),
|
||||
_constraint(constraint) {
|
||||
size_t numCommands = outputSectionCommands.size();
|
||||
const Command **commandsStart =
|
||||
getAllocator().Allocate<const Command *>(numCommands);
|
||||
std::copy(std::begin(outputSectionCommands),
|
||||
std::end(outputSectionCommands), commandsStart);
|
||||
_outputSectionCommands = llvm::makeArrayRef(commandsStart, numCommands);
|
||||
_outputSectionCommands =
|
||||
save_array<const Command *>(getAllocator(), outputSectionCommands);
|
||||
_phdrs = save_array<StringRef>(getAllocator(), phdrs);
|
||||
}
|
||||
|
||||
static bool classof(const Command *c) {
|
||||
|
|
@ -779,6 +790,7 @@ private:
|
|||
bool _discard;
|
||||
Constraint _constraint;
|
||||
llvm::ArrayRef<const Command *> _outputSectionCommands;
|
||||
ArrayRef<StringRef> _phdrs;
|
||||
};
|
||||
|
||||
/// Represents an Overlay structure as documented in
|
||||
|
|
@ -794,6 +806,47 @@ public:
|
|||
void dump(raw_ostream &os) const override { os << "Overlay description\n"; }
|
||||
};
|
||||
|
||||
class PHDR {
|
||||
public:
|
||||
PHDR(StringRef name, uint64_t type, bool includeFileHdr, bool includePHDRs,
|
||||
const Expression *at, uint64_t flags)
|
||||
: _name(name), _type(type), _includeFileHdr(includeFileHdr),
|
||||
_includePHDRs(includePHDRs), _at(at), _flags(flags) {}
|
||||
|
||||
~PHDR() = delete;
|
||||
|
||||
void dump(raw_ostream &os) const;
|
||||
|
||||
private:
|
||||
StringRef _name;
|
||||
uint64_t _type;
|
||||
bool _includeFileHdr;
|
||||
bool _includePHDRs;
|
||||
const Expression *_at;
|
||||
uint64_t _flags;
|
||||
};
|
||||
|
||||
class PHDRS : public Command {
|
||||
public:
|
||||
typedef ArrayRef<const PHDR *>::const_iterator const_iterator;
|
||||
|
||||
PHDRS(Parser &ctx, const SmallVectorImpl<const PHDR *> &phdrs)
|
||||
: Command(ctx, Kind::PHDRS) {
|
||||
_phdrs = save_array<const PHDR *>(getAllocator(), phdrs);
|
||||
}
|
||||
|
||||
static bool classof(const Command *c) {
|
||||
return c->getKind() == Kind::PHDRS;
|
||||
}
|
||||
|
||||
void dump(raw_ostream &os) const override;
|
||||
const_iterator begin() const { return _phdrs.begin(); }
|
||||
const_iterator end() const { return _phdrs.end(); }
|
||||
|
||||
private:
|
||||
ArrayRef<const PHDR *> _phdrs;
|
||||
};
|
||||
|
||||
/// Represents all the contents of the SECTIONS {} construct.
|
||||
class Sections : public Command {
|
||||
public:
|
||||
|
|
@ -802,12 +855,8 @@ public:
|
|||
Sections(Parser &ctx,
|
||||
const SmallVectorImpl<const Command *> §ionsCommands)
|
||||
: Command(ctx, Kind::Sections) {
|
||||
size_t numCommands = sectionsCommands.size();
|
||||
const Command **commandsStart =
|
||||
getAllocator().Allocate<const Command *>(numCommands);
|
||||
std::copy(std::begin(sectionsCommands), std::end(sectionsCommands),
|
||||
commandsStart);
|
||||
_sectionsCommands = llvm::makeArrayRef(commandsStart, numCommands);
|
||||
_sectionsCommands =
|
||||
save_array<const Command *>(getAllocator(), sectionsCommands);
|
||||
}
|
||||
|
||||
static bool classof(const Command *c) {
|
||||
|
|
@ -844,11 +893,7 @@ public:
|
|||
Memory(Parser &ctx,
|
||||
const SmallVectorImpl<const MemoryBlock *> &blocks)
|
||||
: Command(ctx, Kind::Memory) {
|
||||
size_t numBlocks = blocks.size();
|
||||
const MemoryBlock **blocksStart =
|
||||
getAllocator().Allocate<const MemoryBlock *>(numBlocks);
|
||||
std::copy(std::begin(blocks), std::end(blocks), blocksStart);
|
||||
_blocks = llvm::makeArrayRef(blocksStart, numBlocks);
|
||||
_blocks = save_array<const MemoryBlock *>(getAllocator(), blocks);
|
||||
}
|
||||
|
||||
static bool classof(const Command *c) {
|
||||
|
|
@ -869,11 +914,7 @@ public:
|
|||
Extern(Parser &ctx,
|
||||
const SmallVectorImpl<StringRef> &symbols)
|
||||
: Command(ctx, Kind::Extern) {
|
||||
size_t numSymbols = symbols.size();
|
||||
StringRef *symbolsStart =
|
||||
getAllocator().Allocate<StringRef>(numSymbols);
|
||||
std::copy(std::begin(symbols), std::end(symbols), symbolsStart);
|
||||
_symbols = llvm::makeArrayRef(symbolsStart, numSymbols);
|
||||
_symbols = save_array<StringRef>(getAllocator(), symbols);
|
||||
}
|
||||
|
||||
static bool classof(const Command *c) {
|
||||
|
|
@ -1133,6 +1174,8 @@ private:
|
|||
/// }
|
||||
const InputSectionsCmd *parseInputSectionsCmd();
|
||||
|
||||
const FillCmd *parseFillCmd();
|
||||
|
||||
/// Parse output section description statements.
|
||||
/// Example:
|
||||
///
|
||||
|
|
@ -1145,6 +1188,10 @@ private:
|
|||
/// Stub for parsing overlay commands. Currently unimplemented.
|
||||
const Overlay *parseOverlay();
|
||||
|
||||
const PHDR *parsePHDR();
|
||||
|
||||
PHDRS *parsePHDRS();
|
||||
|
||||
/// Parse the SECTIONS linker script command.
|
||||
/// Example:
|
||||
///
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
#include "lld/ReaderWriter/LinkerScript.h"
|
||||
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
|
||||
namespace lld {
|
||||
namespace script {
|
||||
void Token::dump(raw_ostream &os) const {
|
||||
|
|
@ -63,6 +67,7 @@ void Token::dump(raw_ostream &os) const {
|
|||
CASE(kw_entry)
|
||||
CASE(kw_exclude_file)
|
||||
CASE(kw_extern)
|
||||
CASE(kw_fill)
|
||||
CASE(kw_group)
|
||||
CASE(kw_hidden)
|
||||
CASE(kw_input)
|
||||
|
|
@ -70,6 +75,7 @@ void Token::dump(raw_ostream &os) const {
|
|||
CASE(kw_length)
|
||||
CASE(kw_memory)
|
||||
CASE(kw_origin)
|
||||
CASE(kw_phdrs)
|
||||
CASE(kw_provide)
|
||||
CASE(kw_provide_hidden)
|
||||
CASE(kw_only_if_ro)
|
||||
|
|
@ -469,6 +475,7 @@ void Lexer::lex(Token &tok) {
|
|||
.Case("ENTRY", Token::kw_entry)
|
||||
.Case("EXCLUDE_FILE", Token::kw_exclude_file)
|
||||
.Case("EXTERN", Token::kw_extern)
|
||||
.Case("FILL", Token::kw_fill)
|
||||
.Case("GROUP", Token::kw_group)
|
||||
.Case("HIDDEN", Token::kw_hidden)
|
||||
.Case("INPUT", Token::kw_input)
|
||||
|
|
@ -486,6 +493,7 @@ void Lexer::lex(Token &tok) {
|
|||
.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)
|
||||
|
|
@ -544,14 +552,14 @@ void Lexer::skipWhitespace() {
|
|||
// Constant functions
|
||||
void Constant::dump(raw_ostream &os) const { os << _num; }
|
||||
|
||||
ErrorOr<int64_t> Constant::evalExpr(SymbolTableTy &symbolTable) const {
|
||||
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(SymbolTableTy &symbolTable) const {
|
||||
ErrorOr<int64_t> Symbol::evalExpr(const SymbolTableTy &symbolTable) const {
|
||||
auto it = symbolTable.find(_name);
|
||||
if (it == symbolTable.end())
|
||||
return LinkerScriptReaderError::unknown_symbol_in_expr;
|
||||
|
|
@ -569,7 +577,8 @@ void FunctionCall::dump(raw_ostream &os) const {
|
|||
os << ")";
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> FunctionCall::evalExpr(SymbolTableTy &symbolTable) const {
|
||||
ErrorOr<int64_t>
|
||||
FunctionCall::evalExpr(const SymbolTableTy &symbolTable) const {
|
||||
return LinkerScriptReaderError::unrecognized_function_in_expr;
|
||||
}
|
||||
|
||||
|
|
@ -584,7 +593,7 @@ void Unary::dump(raw_ostream &os) const {
|
|||
os << ")";
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> Unary::evalExpr(SymbolTableTy &symbolTable) const {
|
||||
ErrorOr<int64_t> Unary::evalExpr(const SymbolTableTy &symbolTable) const {
|
||||
auto child = _child->evalExpr(symbolTable);
|
||||
if (child.getError())
|
||||
return child.getError();
|
||||
|
|
@ -654,7 +663,7 @@ void BinOp::dump(raw_ostream &os) const {
|
|||
os << ")";
|
||||
}
|
||||
|
||||
ErrorOr<int64_t> BinOp::evalExpr(SymbolTableTy &symbolTable) const {
|
||||
ErrorOr<int64_t> BinOp::evalExpr(const SymbolTableTy &symbolTable) const {
|
||||
auto lhs = _lhs->evalExpr(symbolTable);
|
||||
if (lhs.getError())
|
||||
return lhs.getError();
|
||||
|
|
@ -695,7 +704,7 @@ void TernaryConditional::dump(raw_ostream &os) const {
|
|||
}
|
||||
|
||||
ErrorOr<int64_t>
|
||||
TernaryConditional::evalExpr(SymbolTableTy &symbolTable) const {
|
||||
TernaryConditional::evalExpr(const SymbolTableTy &symbolTable) const {
|
||||
auto conditional = _conditional->evalExpr(symbolTable);
|
||||
if (conditional.getError())
|
||||
return conditional.getError();
|
||||
|
|
@ -857,6 +866,12 @@ void InputSectionsCmd::dump(raw_ostream &os) const {
|
|||
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)
|
||||
|
|
@ -909,6 +924,9 @@ void OutputSectionDescription::dump(raw_ostream &os) const {
|
|||
}
|
||||
os << " }";
|
||||
|
||||
for (auto && phdr : _phdrs)
|
||||
os << " : " << phdr;
|
||||
|
||||
if (_fillStream.size() > 0) {
|
||||
os << " =";
|
||||
dumpByteStream(os, _fillStream);
|
||||
|
|
@ -918,6 +936,21 @@ void OutputSectionDescription::dump(raw_ostream &os) const {
|
|||
}
|
||||
}
|
||||
|
||||
void PHDR::dump(raw_ostream &os) const {
|
||||
os << _name << " " << _type;
|
||||
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";
|
||||
|
|
@ -1024,6 +1057,13 @@ std::error_code Parser::parse() {
|
|||
_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)
|
||||
|
|
@ -1793,6 +1833,46 @@ const InputSectionsCmd *Parser::parseInputSectionsCmd() {
|
|||
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!");
|
||||
|
|
@ -1892,6 +1972,12 @@ const OutputSectionDescription *Parser::parseOutputSectionDescription() {
|
|||
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:
|
||||
|
|
@ -1921,6 +2007,17 @@ const OutputSectionDescription *Parser::parseOutputSectionDescription() {
|
|||
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")) {
|
||||
|
|
@ -1945,7 +2042,7 @@ const OutputSectionDescription *Parser::parseOutputSectionDescription() {
|
|||
|
||||
return new (_alloc) OutputSectionDescription(
|
||||
*this, sectionName, address, align, subAlign, at, fillExpr, fillStream,
|
||||
alignWithInput, discard, constraint, outputSectionCommands);
|
||||
alignWithInput, discard, constraint, outputSectionCommands, phdrs);
|
||||
}
|
||||
|
||||
const Overlay *Parser::parseOverlay() {
|
||||
|
|
@ -1954,6 +2051,110 @@ const Overlay *Parser::parseOverlay() {
|
|||
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;
|
||||
|
||||
if (_tok._kind == Token::identifier && _tok._range == "FLAGS") {
|
||||
consumeToken();
|
||||
if (!expectAndConsume(Token::l_paren, "Expected ("))
|
||||
return nullptr;
|
||||
const Expression *flagsExpr = parseExpression();
|
||||
if (!flagsExpr)
|
||||
return nullptr;
|
||||
auto f = flagsExpr->evalExpr();
|
||||
if (!f)
|
||||
return nullptr;
|
||||
flags = *f;
|
||||
if (!expectAndConsume(Token::r_paren, "Expected )"))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!expectAndConsume(Token::semicolon, "Expected ;"))
|
||||
return nullptr;
|
||||
|
||||
return new (getAllocator()) PHDR(name, type, false, false, 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();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
Test PHDR parsing and section -> phdr mapping.
|
||||
RUN: linker-script-test %s | FileCheck %s
|
||||
*/
|
||||
|
||||
PHDRS
|
||||
{
|
||||
ph_text PT_LOAD FLAGS (0x1 | 0x4);
|
||||
ph_data PT_LOAD FLAGS (0x2 | 0x4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.init : {} : ph_text
|
||||
}
|
||||
|
||||
/*
|
||||
CHECK: PHDRS
|
||||
CHECK: {
|
||||
CHECK: ph_text 1 FLAGS (5);
|
||||
CHECK: ph_data 1 FLAGS (6);
|
||||
CHECK: }
|
||||
CHECK: SECTIONS
|
||||
CHECK: {
|
||||
CHECK: .init :
|
||||
CHECK: {
|
||||
CHECK: } : ph_text
|
||||
CHECK: }
|
||||
*/
|
||||
|
|
@ -26,6 +26,7 @@ SECTIONS
|
|||
}
|
||||
.init :
|
||||
{
|
||||
FILL (0x90909090)
|
||||
KEEP (*(SORT_NONE(.init)))
|
||||
} =0x909090909090909090909090
|
||||
PROVIDE (__etext = .);
|
||||
|
|
@ -181,6 +182,10 @@ CHECK: r_brace: }
|
|||
CHECK: identifier: .init
|
||||
CHECK: colon: :
|
||||
CHECK: l_brace: {
|
||||
CHECK: kw_fill: FILL
|
||||
CHECK: l_paren: (
|
||||
CHECK: number: 0x90909090
|
||||
CHECK: r_paren: )
|
||||
CHECK: kw_keep: KEEP
|
||||
CHECK: l_paren: (
|
||||
CHECK: star: *
|
||||
|
|
@ -556,6 +561,7 @@ CHECK: PROVIDE_HIDDEN(__rela_iplt_end = .)
|
|||
CHECK: }
|
||||
CHECK: .init :
|
||||
CHECK: {
|
||||
CHECK: FILL(0x90909090)
|
||||
CHECK: KEEP(*(SORT_NONE(.init)))
|
||||
CHECK: } =0x909090909090909090909090
|
||||
CHECK: PROVIDE(__etext = .)
|
||||
|
|
|
|||
Loading…
Reference in New Issue