From f41550077a084183e69b70404c6f7b89f0acdb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 1 Oct 2014 16:48:02 +0200 Subject: [PATCH 1/2] Implementing RETURN and STOP instructions --- evmcc/Compiler.cpp | 48 ++++++++++++++++++++++++++++++++++--- evmcc/ExecutionEngine.cpp | 10 ++++++-- evmcc/Memory.cpp | 15 ++++-------- evmcc/bytecode/ext_test.evm | 2 +- evmcc/lll/ext_test.lll | 5 ++++ 5 files changed, 63 insertions(+), 17 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 1b3edd8bd..e258f840d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -49,7 +49,10 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) IRBuilder<> builder(context); // Create main function - auto mainFuncType = FunctionType::get(llvm::Type::getInt32Ty(context), false); + const auto i32Ty = builder.getInt32Ty(); + Type* retTypeElems[] = {i32Ty, i32Ty}; + auto retType = StructType::create(retTypeElems, "MemRef", true); + auto mainFuncType = FunctionType::get(builder.getInt64Ty(), false); auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get()); auto entryBlock = BasicBlock::Create(context, "entry", mainFunc); @@ -61,7 +64,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto ext = Ext(builder); - for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) + auto userRet = false; + auto finished = false; + for (auto pc = bytecode.cbegin(); pc != bytecode.cend() && !finished; ++pc) { using dev::eth::Instruction; @@ -313,10 +318,47 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::CODESIZE: + { + auto value = builder.getIntN(256, bytecode.size()); + stack.push(value); + break; + } + + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); + + // MCJIT does not support returning structs + //auto index32 = builder.CreateTrunc(index, i32Ty, "index32"); + //auto size32 = builder.CreateTrunc(size, i32Ty, "size32"); + //auto ret = builder.CreateInsertValue(UndefValue::get(retType), index32, 0, "ret"); + //ret = builder.CreateInsertValue(ret, size32, 1, "ret"); + + auto ret = builder.CreateTrunc(index, builder.getInt64Ty()); + ret = builder.CreateShl(ret, 32); + size = builder.CreateTrunc(size, i32Ty); + size = builder.CreateZExt(size, builder.getInt64Ty()); + ret = builder.CreateOr(ret, size); + + builder.CreateRet(ret); + finished = true; + userRet = true; + break; + } + + case Instruction::STOP: + { + finished = true; + break; + } + } } - builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 0)); + if (!userRet) + builder.CreateRet(builder.getInt64(0)); return module; } diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 616bde402..410e80a0b 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -86,8 +86,14 @@ int ExecutionEngine::run(std::unique_ptr _module) } auto result = exec->runFunction(entryFunc, {}); - auto intResult = result.IntVal.getZExtValue(); - return intResult; + if (auto intResult = result.IntVal.getZExtValue()) + { + auto index = intResult >> 32; + auto size = 0xFFFFFFFF & intResult; + // TODO: Get the data from memory + return 10; + } + return 0; } } \ No newline at end of file diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 9e3c2942e..7c8d2d54a 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -10,6 +10,8 @@ #include +#include "Utils.h" + #ifdef _MSC_VER #define EXPORT __declspec(dllexport) #else @@ -19,15 +21,6 @@ namespace evmcc { -struct i256 -{ - uint64_t a; - uint64_t b; - uint64_t c; - uint64_t d; -}; -static_assert(sizeof(i256) == 32, "Wrong i256 size"); - using MemoryImpl = dev::bytes; @@ -102,7 +95,7 @@ extern "C" { using namespace evmcc; -EXPORT MemoryImpl* evmccrt_memory; +static MemoryImpl* evmccrt_memory; EXPORT void evmccrt_memory_create(void) { @@ -121,7 +114,7 @@ EXPORT void* evmccrt_memory_require(uint64_t _size) if (evmccrt_memory->size() < _size) evmccrt_memory->resize(_size); - return &(*evmccrt_memory)[0]; + return evmccrt_memory->data(); } EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) diff --git a/evmcc/bytecode/ext_test.evm b/evmcc/bytecode/ext_test.evm index ccca5e56b..5bcc94ba1 100644 --- a/evmcc/bytecode/ext_test.evm +++ b/evmcc/bytecode/ext_test.evm @@ -1 +1 @@ -30333234363a600035602635601335 +30333234363a600035602635601335380060016002f2 diff --git a/evmcc/lll/ext_test.lll b/evmcc/lll/ext_test.lll index f6680f2a7..f32bfb440 100644 --- a/evmcc/lll/ext_test.lll +++ b/evmcc/lll/ext_test.lll @@ -12,4 +12,9 @@ CALLDATALOAD CALLDATALOAD 19 CALLDATALOAD +CODESIZE +STOP +1 +2 +RETURN ) \ No newline at end of file From f6759913e4aad3c577067ae089f0890fe93b73b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 1 Oct 2014 17:30:04 +0200 Subject: [PATCH 2/2] Print returned memory to standard output --- evmcc/Compiler.cpp | 2 +- evmcc/ExecutionEngine.cpp | 10 +++++++++- evmcc/Memory.cpp | 34 ++++++++++++++++------------------ evmcc/Memory.h | 6 +++++- evmcc/bytecode/return_test.evm | 1 + evmcc/lll/return_test.lll | 15 +++++++++++++++ 6 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 evmcc/bytecode/return_test.evm create mode 100644 evmcc/lll/return_test.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 51d74bb2f..c55b33cc6 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -60,7 +60,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Init stack and memory auto stack = Stack(builder, module.get()); - auto memory = Memory(builder, module.get()); + auto memory = Memory(builder); auto ext = Ext(builder); diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 410e80a0b..4d847388e 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -14,6 +14,7 @@ #include #include "Ext.h" +#include "Memory.h" namespace evmcc { @@ -68,6 +69,8 @@ int ExecutionEngine::run(std::unique_ptr _module) _module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module exec->finalizeObject(); + auto&& memory = Memory::init(); + auto ext = std::make_unique(); ext->myAddress = dev::Address(1122334455667788); ext->caller = dev::Address(0xfacefacefaceface); @@ -90,7 +93,12 @@ int ExecutionEngine::run(std::unique_ptr _module) { auto index = intResult >> 32; auto size = 0xFFFFFFFF & intResult; - // TODO: Get the data from memory + + std::cout << "RETURN [ "; + for (dev::bytes::const_iterator it = memory.cbegin() + index, end = it + size; it != end; ++it) + std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; + std::cout << "]"; + return 10; } return 0; diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 9897496de..2a1a0f727 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -23,33 +23,40 @@ namespace evmcc using MemoryImpl = dev::bytes; +static MemoryImpl* evmccrt_memory; + -Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) +Memory::Memory(llvm::IRBuilder<>& _builder) : m_builder(_builder) { auto voidTy = m_builder.getVoidTy(); auto i64Ty = m_builder.getInt64Ty(); - - auto memoryCreate = llvm::Function::Create(llvm::FunctionType::get(voidTy, false), - llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_create", _module); - m_builder.CreateCall(memoryCreate); + auto module = _builder.GetInsertBlock()->getParent()->getParent(); auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false); m_memRequire = llvm::Function::Create(memRequireTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_require", _module); + "evmccrt_memory_require", module); auto memSizeTy = llvm::FunctionType::get(i64Ty, false); m_memSize = llvm::Function::Create(memSizeTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_size", _module); + "evmccrt_memory_size", module); std::vector argTypes = {i64Ty, i64Ty}; auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef(argTypes), false); m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - "evmccrt_memory_dump", _module); + "evmccrt_memory_dump", module); +} + +const dev::bytes& Memory::init() +{ + evmccrt_memory = new MemoryImpl(); + std::cerr << "MEMORY: create(), initial size = " << evmccrt_memory->size() + << std::endl; + + return *evmccrt_memory; } @@ -123,15 +130,6 @@ extern "C" { using namespace evmcc; -static MemoryImpl* evmccrt_memory; - -EXPORT void evmccrt_memory_create(void) -{ - evmccrt_memory = new MemoryImpl(); - std::cerr << "MEMORY: create(), initial size = " << evmccrt_memory->size() - << std::endl; -} - // Resizes memory to contain at least _index + 1 bytes and returns the base address. EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) { diff --git a/evmcc/Memory.h b/evmcc/Memory.h index 8fbbe0a58..b36386325 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -2,13 +2,17 @@ #include +#include + namespace evmcc { class Memory { public: - Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); + Memory(llvm::IRBuilder<>& _builder); + + static const dev::bytes& init(); llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); diff --git a/evmcc/bytecode/return_test.evm b/evmcc/bytecode/return_test.evm new file mode 100644 index 000000000..977cf7c19 --- /dev/null +++ b/evmcc/bytecode/return_test.evm @@ -0,0 +1 @@ +60016064546002608454600360a45460606064f2 diff --git a/evmcc/lll/return_test.lll b/evmcc/lll/return_test.lll new file mode 100644 index 000000000..c87a2d812 --- /dev/null +++ b/evmcc/lll/return_test.lll @@ -0,0 +1,15 @@ + +(asm +1 +100 +MSTORE +2 +132 +MSTORE +3 +164 +MSTORE +96 +100 +RETURN +) \ No newline at end of file