From 2458aaae9fc525daa958a757a922ea662fba9cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 13 Jan 2015 11:51:57 +0100 Subject: [PATCH 1/5] Fix evmjit standalone compilation --- .gitignore | 1 + CMakeLists.txt | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..84c048a73c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 18601b921f..856cb56c26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,11 @@ project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +else () + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") +endif() + # LLVM if(LLVM_DIR) # local LLVM build find_package(LLVM REQUIRED CONFIG) @@ -18,11 +23,18 @@ else() execute_process(COMMAND llvm-config-3.5 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS) message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}") set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") + add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS) endif() # Boost find_package(Boost REQUIRED) add_subdirectory(libevmjit) -add_subdirectory(libevmjit-cpp) -add_subdirectory(evmcc) + +if(EVMJIT_CPP) + add_subdirectory(libevmjit-cpp) +endif() + +if(EVMJIT_TOOLS) + add_subdirectory(evmcc) +endif() From 1861843a24d1a4aa62e20a3cfdab383131a4ebfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 14 Jan 2015 09:08:17 +0100 Subject: [PATCH 2/5] EVM JIT called from Go, env_sha3 callback works --- libevmjit/CMakeLists.txt | 3 +- libevmjit/ExecutionEngine.cpp | 2 +- libevmjit/interface.cpp | 63 ++++++++++++++++++++++++++ libevmjit/{interface.c => interface.h} | 17 ++++++- 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 libevmjit/interface.cpp rename libevmjit/{interface.c => interface.h} (87%) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 7c35169a7a..28b501ee3a 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -10,7 +10,8 @@ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) endif () -add_library(${TARGET_NAME} ${SOURCES} ${HEADERS}) +link_directories(/usr/lib/llvm-3.5/lib) +add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS}) set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 7e99932c37..71142fbeee 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -49,7 +49,7 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) std::string codeHash(bytes const& _code) { - std::array binHash; + std::array binHash; env_sha3(_code.data(), _code.size(), &binHash); std::ostringstream os; diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp new file mode 100644 index 0000000000..ec7d07b336 --- /dev/null +++ b/libevmjit/interface.cpp @@ -0,0 +1,63 @@ +#include "interface.h" +#include +#include "ExecutionEngine.h" + +extern "C" +{ + +int evmjit_run() +{ + using namespace dev::eth::jit; + + ExecutionEngine engine; + u256 gas = 100000; + + bytes bytecode = { 0x60, 0x01 }; + + // Create random runtime data + RuntimeData data; + data.set(RuntimeData::Gas, gas); + data.set(RuntimeData::Address, 0); + data.set(RuntimeData::Caller, 0); + data.set(RuntimeData::Origin, 0); + data.set(RuntimeData::CallValue, 0xabcd); + data.set(RuntimeData::CallDataSize, 3); + data.set(RuntimeData::GasPrice, 1003); + data.set(RuntimeData::CoinBase, 0); + data.set(RuntimeData::TimeStamp, 1005); + data.set(RuntimeData::Number, 1006); + data.set(RuntimeData::Difficulty, 16); + data.set(RuntimeData::GasLimit, 1008); + data.set(RuntimeData::CodeSize, bytecode.size()); + data.callData = (uint8_t*)"abc"; + data.code = bytecode.data(); + + // BROKEN: env_* functions must be implemented & RuntimeData struct created + // TODO: Do not compile module again + auto result = engine.run(bytecode, &data, nullptr); + return static_cast(result); +} + +// Runtime callback functions - implementations must be provided by external language (Go, C++, Python) +void evm_jit_rt_sload(evm_jit_rt* _rt, i256* _index, i256* _ret); +void evm_jit_rt_sstore(evm_jit_rt* _rt, i256* _index, i256* _value); +void evm_jit_rt_balance(evm_jit_rt* _rt, h256* _address, i256* _ret); +// And so on... + +evm_jit* evm_jit_create(evm_jit_rt*) +{ + printf("EVM JIT create"); + + int* a = nullptr; + *a = 1; + + return nullptr; +} + +evm_jit_return_code evm_jit_execute(evm_jit* _jit); + +void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); + +void evm_jit_destroy(evm_jit* _jit); + +} diff --git a/libevmjit/interface.c b/libevmjit/interface.h similarity index 87% rename from libevmjit/interface.c rename to libevmjit/interface.h index 47589578b6..0e30762836 100644 --- a/libevmjit/interface.c +++ b/libevmjit/interface.h @@ -1,4 +1,10 @@ -#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int evmjit_run(); // JIT object opaque type typedef struct evm_jit evm_jit; @@ -9,6 +15,11 @@ typedef int evm_jit_return_code; // Host-endian 256-bit integer type typedef struct i256 i256; +struct h256 +{ + char b[33]; +}; + // Big-endian right aligned 256-bit hash typedef struct h256 h256; @@ -28,3 +39,7 @@ evm_jit_return_code evm_jit_execute(evm_jit* _jit); void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); void evm_jit_destroy(evm_jit* _jit); + +#ifdef __cplusplus +} +#endif From 4101e680c814c0faadaa2de1e228e56a6acea3fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 14 Jan 2015 13:49:56 +0100 Subject: [PATCH 3/5] Changes in EVM JIT C interface --- libevmjit/interface.cpp | 34 ++++++++++------------------------ libevmjit/interface.h | 4 ++-- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp index ec7d07b336..6a729f3d00 100644 --- a/libevmjit/interface.cpp +++ b/libevmjit/interface.cpp @@ -5,36 +5,22 @@ extern "C" { -int evmjit_run() +int evmjit_run(void* _data, void* _env) { using namespace dev::eth::jit; + auto data = static_cast(_data); + + std::cerr << "GAS: " << data->elems[RuntimeData::Gas].a << "\n"; + ExecutionEngine engine; - u256 gas = 100000; - bytes bytecode = { 0x60, 0x01 }; + auto codePtr = data->code; + auto codeSize = data->elems[RuntimeData::CodeSize].a; + bytes bytecode; + bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); - // Create random runtime data - RuntimeData data; - data.set(RuntimeData::Gas, gas); - data.set(RuntimeData::Address, 0); - data.set(RuntimeData::Caller, 0); - data.set(RuntimeData::Origin, 0); - data.set(RuntimeData::CallValue, 0xabcd); - data.set(RuntimeData::CallDataSize, 3); - data.set(RuntimeData::GasPrice, 1003); - data.set(RuntimeData::CoinBase, 0); - data.set(RuntimeData::TimeStamp, 1005); - data.set(RuntimeData::Number, 1006); - data.set(RuntimeData::Difficulty, 16); - data.set(RuntimeData::GasLimit, 1008); - data.set(RuntimeData::CodeSize, bytecode.size()); - data.callData = (uint8_t*)"abc"; - data.code = bytecode.data(); - - // BROKEN: env_* functions must be implemented & RuntimeData struct created - // TODO: Do not compile module again - auto result = engine.run(bytecode, &data, nullptr); + auto result = engine.run(bytecode, data, static_cast(_env)); return static_cast(result); } diff --git a/libevmjit/interface.h b/libevmjit/interface.h index 0e30762836..1515fed861 100644 --- a/libevmjit/interface.h +++ b/libevmjit/interface.h @@ -4,7 +4,7 @@ extern "C" { #endif -int evmjit_run(); +int evmjit_run(void* _data, void* _env); // JIT object opaque type typedef struct evm_jit evm_jit; @@ -15,7 +15,7 @@ typedef int evm_jit_return_code; // Host-endian 256-bit integer type typedef struct i256 i256; -struct h256 +struct i256 { char b[33]; }; From 313b77fabd7b2f418ec18320b179d82bd06f06b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 15 Jan 2015 14:21:29 +0100 Subject: [PATCH 4/5] Allow undefined symbols in shared library on OSX --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 856cb56c26..acb113207e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,10 @@ else () set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") endif() +if(APPLE) + set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") +endif() + # LLVM if(LLVM_DIR) # local LLVM build find_package(LLVM REQUIRED CONFIG) From 70d02b1d661b4c057f53bb1c5ca563e289c80dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 15 Jan 2015 16:27:57 +0100 Subject: [PATCH 5/5] RETURN implementation: JIT returns data --- libevmjit/interface.cpp | 39 ++++++++++++--------------------------- libevmjit/interface.h | 11 ++++++++++- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp index 6a729f3d00..eef92d00fd 100644 --- a/libevmjit/interface.cpp +++ b/libevmjit/interface.cpp @@ -5,14 +5,12 @@ extern "C" { -int evmjit_run(void* _data, void* _env) +evmjit_result evmjit_run(void* _data, void* _env) { using namespace dev::eth::jit; auto data = static_cast(_data); - std::cerr << "GAS: " << data->elems[RuntimeData::Gas].a << "\n"; - ExecutionEngine engine; auto codePtr = data->code; @@ -20,30 +18,17 @@ int evmjit_run(void* _data, void* _env) bytes bytecode; bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); - auto result = engine.run(bytecode, data, static_cast(_env)); - return static_cast(result); + auto returnCode = engine.run(bytecode, data, static_cast(_env)); + evmjit_result result = {static_cast(returnCode), 0, nullptr}; + if (returnCode == ReturnCode::Return && !engine.returnData.empty()) + { + // TODO: Optimized returning data. Allocating memory on client side by callback function might be a good idea + result.returnDataSize = engine.returnData.size(); + result.returnData = std::malloc(result.returnDataSize); + std::memcpy(result.returnData, engine.returnData.data(), result.returnDataSize); + } + + return result; } -// Runtime callback functions - implementations must be provided by external language (Go, C++, Python) -void evm_jit_rt_sload(evm_jit_rt* _rt, i256* _index, i256* _ret); -void evm_jit_rt_sstore(evm_jit_rt* _rt, i256* _index, i256* _value); -void evm_jit_rt_balance(evm_jit_rt* _rt, h256* _address, i256* _ret); -// And so on... - -evm_jit* evm_jit_create(evm_jit_rt*) -{ - printf("EVM JIT create"); - - int* a = nullptr; - *a = 1; - - return nullptr; -} - -evm_jit_return_code evm_jit_execute(evm_jit* _jit); - -void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); - -void evm_jit_destroy(evm_jit* _jit); - } diff --git a/libevmjit/interface.h b/libevmjit/interface.h index 1515fed861..5d9307ab2b 100644 --- a/libevmjit/interface.h +++ b/libevmjit/interface.h @@ -1,10 +1,19 @@ #include +#include #ifdef __cplusplus extern "C" { #endif -int evmjit_run(void* _data, void* _env); +typedef struct evmjit_result +{ + int32_t returnCode; + uint64_t returnDataSize; + void* returnData; + +} evmjit_result; + +evmjit_result evmjit_run(void* _data, void* _env); // JIT object opaque type typedef struct evm_jit evm_jit;