From 65b9e612737886e5f5ba07b591c5f4d6b40e667b Mon Sep 17 00:00:00 2001 From: Silur Date: Sun, 14 Jan 2018 18:41:32 +0100 Subject: [PATCH 1/3] squash commits --- .gitignore | 8 +- CMakeLists.txt | 16 +- evm2wast.c | 676 +++++++++++++++++++++++++++++++++++++ evm2wast.h | 7 + gadgets.h | 5 + gen_gadgets.sh | 57 ++++ libs/evm2wasm/evm2wasm.cpp | 40 ++- makefile | 24 ++ 8 files changed, 814 insertions(+), 19 deletions(-) create mode 100644 evm2wast.c create mode 100644 evm2wast.h create mode 100644 gadgets.h create mode 100755 gen_gadgets.sh create mode 100644 makefile diff --git a/.gitignore b/.gitignore index efc294f2..cef642d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,8 @@ .swp .gch - /build /.idea /deps - -tmp/* -!tmp/.gitkeep -node_modules/ +gadgets.c +*.o +*.so diff --git a/CMakeLists.txt b/CMakeLists.txt index 8998cff9..c7b9a33e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,19 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_CXX_EXTENSIONS Off) -add_compile_options(-Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas) - project(evm2wasm) include(ProjectBinaryen) -add_subdirectory(libs) -add_subdirectory(tools) +add_custom_target(gen_gadgets + ${PROJECT_SOURCE_DIR}/gen_gadgets.sh + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} +) + +add_executable(evm2wasm + evm2wasm.cpp + evm2wast.c + gadgets.c +) +add_dependencies(evm2wasm gen_gadgets) +target_link_libraries(evm2wasm PRIVATE binaryen::binaryen) diff --git a/evm2wast.c b/evm2wast.c new file mode 100644 index 00000000..7740420d --- /dev/null +++ b/evm2wast.c @@ -0,0 +1,676 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "evm2wast.h" +#include "gadgets.h" + +struct opcode { + char *name; + size_t fee; + int off_stack; + int on_stack; + char *cb; +}; + +enum op_nums { + STOP = 0x00, + ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, + ADDMOD, MULMOD, EXP, SIGNEXTEND, + LT = 0X10, GT, SLT, SGT, EQ, ISZERO, + AND, OR, XOR, NOT, BYTE, + SHA3 = 0X20, + ADDRESS = 0x30, BALANCE, ORIGIN, CALLER, + CALLVALUE, CALLDATALOAD, CALLDATASIZE, + CALLDATACOPY, CODESIZE, CODECOPY, GASPRICE, + EXTCODESIZE, EXTCODECOPY, RETURNDATASIZE, + RETURNDATACOPY, + BLOCKHASH = 0X40, COINBASE, TIMESTAMP, NUMBER, + DIFFICULTY, GASLIMIT, + POP = 0X50, MLOAD, MSTORE, MSTORE8, SLOAD, + SSTORE, JUMP, JUMPI, PC, MSIZE, GAS, JUMPDEST, + PUSH1 = 0X60, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, + PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, + PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, + PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, + PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, + PUSH31, PUSH32, + DUP1 = 0X80, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, + DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, + DUP15, DUP16, SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, + SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, + SWAP12, SWAP13, SWAP14, SWAP15, SWAP16, LOG1, + LOG2, LOG3, LOG4, LOG5, + CREATE = 0xf0, CALL, CALLCODE, RETURN, DELEGATECALL, + STATICCALL, REVERT, + INVALID = 0xfe, SELFDESTRUCT +}; + +struct opcode opcodes[] = { + [STOP] = {"STOP", 0, 0, 0}, + [ADD] = {"ADD", 3, 2, 1}, + [MUL] = {"MUL", 5, 2, 1}, + [SUB] = {"SUB", 3, 2, 1}, + [DIV] = {"DIV", 5, 2, 1}, + [SDIV] = {"SDIV", 5, 2, 1}, + [MOD] = {"MOD", 5, 2, 1}, + [SMOD] = {"SMOD", 5, 2, 1}, + [ADDMOD] = {"ADDMOD", 8, 3, 1}, + [MULMOD] = {"MULMOD", 8, 3, 1}, + [EXP] = {"EXP", 10, 2, 1}, + [SIGNEXTEND] = {"SIGNEXTEND", 5, 2, 1}, + + [LT] = {"LT", 3, 2, 1}, + [GT] = {"GT", 3, 2, 1}, + [SLT] = {"SLT", 3, 2, 1}, + [SGT] = {"SGT", 3, 2, 1}, + [EQ] = {"EQ", 3, 2, 1}, + [ISZERO] = {"ISZERO", 3, 1, 1}, + [AND] = {"AND", 3, 2, 1}, + [OR] = {"OR", 3, 2, 1}, + [XOR] = {"XOR", 3, 2, 1}, + [NOT] = {"NOT", 3, 1, 1}, + [BYTE] = {"BYTE", 3, 2, 1}, + + // 0x20 range - crypto + [SHA3] = {"SHA3", 30, 2, 1}, + + // 0x30 range - closure state + [ADDRESS] = {"ADDRESS", 2, 0, 1}, + [BALANCE] = {"BALANCE", 400, 1, 1, "$callback_128"}, + [ORIGIN] = {"ORIGIN", 2, 0, 1}, + [CALLER] = {"CALLER", 2, 0, 1}, + [CALLVALUE] = {"CALLVALUE", 2, 0, 1}, + [CALLDATALOAD] = {"CALLDATALOAD", 3, 1, 1}, + [CALLDATASIZE] = {"CALLDATASIZE", 2, 0, 1}, + [CALLDATACOPY] = {"CALLDATACOPY", 3, 3, 0}, + [CODESIZE] = {"CODESIZE", 2, 0, 1, "$callback_32"}, + [CODECOPY] = {"CODECOPY", 3, 3, 0, "$callback"}, + [GASPRICE] = {"GASPRICE", 2, 0, 1}, + [EXTCODESIZE] = {"EXTCODESIZE", 700, 1, 1, "$callback_32"}, + [EXTCODECOPY] = {"EXTCODECOPY", 700, 4, 0, "$callback"}, + [RETURNDATASIZE] = {"RETURNDATASIZE", 2, 0, 1}, + [RETURNDATACOPY] = {"RETURNDATACOPY", 3, 3, 0}, + + // '0x40' range - block operations + [BLOCKHASH] = {"BLOCKHASH", 20, 1, 1, "$callback_256"}, + [COINBASE] = {"COINBASE", 2, 0, 1}, + [TIMESTAMP] = {"TIMESTAMP", 2, 0, 1}, + [NUMBER] = {"NUMBER", 2, 0, 1}, + [DIFFICULTY] = {"DIFFICULTY", 2, 0, 1}, + [GASLIMIT] = {"GASLIMIT", 2, 0, 1}, + + // 0x50 range - 'storage' and execution + [POP] = {"POP", 2, 1, 0}, + [MLOAD] = {"MLOAD", 3, 1, 1}, + [MSTORE] = {"MSTORE", 3, 2, 0}, + [MSTORE8] = {"MSTORE8", 3, 2, 0}, + [SLOAD] = {"SLOAD", 200, 1, 1, "$callback_256"}, + [SSTORE] = {"SSTORE", 0, 2, 0, "$callback"}, + [JUMP] = {"JUMP", 8, 1, 0}, + [JUMPI] = {"JUMPI", 10, 2, 0}, + [PC] = {"PC", 2, 0, 1}, + [MSIZE] = {"MSIZE", 2, 0, 1}, + [GAS] = {"GAS", 2, 0, 1}, + [JUMPDEST] = {"JUMPDEST", 1, 0, 0}, + + // 0x60, range + [PUSH1] = {"PUSH", 3, 0, 1}, + [PUSH2] = {"PUSH", 3, 0, 1}, + [PUSH3] = {"PUSH", 3, 0, 1}, + [PUSH4] = {"PUSH", 3, 0, 1}, + [PUSH5] = {"PUSH", 3, 0, 1}, + [PUSH6] = {"PUSH", 3, 0, 1}, + [PUSH7] = {"PUSH", 3, 0, 1}, + [PUSH8] = {"PUSH", 3, 0, 1}, + [PUSH9] = {"PUSH", 3, 0, 1}, + [PUSH10] = {"PUSH", 3, 0, 1}, + [PUSH11] = {"PUSH", 3, 0, 1}, + [PUSH12] = {"PUSH", 3, 0, 1}, + [PUSH13] = {"PUSH", 3, 0, 1}, + [PUSH14] = {"PUSH", 3, 0, 1}, + [PUSH15] = {"PUSH", 3, 0, 1}, + [PUSH16] = {"PUSH", 3, 0, 1}, + [PUSH17] = {"PUSH", 3, 0, 1}, + [PUSH18] = {"PUSH", 3, 0, 1}, + [PUSH19] = {"PUSH", 3, 0, 1}, + [PUSH20] = {"PUSH", 3, 0, 1}, + [PUSH21] = {"PUSH", 3, 0, 1}, + [PUSH22] = {"PUSH", 3, 0, 1}, + [PUSH23] = {"PUSH", 3, 0, 1}, + [PUSH24] = {"PUSH", 3, 0, 1}, + [PUSH25] = {"PUSH", 3, 0, 1}, + [PUSH26] = {"PUSH", 3, 0, 1}, + [PUSH27] = {"PUSH", 3, 0, 1}, + [PUSH28] = {"PUSH", 3, 0, 1}, + [PUSH29] = {"PUSH", 3, 0, 1}, + [PUSH30] = {"PUSH", 3, 0, 1}, + [PUSH31] = {"PUSH", 3, 0, 1}, + [PUSH32] = {"PUSH", 3, 0, 1}, + + [DUP1] = {"DUP", 3, 0, 1}, + [DUP2] = {"DUP", 3, 0, 1}, + [DUP3] = {"DUP", 3, 0, 1}, + [DUP4] = {"DUP", 3, 0, 1}, + [DUP5] = {"DUP", 3, 0, 1}, + [DUP6] = {"DUP", 3, 0, 1}, + [DUP7] = {"DUP", 3, 0, 1}, + [DUP8] = {"DUP", 3, 0, 1}, + [DUP9] = {"DUP", 3, 0, 1}, + [DUP10] = {"DUP", 3, 0, 1}, + [DUP11] = {"DUP", 3, 0, 1}, + [DUP12] = {"DUP", 3, 0, 1}, + [DUP13] = {"DUP", 3, 0, 1}, + [DUP14] = {"DUP", 3, 0, 1}, + [DUP15] = {"DUP", 3, 0, 1}, + [DUP16] = {"DUP", 3, 0, 1}, + + [SWAP1] = {"SWAP", 3, 0, 0}, + [SWAP2] = {"SWAP", 3, 0, 0}, + [SWAP3] = {"SWAP", 3, 0, 0}, + [SWAP4] = {"SWAP", 3, 0, 0}, + [SWAP5] = {"SWAP", 3, 0, 0}, + [SWAP6] = {"SWAP", 3, 0, 0}, + [SWAP7] = {"SWAP", 3, 0, 0}, + [SWAP8] = {"SWAP", 3, 0, 0}, + [SWAP9] = {"SWAP", 3, 0, 0}, + [SWAP10] = {"SWAP", 3, 0, 0}, + [SWAP11] = {"SWAP", 3, 0, 0}, + [SWAP12] = {"SWAP", 3, 0, 0}, + [SWAP13] = {"SWAP", 3, 0, 0}, + [SWAP14] = {"SWAP", 3, 0, 0}, + [SWAP15] = {"SWAP", 3, 0, 0}, + [SWAP16] = {"SWAP", 3, 0, 0}, + + [LOG1] = {"LOG", 375, 2, 0}, + [LOG2] = {"LOG", 375, 2, 0}, + [LOG3] = {"LOG", 375, 2, 0}, + [LOG4] = {"LOG", 375, 2, 0}, + [LOG5] = {"LOG", 375, 2, 0}, + + // '0xf0' range - closures + [CREATE] = {"CREATE", 32000, 3, 1, "$callback_160"}, + [CALL] = {"CALL", 700, 7, 1, "$callback_32"}, + [CALLCODE] = {"CALLCODE", 700, 7, 1, "$callback_32"}, + [RETURN] = {"RETURN", 0, 2, 0}, + [DELEGATECALL] = {"DELEGATECALL", 700, 6, 1, "$callback"}, + [STATICCALL] = {"STATICCALL", 700, 6, 1}, + [REVERT] = {"REVERT", 0, 2, 0}, + + // '0x70', range - other + [INVALID] = {"INVALID", 0, 0, 0}, + [SELFDESTRUCT] = {"SELFDESTRUCT", 5000, 1, 0} +}; + + +static inline int digits(unsigned long x) { return (floor(log10(abs(x))) + 1); } +static int64_t bytes2long(char *bytes) +{ + int64_t ret = 0; + int i; + for(i = 0; i < 8; i++) + { + ret = (ret << 8) | bytes[i]; + } + return ret; +} +static char *padleft(char *bytes, int curr_len, int len) +{ + if(curr_len > len) + { + fprintf(stderr, "pad failed to prevent memory overlap\n"); + return 0; + } + char *ret = calloc(len, 1); + if(!ret) return 0; + ret = memcpy(ret+(len-curr_len)-1, bytes, curr_len); + + return ret; +} +static char *slice(char *bytes, int len) +{ + char *ret = malloc(sizeof(len)); + ret = memcpy(ret, bytes, len); + return ret; +} +static int index_of(char **table, char *elem, int len) +{ + int i; + for(i=0; i= PUSH1 && evm_code[i] <= PUSH32) + { + i+=evm_code[i]-0x59; + break; + } + } + return --i; +} +char *build_module(char *wast) +{ + int i; + char *ret = malloc(819200); + if(!ret) return 0; + ret = strcat(ret, "(module "); + for(i=0; i stack_high) stack_high = stack_delta; + stack_delta = op.on_stack; + if(stack_delta < stack_low) stack_low = stack_delta; + + switch(evm_code[i]) + { + case JUMP: + has_jump=1; + append_segment("(set_local $jump_dest (call $check_overflow \ + (i64.load (get_global $sp)) \ + (i64.load (i32.add (get_global $sp) (i32.const 8)))\ + (i64.load (i32.add (get_global $sp) (i32.const 16)))\ + (i64.load (i32.add (get_global $sp) (i32.const 24)))))\ + (set_global $sp (i32.sub (get_global $sp) (i32.const 32)))\ + (br $loop)"); + i = next_jump_dest(evm_code, len, i); + break; + + case JUMPI: + has_jump=1; + append_segment("(set_local $jump_dest (call $check_overflow \ + (i64.load (get_global $sp)) \ + (i64.load (i32.add (get_global $sp) (i32.const 8))) \ + (i64.load (i32.add (get_global $sp) (i32.const 16))) \ + (i64.load (i32.add (get_global $sp) (i32.const 24))))) \ + (set_global $sp (i32.sub (get_global $sp) (i32.const 64))) \ + (br_if $loop (i32.eqz (i64.eqz (i64.or \ + (i64.load (i32.add (get_global $sp) (i 32.const 32))) \ + (i64.or \ + (i64.load (i32.add (get_global $sp) (i32.const 40))) \ + (i64.or \ + (i64.load (i32.add (get_global $sp) (i32.const 48))) \ + (i64.load (i32.add (get_global $sp) (i32.const 56))) \ + ) \ + ) \ + ))))"); + add_stack_check(segment); + add_metering(wast_code, segment); + break; + + case JUMPDEST: + end_segment(wast_code, segment); + jumps = realloc(jumps, jumps_len); + jumps[jumps_len++] = i; + gas_count = 1; + break; + + case GAS: + append_segment("(call $GAS)\n"); + add_metering(wast_code, segment); + break; + + case LOG1: + case LOG2: + case LOG3: + case LOG4: + case LOG5: + format_segment("(call $LOG (i32.const %d))", 36, (int)evm_code[i]); + break; + + case DUP1: + case DUP2: + case DUP3: + case DUP4: + case DUP5: + case DUP6: + case DUP7: + case DUP8: + case DUP9: + case DUP10: + case DUP11: + case DUP12: + case DUP13: + case DUP14: + case DUP15: + case DUP16: + case SWAP1: + case SWAP2: + case SWAP3: + case SWAP4: + case SWAP5: + case SWAP6: + case SWAP7: + case SWAP8: + case SWAP9: + case SWAP10: + case SWAP11: + case SWAP12: + case SWAP13: + case SWAP14: + case SWAP15: + case SWAP16: + format_segment("(call $%s (i32.const $%d))\n", 60, + op.name, (int)evm_code[i]); + break; + + case PC: + format_segment("(call $PC (i32.const %ld", 40, i); + break; + + case PUSH1: + case PUSH2: + case PUSH3: + case PUSH4: + case PUSH5: + case PUSH6: + case PUSH7: + case PUSH8: + case PUSH9: + case PUSH10: + case PUSH11: + case PUSH12: + case PUSH13: + case PUSH14: + case PUSH15: + case PUSH16: + case PUSH17: + case PUSH18: + case PUSH19: + case PUSH20: + case PUSH21: + case PUSH22: + case PUSH23: + case PUSH24: + case PUSH25: + case PUSH26: + case PUSH27: + case PUSH28: + case PUSH29: + case PUSH30: + case PUSH31: + case PUSH32: + { + char *bytes = padleft(evm_code+i+1, evm_code[i]-0x59, 32); + i+=(size_t)evm_code[i]-0x59; + if(!bytes) goto err; + int bytes_rounded = (int)ceil((double)(evm_code[i]/8)); + char *push = 0; + int q; + for(q=0; q<4-bytes_rounded; q++) + { + push = realloc(push, (q+1)*32); // FIXME segfault + if(!push) goto err; + sprintf(push, "(i64.const 0)%s", push); + } + for(; q<4; q++) + { + int64_t i64 = bytes2long(slice(bytes+(q*8), q*8+8)); + push = realloc(push, (q+1)*32); + if(!push) goto err; + sprintf(push, "%s (i64.const $%ld)", push, i64); + + } + format_segment("(call $PUSH %s)", 13+strlen(push), push); + i--; + //free(bytes); + //free(push); + } + break; + + case POP: + // do nothing + break; + + case STOP: + append_segment("(br $done)"); + if(has_jump) + { + i = next_jump_dest(evm_code, len, i); + } + else + { + i = len; + } + break; + + //case SUICIDE: + case RETURN: + format_segment("(call $%s) (br $done)\n", 56, op.name); + if(has_jump) + { + i = next_jump_dest(evm_code, len, i); + } + else + { + i = len; + } + break; + + case INVALID: + append_segment("(unreachable)"); + i = next_jump_dest(evm_code, len, i); + break; + + default: + printf("found cb for op %s\n", op.name); + if(op.cb != 0) + { + int cb_index = index_of(cb_array, op.name, cb_len); + if(cb_index == -1) + { + cb_array[cb_len++] = op.cb; + } + format_segment("(call $%s (i32.const %d))", 72, op.name, cb_index); + } + format_segment("(call $%s)", 32, op.name); + break; + } + + stack_delta = op.on_stack - op.off_stack; + if(stack_delta != 0) + { + format_segment("(set_global $sp (i32.add (get_global $sp) (i32.const %ld)))\n", + 72, stack_delta); + } + + //TODO stacktrace + if(op.cb != 0) + { + format_segment("(set_global $cb_dest (i32.const %ld)) (br $done))", 72, jumps_len+1); + jumps = realloc(jumps, (jumps_len+1)*sizeof(size_t)); + if(!jumps) goto err; + jumps[jumps_len++] = i; + } + } + end_segment(wast_code, segment); + char *with_jumps = assemble_segments(jumps, jumps_len); + wast_code = realloc(wast_code, strlen(wast_code) + strlen(with_jumps)); + if(wast_code == 0) goto err; + wast_code = strcat(with_jumps, wast_code); + wast_code = strcat(wast_code, "))"); + wast_code = build_module(wast_code); + free(segment); + free(with_jumps); + free(jumps); + *wast_ret = wast_code; + *wast_size = strlen(wast_code); + return 1; +#undef append_segment +err: + // TODO optimize this double-branch + if(segment) free(segment); + if(wast_code) free(wast_code); + //if(with_jumps) free(with_jumps); + if(jumps) free(jumps); + return 0; +} diff --git a/evm2wast.h b/evm2wast.h new file mode 100644 index 00000000..04d6a996 --- /dev/null +++ b/evm2wast.h @@ -0,0 +1,7 @@ +#ifndef __EVM2WAST_H +#define __EVM2WAST_H +#include +#ifdef __cplusplus +extern "C" int evm2wast(char *evm_code, size_t len, char **wast_code, size_t *wast_size); +#endif +#endif diff --git a/gadgets.h b/gadgets.h new file mode 100644 index 00000000..c4246f24 --- /dev/null +++ b/gadgets.h @@ -0,0 +1,5 @@ +#ifndef __EVM2WASM_GADGETS_H +#define __EVM2WASM_GADGETS_H +extern int gadget_count; +extern const char *gadgets[]; +#endif diff --git a/gen_gadgets.sh b/gen_gadgets.sh new file mode 100755 index 00000000..b2d9277c --- /dev/null +++ b/gen_gadgets.sh @@ -0,0 +1,57 @@ +#!/bin/bash +cstr () { +sed '$!s/$/\\n\\/' $1 2>/dev/null | sed 's/"/\\"/g' +} +fill () { + for i in {0..$1} + do + echo "\"\"," >> gadgets.c + done +} +#0x00 +opcodes=("STOP" "ADD" "MUL" "SUB" "DIV" "SDIV" "MOD" +"ADDMOD" "MULMOD" "EXP" "SIGNEXTEND" 0 0 0 0 +"LT" "GT" "SLT" "SGT" "EQ" "ISZERO" "AND" "OR" "XOR" +"NOT" "BYTE" 0 0 0 0 0 "SHA3" 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 "ADDRESS" "BALANCE" "ORIGIN" "CALLER" +"CALLVALUE" "CALLDATALOAD" "CALLDATASIZE" +"CALLDATACOPY" "CODESIZE" "CODECOPY" "GASPRICE" +"EXTCODZISE" "EXTCODECOPY" "RETURNDATASIZE" +"RETURNDATACOPY" 0 "BLOCKHASH" "COINBASE" "TIMESTAMP" +"NUMBER" "DIFFICULTY" "GASLIMIT" 0 0 0 0 0 0 0 0 0 0 +"POP" "MLOAD" "MSTORE" "MSTORE8" "SLOAD" "SLOAD" "SSTORE" +"JUMP" "JUMPI" "PC" "MSIZE" "GAS" "JUMPDEST" 0 0 0 0 0 +"SELFDESTRUCT" 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +"CALL" "CALLCODE" "RETURN" "DELEGATECALL" "STATICCALL" +"REVERT" 0 0 0 0 0 0 0 "bswap_i32" "bswap_i64" +"bswap_m128" "bswap_m160" "bswap_m256" "callback_128" +"callback_160" "callback_256" "callback_32" "callback" +"check_overflow_i64" "check_overflow" "gte_256" +"gte_320" "gte_512" "iszero_256" "iszero_320" "iszero_512" +"keccak" "memcpy" "memset" "memusegas" "mod_320" +"mod_512" "mul_256") + +cat < gadgets.c +#ifndef __EVM2WASM_GADGETS_H +#define __EVM2WASM_GADGETS_H +#pragma GCC diagnostic ignored "-Woverlength-strings" +#include "gadgets.h" +EOF +echo "const int gadget_count = ${#opcodes[@]};" >> gadgets.c +echo "const char *gadgets[${#opcodes[@]}+1] = {" >> gadgets.c +for i in ${opcodes[@]} +do + if [[ $i == 0 ]] + then + echo "\"\"," >> gadgets.c + continue + fi + echo "\"$(cstr wasm/$i.wast)\"," >> gadgets.c +done +echo "\"\"};" >> gadgets.c +echo '#endif' >> gadgets.c +exit 0 diff --git a/libs/evm2wasm/evm2wasm.cpp b/libs/evm2wasm/evm2wasm.cpp index 3fc6d1a1..8d342336 100644 --- a/libs/evm2wasm/evm2wasm.cpp +++ b/libs/evm2wasm/evm2wasm.cpp @@ -2,12 +2,13 @@ #include "wasm-binary.h" #include "wasm-s-parser.h" +#include "evm2wast.h" using namespace std; namespace { -string wast2wasm(const string& input, bool debug = false) { +string wast2wasm(string input, bool debug = true) { wasm::Module wasm; try { @@ -19,9 +20,7 @@ string wast2wasm(const string& input, bool debug = false) { } catch (wasm::ParseException& p) { p.dump(std::cerr); wasm::Fatal() << "error in parsing input"; - } - - // FIXME: perhaps call validate() here? + } if (debug) std::cerr << "binarification..." << std::endl; wasm::BufferWithRandomAccess buffer(debug); @@ -38,14 +37,35 @@ string wast2wasm(const string& input, bool debug = false) { return output.str(); } -string evm2wast(string input) { - (void)input; - // FIXME: do evm magic here - return "(module (func $test))"; +string evm2wast_wrapper(string input) { + size_t len = 0; + char *output = NULL; + if (evm2wast(const_cast(input.c_str()), input.size(), &output, &len) < 0) + return string(); + string ret(output, output + len); + free(output); + cout << ret << endl; + return ret; +} + +string evm2wasm(string input) { + return wast2wasm(evm2wast_wrapper(input)); } } -string evm2wasm(const string& input) { - return wast2wasm(evm2wast(input)); +int main(int argc, char **argv) { + if(argc<2) { + cout << "usage " << argv[0] << " " << endl; + return 1; + } + FILE *fd = fopen(argv[1], "r"); + fseek(fd, 0, SEEK_END); + size_t offset = ftell(fd); + rewind(fd); + char *code = (char*)malloc(8192); + fread(code, 1, 8192, fd); + fclose(fd); + cout << evm2wasm(string(code)) << endl; + return 0; } diff --git a/makefile b/makefile new file mode 100644 index 00000000..ba5bb0c2 --- /dev/null +++ b/makefile @@ -0,0 +1,24 @@ +.POSIX: +.SUFFIXES: +CC = gcc +CFLAGS = -Wall -Werror -O2 -pedantic +LDFLAGS = -shared -fPIC -lm + +all: gadgets.o evm2wast.o + $(CC) -o evm2wasm.so evm2wast.o $(LDFLAGS) + +evm2wast.o: evm2wast.c + $(CC) -o evm2wast.o -c evm2wast.c $(CFLAGS) $(LDFLAGS) + +gadgets.o: gadgets + $(CC) -c -o gadgets.o gadgets.c + +lint: + indent *.c + indent *.h + +clean: + rm *.o *.so + +gadgets: + $(shell ./gen_gadgets.sh) From 0f88dc824b7e10b4626bc3c5bcdf6fb8e61d9c5a Mon Sep 17 00:00:00 2001 From: Silur Date: Sun, 14 Jan 2018 18:41:32 +0100 Subject: [PATCH 2/3] Reimplement the translator in C Reimplement the translator in C minor memory fixes shitty size fixes shitty size fixes remove debug printf --- .gitignore | 9 +- libs/evm2wasm/CMakeLists.txt | 10 + libs/evm2wasm/evm2wasm.cpp | 18 +- libs/evm2wasm/evm2wast.c | 693 +++++++++++++++++++++++++++++++++++ libs/evm2wasm/evm2wast.h | 16 + libs/evm2wasm/gadgets.h | 5 + libs/evm2wasm/gen_gadgets.sh | 55 +++ tools/evm2wasm/main.cpp | 1 - wasm/SIGNEXTEND.wast | 1 - wasm/bswap_i32.wast | 3 +- wasm/bswap_i64.wast | 3 +- 11 files changed, 800 insertions(+), 14 deletions(-) create mode 100644 libs/evm2wasm/evm2wast.c create mode 100644 libs/evm2wasm/evm2wast.h create mode 100644 libs/evm2wasm/gadgets.h create mode 100755 libs/evm2wasm/gen_gadgets.sh diff --git a/.gitignore b/.gitignore index cef642d8..5ac08d35 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ /build /.idea /deps -gadgets.c -*.o -*.so + +tmp/* +!tmp/.gitkeep +node_modules/ + +libs/evm2wasm/gadgets.c diff --git a/libs/evm2wasm/CMakeLists.txt b/libs/evm2wasm/CMakeLists.txt index f7c6901c..bc5b31dd 100644 --- a/libs/evm2wasm/CMakeLists.txt +++ b/libs/evm2wasm/CMakeLists.txt @@ -1,9 +1,19 @@ set(include_dir ${PROJECT_SOURCE_DIR}/include) +add_custom_target(gen_gadgets + ${CMAKE_CURRENT_SOURCE_DIR}/gen_gadgets.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/gadgets.c +) + add_library(libevm2wasm evm2wasm.cpp ${include_dir}/evm2wasm.h + evm2wast.c + gadgets.c ) set_target_properties(libevm2wasm PROPERTIES OUTPUT_NAME evm2wasm) +add_dependencies(libevm2wasm gen_gadgets) + target_include_directories(libevm2wasm PUBLIC ${include_dir}) target_link_libraries(libevm2wasm PRIVATE binaryen::binaryen) \ No newline at end of file diff --git a/libs/evm2wasm/evm2wasm.cpp b/libs/evm2wasm/evm2wasm.cpp index 46ec3984..3b4ac270 100644 --- a/libs/evm2wasm/evm2wasm.cpp +++ b/libs/evm2wasm/evm2wasm.cpp @@ -4,6 +4,10 @@ #include #include +#include "evm2wast.h" + +#include "evm2wast.h" + using namespace std; namespace { @@ -48,14 +52,18 @@ string wast2wasm(const string& input, bool debug = false) { return output.str(); } -string evm2wast(const string& input) { - (void)input; - // FIXME: do evm magic here - return "(module (export \"main\" (func $main)) (func $main))"; +string evm2wast_wrapper(string input) { + size_t len = 0; + char *output = NULL; + if (evm2wast(input.c_str(), input.size(), &output, &len) < 0) + return string(); + string ret(output, output + len); + free(output); + return ret; } } string evm2wasm(const string& input) { - return wast2wasm(evm2wast(input)); + return wast2wasm(evm2wast_wrapper(input), true); } diff --git a/libs/evm2wasm/evm2wast.c b/libs/evm2wasm/evm2wast.c new file mode 100644 index 00000000..fa01ec9d --- /dev/null +++ b/libs/evm2wasm/evm2wast.c @@ -0,0 +1,693 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "evm2wast.h" +#include "gadgets.h" + +struct opcode { + char *name; + size_t fee; + int off_stack; + int on_stack; + char *cb; +}; + +enum op_nums { + STOP = 0x00, + ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, + ADDMOD, MULMOD, EXP, SIGNEXTEND, + LT = 0X10, GT, SLT, SGT, EQ, ISZERO, + AND, OR, XOR, NOT, BYTE, + SHA3 = 0X20, + ADDRESS = 0x30, BALANCE, ORIGIN, CALLER, + CALLVALUE, CALLDATALOAD, CALLDATASIZE, + CALLDATACOPY, CODESIZE, CODECOPY, GASPRICE, + EXTCODESIZE, EXTCODECOPY, RETURNDATASIZE, + RETURNDATACOPY, + BLOCKHASH = 0X40, COINBASE, TIMESTAMP, NUMBER, + DIFFICULTY, GASLIMIT, + POP = 0X50, MLOAD, MSTORE, MSTORE8, SLOAD, + SSTORE, JUMP, JUMPI, PC, MSIZE, GAS, JUMPDEST, + PUSH1 = 0X60, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, + PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, + PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, + PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, + PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, + PUSH31, PUSH32, + DUP1 = 0X80, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, + DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, + DUP15, DUP16, SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, + SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, + SWAP12, SWAP13, SWAP14, SWAP15, SWAP16, LOG1, + LOG2, LOG3, LOG4, LOG5, + CREATE = 0xf0, CALL, CALLCODE, RETURN, DELEGATECALL, + STATICCALL, REVERT, + INVALID = 0xfe, SELFDESTRUCT +}; + +struct opcode opcodes[] = { + [STOP] = {"STOP", 0, 0, 0}, + [ADD] = {"ADD", 3, 2, 1}, + [MUL] = {"MUL", 5, 2, 1}, + [SUB] = {"SUB", 3, 2, 1}, + [DIV] = {"DIV", 5, 2, 1}, + [SDIV] = {"SDIV", 5, 2, 1}, + [MOD] = {"MOD", 5, 2, 1}, + [SMOD] = {"SMOD", 5, 2, 1}, + [ADDMOD] = {"ADDMOD", 8, 3, 1}, + [MULMOD] = {"MULMOD", 8, 3, 1}, + [EXP] = {"EXP", 10, 2, 1}, + [SIGNEXTEND] = {"SIGNEXTEND", 5, 2, 1}, + + [LT] = {"LT", 3, 2, 1}, + [GT] = {"GT", 3, 2, 1}, + [SLT] = {"SLT", 3, 2, 1}, + [SGT] = {"SGT", 3, 2, 1}, + [EQ] = {"EQ", 3, 2, 1}, + [ISZERO] = {"ISZERO", 3, 1, 1}, + [AND] = {"AND", 3, 2, 1}, + [OR] = {"OR", 3, 2, 1}, + [XOR] = {"XOR", 3, 2, 1}, + [NOT] = {"NOT", 3, 1, 1}, + [BYTE] = {"BYTE", 3, 2, 1}, + + // 0x20 range - crypto + [SHA3] = {"SHA3", 30, 2, 1}, + + // 0x30 range - closure state + [ADDRESS] = {"ADDRESS", 2, 0, 1}, + [BALANCE] = {"BALANCE", 400, 1, 1, "$callback_128"}, + [ORIGIN] = {"ORIGIN", 2, 0, 1}, + [CALLER] = {"CALLER", 2, 0, 1}, + [CALLVALUE] = {"CALLVALUE", 2, 0, 1}, + [CALLDATALOAD] = {"CALLDATALOAD", 3, 1, 1}, + [CALLDATASIZE] = {"CALLDATASIZE", 2, 0, 1}, + [CALLDATACOPY] = {"CALLDATACOPY", 3, 3, 0}, + [CODESIZE] = {"CODESIZE", 2, 0, 1, "$callback_32"}, + [CODECOPY] = {"CODECOPY", 3, 3, 0, "$callback"}, + [GASPRICE] = {"GASPRICE", 2, 0, 1}, + [EXTCODESIZE] = {"EXTCODESIZE", 700, 1, 1, "$callback_32"}, + [EXTCODECOPY] = {"EXTCODECOPY", 700, 4, 0, "$callback"}, + [RETURNDATASIZE] = {"RETURNDATASIZE", 2, 0, 1}, + [RETURNDATACOPY] = {"RETURNDATACOPY", 3, 3, 0}, + + // '0x40' range - block operations + [BLOCKHASH] = {"BLOCKHASH", 20, 1, 1, "$callback_256"}, + [COINBASE] = {"COINBASE", 2, 0, 1}, + [TIMESTAMP] = {"TIMESTAMP", 2, 0, 1}, + [NUMBER] = {"NUMBER", 2, 0, 1}, + [DIFFICULTY] = {"DIFFICULTY", 2, 0, 1}, + [GASLIMIT] = {"GASLIMIT", 2, 0, 1}, + + // 0x50 range - 'storage' and execution + [POP] = {"POP", 2, 1, 0}, + [MLOAD] = {"MLOAD", 3, 1, 1}, + [MSTORE] = {"MSTORE", 3, 2, 0}, + [MSTORE8] = {"MSTORE8", 3, 2, 0}, + [SLOAD] = {"SLOAD", 200, 1, 1, "$callback_256"}, + [SSTORE] = {"SSTORE", 0, 2, 0, "$callback"}, + [JUMP] = {"JUMP", 8, 1, 0}, + [JUMPI] = {"JUMPI", 10, 2, 0}, + [PC] = {"PC", 2, 0, 1}, + [MSIZE] = {"MSIZE", 2, 0, 1}, + [GAS] = {"GAS", 2, 0, 1}, + [JUMPDEST] = {"JUMPDEST", 1, 0, 0}, + + // 0x60, range + [PUSH1] = {"PUSH", 3, 0, 1}, + [PUSH2] = {"PUSH", 3, 0, 1}, + [PUSH3] = {"PUSH", 3, 0, 1}, + [PUSH4] = {"PUSH", 3, 0, 1}, + [PUSH5] = {"PUSH", 3, 0, 1}, + [PUSH6] = {"PUSH", 3, 0, 1}, + [PUSH7] = {"PUSH", 3, 0, 1}, + [PUSH8] = {"PUSH", 3, 0, 1}, + [PUSH9] = {"PUSH", 3, 0, 1}, + [PUSH10] = {"PUSH", 3, 0, 1}, + [PUSH11] = {"PUSH", 3, 0, 1}, + [PUSH12] = {"PUSH", 3, 0, 1}, + [PUSH13] = {"PUSH", 3, 0, 1}, + [PUSH14] = {"PUSH", 3, 0, 1}, + [PUSH15] = {"PUSH", 3, 0, 1}, + [PUSH16] = {"PUSH", 3, 0, 1}, + [PUSH17] = {"PUSH", 3, 0, 1}, + [PUSH18] = {"PUSH", 3, 0, 1}, + [PUSH19] = {"PUSH", 3, 0, 1}, + [PUSH20] = {"PUSH", 3, 0, 1}, + [PUSH21] = {"PUSH", 3, 0, 1}, + [PUSH22] = {"PUSH", 3, 0, 1}, + [PUSH23] = {"PUSH", 3, 0, 1}, + [PUSH24] = {"PUSH", 3, 0, 1}, + [PUSH25] = {"PUSH", 3, 0, 1}, + [PUSH26] = {"PUSH", 3, 0, 1}, + [PUSH27] = {"PUSH", 3, 0, 1}, + [PUSH28] = {"PUSH", 3, 0, 1}, + [PUSH29] = {"PUSH", 3, 0, 1}, + [PUSH30] = {"PUSH", 3, 0, 1}, + [PUSH31] = {"PUSH", 3, 0, 1}, + [PUSH32] = {"PUSH", 3, 0, 1}, + + [DUP1] = {"DUP", 3, 0, 1}, + [DUP2] = {"DUP", 3, 0, 1}, + [DUP3] = {"DUP", 3, 0, 1}, + [DUP4] = {"DUP", 3, 0, 1}, + [DUP5] = {"DUP", 3, 0, 1}, + [DUP6] = {"DUP", 3, 0, 1}, + [DUP7] = {"DUP", 3, 0, 1}, + [DUP8] = {"DUP", 3, 0, 1}, + [DUP9] = {"DUP", 3, 0, 1}, + [DUP10] = {"DUP", 3, 0, 1}, + [DUP11] = {"DUP", 3, 0, 1}, + [DUP12] = {"DUP", 3, 0, 1}, + [DUP13] = {"DUP", 3, 0, 1}, + [DUP14] = {"DUP", 3, 0, 1}, + [DUP15] = {"DUP", 3, 0, 1}, + [DUP16] = {"DUP", 3, 0, 1}, + + [SWAP1] = {"SWAP", 3, 0, 0}, + [SWAP2] = {"SWAP", 3, 0, 0}, + [SWAP3] = {"SWAP", 3, 0, 0}, + [SWAP4] = {"SWAP", 3, 0, 0}, + [SWAP5] = {"SWAP", 3, 0, 0}, + [SWAP6] = {"SWAP", 3, 0, 0}, + [SWAP7] = {"SWAP", 3, 0, 0}, + [SWAP8] = {"SWAP", 3, 0, 0}, + [SWAP9] = {"SWAP", 3, 0, 0}, + [SWAP10] = {"SWAP", 3, 0, 0}, + [SWAP11] = {"SWAP", 3, 0, 0}, + [SWAP12] = {"SWAP", 3, 0, 0}, + [SWAP13] = {"SWAP", 3, 0, 0}, + [SWAP14] = {"SWAP", 3, 0, 0}, + [SWAP15] = {"SWAP", 3, 0, 0}, + [SWAP16] = {"SWAP", 3, 0, 0}, + + [LOG1] = {"LOG", 375, 2, 0}, + [LOG2] = {"LOG", 375, 2, 0}, + [LOG3] = {"LOG", 375, 2, 0}, + [LOG4] = {"LOG", 375, 2, 0}, + [LOG5] = {"LOG", 375, 2, 0}, + + // '0xf0' range - closures + [CREATE] = {"CREATE", 32000, 3, 1, "$callback_160"}, + [CALL] = {"CALL", 700, 7, 1, "$callback_32"}, + [CALLCODE] = {"CALLCODE", 700, 7, 1, "$callback_32"}, + [RETURN] = {"RETURN", 0, 2, 0}, + [DELEGATECALL] = {"DELEGATECALL", 700, 6, 1, "$callback"}, + [STATICCALL] = {"STATICCALL", 700, 6, 1}, + [REVERT] = {"REVERT", 0, 2, 0}, + + // '0x70', range - other + [INVALID] = {"INVALID", 0, 0, 0}, + [SELFDESTRUCT] = {"SELFDESTRUCT", 5000, 1, 0} +}; + + +static inline int digits(unsigned long x) { return (floor(log10(abs(x))) + 1); } +static void *safe_realloc(void *p, size_t s) +{ + void *ret = realloc(p, s); + if(!ret) + { + perror("allocation error "); + free(p); + return 0; + } + return ret; +} +static int64_t bytes2long(const char *bytes) +{ + int64_t ret = 0; + int i; + for(i = 0; i < 8; i++) + { + ret = (ret << 8) | bytes[i]; + } + return ret; +} +static char *padleft(char *bytes, int curr_len, int len) +{ + if(curr_len > len) + { + fprintf(stderr, "pad failed to prevent memory overlap\n"); + return 0; + } + char *ret = calloc(len, 1); + if(!ret) return 0; + ret = memcpy(ret+(len-curr_len)-1, bytes, curr_len); + + return ret; +} + +/*static char *slice(char *bytes, int len) +{ + char *ret = malloc(sizeof(len)); + ret = memcpy(ret, bytes, len); + return ret; +}*/ + +static int index_of(char **table, char *elem, int len) +{ + int i; + for(i=0; i= PUSH1 && evm_code[i] <= PUSH32) + { + i+=evm_code[i]-0x59; + break; + } + } + return --i; +} +char *build_module(const char *wast) +{ + int i; + size_t gadgets_len = 0; + for(i=0; i stack_high) stack_high = stack_delta; + stack_delta = op.on_stack; + if(stack_delta < stack_low) stack_low = stack_delta; + + switch((unsigned char)evm_code[i]) + { + case JUMP: + has_jump=1; + append_segment("(set_local $jump_dest (call $check_overflow \ + (i64.load (get_global $sp)) \ + (i64.load (i32.add (get_global $sp) (i32.const 8)))\ + (i64.load (i32.add (get_global $sp) (i32.const 16)))\ + (i64.load (i32.add (get_global $sp) (i32.const 24)))))\ + (set_global $sp (i32.sub (get_global $sp) (i32.const 32)))\ + (br $loop)"); + i = next_jump_dest(evm_code, len, i); + break; + + case JUMPI: + has_jump=1; + append_segment("(set_local $jump_dest (call $check_overflow \ + (i64.load (get_global $sp)) \ + (i64.load (i32.add (get_global $sp) (i32.const 8))) \ + (i64.load (i32.add (get_global $sp) (i32.const 16))) \ + (i64.load (i32.add (get_global $sp) (i32.const 24))))) \ + (set_global $sp (i32.sub (get_global $sp) (i32.const 64))) \ + (br_if $loop (i32.eqz (i64.eqz (i64.or \ + (i64.load (i32.add (get_global $sp) (i 32.const 32))) \ + (i64.or \ + (i64.load (i32.add (get_global $sp) (i32.const 40))) \ + (i64.or \ + (i64.load (i32.add (get_global $sp) (i32.const 48))) \ + (i64.load (i32.add (get_global $sp) (i32.const 56))) \ + ) \ + ) \ + ))))"); + add_stack_check(&segment); + add_metering(&wast_code, &segment); + break; + + case JUMPDEST: + end_segment(wast_code, segment); + jumps = realloc(jumps, jumps_len); + jumps[jumps_len++] = i; + gas_count = 1; + break; + + case GAS: + append_segment("(call $GAS)\n"); + add_metering(wast_code, segment); + break; + + case LOG1: + case LOG2: + case LOG3: + case LOG4: + case LOG5: + format_segment("(call $LOG (i32.const %d))", 36, (int)evm_code[i]); + break; + + case DUP1: + case DUP2: + case DUP3: + case DUP4: + case DUP5: + case DUP6: + case DUP7: + case DUP8: + case DUP9: + case DUP10: + case DUP11: + case DUP12: + case DUP13: + case DUP14: + case DUP15: + case DUP16: + case SWAP1: + case SWAP2: + case SWAP3: + case SWAP4: + case SWAP5: + case SWAP6: + case SWAP7: + case SWAP8: + case SWAP9: + case SWAP10: + case SWAP11: + case SWAP12: + case SWAP13: + case SWAP14: + case SWAP15: + case SWAP16: + format_segment("(call $%s (i32.const $%d))\n", 60, + op.name, (int)evm_code[i]); + break; + + case PC: + format_segment("(call $PC (i32.const %ld", 40, i); + break; + + case PUSH1: + case PUSH2: + case PUSH3: + case PUSH4: + case PUSH5: + case PUSH6: + case PUSH7: + case PUSH8: + case PUSH9: + case PUSH10: + case PUSH11: + case PUSH12: + case PUSH13: + case PUSH14: + case PUSH15: + case PUSH16: + case PUSH17: + case PUSH18: + case PUSH19: + case PUSH20: + case PUSH21: + case PUSH22: + case PUSH23: + case PUSH24: + case PUSH25: + case PUSH26: + case PUSH27: + case PUSH28: + case PUSH29: + case PUSH30: + case PUSH31: + case PUSH32: + { + char *bytes = padleft(evm_code+1, evm_code[i]-0x5f, 32); + if(!bytes) goto err; + int bytes_rounded = (evm_code[i-1] + 7) >> 3; + char *push = 0; + int q; + for(q=0; q<4-bytes_rounded; q++) + { + push = realloc(push, (q+1)*32); // FIXME segfault + if(!push) goto err; + sprintf(push, "(i64.const 0)%s", push); + } + for(; q<4; q++) + { + int64_t i64 = bytes2long(slice(bytes+(q*8), q*8+8)); + push = realloc(push, (q+1)*32); + if(!push) goto err; + sprintf(push, "%s (i64.const %ld)", push, i64); + + } + format_segment("(call $PUSH %s)", 13+strlen(push), push); + i+=(size_t)evm_code[i]-0x5f; + free(push); + } + break; + + case POP: + // do nothing + break; + + case STOP: + append_segment("(br $done)"); + if(has_jump) + { + i = next_jump_dest(evm_code, len, i); + } + else + { + i = len; + } + break; + + //case SUICIDE: + case RETURN: + format_segment("(call $%s) (br $done)\n", 56, op.name); + if(has_jump) + { + i = next_jump_dest(evm_code, len, i); + } + else + { + i = len; + } + break; + + case INVALID: + append_segment("(unreachable)"); + i = next_jump_dest(evm_code, len, i); + break; + + default: + if(op.cb != 0) + { + int cb_index = index_of(cb_array, op.name, cb_len); + if(cb_index == -1) + { + cb_array[cb_len++] = op.cb; + } + format_segment("(call $%s (i32.const %d))", 72, op.name, cb_index); + } + format_segment("(call $%s)", 32, op.name); + break; + } + + stack_delta = op.on_stack - op.off_stack; + if(stack_delta != 0) + { + format_segment("(set_global $sp (i32.add (get_global $sp) (i32.const %ld)))\n", + 72, stack_delta); + } + + //TODO stacktrace + if(op.cb != 0) + { + format_segment("(set_global $cb_dest (i32.const %ld)) (br $done))", 72, jumps_len+1); + jumps = realloc(jumps, (jumps_len+1)*sizeof(size_t)); + if(!jumps) goto err; + jumps[jumps_len++] = i; + } + } + end_segment(wast_code, segment); + char *with_jumps = assemble_segments(jumps, jumps_len); + wast_code = realloc(wast_code, strlen(wast_code) + strlen(with_jumps)); + if(wast_code == 0) goto err; + wast_code = strcat(with_jumps, wast_code); + wast_code = strcat(wast_code, "))"); + wast_code = build_module(wast_code); + free(segment); + free(with_jumps); + free(jumps); + *wast_ret = wast_code; + *wast_size = strlen(wast_code); + return 1; +#undef append_segment +err: + // TODO optimize this double-branch + if(segment) free(segment); + if(wast_code) free(wast_code); + //if(with_jumps) free(with_jumps); + if(jumps) free(jumps); + return 0; +} diff --git a/libs/evm2wasm/evm2wast.h b/libs/evm2wasm/evm2wast.h new file mode 100644 index 00000000..93549b65 --- /dev/null +++ b/libs/evm2wasm/evm2wast.h @@ -0,0 +1,16 @@ +#ifndef __EVM2WAST_H +#define __EVM2WAST_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int evm2wast(const char *evm_code, size_t len, char **wast_code, size_t *wast_size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/evm2wasm/gadgets.h b/libs/evm2wasm/gadgets.h new file mode 100644 index 00000000..c4246f24 --- /dev/null +++ b/libs/evm2wasm/gadgets.h @@ -0,0 +1,5 @@ +#ifndef __EVM2WASM_GADGETS_H +#define __EVM2WASM_GADGETS_H +extern int gadget_count; +extern const char *gadgets[]; +#endif diff --git a/libs/evm2wasm/gen_gadgets.sh b/libs/evm2wasm/gen_gadgets.sh new file mode 100755 index 00000000..288fb51a --- /dev/null +++ b/libs/evm2wasm/gen_gadgets.sh @@ -0,0 +1,55 @@ +#!/bin/bash +cstr () { +sed 's/;;.*//g' $1 2>/dev/null | sed '$!s/$/\\n\\/' | sed 's/"/\\"/g' +} +fill () { + for i in {0..$1} + do + echo "\"\"," >> gadgets.c + done +} +#0x00 +opcodes=("STOP" "ADD" "MUL" "SUB" "DIV" "SDIV" "MOD" +"ADDMOD" "MULMOD" "EXP" "SIGNEXTEND" 0 0 0 0 +"LT" "GT" "SLT" "SGT" "EQ" "ISZERO" "AND" "OR" "XOR" +"NOT" "BYTE" 0 0 0 0 0 "SHA3" 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 "ADDRESS" "BALANCE" "ORIGIN" "CALLER" +"CALLVALUE" "CALLDATALOAD" "CALLDATASIZE" +"CALLDATACOPY" "CODESIZE" "CODECOPY" "GASPRICE" +"EXTCODZISE" "EXTCODECOPY" "RETURNDATASIZE" +"RETURNDATACOPY" 0 "BLOCKHASH" "COINBASE" "TIMESTAMP" +"NUMBER" "DIFFICULTY" "GASLIMIT" 0 0 0 0 0 0 0 0 0 0 +"POP" "MLOAD" "MSTORE" "MSTORE8" "SLOAD" "SLOAD" "SSTORE" +"JUMP" "JUMPI" "PC" "MSIZE" "GAS" "JUMPDEST" 0 0 0 0 0 +"SELFDESTRUCT" 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +"CALL" "CALLCODE" "RETURN" "DELEGATECALL" "STATICCALL" +"REVERT" 0 0 0 0 0 0 0 "bswap_i32" "bswap_i64" +"bswap_m128" "bswap_m160" "bswap_m256" "callback_128" +"callback_160" "callback_256" "callback_32" "callback" +"check_overflow_i64" "check_overflow" "gte_256" +"gte_320" "gte_512" "iszero_256" "iszero_320" "iszero_512" +"keccak" "memcpy" "memset" "memusegas" "mod_320" +"mod_512" "mul_256") + +cat < gadgets.c +/* This is an autogenerated output by gen_gadgets.sh. DO NOT CHANGE */ +#pragma GCC diagnostic ignored "-Woverlength-strings" +#include "gadgets.h" +EOF +echo "int gadget_count = ${#opcodes[@]};" >> gadgets.c +echo "const char *gadgets[${#opcodes[@]}+1] = {" >> gadgets.c +for i in ${opcodes[@]} +do + if [[ $i == 0 ]] + then + echo "\"\"," >> gadgets.c + continue + fi + echo "\"$(cstr ../../wasm/$i.wast)\"," >> gadgets.c +done +echo "\"\"};" >> gadgets.c +exit 0 diff --git a/tools/evm2wasm/main.cpp b/tools/evm2wasm/main.cpp index e41be68e..22a8d028 100644 --- a/tools/evm2wasm/main.cpp +++ b/tools/evm2wasm/main.cpp @@ -2,7 +2,6 @@ #include #include #include - #include using namespace std; diff --git a/wasm/SIGNEXTEND.wast b/wasm/SIGNEXTEND.wast index ca60bc57..0c726e0d 100644 --- a/wasm/SIGNEXTEND.wast +++ b/wasm/SIGNEXTEND.wast @@ -46,4 +46,3 @@ ) ) ) - diff --git a/wasm/bswap_i32.wast b/wasm/bswap_i32.wast index fbaa91fd..c62a5cc8 100644 --- a/wasm/bswap_i32.wast +++ b/wasm/bswap_i32.wast @@ -8,5 +8,4 @@ (i32.and (i32.shr_u (get_local $int) (i32.const 8)) (i32.const 0xff00))) ;; 6 -> 1 (i32.or (i32.and (i32.shl (get_local $int) (i32.const 8)) (i32.const 0xff0000)) ;; 5 -> 2 - (i32.and (i32.shl (get_local $int) (i32.const 24)) (i32.const 0xff000000)))) ;; 4 -> 3 -) + (i32.and (i32.shl (get_local $int) (i32.const 24)) (i32.const 0xff000000))))) ;; 4 -> 3 diff --git a/wasm/bswap_i64.wast b/wasm/bswap_i64.wast index c5a8ab04..0dda2acb 100644 --- a/wasm/bswap_i64.wast +++ b/wasm/bswap_i64.wast @@ -16,5 +16,4 @@ (i64.and (i64.shl (get_local $int) (i64.const 24)) (i64.const 0xff0000000000))) ;; 2 -> 5 (i64.or (i64.and (i64.shl (get_local $int) (i64.const 40)) (i64.const 0xff000000000000)) ;; 1 -> 6 - (i64.and (i64.shl (get_local $int) (i64.const 56)) (i64.const 0xff00000000000000))))) ;; 0 -> 7 -) + (i64.and (i64.shl (get_local $int) (i64.const 56)) (i64.const 0xff00000000000000)))))) ;; 0 -> 7 From 968019a2f620913bf08878a4140249b7086e25cc Mon Sep 17 00:00:00 2001 From: Silur Date: Thu, 25 Jan 2018 15:30:30 +0100 Subject: [PATCH 3/3] rebase&squash --- evm2wast.c | 676 ------------------------------------------------- evm2wast.h | 7 - gadgets.h | 5 - gen_gadgets.sh | 57 ----- makefile | 24 -- 5 files changed, 769 deletions(-) delete mode 100644 evm2wast.c delete mode 100644 evm2wast.h delete mode 100644 gadgets.h delete mode 100755 gen_gadgets.sh delete mode 100644 makefile diff --git a/evm2wast.c b/evm2wast.c deleted file mode 100644 index 7740420d..00000000 --- a/evm2wast.c +++ /dev/null @@ -1,676 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "evm2wast.h" -#include "gadgets.h" - -struct opcode { - char *name; - size_t fee; - int off_stack; - int on_stack; - char *cb; -}; - -enum op_nums { - STOP = 0x00, - ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, - ADDMOD, MULMOD, EXP, SIGNEXTEND, - LT = 0X10, GT, SLT, SGT, EQ, ISZERO, - AND, OR, XOR, NOT, BYTE, - SHA3 = 0X20, - ADDRESS = 0x30, BALANCE, ORIGIN, CALLER, - CALLVALUE, CALLDATALOAD, CALLDATASIZE, - CALLDATACOPY, CODESIZE, CODECOPY, GASPRICE, - EXTCODESIZE, EXTCODECOPY, RETURNDATASIZE, - RETURNDATACOPY, - BLOCKHASH = 0X40, COINBASE, TIMESTAMP, NUMBER, - DIFFICULTY, GASLIMIT, - POP = 0X50, MLOAD, MSTORE, MSTORE8, SLOAD, - SSTORE, JUMP, JUMPI, PC, MSIZE, GAS, JUMPDEST, - PUSH1 = 0X60, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, - PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, - PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, - PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, - PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, - PUSH31, PUSH32, - DUP1 = 0X80, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, - DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, - DUP15, DUP16, SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, - SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, - SWAP12, SWAP13, SWAP14, SWAP15, SWAP16, LOG1, - LOG2, LOG3, LOG4, LOG5, - CREATE = 0xf0, CALL, CALLCODE, RETURN, DELEGATECALL, - STATICCALL, REVERT, - INVALID = 0xfe, SELFDESTRUCT -}; - -struct opcode opcodes[] = { - [STOP] = {"STOP", 0, 0, 0}, - [ADD] = {"ADD", 3, 2, 1}, - [MUL] = {"MUL", 5, 2, 1}, - [SUB] = {"SUB", 3, 2, 1}, - [DIV] = {"DIV", 5, 2, 1}, - [SDIV] = {"SDIV", 5, 2, 1}, - [MOD] = {"MOD", 5, 2, 1}, - [SMOD] = {"SMOD", 5, 2, 1}, - [ADDMOD] = {"ADDMOD", 8, 3, 1}, - [MULMOD] = {"MULMOD", 8, 3, 1}, - [EXP] = {"EXP", 10, 2, 1}, - [SIGNEXTEND] = {"SIGNEXTEND", 5, 2, 1}, - - [LT] = {"LT", 3, 2, 1}, - [GT] = {"GT", 3, 2, 1}, - [SLT] = {"SLT", 3, 2, 1}, - [SGT] = {"SGT", 3, 2, 1}, - [EQ] = {"EQ", 3, 2, 1}, - [ISZERO] = {"ISZERO", 3, 1, 1}, - [AND] = {"AND", 3, 2, 1}, - [OR] = {"OR", 3, 2, 1}, - [XOR] = {"XOR", 3, 2, 1}, - [NOT] = {"NOT", 3, 1, 1}, - [BYTE] = {"BYTE", 3, 2, 1}, - - // 0x20 range - crypto - [SHA3] = {"SHA3", 30, 2, 1}, - - // 0x30 range - closure state - [ADDRESS] = {"ADDRESS", 2, 0, 1}, - [BALANCE] = {"BALANCE", 400, 1, 1, "$callback_128"}, - [ORIGIN] = {"ORIGIN", 2, 0, 1}, - [CALLER] = {"CALLER", 2, 0, 1}, - [CALLVALUE] = {"CALLVALUE", 2, 0, 1}, - [CALLDATALOAD] = {"CALLDATALOAD", 3, 1, 1}, - [CALLDATASIZE] = {"CALLDATASIZE", 2, 0, 1}, - [CALLDATACOPY] = {"CALLDATACOPY", 3, 3, 0}, - [CODESIZE] = {"CODESIZE", 2, 0, 1, "$callback_32"}, - [CODECOPY] = {"CODECOPY", 3, 3, 0, "$callback"}, - [GASPRICE] = {"GASPRICE", 2, 0, 1}, - [EXTCODESIZE] = {"EXTCODESIZE", 700, 1, 1, "$callback_32"}, - [EXTCODECOPY] = {"EXTCODECOPY", 700, 4, 0, "$callback"}, - [RETURNDATASIZE] = {"RETURNDATASIZE", 2, 0, 1}, - [RETURNDATACOPY] = {"RETURNDATACOPY", 3, 3, 0}, - - // '0x40' range - block operations - [BLOCKHASH] = {"BLOCKHASH", 20, 1, 1, "$callback_256"}, - [COINBASE] = {"COINBASE", 2, 0, 1}, - [TIMESTAMP] = {"TIMESTAMP", 2, 0, 1}, - [NUMBER] = {"NUMBER", 2, 0, 1}, - [DIFFICULTY] = {"DIFFICULTY", 2, 0, 1}, - [GASLIMIT] = {"GASLIMIT", 2, 0, 1}, - - // 0x50 range - 'storage' and execution - [POP] = {"POP", 2, 1, 0}, - [MLOAD] = {"MLOAD", 3, 1, 1}, - [MSTORE] = {"MSTORE", 3, 2, 0}, - [MSTORE8] = {"MSTORE8", 3, 2, 0}, - [SLOAD] = {"SLOAD", 200, 1, 1, "$callback_256"}, - [SSTORE] = {"SSTORE", 0, 2, 0, "$callback"}, - [JUMP] = {"JUMP", 8, 1, 0}, - [JUMPI] = {"JUMPI", 10, 2, 0}, - [PC] = {"PC", 2, 0, 1}, - [MSIZE] = {"MSIZE", 2, 0, 1}, - [GAS] = {"GAS", 2, 0, 1}, - [JUMPDEST] = {"JUMPDEST", 1, 0, 0}, - - // 0x60, range - [PUSH1] = {"PUSH", 3, 0, 1}, - [PUSH2] = {"PUSH", 3, 0, 1}, - [PUSH3] = {"PUSH", 3, 0, 1}, - [PUSH4] = {"PUSH", 3, 0, 1}, - [PUSH5] = {"PUSH", 3, 0, 1}, - [PUSH6] = {"PUSH", 3, 0, 1}, - [PUSH7] = {"PUSH", 3, 0, 1}, - [PUSH8] = {"PUSH", 3, 0, 1}, - [PUSH9] = {"PUSH", 3, 0, 1}, - [PUSH10] = {"PUSH", 3, 0, 1}, - [PUSH11] = {"PUSH", 3, 0, 1}, - [PUSH12] = {"PUSH", 3, 0, 1}, - [PUSH13] = {"PUSH", 3, 0, 1}, - [PUSH14] = {"PUSH", 3, 0, 1}, - [PUSH15] = {"PUSH", 3, 0, 1}, - [PUSH16] = {"PUSH", 3, 0, 1}, - [PUSH17] = {"PUSH", 3, 0, 1}, - [PUSH18] = {"PUSH", 3, 0, 1}, - [PUSH19] = {"PUSH", 3, 0, 1}, - [PUSH20] = {"PUSH", 3, 0, 1}, - [PUSH21] = {"PUSH", 3, 0, 1}, - [PUSH22] = {"PUSH", 3, 0, 1}, - [PUSH23] = {"PUSH", 3, 0, 1}, - [PUSH24] = {"PUSH", 3, 0, 1}, - [PUSH25] = {"PUSH", 3, 0, 1}, - [PUSH26] = {"PUSH", 3, 0, 1}, - [PUSH27] = {"PUSH", 3, 0, 1}, - [PUSH28] = {"PUSH", 3, 0, 1}, - [PUSH29] = {"PUSH", 3, 0, 1}, - [PUSH30] = {"PUSH", 3, 0, 1}, - [PUSH31] = {"PUSH", 3, 0, 1}, - [PUSH32] = {"PUSH", 3, 0, 1}, - - [DUP1] = {"DUP", 3, 0, 1}, - [DUP2] = {"DUP", 3, 0, 1}, - [DUP3] = {"DUP", 3, 0, 1}, - [DUP4] = {"DUP", 3, 0, 1}, - [DUP5] = {"DUP", 3, 0, 1}, - [DUP6] = {"DUP", 3, 0, 1}, - [DUP7] = {"DUP", 3, 0, 1}, - [DUP8] = {"DUP", 3, 0, 1}, - [DUP9] = {"DUP", 3, 0, 1}, - [DUP10] = {"DUP", 3, 0, 1}, - [DUP11] = {"DUP", 3, 0, 1}, - [DUP12] = {"DUP", 3, 0, 1}, - [DUP13] = {"DUP", 3, 0, 1}, - [DUP14] = {"DUP", 3, 0, 1}, - [DUP15] = {"DUP", 3, 0, 1}, - [DUP16] = {"DUP", 3, 0, 1}, - - [SWAP1] = {"SWAP", 3, 0, 0}, - [SWAP2] = {"SWAP", 3, 0, 0}, - [SWAP3] = {"SWAP", 3, 0, 0}, - [SWAP4] = {"SWAP", 3, 0, 0}, - [SWAP5] = {"SWAP", 3, 0, 0}, - [SWAP6] = {"SWAP", 3, 0, 0}, - [SWAP7] = {"SWAP", 3, 0, 0}, - [SWAP8] = {"SWAP", 3, 0, 0}, - [SWAP9] = {"SWAP", 3, 0, 0}, - [SWAP10] = {"SWAP", 3, 0, 0}, - [SWAP11] = {"SWAP", 3, 0, 0}, - [SWAP12] = {"SWAP", 3, 0, 0}, - [SWAP13] = {"SWAP", 3, 0, 0}, - [SWAP14] = {"SWAP", 3, 0, 0}, - [SWAP15] = {"SWAP", 3, 0, 0}, - [SWAP16] = {"SWAP", 3, 0, 0}, - - [LOG1] = {"LOG", 375, 2, 0}, - [LOG2] = {"LOG", 375, 2, 0}, - [LOG3] = {"LOG", 375, 2, 0}, - [LOG4] = {"LOG", 375, 2, 0}, - [LOG5] = {"LOG", 375, 2, 0}, - - // '0xf0' range - closures - [CREATE] = {"CREATE", 32000, 3, 1, "$callback_160"}, - [CALL] = {"CALL", 700, 7, 1, "$callback_32"}, - [CALLCODE] = {"CALLCODE", 700, 7, 1, "$callback_32"}, - [RETURN] = {"RETURN", 0, 2, 0}, - [DELEGATECALL] = {"DELEGATECALL", 700, 6, 1, "$callback"}, - [STATICCALL] = {"STATICCALL", 700, 6, 1}, - [REVERT] = {"REVERT", 0, 2, 0}, - - // '0x70', range - other - [INVALID] = {"INVALID", 0, 0, 0}, - [SELFDESTRUCT] = {"SELFDESTRUCT", 5000, 1, 0} -}; - - -static inline int digits(unsigned long x) { return (floor(log10(abs(x))) + 1); } -static int64_t bytes2long(char *bytes) -{ - int64_t ret = 0; - int i; - for(i = 0; i < 8; i++) - { - ret = (ret << 8) | bytes[i]; - } - return ret; -} -static char *padleft(char *bytes, int curr_len, int len) -{ - if(curr_len > len) - { - fprintf(stderr, "pad failed to prevent memory overlap\n"); - return 0; - } - char *ret = calloc(len, 1); - if(!ret) return 0; - ret = memcpy(ret+(len-curr_len)-1, bytes, curr_len); - - return ret; -} -static char *slice(char *bytes, int len) -{ - char *ret = malloc(sizeof(len)); - ret = memcpy(ret, bytes, len); - return ret; -} -static int index_of(char **table, char *elem, int len) -{ - int i; - for(i=0; i= PUSH1 && evm_code[i] <= PUSH32) - { - i+=evm_code[i]-0x59; - break; - } - } - return --i; -} -char *build_module(char *wast) -{ - int i; - char *ret = malloc(819200); - if(!ret) return 0; - ret = strcat(ret, "(module "); - for(i=0; i stack_high) stack_high = stack_delta; - stack_delta = op.on_stack; - if(stack_delta < stack_low) stack_low = stack_delta; - - switch(evm_code[i]) - { - case JUMP: - has_jump=1; - append_segment("(set_local $jump_dest (call $check_overflow \ - (i64.load (get_global $sp)) \ - (i64.load (i32.add (get_global $sp) (i32.const 8)))\ - (i64.load (i32.add (get_global $sp) (i32.const 16)))\ - (i64.load (i32.add (get_global $sp) (i32.const 24)))))\ - (set_global $sp (i32.sub (get_global $sp) (i32.const 32)))\ - (br $loop)"); - i = next_jump_dest(evm_code, len, i); - break; - - case JUMPI: - has_jump=1; - append_segment("(set_local $jump_dest (call $check_overflow \ - (i64.load (get_global $sp)) \ - (i64.load (i32.add (get_global $sp) (i32.const 8))) \ - (i64.load (i32.add (get_global $sp) (i32.const 16))) \ - (i64.load (i32.add (get_global $sp) (i32.const 24))))) \ - (set_global $sp (i32.sub (get_global $sp) (i32.const 64))) \ - (br_if $loop (i32.eqz (i64.eqz (i64.or \ - (i64.load (i32.add (get_global $sp) (i 32.const 32))) \ - (i64.or \ - (i64.load (i32.add (get_global $sp) (i32.const 40))) \ - (i64.or \ - (i64.load (i32.add (get_global $sp) (i32.const 48))) \ - (i64.load (i32.add (get_global $sp) (i32.const 56))) \ - ) \ - ) \ - ))))"); - add_stack_check(segment); - add_metering(wast_code, segment); - break; - - case JUMPDEST: - end_segment(wast_code, segment); - jumps = realloc(jumps, jumps_len); - jumps[jumps_len++] = i; - gas_count = 1; - break; - - case GAS: - append_segment("(call $GAS)\n"); - add_metering(wast_code, segment); - break; - - case LOG1: - case LOG2: - case LOG3: - case LOG4: - case LOG5: - format_segment("(call $LOG (i32.const %d))", 36, (int)evm_code[i]); - break; - - case DUP1: - case DUP2: - case DUP3: - case DUP4: - case DUP5: - case DUP6: - case DUP7: - case DUP8: - case DUP9: - case DUP10: - case DUP11: - case DUP12: - case DUP13: - case DUP14: - case DUP15: - case DUP16: - case SWAP1: - case SWAP2: - case SWAP3: - case SWAP4: - case SWAP5: - case SWAP6: - case SWAP7: - case SWAP8: - case SWAP9: - case SWAP10: - case SWAP11: - case SWAP12: - case SWAP13: - case SWAP14: - case SWAP15: - case SWAP16: - format_segment("(call $%s (i32.const $%d))\n", 60, - op.name, (int)evm_code[i]); - break; - - case PC: - format_segment("(call $PC (i32.const %ld", 40, i); - break; - - case PUSH1: - case PUSH2: - case PUSH3: - case PUSH4: - case PUSH5: - case PUSH6: - case PUSH7: - case PUSH8: - case PUSH9: - case PUSH10: - case PUSH11: - case PUSH12: - case PUSH13: - case PUSH14: - case PUSH15: - case PUSH16: - case PUSH17: - case PUSH18: - case PUSH19: - case PUSH20: - case PUSH21: - case PUSH22: - case PUSH23: - case PUSH24: - case PUSH25: - case PUSH26: - case PUSH27: - case PUSH28: - case PUSH29: - case PUSH30: - case PUSH31: - case PUSH32: - { - char *bytes = padleft(evm_code+i+1, evm_code[i]-0x59, 32); - i+=(size_t)evm_code[i]-0x59; - if(!bytes) goto err; - int bytes_rounded = (int)ceil((double)(evm_code[i]/8)); - char *push = 0; - int q; - for(q=0; q<4-bytes_rounded; q++) - { - push = realloc(push, (q+1)*32); // FIXME segfault - if(!push) goto err; - sprintf(push, "(i64.const 0)%s", push); - } - for(; q<4; q++) - { - int64_t i64 = bytes2long(slice(bytes+(q*8), q*8+8)); - push = realloc(push, (q+1)*32); - if(!push) goto err; - sprintf(push, "%s (i64.const $%ld)", push, i64); - - } - format_segment("(call $PUSH %s)", 13+strlen(push), push); - i--; - //free(bytes); - //free(push); - } - break; - - case POP: - // do nothing - break; - - case STOP: - append_segment("(br $done)"); - if(has_jump) - { - i = next_jump_dest(evm_code, len, i); - } - else - { - i = len; - } - break; - - //case SUICIDE: - case RETURN: - format_segment("(call $%s) (br $done)\n", 56, op.name); - if(has_jump) - { - i = next_jump_dest(evm_code, len, i); - } - else - { - i = len; - } - break; - - case INVALID: - append_segment("(unreachable)"); - i = next_jump_dest(evm_code, len, i); - break; - - default: - printf("found cb for op %s\n", op.name); - if(op.cb != 0) - { - int cb_index = index_of(cb_array, op.name, cb_len); - if(cb_index == -1) - { - cb_array[cb_len++] = op.cb; - } - format_segment("(call $%s (i32.const %d))", 72, op.name, cb_index); - } - format_segment("(call $%s)", 32, op.name); - break; - } - - stack_delta = op.on_stack - op.off_stack; - if(stack_delta != 0) - { - format_segment("(set_global $sp (i32.add (get_global $sp) (i32.const %ld)))\n", - 72, stack_delta); - } - - //TODO stacktrace - if(op.cb != 0) - { - format_segment("(set_global $cb_dest (i32.const %ld)) (br $done))", 72, jumps_len+1); - jumps = realloc(jumps, (jumps_len+1)*sizeof(size_t)); - if(!jumps) goto err; - jumps[jumps_len++] = i; - } - } - end_segment(wast_code, segment); - char *with_jumps = assemble_segments(jumps, jumps_len); - wast_code = realloc(wast_code, strlen(wast_code) + strlen(with_jumps)); - if(wast_code == 0) goto err; - wast_code = strcat(with_jumps, wast_code); - wast_code = strcat(wast_code, "))"); - wast_code = build_module(wast_code); - free(segment); - free(with_jumps); - free(jumps); - *wast_ret = wast_code; - *wast_size = strlen(wast_code); - return 1; -#undef append_segment -err: - // TODO optimize this double-branch - if(segment) free(segment); - if(wast_code) free(wast_code); - //if(with_jumps) free(with_jumps); - if(jumps) free(jumps); - return 0; -} diff --git a/evm2wast.h b/evm2wast.h deleted file mode 100644 index 04d6a996..00000000 --- a/evm2wast.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __EVM2WAST_H -#define __EVM2WAST_H -#include -#ifdef __cplusplus -extern "C" int evm2wast(char *evm_code, size_t len, char **wast_code, size_t *wast_size); -#endif -#endif diff --git a/gadgets.h b/gadgets.h deleted file mode 100644 index c4246f24..00000000 --- a/gadgets.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef __EVM2WASM_GADGETS_H -#define __EVM2WASM_GADGETS_H -extern int gadget_count; -extern const char *gadgets[]; -#endif diff --git a/gen_gadgets.sh b/gen_gadgets.sh deleted file mode 100755 index b2d9277c..00000000 --- a/gen_gadgets.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -cstr () { -sed '$!s/$/\\n\\/' $1 2>/dev/null | sed 's/"/\\"/g' -} -fill () { - for i in {0..$1} - do - echo "\"\"," >> gadgets.c - done -} -#0x00 -opcodes=("STOP" "ADD" "MUL" "SUB" "DIV" "SDIV" "MOD" -"ADDMOD" "MULMOD" "EXP" "SIGNEXTEND" 0 0 0 0 -"LT" "GT" "SLT" "SGT" "EQ" "ISZERO" "AND" "OR" "XOR" -"NOT" "BYTE" 0 0 0 0 0 "SHA3" 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 "ADDRESS" "BALANCE" "ORIGIN" "CALLER" -"CALLVALUE" "CALLDATALOAD" "CALLDATASIZE" -"CALLDATACOPY" "CODESIZE" "CODECOPY" "GASPRICE" -"EXTCODZISE" "EXTCODECOPY" "RETURNDATASIZE" -"RETURNDATACOPY" 0 "BLOCKHASH" "COINBASE" "TIMESTAMP" -"NUMBER" "DIFFICULTY" "GASLIMIT" 0 0 0 0 0 0 0 0 0 0 -"POP" "MLOAD" "MSTORE" "MSTORE8" "SLOAD" "SLOAD" "SSTORE" -"JUMP" "JUMPI" "PC" "MSIZE" "GAS" "JUMPDEST" 0 0 0 0 0 -"SELFDESTRUCT" 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -"CALL" "CALLCODE" "RETURN" "DELEGATECALL" "STATICCALL" -"REVERT" 0 0 0 0 0 0 0 "bswap_i32" "bswap_i64" -"bswap_m128" "bswap_m160" "bswap_m256" "callback_128" -"callback_160" "callback_256" "callback_32" "callback" -"check_overflow_i64" "check_overflow" "gte_256" -"gte_320" "gte_512" "iszero_256" "iszero_320" "iszero_512" -"keccak" "memcpy" "memset" "memusegas" "mod_320" -"mod_512" "mul_256") - -cat < gadgets.c -#ifndef __EVM2WASM_GADGETS_H -#define __EVM2WASM_GADGETS_H -#pragma GCC diagnostic ignored "-Woverlength-strings" -#include "gadgets.h" -EOF -echo "const int gadget_count = ${#opcodes[@]};" >> gadgets.c -echo "const char *gadgets[${#opcodes[@]}+1] = {" >> gadgets.c -for i in ${opcodes[@]} -do - if [[ $i == 0 ]] - then - echo "\"\"," >> gadgets.c - continue - fi - echo "\"$(cstr wasm/$i.wast)\"," >> gadgets.c -done -echo "\"\"};" >> gadgets.c -echo '#endif' >> gadgets.c -exit 0 diff --git a/makefile b/makefile deleted file mode 100644 index ba5bb0c2..00000000 --- a/makefile +++ /dev/null @@ -1,24 +0,0 @@ -.POSIX: -.SUFFIXES: -CC = gcc -CFLAGS = -Wall -Werror -O2 -pedantic -LDFLAGS = -shared -fPIC -lm - -all: gadgets.o evm2wast.o - $(CC) -o evm2wasm.so evm2wast.o $(LDFLAGS) - -evm2wast.o: evm2wast.c - $(CC) -o evm2wast.o -c evm2wast.c $(CFLAGS) $(LDFLAGS) - -gadgets.o: gadgets - $(CC) -c -o gadgets.o gadgets.c - -lint: - indent *.c - indent *.h - -clean: - rm *.o *.so - -gadgets: - $(shell ./gen_gadgets.sh)