Skip to content

Instantly share code, notes, and snippets.

@nolash
Last active September 6, 2020 21:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nolash/62e6c872ec126594359d20cbe26cd3aa to your computer and use it in GitHub Desktop.
Save nolash/62e6c872ec126594359d20cbe26cd3aa to your computer and use it in GitHub Desktop.
solidity contract disassembly interpretation

contract

pragma solidity ^0.4.11;

contract Simple {
	bytes32 public v;
	function set(bytes32 _v) {
		v = _v;
	}
}

interpretation of disassembly

  • opcodes have been inserted at line starts
  • goeth evm cmd compiler seems not to accept 0x values nor push# instructions, so values have been converted to decimal and instruction replaced with push
  • invalid opcode is not understood by go-eth evm cmd
///////////////////////////////////////
// PART 1
// contract creation part
// store 0x60 at 0x40+0x1f
// this is the memory storage offset
// see https://ethereum.stackexchange.com/a/2829/5711 for quick and simple explanation
60 push 96 // (0x60)
60 push 64 // (0x40)
52 mstore
// if there is eth sent with this transaction
// if not, jump to PART 2
34 callvalue
15 iszero
60 push 15 // (61 push2 0x000f)
57 jumpi
60 push 00
80 dup
// (not implemented in go-eth evm cmd)
// maybe see https://github.com/ethereum/go-ethereum/issues/14376
fd invalid 
5b jumpdest

///////////////////////////////////////
// PART 2
// copy 218 bytes from code pos 30 to mem pos 0
// this is presumably contract constructor?
5b jumpdest
60 push 218 // (0xda)
80 dup1
61 push 30 // (61 push2 0x001e), why is this push2?
60 push 0 
39 codecopy
// return 218 bytes from mem pos 0
60 push 00
f3 return
00 stop

///////////////////////////////////////
//
// WARNING!
// instruction byteaddresses from here on 
// are from the RUNTIME binary
//
///////////////////////////////////////

///////////////////////////////////////
// PART 3
// this is the actual contract
// the "runtime binary" starts here
60 push 96 (0x60)
60 push 64 (0x40)
52 mstore
// call calldata from pos 0
// this is function name digest
// divide it by 2^(8*29), which removes the trailing 0's
// then AND with all 1's (to make sure the length of the data is ok?)
60 push 00
35 calldataload
60 push 26959946667150639794667015087019630673637144422540572481103610249216 // (7c push29 0100000000000000000000000000000000000000000000000000000000)
90 swap1
04 div
60 push 4294967295 (63 push4 ffffffff)
16 and 
// if callvalue matches the "v()" function
// jump to PART 4
80 dup1
60 push 2083454138// (63 push4 0x7c2efcba)
14 eq
60 push 71 //(0x47)
57 jumpi
// if callvalue matches the set(bytes32) function
// jump to PART 6
80 dup1
60 push 3682631999 (63 push4 0xdb80813f)
14 eq
60 push 117 // (0x75)
57 jumpi
5b jumpdest
60 push 00
80 dup1
fd invalid

///////////////////////////////////////
// PART 4
// entrypoint for v()
// if any eth is sent with the call
// pass through and fail
5b jumpdest
34 callvalue
15 iszero
60 push 81 // (0x51)
57 jumpi
60 push 00
80 dup1
fd invalid 
// jump to PART 8
// the 0x57 is return jump address (PART 5)
5b jumpdest
60 push 87 // (0x57)
60 push 153 // (0x99)
56 jump

///////////////////////////////////////
// PART 5
// returns the v member we retrieved in PART 8
// retrieves the safe memory position from 0x40 (which is 0x60)
// stores the value there
// calculates the length of the data to be returned and offset
// returns
5b jumpdest
60 push 64 // (0x40)
51 mload
80 dup1
82 dup3
60 push 00
19 NOT
16 AND
60 push 00
19 NOT
16 AND
81 dup2
52 MSTORE
60 push 32 //(0x20)
01 add
91 swap2
50 pop
50 pop
60 push 64 //(0x40)
51 mload
80 dup1
91 swap2
03 sub
90 swap1
f3 return

///////////////////////////////////////
// PART 6
// entrypoint for set(byte32)
// if any eth is sent with the call
// pass through and fail
5b jumpdest 
34 callvalue
15 iszero
60 push 127 // (0x7f)
57 jumpi
60 push 00
80 dup1
fd invalid
// set return jump position after PART 9
// (151 is the position of PART 7)
5b jumpdest
60 push 151 // (0x97)
60 push 04
80 dup1
// get (32 bytes) calldata at pos 0x4
// which is after the function digest part
// thus our first and only argument
// todo: does the popped data serve any function here?
80 dup1
35 calldataload
60 push 00
19 not
16 and
90 swap1
60 push 32 (0x20)
01 add
90 swap1
91 swap2
90 swap1
50 pop
50 pop
// input value is now on top of stack
// jump to PART 9
60 push 159 //(0x9f)
56 jump

