This is an archive of the discontinued LLVM Phabricator instance.

[ELF] - Linkerscript: implemented ASSERT() keyword.
ClosedPublic

Authored by grimar on Jul 28 2016, 4:44 AM.

Details

Summary

ASSERT(exp, message)
Ensure that exp is non-zero. If it is zero, then exit the linker with an error
code, and print message.

Looks ASSERT is useful and used by some projects. I noticed it here:
https://searchcode.com/codesearch/view/42878166/

Diff Detail

Repository
rL LLVM

Event Timeline

grimar updated this revision to Diff 65911.Jul 28 2016, 4:44 AM
grimar retitled this revision from to [ELF] - Linkerscript: implemented ASSERT() keyword..
grimar updated this object.
grimar added reviewers: ruiu, rafael.
grimar added subscribers: llvm-commits, grimar, davide, evgeny777.
emaste added a subscriber: emaste.Jul 28 2016, 10:41 AM
ruiu edited edge metadata.Jul 28 2016, 12:38 PM

Last time we made a decision not to implement ASSERT, but now we have a good codebase to support arbitrary functions, it is probably time to do it. Thank you for doing this.

ELF/LinkerScript.cpp
909 ↗(On Diff #65911)

Is it true that ASSERT() returns the current value of "."?

test/ELF/linkerscript/linkerscript-assert.s
4 ↗(On Diff #65911)

I don't think we need this complex test case. This can just be something like

ASSERT(0, "fail");

and

ASSERT(1, "success");
grimar added inline comments.Jul 28 2016, 2:35 PM
ELF/LinkerScript.cpp
909 ↗(On Diff #65911)

Hmm I was sure that yes because linkerscript from link I provided contains:

/*
	. = ASSERT(_end <= 0x8000, "Setup too big!");
	. = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
	/* Necessary for the very-old-loader check to work... */
	. = ASSERT(__end_init <= 5*512, "init sections too big!");

at the end. And I relied on the fact that location counter should not be moved backward as
"location counter may not be moved backwards outside of an output section if so doing creates areas with overlapping LMAs."
(https://sourceware.org/binutils/docs-2.23/ld/Location-Counter.html)

But I just checked gold behavior and it seems it just returns the result of expression instead.
So it allows moving location counter backward to the begin of address space here since assert are placed at the end and
technically no overlapping happens.

I`ll change that then.

test/ELF/linkerscript/linkerscript-assert.s
4 ↗(On Diff #65911)

Ok + I suggest at least to check the return value of ASSERT as it probably can be used and
already had trobles above.

ruiu added inline comments.Jul 28 2016, 2:39 PM
test/ELF/linkerscript/linkerscript-assert.s
4 ↗(On Diff #65911)

You can add one more test

ASSERT(ASSERT(42, "success") == 42, "success");
grimar updated this revision to Diff 66102.Jul 29 2016, 2:51 AM
grimar edited edge metadata.
  • Addressed review comments.

I found there are 2 forms of ASSERT that can be used in scripts:

  1. Like common assert: ASSERT(1, "true")
  2. Like expression that assigns result to something: xxx = ASSERT(1, "true");

I updated the code to support first form as well.

ruiu added inline comments.Jul 29 2016, 9:13 AM
ELF/LinkerScript.cpp
366 ↗(On Diff #66102)

I didn't even look at other changes in this patch, but I think I can say the new check looks very weird. SymbolAssignment is for assignments. If it is not an assignment, you need to define a new type. Please don't give a new (obscure) meaning by defining a special case.

grimar added inline comments.Jul 29 2016, 9:16 AM
ELF/LinkerScript.cpp
366 ↗(On Diff #66102)

Ok. Actually I was thinking about it as about expression that calculates itself but assigns to nothing.
If you thing it should be another type, I`ll do that.

grimar added inline comments.Aug 2 2016, 2:50 AM
ELF/LinkerScript.cpp
366 ↗(On Diff #66102)

SymbolAssignment is for assignments. If it is not an assignment, you need to define a new type.

By the way, we treat PROVIDE as SymbolAssignment. I think it is also a command and not an assigment.

grimar updated this revision to Diff 66455.Aug 2 2016, 3:58 AM
  • Addressed review comments.
ELF/LinkerScript.cpp
366 ↗(On Diff #66102)

I reimplemented this. At first I was thinking about creating some generic class like MiscellaneousCommand.
But after looking at the lists of possible LS commands:
https://sourceware.org/binutils/docs/ld/Simple-Commands.html#Simple-Commands

I think that ASSERT is probably the only one we need to add into queue. All others seems to be easy to
proccess inplace (like we do with ENTRY, for example). So I ended up with AssertCommand.

ruiu added a comment.Aug 2 2016, 10:38 AM

Almost looking good, but looks like there is a bug.

ELF/LinkerScript.cpp
675–676 ↗(On Diff #66455)

Is this correct? I mean, you didn't consume the token "ASSERT", so readExpr() will read "ASSERT" as an expression, no?

grimar updated this revision to Diff 66628.Aug 3 2016, 2:01 AM
  • Addressed review comments.
ELF/LinkerScript.cpp
675–676 ↗(On Diff #66455)

Initially I did it to reuse new code from below:

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;
  };
}

But you right, it was not 100% correct as probably allowed things like
ASSERT(...) + 55;
And there is a better way to achieve the same. I changed that.

ruiu accepted this revision.Aug 3 2016, 11:06 AM
ruiu edited edge metadata.

LGTM

ELF/LinkerScript.cpp
1051–1052 ↗(On Diff #66628)

Move this above "ALIGN".

This revision is now accepted and ready to land.Aug 3 2016, 11:06 AM
This revision was automatically updated to reflect the committed changes.