Skip to content

Commit

Permalink
eof: Implement stack height calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
rodiazet committed Nov 29, 2024
1 parent 3a4ffc3 commit 9b19cc7
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 16 deletions.
82 changes: 80 additions & 2 deletions libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <fstream>
#include <limits>
#include <iterator>
#include <stack>

using namespace solidity;
using namespace solidity::evmasm;
Expand Down Expand Up @@ -971,6 +972,84 @@ void appendBigEndianUint16(bytes& _dest, ValueT _value)
assertThrow(_value <= 0xFFFF, AssemblyException, "");
appendBigEndian(_dest, 2, static_cast<size_t>(_value));
}

uint16_t calculateMaxStackHeight(AssemblyItems const& _items, uint16_t _args)
{
static auto constexpr UNVISITED = std::numeric_limits<size_t>::max();

solAssert(!_items.empty());
uint16_t maxStackHeight = _args;
std::stack<size_t> worklist;
std::vector<size_t> stackHeights(_items.size(), UNVISITED);

// Init first item stack height to number of inputs to the code section
// stackHeights stores stack height for an item before the item execution
stackHeights[0] = _args;
// Push first item index to the worklist
worklist.push(0u);
while (!worklist.empty())
{
size_t idx = worklist.top();
worklist.pop();
AssemblyItem const& item = _items[idx];
size_t stackHeightChange = item.deposit();
size_t stackHeight = stackHeights[idx];
solAssert(stackHeight != UNVISITED);

std::vector<size_t> successors;

// Add next instruction to successors for non-changing control flow instructions
if (!(item.hasInstruction() && SemanticInformation::terminatesControlFlow(item.instruction())) &&
item.type() != RelativeJump &&
item.type() != RetF &&
item.type() != ReturnContract &&
item.type() != JumpF
)
{
solAssert(idx < _items.size() - 1, "No terminating instruction.");
successors.emplace_back(idx + 1);
}

// Add jumps destinations to successors
if (item.type() == RelativeJump || item.type() == ConditionalRelativeJump)
{
auto const it = std::find(_items.begin(), _items.end(), item.tag());
solAssert(it != _items.end(), "Tag not found.");
successors.emplace_back(static_cast<size_t>(std::distance(_items.begin(), it)));
}

solAssert(stackHeight + stackHeightChange <= std::numeric_limits<uint16_t>::max(), "Invalid stack height");
maxStackHeight = std::max(maxStackHeight, static_cast<uint16_t>(stackHeight + stackHeightChange));
stackHeight += stackHeightChange;

// Set stack height for all instruction successors
for (size_t s: successors)
{
solAssert(s < stackHeights.size());
// Set stack height for newly visited
if (stackHeights[s] == UNVISITED)
{
stackHeights[s] = stackHeight;
worklist.push(s);
}
else
{
solAssert(s < stackHeights.size());
// For backward jump successor stack height must be equal
if (s < idx)
solAssert(stackHeights[s] == stackHeight, "Stack height mismatch.");

// If successor stack height is smaller update it and recalculate
if (stackHeight > stackHeights[s])
{
stackHeights[s] = stackHeight;
worklist.push(s);
}
}
}
}
return maxStackHeight;
}
}

