This is an archive of the discontinued LLVM Phabricator instance.

[lld] [LinkerScript] Implement linker script expression evaluation
ClosedPublic

Authored by rafaelauler on Mar 8 2015, 6:40 PM.

Details

Summary

As suggested by Rui, I broke up the original patch in D7915 in two, separating
the part that implements the linker script expression evaluation.

The expression evaluation is needed when interpreting linker scripts, in order
to calculate the value for new symbols or to determine a new position to load
sections in memory. This patch extends Expression nodes from the linker script
AST with evaluation functions. It also contains a unit test.

Diff Detail

Event Timeline

rafaelauler updated this revision to Diff 21465.Mar 8 2015, 6:40 PM
rafaelauler retitled this revision from to [lld] [LinkerScript] Implement linker script expression evaluation.
rafaelauler updated this object.
rafaelauler edited the test plan for this revision. (Show Details)
rafaelauler added a subscriber: Unknown Object (MLST).
ruiu added inline comments.Mar 8 2015, 7:01 PM
lib/ReaderWriter/LinkerScript.cpp
545

Maybe you want to use find and compare the return value with end, so that you don't look up the table twice.

583

nit: return -childRes;

589

Remove this line. I believe llvm_unreachable has attribute((noreturn)), so no warning would be issued.

674

Ditto

704

Is it okay to compute both "then" and "else" clauses regardless of a condition value? In a normal programming language, we don't do that -- for example, if (true) {} else { 1 / 0; } doesn't fail.

shankarke added inline comments.
include/lld/ReaderWriter/ELFLinkingContext.h
304–306

do you want to add a boolean hasLinkerScript that checks the size and returns ?

include/lld/ReaderWriter/LinkerScript.h
366

you could replace this with a llvm::DenseMap<StringRef, int64_t> and use a common StringRefMappingInfo.

794–795

Use lld::range,once you replace it with range, you can remove the typedef for const_iterator.

lib/ReaderWriter/LinkerScript.cpp
582

Do you want to handle Unary::Plus ??

585

I thought linker script uses only a boolean value of a Unary Not, no ??

702

no need of else.

unittests/DriverTests/GnuLdDriverTest.cpp
262

Can we change SymbolAssignment::Normal to SymbolAssignment::Default ?

Looks like you are using the same SymboAssignment to name two different things, assignmentKind and assignmentVisibilty. I would recommend separating them.

Hi all,

Thank you for your fast replies. Comments inline.

include/lld/ReaderWriter/ELFLinkingContext.h
304–306

Well, I added this function just to make this patch self-contained and allow us to properly unit-test the evaluator. It gets deleted in the follow-up patch because script::Sema is introduced to manage Parser copies.

include/lld/ReaderWriter/LinkerScript.h
366

I used this type because that is what Clang uses for its symbol table, but added the comment to make it easier to refactor this later in favour of other data structures, if needed.

But If we're gonna use std::map<std::string, T>, I'd rather stick with llvm::StringMap, since it is available in the LLVM library :)

794–795

Thanks for the tip. Now that I'm thinking about this, there is also little reason to also use the typedef here, since we typically iterate through these elements with "auto", so we don't need to type the full name anyway. I used this mostly to keep code consistent with other classes and to make function signature cleaner. But if we're changing this, I'd rather do it in the follow-up patch, which introduces a whole lot more of iterators for accessing linker script AST nodes.

lib/ReaderWriter/LinkerScript.cpp
545

Thanks, will do.

582

I guess this is currently not supported by the parser. Pardon my ignorance, but what is the semantic for this?

583

Fixed

585

That would be the token "!", but currently Unary::Not comes from parsing "~" tokens. I will update the parser to recognize "!" as a unary operator in a separate patch.

589

Ok

702

Fixed

704

I previously thought that:

if (true) {} else { undefined_symbol + 1 }

should return an error, even though the else branch is not used. But now I see that this is just wrong, since, if we want to generate diagnostics for my example above, we should do this in the semantic analysis, not in the evaluator. I will fix this.

unittests/DriverTests/GnuLdDriverTest.cpp
262

Sure, I changed the names.

About separating the concept of visibility, I'll do it in a separate patch when appropriate, thanks for the heads up.

rafaelauler updated this revision to Diff 21483.Mar 9 2015, 6:31 AM

Addressed reviewers' concerns.

shankar.easwaran edited edge metadata.

LGTM

This revision is now accepted and ready to land.Mar 9 2015, 6:56 AM
ruiu accepted this revision.Mar 9 2015, 11:13 AM
ruiu edited edge metadata.

LGTM with this change.

include/lld/ReaderWriter/LinkerScript.h
794–795

Typedef is fine and preferred. I found lld::range is used in some places in LLD to "hide" actual types of return values. It on first sight seemed like a good idea, but it actually introduced a dependency to lld::range instead of to an actual type, adding an additional layer which doesn't do anything specific. Use of lld::range cannot be replaced with llvm::iterator_range in some cases because there is code assuming lld::range is a random access iterator (llvm::iterator_range isn't). I don't disagree that an abstraction like lld::range would be meaningful in some cases, but many existing use cases in LLD doesn't make much sense.

lib/ReaderWriter/LinkerScript.cpp
699

You can just return a return value of evalExpr.

if (conditional) {
  return _trueExpr->evalExpr(symbolTable);
return _falseExpr->evalExpr(symbolTable);
rafaelauler closed this revision.Mar 9 2015, 2:51 PM

Committed r231707.