Index: ELF/ScriptLexer.h =================================================================== --- ELF/ScriptLexer.h +++ ELF/ScriptLexer.h @@ -29,6 +29,7 @@ bool atEOF(); StringRef next(); StringRef peek(); + StringRef peek2(); void skip(); bool consume(StringRef Tok); void expect(StringRef Expect); Index: ELF/ScriptLexer.cpp =================================================================== --- ELF/ScriptLexer.cpp +++ ELF/ScriptLexer.cpp @@ -244,6 +244,15 @@ return Tok; } +StringRef ScriptLexer::peek2() { + skip(); + StringRef Tok = next(); + if (errorCount()) + return ""; + Pos = Pos - 2; + return Tok; +} + bool ScriptLexer::consume(StringRef Tok) { if (peek() == Tok) { skip(); Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -80,6 +80,7 @@ ByteCommand *readByteCommand(StringRef Tok); uint32_t readFill(); uint32_t parseFill(StringRef Tok); + bool readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2); void readSectionAddressType(OutputSection *Cmd); OutputSection *readOverlaySectionDescription(); OutputSection *readOutputSectionDescription(StringRef OutSec); @@ -699,6 +700,26 @@ return V; } +// Tries to read the special directive for an output section definition which +// can be one of following: "(NOLOAD)", "(COPY)", "(INFO)" or "(OVERLAY)". +// Tok1 and Tok2 are next 2 tokens peeked. See comment for readSectionAddressType below. +bool ScriptParser::readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2) { + if (Tok1 != "(") + return false; + if (Tok2 != "NOLOAD" && Tok2 != "COPY" && Tok2 != "INFO" && Tok2 != "OVERLAY") + return false; + + expect("("); + if (consume("NOLOAD")) { + Cmd->Noload = true; + } else { + skip(); // This is "COPY", "INFO" or "OVERLAY". + Cmd->NonAlloc = true; + } + expect(")"); + return true; +} + // Reads an expression and/or the special directive for an output // section definition. Directive is one of following: "(NOLOAD)", // "(COPY)", "(INFO)" or "(OVERLAY)". @@ -711,28 +732,12 @@ // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html // https://sourceware.org/binutils/docs/ld/Output-Section-Type.html void ScriptParser::readSectionAddressType(OutputSection *Cmd) { - if (consume("(")) { - if (consume("NOLOAD")) { - expect(")"); - Cmd->Noload = true; - return; - } - if (consume("COPY") || consume("INFO") || consume("OVERLAY")) { - expect(")"); - Cmd->NonAlloc = true; - return; - } - Cmd->AddrExpr = readExpr(); - expect(")"); - } else { - Cmd->AddrExpr = readExpr(); - } + if (readSectionDirective(Cmd, peek(), peek2())) + return; - if (consume("(")) { - expect("NOLOAD"); - expect(")"); - Cmd->Noload = true; - } + Cmd->AddrExpr = readExpr(); + if (peek() == "(" && !readSectionDirective(Cmd, "(", peek2())) + setError("unknown section directive: " + peek2()); } static Expr checkAlignment(Expr E, std::string &Loc) { Index: test/ELF/linkerscript/info-section-type.s =================================================================== --- test/ELF/linkerscript/info-section-type.s +++ test/ELF/linkerscript/info-section-type.s @@ -29,5 +29,14 @@ # RUN: ld.lld -o %t --script %t.script %t.o # RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC +# RUN: echo "SECTIONS { .bar 0x20000 (INFO) : { *(.foo) } };" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC + +# RUN: echo "SECTIONS { .bar 0x20000 (BAR) : { *(.foo) } };" > %t.script +# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 |\ +# RUN: FileCheck %s --check-prefix=UNKNOWN +# UNKNOWN: unknown section directive: BAR + .section .foo,"a",@progbits .zero 1