///////////////////////////////////////
// PART 7
// the set(bytes32) method stops here
5b jumpdest
00 stop

///////////////////////////////////////
// PART 8
// get the v member of contract
// retrieve stored value at 0
// then jump back to part 5
5b jumpdest
60 push 00
54 sload
// jump to PART 5
// (the dup2 copies the push 0x57 from the end of PART 4 to the stack top)
// after this jump the value of v will be on the top of the stack
81 dup2
56 jump

///////////////////////////////////////
// PART 9
// set the v member
// the input value is on top of stack
5b jumpdest
80 dup1
60 push 00
81 dup2
60 push 00
19 not
16 and
90 swap1
55 sstore
50 pop
5b jumpdest
// jump to PART 7
// (remix debugger says stack[0] here is 0x97)
50 pop
56 jump
00 stop

/////////////////////////
// PART 10
// the remaining bytecode is metadata
// see http://solidity.readthedocs.io/en/develop/miscellaneous.html#contract-metadata
// a165627a7a7230582042d3fc516aa5c0d6c9cf48399e78cfae9270c79071086c71049c2fb3b23603640029  
// cbor encoing of swarm hash 42d3fc516aa5c0d6c9cf48399e78cfae9270c79071086c71049c2fb3b2360364

bytecode and disassembly of contract binary (go-eth evm cmd)

6060604052341561000f57600080fd5b5b60da8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637c2efcba146047578063db80813f146075575b600080fd5b3415605157600080fd5b60576099565b60405180826000191660001916815260200191505060405180910390f35b3415607f57600080fd5b6097600480803560001916906020019091905050609f565b005b60005481565b80600081600019169055505b505600a165627a7a7230582042d3fc516aa5c0d6c9cf48399e78cfae9270c79071086c71049c2fb3b23603640029
000000: PUSH1 0x60
000002: PUSH1 0x40
000004: MSTORE
000005: CALLVALUE
000006: ISZERO
000007: PUSH2 0x000f
000010: JUMPI
000011: PUSH1 0x00
000013: DUP1
000014: Missing opcode 0xfd
000015: JUMPDEST
000016: JUMPDEST
000017: PUSH1 0xda
000019: DUP1
000020: PUSH2 0x001e
000023: PUSH1 0x00
000025: CODECOPY
000026: PUSH1 0x00
000028: RETURN
000029: STOP
000030: PUSH1 0x60
000032: PUSH1 0x40
000034: MSTORE
000035: PUSH1 0x00
000037: CALLDATALOAD
000038: PUSH29 0x0100000000000000000000000000000000000000000000000000000000
000068: SWAP1
000069: DIV
000070: PUSH4 0xffffffff
000075: AND
000076: DUP1
000077: PUSH4 0x7c2efcba
000082: EQ
000083: PUSH1 0x47
000085: JUMPI
000086: DUP1
000087: PUSH4 0xdb80813f
000092: EQ
000093: PUSH1 0x75
000095: JUMPI
000096: JUMPDEST
000097: PUSH1 0x00
000099: DUP1
000100: Missing opcode 0xfd
000101: JUMPDEST
000102: CALLVALUE
000103: ISZERO
000104: PUSH1 0x51
000106: JUMPI
000107: PUSH1 0x00
000109: DUP1
000110: Missing opcode 0xfd
000111: JUMPDEST
000112: PUSH1 0x57
000114: PUSH1 0x99
000116: JUMP
000117: JUMPDEST
000118: PUSH1 0x40
000120: MLOAD
000121: DUP1
000122: DUP3
000123: PUSH1 0x00
000125: NOT
000126: AND
000127: PUSH1 0x00
000129: NOT
000130: AND
000131: DUP2
000132: MSTORE
000133: PUSH1 0x20
000135: ADD
000136: SWAP2
000137: POP
000138: POP
000139: PUSH1 0x40
000141: MLOAD
000142: DUP1
000143: SWAP2
000144: SUB
000145: SWAP1
000146: RETURN
000147: JUMPDEST
000148: CALLVALUE
000149: ISZERO
000150: PUSH1 0x7f
000152: JUMPI
000153: PUSH1 0x00
000155: DUP1
000156: Missing opcode 0xfd
000157: JUMPDEST
000158: PUSH1 0x97
000160: PUSH1 0x04
000162: DUP1
000163: DUP1
000164: CALLDATALOAD
000165: PUSH1 0x00
000167: NOT
000168: AND
000169: SWAP1
000170: PUSH1 0x20
000172: ADD
000173: SWAP1
000174: SWAP2
000175: SWAP1
000176: POP
000177: POP
000178: PUSH1 0x9f
000180: JUMP
000181: JUMPDEST
000182: STOP
000183: JUMPDEST
000184: PUSH1 0x00
000186: SLOAD
000187: DUP2
000188: JUMP
000189: JUMPDEST
000190: DUP1
000191: PUSH1 0x00
000193: DUP2
000194: PUSH1 0x00
000196: NOT
000197: AND
000198: SWAP1
000199: SSTORE
000200: POP
000201: JUMPDEST
000202: POP
000203: JUMP
000204: STOP
000205: LOG1
000206: PUSH6 0x627a7a723058
000213: SHA3
000214: TIMESTAMP
000215: Missing opcode 0xd3
000216: Missing opcode 0xfc
000217: MLOAD
000218: PUSH11 0xa5c0d6c9cf48399e78cfae
000230: SWAP3
(incomplete push instruction at 000231)

