diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 4c3a8a5f2..1114bde52 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -3,6 +3,7 @@ #include +#include "Memory.h" #include "Stack.h" namespace evmcc @@ -41,24 +42,6 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto module = std::make_unique("main", context); IRBuilder<> builder(context); - // Create globals for memory, memory size, stack and stack top - auto memory = new GlobalVariable(*module, Types.word8ptr, false, - GlobalValue::LinkageTypes::PrivateLinkage, - Constant::getNullValue(Types.word8ptr), "memory"); - auto memSize = new GlobalVariable(*module, Types.size, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantInt::get(Types.size, 0), "memsize"); - auto stack2 = new GlobalVariable(*module, Types.word256arr, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantAggregateZero::get(Types.word256arr), "stack"); - auto stackTop2 = new GlobalVariable(*module, Types.size, false, - GlobalValue::LinkageTypes::PrivateLinkage, - ConstantInt::get(Types.size, 0), "stackTop"); - - // Create value for void* malloc(size_t) - auto mallocVal = Function::Create(FunctionType::get(Types.word8ptr, { Types.size }, false), - GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module.get()); - // Create main function FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false); Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module.get()); @@ -66,13 +49,9 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) BasicBlock* entryBlock = BasicBlock::Create(context, "entry", mainFunc); builder.SetInsertPoint(entryBlock); - // Initialize memory with call to malloc, update memsize - std::vector mallocMemArgs = { ConstantInt::get(Types.size, 100) }; - auto mallocMemCall = builder.CreateCall(mallocVal, mallocMemArgs, "malloc_mem"); - builder.CreateStore(mallocMemCall, memory); - builder.CreateStore(ConstantInt::get(Types.size, 100), memSize); auto stack = Stack(builder, module.get()); + auto memory = Memory(builder, module.get()); uint64_t words[] = { 1, 2, 3, 4 }; auto val = llvm::APInt(256, 4, words); @@ -83,20 +62,19 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto top = stack.top(); stack.push(top); // dup - stack.pop(); + auto index = ConstantInt::get(Types.word256, 123); + memory.storeWord(index, c); - /* - std::vector mallocStackArgs = { ConstantInt::get(sizeTy, 200) }; - auto mallocStackCall = builder.CreateCall(mallocVal, mallocStackArgs, "malloc_stack"); - auto mallocCast = builder.CreatePointerBitCastOrAddrSpaceCast(mallocStackCall, int256ptr); - builder.CreateStore(mallocCast, stackVal); - */ + memory.dump(123, 123+32); - builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 13)); + auto index2 = ConstantInt::get(Types.word256, 123 + 16); + auto byte = memory.loadByte(index2); + auto result = builder.CreateZExt(byte, builder.getInt32Ty()); + builder.CreateRet(result); // should return 3 return module; } -} \ No newline at end of file +} diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index ae7033ac0..5a07e685d 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -18,4 +18,4 @@ public: }; -} \ No newline at end of file +} diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp new file mode 100644 index 000000000..9e3c2942e --- /dev/null +++ b/evmcc/Memory.cpp @@ -0,0 +1,145 @@ +#include "Memory.h" + +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef _MSC_VER + #define EXPORT __declspec(dllexport) +#else + #define EXPORT +#endif + +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; + + +Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module) + : m_builder(_builder) +{ + auto memoryCreate = llvm::Function::Create(llvm::FunctionType::get(m_builder.getVoidTy(), false), + llvm::GlobalValue::LinkageTypes::ExternalLinkage, + "evmccrt_memory_create", _module); + m_builder.CreateCall(memoryCreate); + + + auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), m_builder.getInt64Ty(), false); + m_memRequire = llvm::Function::Create(memRequireTy, + llvm::GlobalValue::LinkageTypes::ExternalLinkage, + "evmccrt_memory_require", _module); + + auto i64Ty = m_builder.getInt64Ty(); + 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); +} + + +llvm::Value* Memory::loadByte(llvm::Value* _addr) +{ + // trunc _addr (an i256) to i64 index and use it to index the memory + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); + + // load from evmccrt_memory_require()[index] + auto base = m_builder.CreateCall(m_memRequire, index, "base"); + auto ptr = m_builder.CreateGEP(base, index, "ptr"); + auto byte = m_builder.CreateLoad(ptr, "byte"); + return byte; +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); + auto index32 = m_builder.CreateAdd(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), 32), "index32"); + + auto base = m_builder.CreateCall(m_memRequire, index32, "base"); + auto ptr = m_builder.CreateGEP(base, index, "ptr"); + + auto i256ptrTy = m_builder.getIntNTy(256)->getPointerTo(); + auto wordPtr = m_builder.CreateBitCast(ptr, i256ptrTy, "wordptr"); + m_builder.CreateStore(_word, wordPtr); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _byte) +{ + auto index = m_builder.CreateTrunc(_addr, m_builder.getInt64Ty(), "index"); + + auto base = m_builder.CreateCall(m_memRequire, index, "base"); + auto ptr = m_builder.CreateGEP(base, index, "ptr"); + m_builder.CreateStore(_byte, ptr); +} + +void Memory::dump(uint64_t _begin, uint64_t _end) +{ + auto beginVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _begin); + auto endVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _end); + + std::vector args = {beginVal, endVal}; + m_builder.CreateCall(m_memDump, llvm::ArrayRef(args)); +} + +} // namespace evmcc + +extern "C" +{ + using namespace evmcc; + +EXPORT MemoryImpl* evmccrt_memory; + +EXPORT void evmccrt_memory_create(void) +{ + evmccrt_memory = new MemoryImpl(1); + std::cerr << "MEMORY: create(), initial size = " << evmccrt_memory->size() + << std::endl; +} + +// Resizes memory to contain at least _size bytes and returns the base address. +EXPORT void* evmccrt_memory_require(uint64_t _size) +{ + std::cerr << "MEMORY: require(), current size = " << evmccrt_memory->size() + << ", required size = " << _size + << std::endl; + + if (evmccrt_memory->size() < _size) + evmccrt_memory->resize(_size); + + return &(*evmccrt_memory)[0]; +} + +EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end) +{ + std::cerr << "Memory dump from " << std::hex << _begin << " to " << std::hex << _end << ":"; + if (_end <= _begin) + return; + + _begin = _begin / 16 * 16; + for (size_t i = _begin; i < _end; i++) + { + if ((i - _begin) % 16 == 0) + std::cerr << '\n' << std::dec << i << ": "; + + uint8_t b = (*evmccrt_memory)[i]; + std::cerr << std::hex << std::setw(2) << static_cast(b) << ' '; + } + std::cerr << std::endl; +} + +} // extern "C" diff --git a/evmcc/Memory.h b/evmcc/Memory.h new file mode 100644 index 000000000..16a7ab4ca --- /dev/null +++ b/evmcc/Memory.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace evmcc +{ + +class Memory +{ +public: + Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module); + + llvm::Value* loadByte(llvm::Value* _addr); + void storeWord(llvm::Value* _addr, llvm::Value* _word); + void storeByte(llvm::Value* _addr, llvm::Value* _byte); + + void dump(uint64_t _begin, uint64_t _end); + +private: + llvm::IRBuilder<>& m_builder; + + llvm::Function* m_memRequire; + llvm::Function* m_memDump; +}; + +}