-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
eof: Support relative jumps #15547
eof: Support relative jumps #15547
Conversation
Thank you for your contribution to the Solidity compiler! A team member will follow up shortly. If you haven't read our contributing guidelines and our review checklist before, please do it now, this makes the reviewing process and accepting your contribution smoother. If you have any questions or need our help, feel free to post them in the PR or talk to us directly on the #solidity-dev channel on Matrix. |
713beaa
to
3c9e0f8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did an initial pass through the PR (without the libevmasm optimizer changes yet) and so far did not find any substantial problems. There are a few small things to correct and some suggestions.
ef51b68
to
19f9469
Compare
b936bd0
to
3f08232
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two things are still not right: missing gas tier for RJUMP
and excluding 0x7fff
as a relative offset. Other than that, just a few missing asserts and cosmetic changes.
libevmasm/Assembly.cpp
Outdated
solAssert(tagPos != std::numeric_limits<size_t>::max(), "Reference to tag without position."); | ||
|
||
ptrdiff_t const relativeJumpOffset = static_cast<ptrdiff_t>(tagPos) - (static_cast<ptrdiff_t>(refPos) + 2); | ||
solRequire(relativeJumpOffset < 0x7FFF && relativeJumpOffset >= -0x8000, AssemblyException, "Relative jump too far"); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we should think what we're going to do when this happens in practice. Do we just refuse to generate code for functions that are too long?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, please also assert that the offset is not -1 or -2 since that would end up in the middle of the jump instruction itself.
Actually, it would be nice to have a more general sanity check that we're not landing in the middle of another multi-byte instruction as well, but I guess that one would be a bit complex so maybe not worth the effort. Having the offset generated from a tag should make this kind of mistake very unlikely anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could potentially take evmone (https://github.com/ethereum/evmone/blob/master/lib/evmone/eof.cpp#L887) verification code and adjust it to our case by adding proper reporting. It can be done after bytecode generation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good but it would be enough as a sanity check.
Still does not solve the issue of functions that are too long though. I guess that will just be a code generation error? If so, we'll need to find a way to point at the function that caused it. Errors without source location are a pain for users (we have a lot of complaints about that with StackTooDeep).
// Bytecode: ef00010100040200010010040000000080ffff6001e1000460205ff360015f52e0fff5 | ||
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP LT DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH1 0x1 RJUMPI 0x4 PUSH1 0x20 PUSH0 RETURN PUSH1 0x1 PUSH0 MSTORE RJUMP 0xFFF5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to eventually have a test type that makes verifying this on a bytecode level less tedious. For now I checked it by hand and it seems correct:
RJUMP 0xFFF5
jumps 3 bytes ahead and 11 back, which gives13 + 3 - 11 = 5 = tag_2
RJUMPI 0x4
jumps to2 + 3 + 4 = 9 = tag_1
00: PUSH1 0x1
02: RJUMPI 0x4
05: PUSH1 0x20 // tag_2
07: PUSH0
08: RETURN
09: PUSH1 0x1 // tag_1
11: PUSH0
12: MSTORE
13: RJUMP 0xFFF5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand it as a comment for the future or we can do something with this now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, for the future.
But your suggestion from #15547 (comment) to use validate_eof()
sounds like a good and easy solution. We should assert that somewhere.
4506bff
to
675680b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just needs some cleanup and then we can merge: there are some typos in function names and a few other minor things.
// Bytecode: ef00010100040200010010040000000080ffff6001e1000460205ff360015f52e0fff5 | ||
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP LT DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH1 0x1 RJUMPI 0x4 PUSH1 0x20 PUSH0 RETURN PUSH1 0x1 PUSH0 MSTORE RJUMP 0xFFF5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, for the future.
But your suggestion from #15547 (comment) to use validate_eof()
sounds like a good and easy solution. We should assert that somewhere.
libevmasm/SemanticInformation.cpp
Outdated
@@ -613,6 +621,7 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction) | |||
|
|||
bool SemanticInformation::invalidInViewFunctions(Instruction _instruction) | |||
{ | |||
// Relative jumps cannot jump out of the current code section of EOF so they are valid in view function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Relative jumps cannot jump out of the current code section of EOF so they are valid in view function. | |
// Relative jumps cannot jump out of the current code section of EOF so they are valid in view functions | |
// (under the assumption that every Solidity function actually gets its own code section). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. Missed this one
64a6aa1
to
eaab6b3
Compare
// /* "source":46:70 */ | ||
// rjumpi{tag_1} | ||
// /* "source":22:112 */ | ||
// tag_2: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rodiazet I just noticed an odd thing while reviewing #15550. RJUMPI
seems to always insert an extra tag that often goes unused. It did get used in the case you added here so this went unnoticed, but you can see it in objectCompiler/eof/functions.yul
in the CALLF
PR. And it's reproducible without functions as well:
test.yul
:
{
if calldataload(0) {
return(0, 0)
}
}
solc --strict-assembly test.yul --asm --debug-info none --experimental-eof-version 1 --evm-version prague
0x00
calldataload
rjumpi{tag_1}
tag_2:
stop
tag_1:
0x00
dup1
return
It does not happen with JUMPI
so it must be something introduced by this PR:
solc --strict-assembly test.yul --asm --debug-info none --evm-version prague
0x00
calldataload
tag_1
jumpi
stop
tag_1:
0x00
dup1
return
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's related to lack of optimizations for EOF. In this case PeepholeOptimizer
is disabled for EOF. For legacy tag_2
is removed by the UnreachableCode
optimizer step. I checked that for legacy the tag_2
is present in the code section 0
before optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok then. I didn't consider that it may be the optimizer's responsibility but it makes sense.
Depends on #15512Merged