Add PHDR and FILL parsing.

llvm-svn: 238383
This commit is contained in:
Michael J. Spencer 2015-05-28 00:14:58 +00:00
parent 95a192a3ab
commit cc0554d057
4 changed files with 343 additions and 60 deletions

View File

@ -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 *> &sections)
: 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 *> &sectionsCommands)
: 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:
///

View File

@ -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();

View File

@ -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: }
*/

View File

@ -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 = .)