Index: ELF/ScriptLexer.cpp =================================================================== --- ELF/ScriptLexer.cpp +++ ELF/ScriptLexer.cpp @@ -170,7 +170,7 @@ // Split a given string as an expression. // This function returns "3", "*" and "5" for "3*5" for example. static std::vector tokenizeExpr(StringRef S) { - StringRef Ops = "+-*/:!~"; // List of operators + StringRef Ops = "+-*/:!~=<>"; // List of operators // Quoted strings are literal strings, so we don't want to split it. if (S.startswith("\"")) @@ -191,8 +191,11 @@ if (E != 0) Ret.push_back(S.substr(0, E)); - // Get the operator as a token. Keep != as one token. - if (S.substr(E).startswith("!=")) { + // Get the operator as a token. + // Keep !=, ==, >=, <=, << and >> operators as a single tokens. + if (S.substr(E).startswith("!=") || S.substr(E).startswith("==") || + S.substr(E).startswith(">=") || S.substr(E).startswith("<=") || + S.substr(E).startswith("<<") || S.substr(E).startswith(">>")) { Ret.push_back(S.substr(E, 2)); S = S.substr(E + 2); } else { Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -78,7 +78,6 @@ SymbolAssignment *readSymbolAssignment(StringRef Name); ByteCommand *readByteCommand(StringRef Tok); std::array readFill(); - std::array parseFill(StringRef Tok); bool readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2); void readSectionAddressType(OutputSection *Cmd); OutputSection *readOverlaySectionDescription(); @@ -728,17 +727,6 @@ }; } -// Reads a FILL(expr) command. We handle the FILL command as an -// alias for =fillexp section attribute, which is different from -// what GNU linkers do. -// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html -std::array ScriptParser::readFill() { - expect("("); - std::array V = parseFill(next()); - expect(")"); - 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. @@ -839,6 +827,9 @@ // by name. This is for very old file formats such as ECOFF/XCOFF. // For ELF, we should ignore. } else if (Tok == "FILL") { + // We handle the FILL command as an alias for =fillexp section attribute, + // which is different from what GNU linkers do. + // https://sourceware.org/binutils/docs/ld/Output-Section-Data.html Cmd->Filler = readFill(); } else if (Tok == "SORT") { readSort(); @@ -869,10 +860,12 @@ Cmd->Phdrs = readOutputSectionPhdrs(); - if (consume("=")) - Cmd->Filler = parseFill(next()); - else if (peek().startswith("=")) - Cmd->Filler = parseFill(next().drop_front()); + if (peek() == "=" || peek().startswith("=")) { + InExpr = true; + consume("="); + Cmd->Filler = readFill(); + InExpr = false; + } // Consume optional comma following output section command. consume(","); @@ -882,20 +875,21 @@ return Cmd; } -// Parses a given string as a octal/decimal/hexadecimal number and -// returns it as a big-endian number. Used for `=`. +// Reads a `=` expression and returns its value as a big-endian number. // https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html +// We do not support using symbols in such expressions. // // When reading a hexstring, ld.bfd handles it as a blob of arbitrary // size, while ld.gold always handles it as a 32-bit big-endian number. // We are compatible with ld.gold because it's easier to implement. -std::array ScriptParser::parseFill(StringRef Tok) { - uint32_t V = 0; - if (!to_integer(Tok, V)) - setError("invalid filler expression: " + Tok); +std::array ScriptParser::readFill() { + uint64_t Value = readExpr()().Val; + if (Value > UINT32_MAX) + setError("filler expression result does not fit 32-bit: 0x" + + Twine::utohexstr(Value)); std::array Buf; - write32be(Buf.data(), V); + write32be(Buf.data(), (uint32_t)Value); return Buf; } Index: test/ELF/linkerscript/fill.test =================================================================== --- test/ELF/linkerscript/fill.test +++ test/ELF/linkerscript/fill.test @@ -11,7 +11,7 @@ . += 4; *(.bbb) . += 4; - FILL(0x22222222); + FILL(0x22220000 + 0x2222); . += 4; } } Index: test/ELF/linkerscript/sections-padding.s =================================================================== --- test/ELF/linkerscript/sections-padding.s +++ test/ELF/linkerscript/sections-padding.s @@ -29,9 +29,9 @@ # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99XX }" > %t.script # RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \ # RUN: | FileCheck --check-prefix=ERR2 %s -# ERR2: invalid filler expression: 0x99XX +# ERR2: malformed number: 0x99XX -## Check case with space between '=' and expression: +## Check case with space between '=' and a value: # RUN: echo "SECTIONS { .mysec : { *(.mysec*) } = 0x1122 }" > %t.script # RUN: ld.lld -o %t.out --script %t.script %t # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s @@ -41,6 +41,26 @@ # RUN: ld.lld -o %t.out --script %t.script %t # RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s +## Check we can use an artbitrary expression as a filler. +# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } = ((0x11<<8) | 0x22) }" > %t.script +# RUN: ld.lld -o %t.out --script %t.script %t +# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s + +## Check case with space between '=' and expression: +# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =((0x11 << 8) | 0x22) }" > %t.script +# RUN: ld.lld -o %t.out --script %t.script %t +# RUN: llvm-objdump -s %t.out | FileCheck -check-prefix=YES %s + +## Check we report an error if expression value is larger that 32-bits. +# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =(0x11 << 32) }" > %t.script +# RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 | FileCheck --check-prefix=ERR3 %s +# ERR3: filler expression result does not fit 32-bit: 0x1100000000 + +## Check we report an error if an expression use a symbol. +# RUN: echo "SECTIONS { foo = 0x11; .mysec : { *(.mysec*) } = foo }" > %t.script +# RUN: not ld.lld -o %t.out %t --script %t.script 2>&1 | FileCheck --check-prefix=ERR4 %s +# ERR4: symbol not found: foo + .section .mysec.1,"a" .align 16 .byte 0x66