From eefa758ee2a65b80c53aae4688b20448d78a300d Mon Sep 17 00:00:00 2001 From: George Rimar Date: Thu, 4 Aug 2016 09:29:31 +0000 Subject: [PATCH] [ELF] - Linkerscript: implemented ASSERT() keyword. 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 | 28 +++++++++++++++++++ lld/ELF/LinkerScript.h | 9 +++++- .../ELF/linkerscript/linkerscript-assert.s | 27 ++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 lld/test/ELF/linkerscript/linkerscript-assert.s diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 6117a031be5a..d47b51998781 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -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 static bool isDiscarded(InputSectionBase *S) { return !S || !S->Live; } @@ -249,6 +253,11 @@ void LinkerScript::assignAddresses( continue; } + if (auto *Cmd = dyn_cast(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(); diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index e853d0c0d57f..dc61e90b153e 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -41,7 +41,8 @@ template class OutputSectionBase; enum SectionsCommandKind { AssignmentKind, OutputSectionKind, - InputSectionKind + InputSectionKind, + AssertKind }; struct BaseCommand { @@ -98,6 +99,12 @@ struct InputSectionDescription : BaseCommand { std::vector 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 index 000000000000..7cda4b027810 --- /dev/null +++ b/lld/test/ELF/linkerscript/linkerscript-assert.s @@ -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