From 471586cc824595ca3b883760b573d831deb08410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 14 Oct 2014 20:49:48 +0200 Subject: [PATCH 1/2] Use longjmp to return OutOfGas code from main function (WIP) [#80660432] --- evmcc/Compiler.cpp | 15 ++++++++++++--- evmcc/Compiler.h | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 00ea5c12e..7b1f6de18 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -6,7 +6,7 @@ #include #include #include -//#include +#include #include @@ -159,6 +159,7 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) m_finalBlock = std::make_unique("FinalBlock", m_mainFunc); m_badJumpBlock = std::make_unique("BadJumpBlock", m_mainFunc); m_jumpTableBlock = std::make_unique("JumpTableBlock", m_mainFunc); + m_outOfGasBlock = std::make_unique("OutOfGas", m_mainFunc); for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { @@ -195,6 +196,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // Create the basic blocks. auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc); builder.SetInsertPoint(entryBlock); + createBasicBlocks(bytecode); // Init runtime structures. @@ -203,7 +205,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) Ext ext(builder, module.get()); // Jump to first instruction - builder.CreateBr(basicBlocks.begin()->second); + auto setjmpFunc = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); + auto jmpBufTy = llvm::ArrayType::get(builder.getInt64Ty(), 5); + auto jmpBuf = new llvm::GlobalVariable(*module, jmpBufTy, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(jmpBufTy), "jmpBuf"); + auto setjmpRet = builder.CreateCall(setjmpFunc, builder.CreateBitCast(jmpBuf, Type::BytePtr)); + auto isNormalFlow = builder.CreateICmpEQ(setjmpRet, builder.getInt32(0)); + builder.CreateCondBr(isNormalFlow, basicBlocks.begin()->second, m_outOfGasBlock->llvm()); for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) { @@ -921,10 +928,12 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) builder.SetInsertPoint(m_finalBlock->llvm()); builder.CreateRet(Constant::get(ReturnCode::Stop)); - // TODO: throw an exception or something builder.SetInsertPoint(m_badJumpBlock->llvm()); builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + builder.SetInsertPoint(m_outOfGasBlock->llvm()); + builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); + builder.SetInsertPoint(m_jumpTableBlock->llvm()); if (m_indirectJumpTargets.size() > 0) { diff --git a/evmcc/Compiler.h b/evmcc/Compiler.h index 7d0cb4ab6..509cf77df 100644 --- a/evmcc/Compiler.h +++ b/evmcc/Compiler.h @@ -59,6 +59,8 @@ private: */ std::unique_ptr m_badJumpBlock; + std::unique_ptr m_outOfGasBlock; + /// Main program function llvm::Function* m_mainFunc = nullptr; }; From 8498ab5695221acbb43d3141610cade3b88b08f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 15 Oct 2014 11:11:07 +0200 Subject: [PATCH 2/2] Trying to implement "exceptions" with longjmp (does not work on Windows 64bit at least) --- evmcc/Compiler.cpp | 14 +++++++++----- evmcc/ExecutionEngine.cpp | 4 +++- evmcc/GasMeter.cpp | 15 +++++++++------ evmcc/GasMeter.h | 2 +- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 7b1f6de18..11e7569db 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -199,16 +199,20 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) createBasicBlocks(bytecode); + // Prepare jump buffer + auto jmpBufStorageTy = llvm::ArrayType::get(Type::Byte, 2048); + auto jmpBufStorage = new llvm::GlobalVariable(*module, jmpBufStorageTy, false, llvm::GlobalVariable::PrivateLinkage, llvm::ConstantAggregateZero::get(jmpBufStorageTy), "jmpBuf"); + jmpBufStorage->setAlignment(16); + auto jmpBuf = builder.CreateConstInBoundsGEP2_32(jmpBufStorage, 0, 0); + // Init runtime structures. - GasMeter gasMeter(builder, module.get()); + GasMeter gasMeter(builder, module.get(), jmpBuf); Memory memory(builder, module.get(), gasMeter); Ext ext(builder, module.get()); - // Jump to first instruction + // Create exception landing with setjmp and jump to first instruction auto setjmpFunc = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); - auto jmpBufTy = llvm::ArrayType::get(builder.getInt64Ty(), 5); - auto jmpBuf = new llvm::GlobalVariable(*module, jmpBufTy, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(jmpBufTy), "jmpBuf"); - auto setjmpRet = builder.CreateCall(setjmpFunc, builder.CreateBitCast(jmpBuf, Type::BytePtr)); + auto setjmpRet = builder.CreateCall(setjmpFunc, jmpBuf); auto isNormalFlow = builder.CreateICmpEQ(setjmpRet, builder.getInt32(0)); builder.CreateCondBr(isNormalFlow, basicBlocks.begin()->second, m_outOfGasBlock->llvm()); diff --git a/evmcc/ExecutionEngine.cpp b/evmcc/ExecutionEngine.cpp index 5cb94ddf0..95c90ec19 100644 --- a/evmcc/ExecutionEngine.cpp +++ b/evmcc/ExecutionEngine.cpp @@ -121,7 +121,9 @@ int ExecutionEngine::run(std::unique_ptr _module) for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it) std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " "; std::cout << "]\n"; - } + } + + std::cout << "RETURN CODE: " << (int)returnCode << std::endl; return static_cast(returnCode); } diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 10a8fca98..0d0927563 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -77,7 +78,7 @@ bool isCostBlockEnd(Instruction _inst) } -GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): +GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Value* _jmpBuf) : m_builder(_builder) { m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); @@ -88,9 +89,9 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "gas.check", _module); InsertPointGuard guard(m_builder); - auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "check", m_gasCheckFunc); - auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "outOfGas", m_gasCheckFunc); - auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "update", m_gasCheckFunc); + auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); + auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); + auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); m_builder.SetInsertPoint(checkBB); llvm::Value* cost = m_gasCheckFunc->arg_begin(); @@ -100,8 +101,10 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module): m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - m_builder.CreateCall(m_rtExit, Constant::get(ReturnCode::OutOfGas)); - m_builder.CreateRetVoid(); + + auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); + m_builder.CreateCall(longjmpFunc, _jmpBuf); + m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); gas = m_builder.CreateSub(gas, cost); diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 8738b49c0..5af117900 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -11,7 +11,7 @@ namespace evmcc class GasMeter { public: - GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* module); + GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Value* _jmpBuf); GasMeter(const GasMeter&) = delete; void operator=(GasMeter) = delete;