[ELF] - Linkerscript: implemented ASSERT() keyword.
authorGeorge Rimar <grimar@accesssoftek.com>
Thu, 4 Aug 2016 09:29:31 +0000 (09:29 +0000)
committerGeorge Rimar <grimar@accesssoftek.com>
Thu, 4 Aug 2016 09:29:31 +0000 (09:29 +0000)
ASSERT(exp, message)
Ensure that exp is non-zero. If it is zero, then exit the linker with an error
code, and print message.

ASSERT is useful and was seen in few projects in the wild.

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

llvm-svn: 277710

lld/ELF/LinkerScript.cpp
lld/ELF/LinkerScript.h
lld/test/ELF/linkerscript/linkerscript-assert.s [new file with mode: 0644]

index 6117a03..d47b519 100644 (file)
@@ -55,6 +55,10 @@ bool InputSectionDescription::classof(const BaseCommand *C) {
   return C->Kind == InputSectionKind;
 }
 
+bool AssertCommand::classof(const BaseCommand *C) {
+  return C->Kind == AssertKind;
+}
+
 template <class ELFT> static bool isDiscarded(InputSectionBase<ELFT> *S) {
   return !S || !S->Live;
 }
@@ -249,6 +253,11 @@ void LinkerScript<ELFT>::assignAddresses(
       continue;
     }
 
+    if (auto *Cmd = dyn_cast<AssertCommand>(Base.get())) {
+      Cmd->Expression(Dot);
+      continue;
+    }
+
     // Find all the sections with required name. There can be more than
     // one section with such name, if the alignment, flags or type
     // attribute differs.
@@ -487,6 +496,7 @@ private:
   SymbolAssignment *readProvide(bool Hidden);
   Expr readAlign();
   void readSort();
+  Expr readAssert();
 
   Expr readExpr();
   Expr readExpr1(Expr Lhs, int MinPrec);
@@ -693,6 +703,8 @@ void ScriptParser::readSections() {
       Cmd = readProvide(false);
     } else if (Tok == "PROVIDE_HIDDEN") {
       Cmd = readProvide(true);
+    } else if (Tok == "ASSERT") {
+      Cmd = new AssertCommand(readAssert());
     } else {
       Cmd = readOutputSectionDescription(Tok);
     }
@@ -796,6 +808,20 @@ void ScriptParser::readSort() {
   expect(")");
 }
 
+Expr ScriptParser::readAssert() {
+  expect("(");
+  Expr E = readExpr();
+  expect(",");
+  StringRef Msg = next();
+  expect(")");
+  return [=](uint64_t Dot) {
+    uint64_t V = E(Dot);
+    if (!V)
+      error(Msg);
+    return V;
+  };
+}
+
 OutputSectionCommand *
 ScriptParser::readOutputSectionDescription(StringRef OutSec) {
   OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec);
@@ -967,6 +993,8 @@ Expr ScriptParser::readPrimary() {
 
   // Built-in functions are parsed here.
   // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
+  if (Tok == "ASSERT")
+    return readAssert();
   if (Tok == "ALIGN") {
     expect("(");
     Expr E = readExpr();
index e853d0c..dc61e90 100644 (file)
@@ -41,7 +41,8 @@ template <class ELFT> class OutputSectionBase;
 enum SectionsCommandKind {
   AssignmentKind,
   OutputSectionKind,
-  InputSectionKind
+  InputSectionKind,
+  AssertKind
 };
 
 struct BaseCommand {
@@ -98,6 +99,12 @@ struct InputSectionDescription : BaseCommand {
   std::vector<StringRef> SectionPatterns;
 };
 
+struct AssertCommand : BaseCommand {
+  AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {}
+  static bool classof(const BaseCommand *C);
+  Expr Expression;
+};
+
 struct PhdrsCommand {
   StringRef Name;
   unsigned Type;
diff --git a/lld/test/ELF/linkerscript/linkerscript-assert.s b/lld/test/ELF/linkerscript/linkerscript-assert.s
new file mode 100644 (file)
index 0000000..7cda4b0
--- /dev/null
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+
+# RUN: echo "SECTIONS {     \
+# RUN:   ASSERT(1, \"true\") \
+# RUN:  }" > %t1.script
+# RUN: ld.lld -shared -o %t1 --script %t1.script %t1.o
+# RUN: llvm-readobj %t1 > /dev/null
+
+# RUN: echo "SECTIONS {                                  \
+# RUN:   ASSERT(ASSERT(42, \"true\") == 42, \"true\") \
+# RUN:  }" > %t2.script
+# RUN: ld.lld -shared -o %t2 --script %t2.script %t1.o
+# RUN: llvm-readobj %t2 > /dev/null
+
+# RUN: echo "SECTIONS {     \
+# RUN:   ASSERT(0,\ "fail\") \
+# RUN:  }" > %t3.script
+# RUN: not ld.lld -shared -o %t3 --script %t3.script %t1.o > %t.log 2>&1
+# RUN: FileCheck %s -check-prefix=FAIL < %t.log
+# FAIL: fail
+
+# RUN: echo "SECTIONS {     \
+# RUN:   . = ASSERT(0x1000, \"true\"); \
+# RUN:  }" > %t4.script
+# RUN: ld.lld -shared -o %t4 --script %t4.script %t1.o
+# RUN: llvm-readobj %t4 > /dev/null