diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 87c96a20d..0dae87213 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -160,12 +160,15 @@ 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()); // Init stack and memory auto stack = Stack(builder, module.get()); - auto memory = Memory(builder, module.get()); + auto memory = Memory(builder); auto ext = Ext(builder); @@ -174,6 +177,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) basicBlocks[0] = entryBlock; createBasicBlocks(bytecode); + auto userRet = false; + auto finished = false; + BasicBlock* currentBlock = nullptr; for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) @@ -509,10 +515,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..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); @@ -86,8 +89,19 @@ 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; + + 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; } } \ No newline at end of file diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 219dfe7fa..2a1a0f727 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,44 +21,42 @@ 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; +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; } @@ -130,15 +130,6 @@ extern "C" { using namespace evmcc; -EXPORT 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) { @@ -154,7 +145,7 @@ EXPORT uint8_t* evmccrt_memory_require(uint64_t _index) evmccrt_memory->resize(requiredSize); } - return &(*evmccrt_memory)[0]; + return evmccrt_memory->data(); } EXPORT uint64_t evmccrt_memory_size() 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/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/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/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 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