Browse Source

PoC-7: JUMPDEST implemented.

cl-refactor
Gav Wood 10 years ago
parent
commit
4c08cda6fd
  1. 2
      libevm/VM.cpp
  2. 15
      libevm/VM.h
  3. 4
      libevmface/Instruction.cpp
  4. 1
      libevmface/Instruction.h
  5. 26
      liblll/Assembly.cpp

2
libevm/VM.cpp

@ -29,4 +29,6 @@ void VM::reset(u256 _gas)
{
m_gas = _gas;
m_curPC = 0;
m_jumpLatch = false;
m_destinations.clear();
}

15
libevm/VM.h

@ -39,6 +39,7 @@ struct VMException: virtual Exception {};
struct StepsDone: virtual VMException {};
struct BreakPointHit: virtual VMException {};
struct BadInstruction: virtual VMException {};
struct BadJumpDestination: virtual VMException {};
struct OutOfGas: virtual VMException {};
class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
@ -83,6 +84,8 @@ private:
u256 m_curPC = 0;
bytes m_temp;
u256s m_stack;
bool m_jumpLatch = false;
u256Set m_destinations;
};
}
@ -565,11 +568,17 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
case Instruction::JUMP:
require(1);
m_jumpLatch = true;
if (!m_destinations.count(m_stack.back()))
BOOST_THROW_EXCEPTION(BadJumpDestination());
nextPC = m_stack.back();
m_stack.pop_back();
break;
case Instruction::JUMPI:
require(2);
m_jumpLatch = true;
if (!m_destinations.count(m_stack.back()))
BOOST_THROW_EXCEPTION(BadJumpDestination());
if (m_stack[m_stack.size() - 2])
nextPC = m_stack.back();
m_stack.pop_back();
@ -584,6 +593,12 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::GAS:
m_stack.push_back(m_gas);
break;
case Instruction::JUMPDEST:
require(1);
if (!m_jumpLatch)
m_destinations.insert(m_stack.back());
m_stack.pop_back();
break;
case Instruction::CREATE:
{
require(3);

4
libevmface/Instruction.cpp

@ -82,6 +82,7 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "PC", Instruction::PC },
{ "MSIZE", Instruction::MSIZE },
{ "GAS", Instruction::GAS },
{ "JUMPDEST", Instruction::JUMPDEST },
{ "PUSH1", Instruction::PUSH1 },
{ "PUSH2", Instruction::PUSH2 },
{ "PUSH3", Instruction::PUSH3 },
@ -208,6 +209,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::PC, { "PC", 0, 0, 1 } },
{ Instruction::MSIZE, { "MSIZE", 0, 0, 1 } },
{ Instruction::GAS, { "GAS", 0, 0, 1 } },
{ Instruction::JUMPDEST, { "JUMPDEST", 0, 1, 0 } },
{ Instruction::PUSH1, { "PUSH1", 1, 0, 1 } },
{ Instruction::PUSH2, { "PUSH2", 2, 0, 1 } },
{ Instruction::PUSH3, { "PUSH3", 3, 0, 1 } },
@ -274,7 +276,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::SWAP16, { "SWAP16", 0, 17, 17 } },
{ Instruction::CREATE, { "CREATE", 0, 3, 1 } },
{ Instruction::CALL, { "CALL", 0, 7, 1 } },
{ Instruction::CALLCODE, { "CALLCODE",0, 7, 1 } },
{ Instruction::CALLCODE, { "CALLCODE", 0, 7, 1 } },
{ Instruction::RETURN, { "RETURN", 0, 2, 0 } },
{ Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} }
};

1
libevmface/Instruction.h

@ -92,6 +92,7 @@ enum class Instruction: uint8_t
PC, ///< get the program counter
MSIZE, ///< get the size of active memory
GAS, ///< get the amount of available gas
JUMPDEST, ///< set a potential jump destination
PUSH1 = 0x60, ///< place 1 byte item on stack
PUSH2, ///< place 2 byte item on stack

26
liblll/Assembly.cpp

@ -149,6 +149,17 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i)
ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const
{
_out << _prefix << ".pre:" << endl;
for (AssemblyItem const& i: m_items)
switch (i.m_type)
{
case PushTag:
_out << _prefix << " PUSH [tag" << i.m_data << "]" << endl;
_out << _prefix << " JUMPDEST" << endl;
break;
default:;
}
_out << _prefix << ".code:" << endl;
for (AssemblyItem const& i: m_items)
switch (i.m_type)
@ -353,9 +364,11 @@ bytes Assembly::assemble() const
ret.reserve(totalBytes);
vector<unsigned> tagPos(m_usedTags);
map<unsigned, unsigned> tagRef;
map<unsigned, unsigned> pretagRef;
multimap<h256, unsigned> dataRef;
unsigned bytesPerTag = dev::bytesRequired(totalBytes);
byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag;
bytes preret;
for (auto const& i: m_subs)
m_data[i.first] = i.second.assemble();
@ -393,6 +406,11 @@ bytes Assembly::assemble() const
ret.push_back(tagPush);
tagRef[ret.size()] = (unsigned)i.m_data;
ret.resize(ret.size() + bytesPerTag);
preret.push_back(tagPush);
pretagRef[preret.size()] = (unsigned)i.m_data;
preret.resize(preret.size() + bytesPerTag);
preret.push_back((byte)Instruction::JUMPDEST);
break;
}
case PushData: case PushSub:
@ -424,6 +442,12 @@ bytes Assembly::assemble() const
toBigEndian(tagPos[i.second], r);
}
for (auto const& i: pretagRef)
{
bytesRef r(preret.data() + i.first, bytesPerTag);
toBigEndian(tagPos[i.second], r);
}
if (m_data.size())
{
ret.push_back(0);
@ -442,5 +466,5 @@ bytes Assembly::assemble() const
}
}
}
return ret;
return preret + ret;
}

Loading…
Cancel
Save