std::tuple<bytes, std::vector<size_t>, size_t> Assembly::createEOFHeader(std::set<ContainerID> const& _referencedSubIds) const
Expand Down Expand Up @@ -1015,8 +1094,7 @@ std::tuple<bytes, std::vector<size_t>, size_t> Assembly::createEOFHeader(std::se
{
retBytecode.push_back(codeSection.inputs);
retBytecode.push_back(codeSection.outputs);
// TODO: Add stack height calculation
appendBigEndianUint16(retBytecode, 0xFFFFu);
appendBigEndianUint16(retBytecode, calculateMaxStackHeight(codeSection.items, codeSection.inputs));
}

return {retBytecode, codeSectionSizePositions, dataSectionSizePosition};
Expand Down
2 changes: 1 addition & 1 deletion test/cmdlineTests/strict_asm_eof_container_prague/output
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ object "object" {


Binary representation:
ef0001010004020001001503000200370037040000000080ffff5f808080ec005f525f808080ec0160205260405ff3ef00010100040200010004030001001b040000000080ffff5f80ee00ef00010100040200010008040000000080ffff60015f5260205ffdef00010100040200010004030001001b040000000080ffff5f80ee00ef00010100040200010008040000000080ffff60205f5260205ffd
ef000101000402000100150300020037003704000000008000045f808080ec005f525f808080ec0160205260405ff3ef00010100040200010004030001001b04000000008000025f80ee00ef00010100040200010008040000000080000260015f5260205ffdef00010100040200010004030001001b04000000008000025f80ee00ef00010100040200010008040000000080000260205f5260205ffd

Text representation:
0x00
Expand Down
2 changes: 1 addition & 1 deletion test/cmdlineTests/strict_asm_eof_dataloadn_prague/output
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ object "a" {


Binary representation:
ef0001010004020001000904002d000080ffffd1000d5f5260205ff348656c6c6f2c20576f726c6421
ef0001010004020001000904002d0000800002d1000d5f5260205ff348656c6c6f2c20576f726c6421

Text representation:
auxdataloadn{0}
Expand Down
4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/256_subcontainers.yul

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/creation_with_immutables.yul
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,6 @@ object "a" {
// return
// }
// }
// Bytecode: ef0001010004020001000c030001008704000d000080ffff5f808080ec005f5260205ff3ef0001010004020001004c0300010023040000000080ffff7f11223344556677889900112233445566778899001122334455667788990011225f527f112233445566778899001122334455667788990011223344556677889900112260205260405fee00ef00010100040200010010040040000080ffffd10000d10020905f5260205260405ff348656c6c6f2c20576f726c6421
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0xC SUB STOP ADD STOP DUP8 DIV STOP 0xD STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH0 DUP1 DUP1 DUP1 EOFCREATE 0x0 PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0x4C SUB STOP ADD STOP 0x23 DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH0 MSTORE PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH1 0x20 MSTORE PUSH1 0x40 PUSH0 RETURNCONTRACT 0x0 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP LT DIV STOP BLOCKHASH STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT DATALOADN 0x0 DATALOADN 0x20 SWAP1 PUSH0 MSTORE PUSH1 0x20 MSTORE PUSH1 0x40 PUSH0 RETURN BASEFEE PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// Bytecode: ef0001010004020001000c030001008704000d00008000045f808080ec005f5260205ff3ef0001010004020001004c030001002304000000008000027f11223344556677889900112233445566778899001122334455667788990011225f527f112233445566778899001122334455667788990011223344556677889900112260205260405fee00ef000101000402000100100400400000800003d10000d10020905f5260205260405ff348656c6c6f2c20576f726c6421
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0xC SUB STOP ADD STOP DUP8 DIV STOP 0xD STOP STOP DUP1 STOP DIV PUSH0 DUP1 DUP1 DUP1 EOFCREATE 0x0 PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0x4C SUB STOP ADD STOP 0x23 DIV STOP STOP STOP STOP DUP1 STOP MUL PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH0 MSTORE PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH1 0x20 MSTORE PUSH1 0x40 PUSH0 RETURNCONTRACT 0x0 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP LT DIV STOP BLOCKHASH STOP STOP DUP1 STOP SUB DATALOADN 0x0 DATALOADN 0x20 SWAP1 PUSH0 MSTORE PUSH1 0x20 MSTORE PUSH1 0x40 PUSH0 RETURN BASEFEE PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// SourceMappings: 80:1:0:-:0;56:26;;;;53:1;46:37;106:2;103:1;96:13
4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/dataloadn.yul
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ object "a" {
// return
// stop
// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421
// Bytecode: ef0001010004020001000904002d000080ffffd1000d5f5260205ff348656c6c6f2c20576f726c6421
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP MULMOD DIV STOP 0x2D STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT DATALOADN 0xD PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN BASEFEE PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// Bytecode: ef0001010004020001000904002d0000800002d1000d5f5260205ff348656c6c6f2c20576f726c6421
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP MULMOD DIV STOP 0x2D STOP STOP DUP1 STOP MUL DATALOADN 0xD PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN BASEFEE PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// SourceMappings: 56:15:0:-:0;53:1;46:26;95:2;92:1;85:13
4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/functions.yul
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,6 @@ object "a" {
// dup1
// revert
// }
// Bytecode: ef000101000c020003001400090003040000000080ffff0101ffff0080ffff5f35e300015f52602035e1000460205ff3e50002e100036063e46005e45f80fd
// Opcodes: 0xEF STOP ADD ADD STOP 0xC MUL STOP SUB STOP EQ STOP MULMOD STOP SUB DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT ADD ADD SELFDESTRUCT SELFDESTRUCT STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH0 CALLDATALOAD CALLF 0x1 PUSH0 MSTORE PUSH1 0x20 CALLDATALOAD RJUMPI 0x4 PUSH1 0x20 PUSH0 RETURN JUMPF 0x2 RJUMPI 0x3 PUSH1 0x63 RETF PUSH1 0x5 RETF PUSH0 DUP1 REVERT
// Bytecode: ef000101000c020003001400090003040000000080000201010001008000025f35e300015f52602035e1000460205ff3e50002e100036063e46005e45f80fd
// Opcodes: 0xEF STOP ADD ADD STOP 0xC MUL STOP SUB STOP EQ STOP MULMOD STOP SUB DIV STOP STOP STOP STOP DUP1 STOP MUL ADD ADD STOP ADD STOP DUP1 STOP MUL PUSH0 CALLDATALOAD CALLF 0x1 PUSH0 MSTORE PUSH1 0x20 CALLDATALOAD RJUMPI 0x4 PUSH1 0x20 PUSH0 RETURN JUMPF 0x2 RJUMPI 0x3 PUSH1 0x63 RETF PUSH1 0x5 RETF PUSH0 DUP1 REVERT
// SourceMappings: 74:1:0:-:0;61:15;56:21::i;53:1::-;46:32;107:2;94:16;91:37;22:364;151:2;148:1;141:13;111:17;113:13::i217:77:0:-:0;203:121;312:2;173:151::o;234:60::-;257:1;275:5::o376:1:0:-:0;366:12;
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,6 @@ object "a" {
// /* "source":421:649 */
// stop
// }
// Bytecode: ef0001010004020001000c030001005b040000000080ffff5f808080ec005f5260205ff3ef00010100040200010048040000000080ffff7f11223344556677889900112233445566778899001122334455667788990011225f527f112233445566778899001122334455667788990011223344556677889900112260205200
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0xC SUB STOP ADD STOP JUMPDEST DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH0 DUP1 DUP1 DUP1 EOFCREATE 0x0 PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP BASEFEE DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH0 MSTORE PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH1 0x20 MSTORE STOP
// Bytecode: ef0001010004020001000c030001005b04000000008000045f808080ec005f5260205ff3ef0001010004020001004804000000008000027f11223344556677889900112233445566778899001122334455667788990011225f527f112233445566778899001122334455667788990011223344556677889900112260205200
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0xC SUB STOP ADD STOP JUMPDEST DIV STOP STOP STOP STOP DUP1 STOP DIV PUSH0 DUP1 DUP1 DUP1 EOFCREATE 0x0 PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP BASEFEE DIV STOP STOP STOP STOP DUP1 STOP MUL PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH0 MSTORE PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH1 0x20 MSTORE STOP
// SourceMappings: 80:1:0:-:0;56:26;;;;53:1;46:37;106:2;103:1;96:13
4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/rjumps.yul
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ object "a" {
// mstore
// /* "source":54:70 */
// rjump{tag_2}
// 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
// Bytecode: ef0001010004020001001004000000008000026001e1000460205ff360015f52e0fff5
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP LT DIV STOP STOP STOP STOP DUP1 STOP MUL PUSH1 0x1 RJUMPI 0x4 PUSH1 0x20 PUSH0 RETURN PUSH1 0x1 PUSH0 MSTORE RJUMP 0xFFF5
// SourceMappings: 49:4:0:-:0;46:24;22:90;93:2;90:1;83:13;54:16;66:1;63;56:12;54:16

0 comments on commit 9b19cc7

Please sign in to comment.