bytecode and disassembly of runtime binary (go-eth evm cmd)

60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637c2efcba146047578063db80813f146075575b600080fd5b3415605157600080fd5b60576099565b60405180826000191660001916815260200191505060405180910390f35b3415607f57600080fd5b6097600480803560001916906020019091905050609f565b005b60005481565b80600081600019169055505b505600a165627a7a7230582042d3fc516aa5c0d6c9cf48399e78cfae9270c79071086c71049c2fb3b23603640029
000000: PUSH1 0x60
000002: PUSH1 0x40
000004: MSTORE
000005: PUSH1 0x00
000007: CALLDATALOAD
000008: PUSH29 0x0100000000000000000000000000000000000000000000000000000000
000038: SWAP1
000039: DIV
000040: PUSH4 0xffffffff
000045: AND
000046: DUP1
000047: PUSH4 0x7c2efcba
000052: EQ
000053: PUSH1 0x47
000055: JUMPI
000056: DUP1
000057: PUSH4 0xdb80813f
000062: EQ
000063: PUSH1 0x75
000065: JUMPI
000066: JUMPDEST
000067: PUSH1 0x00
000069: DUP1
000070: Missing opcode 0xfd
000071: JUMPDEST
000072: CALLVALUE
000073: ISZERO
000074: PUSH1 0x51
000076: JUMPI
000077: PUSH1 0x00
000079: DUP1
000080: Missing opcode 0xfd
000081: JUMPDEST
000082: PUSH1 0x57
000084: PUSH1 0x99
000086: JUMP
000087: JUMPDEST
000088: PUSH1 0x40
000090: MLOAD
000091: DUP1
000092: DUP3
000093: PUSH1 0x00
000095: NOT
000096: AND
000097: PUSH1 0x00
000099: NOT
000100: AND
000101: DUP2
000102: MSTORE
000103: PUSH1 0x20
000105: ADD
000106: SWAP2
000107: POP
000108: POP
000109: PUSH1 0x40
000111: MLOAD
000112: DUP1
000113: SWAP2
000114: SUB
000115: SWAP1
000116: RETURN
000117: JUMPDEST
000118: CALLVALUE
000119: ISZERO
000120: PUSH1 0x7f
000122: JUMPI
000123: PUSH1 0x00
000125: DUP1
000126: Missing opcode 0xfd
000127: JUMPDEST
000128: PUSH1 0x97
000130: PUSH1 0x04
000132: DUP1
000133: DUP1
000134: CALLDATALOAD
000135: PUSH1 0x00
000137: NOT
000138: AND
000139: SWAP1
000140: PUSH1 0x20
000142: ADD
000143: SWAP1
000144: SWAP2
000145: SWAP1
000146: POP
000147: POP
000148: PUSH1 0x9f
000150: JUMP
000151: JUMPDEST
000152: STOP
000153: JUMPDEST
000154: PUSH1 0x00
000156: SLOAD
000157: DUP2
000158: JUMP
000159: JUMPDEST
000160: DUP1
000161: PUSH1 0x00
000163: DUP2
000164: PUSH1 0x00
000166: NOT
000167: AND
000168: SWAP1
000169: SSTORE
000170: POP
000171: JUMPDEST
000172: POP
000173: JUMP
000174: STOP
000175: LOG1
000176: PUSH6 0x627a7a723058
000183: SHA3
000184: TIMESTAMP
000185: Missing opcode 0xd3
000186: Missing opcode 0xfc
000187: MLOAD
000188: PUSH11 0xa5c0d6c9cf48399e78cfae
000200: SWAP3
(incomplete push instruction at 201)

arch

  • remix: 0.4.14+commit.c2215d46.Emscripten.clang
  • evm: 1.7.0-unstable (git commit 3d32690b)
  • solc: 0.4.14-develop.2017.7.27+commit.16ca1eea.Linux.g++
  • gcc/g++: 7.1.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment