Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -363,7 +363,7 @@ template void LinkerScript::addScriptedSymbols() { for (const std::unique_ptr &Base : Opt.Commands) { auto *Cmd = dyn_cast(Base.get()); - if (!Cmd || Cmd->Name == ".") + if (!Cmd || Cmd->Name == "." || Cmd->Name.empty()) continue; // If a symbol was in PROVIDE(), define it only when it is an @@ -447,6 +447,7 @@ void readInputSectionRules(InputSectionDescription *InCmd, bool Keep); unsigned readPhdrType(); void readProvide(bool Hidden); + void readAssert(); void readAlign(OutputSectionCommand *Cmd); void readSort(); @@ -644,6 +645,11 @@ Opt.HasContents = true; expect("{"); while (!Error && !skip("}")) { + if (peek() == "ASSERT") { + readAssert(); + continue; + } + StringRef Tok = next(); if (peek() == "=" || peek() == "+=") { readAssignment(Tok); @@ -812,6 +818,11 @@ return 0; } +void ScriptParser::readAssert() { + auto *Cmd = new SymbolAssignment("", readExpr()); + Opt.Commands.emplace_back(Cmd); +} + SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { StringRef Op = next(); assert(Op == "=" || Op == "+="); @@ -920,6 +931,19 @@ expect(")"); return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); }; } + if (Tok == "ASSERT") { + expect("("); + Expr E = readExpr(); + expect(","); + StringRef Msg = next(); + expect(")"); + return [=](uint64_t Dot) { + uint64_t V = E(Dot); + if (!V) + error(Msg); + return V; + }; + } // Parse a symbol name or a number literal. uint64_t V = 0; Index: test/ELF/linkerscript/linkerscript-assert.s =================================================================== --- test/ELF/linkerscript/linkerscript-assert.s +++ 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