Index: include/lld/ReaderWriter/LinkerScript.h =================================================================== --- include/lld/ReaderWriter/LinkerScript.h +++ include/lld/ReaderWriter/LinkerScript.h @@ -78,6 +78,7 @@ kw_provide_hidden, kw_only_if_ro, kw_only_if_rw, + kw_output, kw_output_arch, kw_output_format, kw_overlay, @@ -149,6 +150,7 @@ Entry, Group, InputSectionsCmd, + Output, OutputArch, OutputFormat, OutputSectionDescription, @@ -171,6 +173,23 @@ Kind _kind; }; +class Output : public Command { +public: + explicit Output(StringRef outputFileName) + : Command(Kind::Output), _outputFileName(outputFileName) {} + + static bool classof(const Command *c) { return c->getKind() == Kind::Output; } + + void dump(raw_ostream &os) const override { + os << "OUTPUT(" << _outputFileName << ")\n"; + } + + StringRef getOutputFileName() const { return _outputFileName; } + +private: + StringRef _outputFileName; +}; + class OutputFormat : public Command { public: explicit OutputFormat(StringRef format) : Command(Kind::OutputFormat) { @@ -834,6 +853,13 @@ // ==== High-level commands parsing ==== + /// Parse the OUTPUT linker script command. + /// Example: + /// OUTPUT(/path/to/file) + /// ^~~~> parseOutput() + /// + Output *parseOutput(); + /// Parse the OUTPUT_FORMAT linker script command. /// Example: /// Index: lib/ReaderWriter/LinkerScript.cpp =================================================================== --- lib/ReaderWriter/LinkerScript.cpp +++ lib/ReaderWriter/LinkerScript.cpp @@ -69,6 +69,7 @@ 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) @@ -515,6 +516,7 @@ .Case("KEEP", Token::kw_keep) .Case("ONLY_IF_RO", Token::kw_only_if_ro) .Case("ONLY_IF_RW", Token::kw_only_if_rw) + .Case("OUTPUT", Token::kw_output) .Case("OUTPUT_ARCH", Token::kw_output_arch) .Case("OUTPUT_FORMAT", Token::kw_output_format) .Case("OVERLAY", Token::kw_overlay) @@ -901,6 +903,13 @@ case Token::semicolon: consumeToken(); break; + case Token::kw_output: { + auto output = parseOutput(); + if (!output) + return nullptr; + _script._commands.push_back(output); + break; + } case Token::kw_output_format: { auto outputFormat = parseOutputFormat(); if (!outputFormat) @@ -1211,6 +1220,27 @@ return new (_alloc) TernaryConditional(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(_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!"); Index: test/LinkerScript/linker-script.test =================================================================== --- test/LinkerScript/linker-script.test +++ test/LinkerScript/linker-script.test @@ -3,6 +3,7 @@ OUTPUT_ARCH(i386:x86_64) OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT("/out/foo") GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) -lm -l:libgcc.a ) ENTRY(init) @@ -19,6 +20,10 @@ CHECK: comma: , CHECK: identifier: elf64-x86-64 CHECK: r_paren: ) +CHECK: kw_output: OUTPUT +CHECK: l_paren: ( +CHECK: identifier: /out/foo +CHECK: r_paren: ) CHECK: kw_group: GROUP CHECK: l_paren: ( CHECK: identifier: /lib/x86_64-linux-gnu/libc.so.6