Last active
April 6, 2019 03:22
-
-
Save charles-cooper/8b5f4f94bbbefcdd00fea679d9dceba4 to your computer and use it in GitHub Desktop.
Use solidity's assembler for fun and profit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ cat foo.ir | |
IR: | |
/******************************************************* | |
* WARNING * | |
* Solidity to Yul compilation is still EXPERIMENTAL * | |
* It can result in LOSS OF FUNDS or worse * | |
* !USE AT YOUR OWN RISK! * | |
*******************************************************/ | |
object "X_17" { | |
code { | |
mstore(64, 128) | |
codecopy(0, dataoffset("X_17_deployed"), datasize("X_17_deployed")) | |
return(0, datasize("X_17_deployed")) | |
} | |
object "X_17_deployed" { | |
code { | |
mstore(64, 128) | |
if iszero(lt(calldatasize(), 4)) | |
{ | |
let selector := shift_right_224_unsigned(calldataload(0)) | |
switch selector | |
case 0xc2985578 | |
{ | |
// foo() | |
if callvalue() { revert(0, 0) } | |
abi_decode_tuple_(4, calldatasize()) | |
let ret_0 := fun_8_foo() | |
let memPos := allocateMemory(0) | |
let memEnd := abi_encode_tuple_t_uint256__to_t_uint256__fromStack(memPos , ret_0) | |
return(memPos, sub(memEnd, memPos)) | |
} | |
case 0xfebb0f7e | |
{ | |
// bar() | |
if callvalue() { revert(0, 0) } | |
abi_decode_tuple_(4, calldatasize()) | |
let ret_0 := fun_16_bar() | |
let memPos := allocateMemory(0) | |
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) | |
return(memPos, sub(memEnd, memPos)) | |
} | |
default {} | |
} | |
revert(0, 0) | |
function abi_decode_tuple_(headStart, dataEnd) { | |
if slt(sub(dataEnd, headStart), 0) { revert(0, 0) } | |
} | |
function abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack(value, pos) -> end { | |
let length := array_length_t_string_memory_ptr(value) | |
pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) | |
copy_memory_to_memory(add(value, 0x20), pos, length) | |
end := add(pos, round_up_to_mul_of_32(length)) | |
} | |
function abi_encode_t_uint256_to_t_uint256_fromStack(value, pos) { | |
mstore(pos, cleanup_t_uint256(value)) | |
} | |
function abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(headStart , value0) -> tail { | |
tail := add(headStart, 32) | |
mstore(add(headStart, 0), sub(tail, headStart)) | |
tail := abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack(value0, tail) | |
} | |
function abi_encode_tuple_t_uint256__to_t_uint256__fromStack(headStart , value0) -> tail { | |
tail := add(headStart, 32) | |
abi_encode_t_uint256_to_t_uint256_fromStack(value0, add(headStart, 0)) | |
} | |
function allocateMemory(size) -> memPtr { | |
memPtr := mload(64) | |
let newFreePtr := add(memPtr, size) | |
// protect against overflow | |
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } | |
mstore(64, newFreePtr) | |
} | |
function array_length_t_string_memory_ptr(value) -> length { | |
length := mload(value) | |
} | |
function array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) -> updated_pos { | |
mstore(pos, length) | |
updated_pos := add(pos, 0x20) | |
} | |
function cleanup_t_uint256(value) -> cleaned { | |
cleaned := value | |
} | |
function copy_memory_to_memory(src, dst, length) { | |
let i := 0 | |
for { } lt(i, length) { i := add(i, 32) } | |
{ | |
mstore(add(dst, i), mload(add(src, i))) | |
} | |
if gt(i, length) | |
{ | |
// clear end | |
mstore(add(dst, length), 0) | |
} | |
} | |
function fun_16_bar() -> vloc__11 {}function fun_8_foo() -> vloc__3 {} | |
function round_up_to_mul_of_32(value) -> result { | |
result := and(add(value, 31), not(31)) | |
} | |
function shift_right_224_unsigned(value) -> newValue { | |
newValue := shr(224, value) | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// compile me with solc --asm | |
contract X { | |
function foo() external returns (uint256) { | |
return 0x7777; | |
} | |
/* | |
function bar() external returns (string memory) { | |
return "this is a really long string that is longer than 32 bytes"; | |
} | |
*/ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
foo.sol:1:1: Warning: Source file does not specify required compiler version! Consider adding "pragma solidity ^0.5.7;" | |
contract X { | |
^ (Relevant source part starts here and spans across multiple lines). | |
foo.sol:2:3: Warning: Function state mutability can be restricted to pure | |
function foo() external returns (uint256) { | |
^ (Relevant source part starts here and spans across multiple lines). | |
======= foo.sol:X ======= | |
EVM assembly: | |
/* "foo.sol":0:220 contract X {... */ | |
mstore(0x40, 0x80) | |
callvalue | |
/* "--CODEGEN--":8:17 */ | |
dup1 | |
/* "--CODEGEN--":5:7 */ | |
iszero | |
tag_1 | |
jumpi | |
/* "--CODEGEN--":30:31 */ | |
0x00 | |
/* "--CODEGEN--":27:28 */ | |
dup1 | |
/* "--CODEGEN--":20:32 */ | |
revert | |
/* "--CODEGEN--":5:7 */ | |
tag_1: | |
/* "foo.sol":0:220 contract X {... */ | |
pop | |
dataSize(sub_0) | |
dup1 | |
dataOffset(sub_0) | |
0x00 | |
codecopy | |
0x00 | |
return | |
stop | |
sub_0: assembly { | |
/* "foo.sol":0:220 contract X {... */ | |
mstore(0x40, 0x80) | |
callvalue | |
/* "--CODEGEN--":8:17 */ | |
dup1 | |
/* "--CODEGEN--":5:7 */ | |
iszero | |
tag_1 | |
jumpi | |
/* "--CODEGEN--":30:31 */ | |
0x00 | |
/* "--CODEGEN--":27:28 */ | |
dup1 | |
/* "--CODEGEN--":20:32 */ | |
revert | |
/* "--CODEGEN--":5:7 */ | |
tag_1: | |
/* "foo.sol":0:220 contract X {... */ | |
pop | |
jumpi(tag_2, lt(calldatasize, 0x04)) | |
shr(0xe0, calldataload(0x00)) | |
dup1 | |
0xc2985578 | |
eq | |
tag_3 | |
jumpi | |
tag_2: | |
0x00 | |
dup1 | |
revert | |
/* "foo.sol":15:81 function foo() external returns (uint256) {... */ | |
tag_3: | |
tag_4 | |
tag_5 | |
jump // in | |
tag_4: | |
mload(0x40) | |
dup1 | |
dup3 | |
dup2 | |
mstore | |
0x20 | |
add | |
swap2 | |
pop | |
pop | |
mload(0x40) | |
dup1 | |
swap2 | |
sub | |
swap1 | |
return | |
tag_5: | |
/* "foo.sol":48:55 uint256 */ | |
0x00 | |
/* "foo.sol":70:76 0x7777 */ | |
0x7777 | |
/* "foo.sol":63:76 return 0x7777 */ | |
swap1 | |
pop | |
/* "foo.sol":15:81 function foo() external returns (uint256) {... */ | |
swap1 | |
jump // out | |
auxdata: 0xa165627a7a7230582000d23883a175630e4f81d9c4f025269a9921ce68a6668f8e16e49e57eec60c130029 | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* compile me with solc --assemble */ | |
// REMOVED | |
// sub_0: assembly { | |
// ADDED | |
{ | |
/* add any code here */ | |
/* "foo.sol":0:220 contract X {... */ | |
mstore(0x40, 0x80) | |
callvalue | |
/* "--CODEGEN--":8:17 */ | |
dup1 | |
/* "--CODEGEN--":5:7 */ | |
iszero | |
tag_1 | |
jumpi | |
/* "--CODEGEN--":30:31 */ | |
0x00 | |
/* "--CODEGEN--":27:28 */ | |
dup1 | |
/* "--CODEGEN--":20:32 */ | |
revert | |
/* "--CODEGEN--":5:7 */ | |
tag_1: | |
/* "foo.sol":0:220 contract X {... */ | |
pop | |
jumpi(tag_2, lt(calldatasize, 0x04)) | |
shr(0xe0, calldataload(0x00)) | |
dup1 | |
0xc2985578 | |
eq | |
tag_3 | |
jumpi | |
tag_2: | |
0x00 | |
dup1 | |
revert | |
/* "foo.sol":15:81 function foo() external returns (uint256) {... */ | |
tag_3: | |
tag_4 | |
tag_5 | |
jump // in | |
tag_4: | |
mload(0x40) | |
dup1 | |
dup3 | |
dup2 | |
mstore | |
0x20 | |
add | |
swap2 | |
pop | |
pop | |
mload(0x40) | |
dup1 | |
swap2 | |
sub | |
swap1 | |
return | |
tag_5: | |
/* "foo.sol":48:55 uint256 */ | |
0x00 | |
/* "foo.sol":70:76 0x7777 */ | |
0x7777 | |
/* "foo.sol":63:76 return 0x7777 */ | |
swap1 | |
pop | |
/* "foo.sol":15:81 function foo() external returns (uint256) {... */ | |
swap1 | |
jump // out | |
// ADDED | |
pop | |
// REMOVED | |
// auxdata: 0xa165627a7a7230582000d23883a175630e4f81d9c4f025269a9921ce68a6668f8e16e49e57eec60c130029 | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
======= runtime.asm (EVM) ======= | |
Pretty printed source: | |
object "object" { | |
code { | |
mstore(0x40, 0x80) | |
callvalue | |
dup1 | |
iszero | |
tag_1 | |
jumpi | |
0x00 | |
dup1 | |
revert | |
tag_1: | |
pop | |
jumpi(tag_2, lt(calldatasize(), 0x04)) | |
shr(0xe0, calldataload(0x00)) | |
dup1 | |
0xc2985578 | |
eq | |
tag_3 | |
jumpi | |
tag_2: | |
0x00 | |
dup1 | |
revert | |
tag_3: | |
tag_4 | |
tag_5 | |
jump | |
tag_4: | |
mload(0x40) | |
dup1 | |
dup3 | |
dup2 | |
mstore | |
0x20 | |
add | |
swap2 | |
pop | |
pop | |
mload(0x40) | |
dup1 | |
swap2 | |
sub | |
swap1 | |
return | |
tag_5: | |
0x00 | |
0x7777 | |
swap1 | |
pop | |
swap1 | |
jump | |
pop | |
} | |
} | |
Binary representation: | |
6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b60006177779050905650 | |
Text representation: | |
/* "runtime.asm":135:139 */ | |
0x80 | |
/* "runtime.asm":129:133 */ | |
0x40 | |
/* "runtime.asm":122:140 */ | |
mstore | |
/* "runtime.asm":147:156 */ | |
callvalue | |
/* "runtime.asm":198:202 */ | |
dup1 | |
/* "runtime.asm":243:249 */ | |
iszero | |
/* "runtime.asm":256:261 */ | |
tag_1 | |
/* "runtime.asm":268:273 */ | |
jumpi | |
/* "runtime.asm":316:320 */ | |
0x00 | |
/* "runtime.asm":363:367 */ | |
dup1 | |
/* "runtime.asm":410:416 */ | |
revert | |
/* "runtime.asm":455:460 */ | |
tag_1: | |
/* "runtime.asm":515:518 */ | |
pop | |
/* "runtime.asm":555:559 */ | |
0x04 | |
/* "runtime.asm":541:553 */ | |
calldatasize | |
/* "runtime.asm":538:560 */ | |
lt | |
/* "runtime.asm":531:536 */ | |
tag_2 | |
/* "runtime.asm":525:561 */ | |
jumpi | |
/* "runtime.asm":591:595 */ | |
0x00 | |
/* "runtime.asm":578:596 */ | |
calldataload | |
/* "runtime.asm":572:576 */ | |
0xe0 | |
/* "runtime.asm":568:597 */ | |
shr | |
/* "runtime.asm":604:608 */ | |
dup1 | |
/* "runtime.asm":615:625 */ | |
0xc2985578 | |
/* "runtime.asm":632:634 */ | |
eq | |
/* "runtime.asm":641:646 */ | |
tag_3 | |
/* "runtime.asm":653:658 */ | |
jumpi | |
/* "runtime.asm":663:668 */ | |
tag_2: | |
/* "runtime.asm":676:680 */ | |
0x00 | |
/* "runtime.asm":687:691 */ | |
dup1 | |
/* "runtime.asm":698:704 */ | |
revert | |
/* "runtime.asm":787:792 */ | |
tag_3: | |
/* "runtime.asm":800:805 */ | |
tag_4 | |
/* "runtime.asm":812:817 */ | |
tag_5 | |
/* "runtime.asm":824:828 */ | |
jump | |
/* "runtime.asm":839:844 */ | |
tag_4: | |
/* "runtime.asm":858:862 */ | |
0x40 | |
/* "runtime.asm":852:863 */ | |
mload | |
/* "runtime.asm":870:874 */ | |
dup1 | |
/* "runtime.asm":881:885 */ | |
dup3 | |
/* "runtime.asm":892:896 */ | |
dup2 | |
/* "runtime.asm":903:909 */ | |
mstore | |
/* "runtime.asm":916:920 */ | |
0x20 | |
/* "runtime.asm":927:930 */ | |
add | |
/* "runtime.asm":937:942 */ | |
swap2 | |
/* "runtime.asm":949:952 */ | |
pop | |
/* "runtime.asm":959:962 */ | |
pop | |
/* "runtime.asm":975:979 */ | |
0x40 | |
/* "runtime.asm":969:980 */ | |
mload | |
/* "runtime.asm":987:991 */ | |
dup1 | |
/* "runtime.asm":998:1003 */ | |
swap2 | |
/* "runtime.asm":1010:1013 */ | |
sub | |
/* "runtime.asm":1020:1025 */ | |
swap1 | |
/* "runtime.asm":1032:1038 */ | |
return | |
/* "runtime.asm":1043:1048 */ | |
tag_5: | |
/* "runtime.asm":1095:1099 */ | |
0x00 | |
/* "runtime.asm":1144:1150 */ | |
0x7777 | |
/* "runtime.asm":1202:1207 */ | |
swap1 | |
/* "runtime.asm":1214:1217 */ | |
pop | |
/* "runtime.asm":1302:1307 */ | |
swap1 | |
/* "runtime.asm":1314:1318 */ | |
jump | |
/* "runtime.asm":1354:1357 */ | |
pop | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* compile me with solc --assemble */ | |
// REMOVED | |
// sub_0: assembly { | |
// ADDED | |
{ | |
/* manual code addition */ | |
0 | |
pop | |
/* end manual code */ | |
/* "foo.sol":0:220 contract X {... */ | |
mstore(0x40, 0x80) | |
callvalue | |
/* "--CODEGEN--":8:17 */ | |
dup1 | |
/* "--CODEGEN--":5:7 */ | |
iszero | |
tag_1 | |
jumpi | |
/* "--CODEGEN--":30:31 */ | |
0x00 | |
/* "--CODEGEN--":27:28 */ | |
dup1 | |
/* "--CODEGEN--":20:32 */ | |
revert | |
/* "--CODEGEN--":5:7 */ | |
tag_1: | |
/* "foo.sol":0:220 contract X {... */ | |
pop | |
jumpi(tag_2, lt(calldatasize, 0x04)) | |
shr(0xe0, calldataload(0x00)) | |
dup1 | |
0xc2985578 | |
eq | |
tag_3 | |
jumpi | |
tag_2: | |
0x00 | |
dup1 | |
revert | |
/* "foo.sol":15:81 function foo() external returns (uint256) {... */ | |
tag_3: | |
tag_4 | |
tag_5 | |
jump // in | |
tag_4: | |
mload(0x40) | |
dup1 | |
dup3 | |
dup2 | |
mstore | |
0x20 | |
add | |
swap2 | |
pop | |
pop | |
mload(0x40) | |
dup1 | |
swap2 | |
sub | |
swap1 | |
return | |
tag_5: | |
/* "foo.sol":48:55 uint256 */ | |
0x00 | |
/* "foo.sol":70:76 0x7777 */ | |
0x7777 | |
/* "foo.sol":63:76 return 0x7777 */ | |
swap1 | |
pop | |
/* "foo.sol":15:81 function foo() external returns (uint256) {... */ | |
swap1 | |
jump // out | |
// ADDED | |
pop | |
// REMOVED | |
// auxdata: 0xa165627a7a7230582000d23883a175630e4f81d9c4f025269a9921ce68a6668f8e16e49e57eec60c130029 | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Pretty printed source: | |
object "object" { | |
code { | |
0 | |
pop | |
mstore(0x40, 0x80) | |
callvalue | |
dup1 | |
iszero | |
tag_1 | |
jumpi | |
0x00 | |
dup1 | |
revert | |
tag_1: | |
pop | |
jumpi(tag_2, lt(calldatasize(), 0x04)) | |
shr(0xe0, calldataload(0x00)) | |
dup1 | |
0xc2985578 | |
eq | |
tag_3 | |
jumpi | |
tag_2: | |
0x00 | |
dup1 | |
revert | |
tag_3: | |
tag_4 | |
tag_5 | |
jump | |
tag_4: | |
mload(0x40) | |
dup1 | |
dup3 | |
dup2 | |
mstore | |
0x20 | |
add | |
swap2 | |
pop | |
pop | |
mload(0x40) | |
dup1 | |
swap2 | |
sub | |
swap1 | |
return | |
tag_5: | |
0x00 | |
0x7777 | |
swap1 | |
pop | |
swap1 | |
jump | |
pop | |
} | |
} | |
Binary representation: | |
6000506080604052348015601257600080fd5b5060043610602b5760003560e01c8063c2985578146030575b600080fd5b6036604c565b6040518082815260200191505060405180910390f35b60006177779050905650 | |
Text representation: | |
/* "runtime.asm":45:46 */ | |
0x00 | |
/* "runtime.asm":51:54 */ | |
pop | |
/* "runtime.asm":147:151 */ | |
0x80 | |
/* "runtime.asm":141:145 */ | |
0x40 | |
/* "runtime.asm":134:152 */ | |
mstore | |
/* "runtime.asm":159:168 */ | |
callvalue | |
/* "runtime.asm":210:214 */ | |
dup1 | |
/* "runtime.asm":255:261 */ | |
iszero | |
/* "runtime.asm":268:273 */ | |
tag_1 | |
/* "runtime.asm":280:285 */ | |
jumpi | |
/* "runtime.asm":328:332 */ | |
0x00 | |
/* "runtime.asm":375:379 */ | |
dup1 | |
/* "runtime.asm":422:428 */ | |
revert | |
/* "runtime.asm":467:472 */ | |
tag_1: | |
/* "runtime.asm":527:530 */ | |
pop | |
/* "runtime.asm":567:571 */ | |
0x04 | |
/* "runtime.asm":553:565 */ | |
calldatasize | |
/* "runtime.asm":550:572 */ | |
lt | |
/* "runtime.asm":543:548 */ | |
tag_2 | |
/* "runtime.asm":537:573 */ | |
jumpi | |
/* "runtime.asm":603:607 */ | |
0x00 | |
/* "runtime.asm":590:608 */ | |
calldataload | |
/* "runtime.asm":584:588 */ | |
0xe0 | |
/* "runtime.asm":580:609 */ | |
shr | |
/* "runtime.asm":616:620 */ | |
dup1 | |
/* "runtime.asm":627:637 */ | |
0xc2985578 | |
/* "runtime.asm":644:646 */ | |
eq | |
/* "runtime.asm":653:658 */ | |
tag_3 | |
/* "runtime.asm":665:670 */ | |
jumpi | |
/* "runtime.asm":675:680 */ | |
tag_2: | |
/* "runtime.asm":688:692 */ | |
0x00 | |
/* "runtime.asm":699:703 */ | |
dup1 | |
/* "runtime.asm":710:716 */ | |
revert | |
/* "runtime.asm":799:804 */ | |
tag_3: | |
/* "runtime.asm":812:817 */ | |
tag_4 | |
/* "runtime.asm":824:829 */ | |
tag_5 | |
/* "runtime.asm":836:840 */ | |
jump | |
/* "runtime.asm":851:856 */ | |
tag_4: | |
/* "runtime.asm":870:874 */ | |
0x40 | |
/* "runtime.asm":864:875 */ | |
mload | |
/* "runtime.asm":882:886 */ | |
dup1 | |
/* "runtime.asm":893:897 */ | |
dup3 | |
/* "runtime.asm":904:908 */ | |
dup2 | |
/* "runtime.asm":915:921 */ | |
mstore | |
/* "runtime.asm":928:932 */ | |
0x20 | |
/* "runtime.asm":939:942 */ | |
add | |
/* "runtime.asm":949:954 */ | |
swap2 | |
/* "runtime.asm":961:964 */ | |
pop | |
/* "runtime.asm":971:974 */ | |
pop | |
/* "runtime.asm":987:991 */ | |
0x40 | |
/* "runtime.asm":981:992 */ | |
mload | |
/* "runtime.asm":999:1003 */ | |
dup1 | |
/* "runtime.asm":1010:1015 */ | |
swap2 | |
/* "runtime.asm":1022:1025 */ | |
sub | |
/* "runtime.asm":1032:1037 */ | |
swap1 | |
/* "runtime.asm":1044:1050 */ | |
return | |
/* "runtime.asm":1055:1060 */ | |
tag_5: | |
/* "runtime.asm":1107:1111 */ | |
0x00 | |
/* "runtime.asm":1156:1162 */ | |
0x7777 | |
/* "runtime.asm":1214:1219 */ | |
swap1 | |
/* "runtime.asm":1226:1229 */ | |
pop | |
/* "runtime.asm":1314:1319 */ | |
swap1 | |
/* "runtime.asm":1326:1330 */ | |
jump | |
/* "runtime.asm":1366:1369 */ | |
pop | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment