I'm trying to understand how contracts look in terms of bytecode and struggling to do that just based on the yellow paper. In particular, consider the following empty contract:

pragma solidity ^0.4.17;

contract Simplest {

Using the Remix compiler, I'm able to compile into the following bytecode:


Which translates to the following op-codes:

PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x35 DUP1 PUSH1 0x1D PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 MSTORE8 LOG2 BLOCKHASH ISZERO 0xf8 DUP8 0xe1 0xdd SWAP16 0xbd 0x5e 0x5c 0xad 0xb3 SWAP8 0xbb 0x5f 0xb3 0x4e DUP11 0xab PUSH28 0x5782D9E28DFD4E986281002900000000000000000000000000000000

1) What does this represent? Is this meant to be the bytecode for the constructor function?

2) There are several sequences which don't make sense to me, in particular:

ISZERO 0xf8 DUP8 0xe1 0xdd SWAP16

Why are 0xf8, 0xe1, 0xdd following opcodes that don't take any arguments? What is their purpose?

3) Once the contract is compiled, where is the bytecode for the "functions" of the contract?

I suspect the 3 questions are quite linked hence asking them together.


What you've got in bytecode here is the contract's constructor / construction bytecode. When you create a contract, the constructor runs, handles any initial arguments or statements you make, and also "creates" the code of the contract.

The way this is done is through a return statement. The deployed contract code will be whatever the constructor returns. So the bytecode you posted will include the bytecode of the constructor, as well as the code of the deployed contract itself. It also includes a third section - some metadata (a Solidity feature). Breaking it down, here are the 3 distinct sections:

Constructor bytecode (basically a deployment script):


This translates to the following opcodes, which I've annotated a bit:

// Set free memory pointer (0x40) to 0x80
[1] PUSH1 0x80
[3] PUSH1 0x40
// Check msg.value
[6] DUP1
// If msg.value == 0, JUMP to 0x0F (15)
[9] PUSH1 0x0f
[10] JUMPI
// Otherwise, the next 3 instructions do: revert(0, 0)
[12] PUSH1 0x00
[13] DUP1
// Here's 0x0F, which has a corresponding JUMPDEST
[16] POP
// Now we need the constructor to set up the deployment bytecode:
// 0x35 is presumably the length of the bytecode to return
[18] PUSH1 0x35
[19] DUP1
// 0x1D is the location in the bytecode from which the CODECOPY starts (29)
[21] PUSH1 0x1d
// 0x00 is where the code is copied to, in memory
[23] PUSH1 0x00
// Now we have the bytecode of the contract in memory, starting at 0x00 (and 0x35 bytes long). We DUP1'd the length earlier, so we can just push 0x00 and RETURN. The RETURN opcode will return 0x35 bytes, starting at position 0x00 in memory.
[26] PUSH1 0x00
[28] STOP 
// A final STOP at 28 (0x1C) marks the end of the constructor bytecode. The code copied started at 0x1D, so the next chunk of bytecode will be the deployed code

And now here's the contract bytecode (with metadata at the end):


Again, translated to opcodes:

// Set free memory pointer (0x40) to 0x80
[30] PUSH1 0x80
[32] PUSH1 0x40
// The next 3 opcodes simply push 0 twice, then REVERT(0, 0)
[35] PUSH1 0x00
[36] DUP1
// And, a final STOP to mark the end of contract bytecode!
[38] STOP
// This next bit is confusing when translated directly from opcodes, because it's simply the metadata Solidity appends to the end of bytecode. It's not meant to be executed
[39] LOG1
[46] PUSH6 0x627a7a723058
[47] SHA3
[48] MSTORE8
[49] LOG2
[52] 'f8'(Unknown Opcode)
[53] DUP8
[54] 'e1'(Unknown Opcode)
[55] 'dd'(Unknown Opcode)
[56] SWAP16
[57] 'bd'(Unknown Opcode)
[58] '5e'(Unknown Opcode)
[59] '5c'(Unknown Opcode)
[60] 'ad'(Unknown Opcode)
[61] 'b3'(Unknown Opcode)
[62] SWAP8
[63] 'bb'(Unknown Opcode)
[64] '5f'(Unknown Opcode)
[65] 'b3'(Unknown Opcode)
[66] '4e'(Unknown Opcode)
[67] DUP11
[68] 'ab'(Unknown Opcode)

Here's more information on contract metadata: https://solidity.readthedocs.io/en/v0.4.24/metadata.html

So, to directly answer your questions:

  1. Yes, this is meant to be the constructor bytecode. Since the constructor needs to return the deployment bytecode, the constructor bytecode includes the deployment bytecode as well.

  2. The sequences to which you are referring are from the contract's metadata, and are not meant to be executed.

  3. The contract you compiled doesn't have any functions, so the entirety of the "runtime bytecode" is the 10-opcode section of the deployed bytecode, which sets the free memory pointer and immediately reverts. A typical contract with functions will do something slightly different -- it will grab the first 4 bytes of calldata (using CALLDATALOAD), and compare those against a series of function selectors. When it finds a match, it will JUMP to that function's position in the code. If no match is found, it executes the fallback function. If that doesn't exist, it reverts!

Hope that cleared it up! Feel free to ask more questions!

  • 2
    Are STOPs always used to mark end of contract code? Can a JUMPI statement reach past a STOP and in that case how would the EVM know which STOP designates constructor code vs. contract code? – Peteris Sep 13 '18 at 10:17
  • 2
    As far as I'm aware, one STOP marks the end of a constructor, and one marks the end of the contract bytecode (and start of the metadata). They're really just there for demarcation - you can absolutely JUMP past them. Nothing in the EVM will stop that! – Alexander Wade Sep 13 '18 at 11:49
  • Noob question, but why is the the free memory pointer set to 0x40 initially? And what is the rationally behind setting it specifically to 0x80 afterward? – Paul Razvan Berg Aug 30 '19 at 15:14

Your Answer

