[lld] r365143 - [LLD][ELF] - Linkerscript: add a support for expressions for section's filling

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 4 07:17:32 PDT 2019


Author: grimar
Date: Thu Jul  4 07:17:31 2019
New Revision: 365143

URL: http://llvm.org/viewvc/llvm-project?rev=365143&view=rev
Log:
[LLD][ELF] - Linkerscript: add a support for expressions for section's filling

Imagine the script:

.section: {
...
} = FILL_EXPR
LLD assumes that FILL_EXPR is a number, and does not allow
it to be an expression. Though that is allowed by specification:
https://sourceware.org/binutils/docs-2.32/ld/Output-Section-Fill.html

This patch adds a support for cases when FILL_EXPR is simple math expression.

Fixes https://bugs.llvm.org/show_bug.cgi?id=42482.

Differential revision: https://reviews.llvm.org/D64130

Modified:
    lld/trunk/ELF/ScriptLexer.cpp
    lld/trunk/ELF/ScriptParser.cpp
    lld/trunk/test/ELF/linkerscript/fill.test
    lld/trunk/test/ELF/linkerscript/sections-padding.s

Modified: lld/trunk/ELF/ScriptLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/ScriptLexer.cpp?rev=365143&r1=365142&r2=365143&view=diff
==============================================================================
--- lld/trunk/ELF/ScriptLexer.cpp (original)
+++ lld/trunk/ELF/ScriptLexer.cpp Thu Jul  4 07:17:31 2019
@@ -170,7 +170,7 @@ bool ScriptLexer::atEOF() { return error
 // Split a given string as an expression.
 // This function returns "3", "*" and "5" for "3*5" for example.
 static std::vector<StringRef> 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 @@ static std::vector<StringRef> tokenizeEx
     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 {

Modified: lld/trunk/ELF/ScriptParser.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/ScriptParser.cpp?rev=365143&r1=365142&r2=365143&view=diff
==============================================================================
--- lld/trunk/ELF/ScriptParser.cpp (original)
+++ lld/trunk/ELF/ScriptParser.cpp Thu Jul  4 07:17:31 2019
@@ -85,7 +85,6 @@ private:
   SymbolAssignment *readSymbolAssignment(StringRef Name);
   ByteCommand *readByteCommand(StringRef Tok);
   std::array<uint8_t, 4> readFill();
-  std::array<uint8_t, 4> parseFill(StringRef Tok);
   bool readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2);
   void readSectionAddressType(OutputSection *Cmd);
   OutputSection *readOverlaySectionDescription();
@@ -726,17 +725,6 @@ Expr ScriptParser::readAssert() {
   };
 }
 
-// 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<uint8_t, 4> ScriptParser::readFill() {
-  expect("(");
-  std::array<uint8_t, 4> 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.
@@ -837,6 +825,9 @@ OutputSection *ScriptParser::readOutputS
       // 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();
@@ -867,10 +858,12 @@ OutputSection *ScriptParser::readOutputS
 
   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(",");
@@ -880,20 +873,21 @@ OutputSection *ScriptParser::readOutputS
   return Cmd;
 }
 
-// Parses a given string as a octal/decimal/hexadecimal number and
-// returns it as a big-endian number. Used for `=<fillexp>`.
+// Reads a `=<fillexp>` 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<uint8_t, 4> ScriptParser::parseFill(StringRef Tok) {
-  uint32_t V = 0;
-  if (!to_integer(Tok, V))
-    setError("invalid filler expression: " + Tok);
+std::array<uint8_t, 4> 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<uint8_t, 4> Buf;
-  write32be(Buf.data(), V);
+  write32be(Buf.data(), (uint32_t)Value);
   return Buf;
 }
 

Modified: lld/trunk/test/ELF/linkerscript/fill.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/fill.test?rev=365143&r1=365142&r2=365143&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/fill.test (original)
+++ lld/trunk/test/ELF/linkerscript/fill.test Thu Jul  4 07:17:31 2019
@@ -11,7 +11,7 @@ SECTIONS {
    . += 4;
    *(.bbb)
    . += 4;
-   FILL(0x22222222);
+   FILL(0x22220000 + 0x2222);
    . += 4;
   }
 }

Modified: lld/trunk/test/ELF/linkerscript/sections-padding.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/sections-padding.s?rev=365143&r1=365142&r2=365143&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/sections-padding.s (original)
+++ lld/trunk/test/ELF/linkerscript/sections-padding.s Thu Jul  4 07:17:31 2019
@@ -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




More information about the llvm-commits mailing list