Add RJUMP

This commit is contained in:
Alex Beregszaszi 2021-09-13 23:13:30 +01:00
parent 591df04211
commit 4d4dfbc456
6 changed files with 44 additions and 7 deletions

View File

@ -533,11 +533,13 @@ LinkerObject const& Assembly::assemble() const
unsigned bytesRequiredForCode = codeSize(static_cast<unsigned>(subTagSize));
m_tagPositionsInBytecode = vector<size_t>(m_usedTags, numeric_limits<size_t>::max());
map<size_t, pair<size_t, size_t>> tagRef;
set<size_t> isStaticTagRef;
multimap<h256, unsigned> dataRef;
multimap<size_t, size_t> subRef;
vector<unsigned> sizeRef; ///< Pointers to code locations where the size of the program is inserted
unsigned bytesPerTag = numberEncodingSize(bytesRequiredForCode);
uint8_t tagPush = static_cast<uint8_t>(pushInstruction(bytesPerTag));
constexpr unsigned bytesPerStaticTag = 2;
unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + static_cast<unsigned>(m_auxiliaryData.size());
for (auto const& sub: m_subs)
@ -574,6 +576,16 @@ LinkerObject const& Assembly::assemble() const
ret.bytecode.resize(ret.bytecode.size() + bytesPerTag);
break;
}
case StaticJump:
case StaticJumpI:
{
ret.bytecode.push_back(static_cast<uint8_t>((i.type() == StaticJump) ? Instruction::RJUMP : Instruction::RJUMPI));
ret.bytecode.push_back(tagPush);
tagRef[ret.bytecode.size()] = i.splitForeignPushTag();
isStaticTagRef.insert(ret.bytecode.size());
ret.bytecode.resize(ret.bytecode.size() + bytesPerStaticTag);
break;
}
case PushData:
ret.bytecode.push_back(dataRefPush);
dataRef.insert(make_pair(h256(i.data()), ret.bytecode.size()));
@ -699,9 +711,17 @@ LinkerObject const& Assembly::assemble() const
assertThrow(tagId < tagPositions.size(), AssemblyException, "Reference to non-existing tag.");
size_t pos = tagPositions[tagId];
assertThrow(pos != numeric_limits<size_t>::max(), AssemblyException, "Reference to tag without position.");
assertThrow(numberEncodingSize(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space.");
bytesRef r(ret.bytecode.data() + i.first, bytesPerTag);
toBigEndian(pos, r);
if (isStaticTagRef.count(i.first)) {
pos = pos - (i.first + bytesPerStaticTag); // TODO: do properly
assertThrow(numberEncodingSize(pos) <= bytesPerStaticTag, AssemblyException, "Tag too large for reserved space.");
//pos = static_cast<uint16_t>(spos);
bytesRef r(ret.bytecode.data() + i.first, bytesPerStaticTag);
toBigEndian(pos, r);
} else {
assertThrow(numberEncodingSize(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space.");
bytesRef r(ret.bytecode.data() + i.first, bytesPerTag);
toBigEndian(pos, r);
}
}
for (auto const& [name, tagInfo]: m_namedTags)
{

View File

@ -83,8 +83,14 @@ public:
append(AssemblyItem(std::move(_data), _arguments, _returnVariables));
}
AssemblyItem appendStaticJump() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(StaticJump, m_usedTags++); }
AssemblyItem appendStaticJumpI() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(StaticJumpI, m_usedTags++); }
// AssemblyItem appendJump() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(StaticJump, m_usedTags++); }
// AssemblyItem appendJumpI() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(StaticJumpI, m_usedTags++); }
AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; }
AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; }
AssemblyItem appendStaticJump(AssemblyItem const& _tag) { /*force typecheck*/_tag.pushTag(); return AssemblyItem(StaticJump, _tag.data()); }
AssemblyItem appendStaticJumpI(AssemblyItem const& _tag) { /*force typecheck*/_tag.pushTag(); return AssemblyItem(StaticJumpI, _tag.data()); }
AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; }
AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; }

View File

@ -62,7 +62,7 @@ AssemblyItem AssemblyItem::toSubAssemblyTag(size_t _subId) const
pair<size_t, size_t> AssemblyItem::splitForeignPushTag() const
{
assertThrow(m_type == PushTag || m_type == Tag, util::Exception, "");
assertThrow(m_type == StaticJump || m_type == StaticJumpI || m_type == PushTag || m_type == Tag, util::Exception, "");
u256 combined = u256(data());
size_t subId = static_cast<size_t>((combined >> 64) - 1);
size_t tag = static_cast<size_t>(combined & 0xffffffffffffffffULL);
@ -159,6 +159,9 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength, Precision _precision)
}
case VerbatimBytecode:
return std::get<2>(*m_verbatimBytecode).size();
case StaticJump:
case StaticJumpI:
return 3;
default:
break;
}

View File

@ -50,7 +50,9 @@ enum AssemblyItemType
PushDeployTimeAddress, ///< Push an address to be filled at deploy time. Should not be touched by the optimizer.
PushImmutable, ///< Push the currently unknown value of an immutable variable. The actual value will be filled in by the constructor.
AssignImmutable, ///< Assigns the current value on the stack to an immutable variable. Only valid during creation code.
VerbatimBytecode ///< Contains data that is inserted into the bytecode code section without modification.
VerbatimBytecode, ///< Contains data that is inserted into the bytecode code section without modification.
StaticJump,
StaticJumpI
};
enum class Precision { Precise , Approximate };
@ -91,8 +93,8 @@ public:
AssemblyItem& operator=(AssemblyItem const&) = default;
AssemblyItem& operator=(AssemblyItem&&) = default;
AssemblyItem tag() const { assertThrow(m_type == PushTag || m_type == Tag, util::Exception, ""); return AssemblyItem(Tag, data()); }
AssemblyItem pushTag() const { assertThrow(m_type == PushTag || m_type == Tag, util::Exception, ""); return AssemblyItem(PushTag, data()); }
AssemblyItem tag() const { assertThrow(m_type == StaticJump || m_type == StaticJumpI || m_type == PushTag || m_type == Tag, util::Exception, ""); return AssemblyItem(Tag, data()); }
AssemblyItem pushTag() const { assertThrow(m_type == StaticJump || m_type == StaticJumpI || m_type == PushTag || m_type == Tag, util::Exception, ""); return AssemblyItem(PushTag, data()); }
/// Converts the tag to a subassembly tag. This has to be called in order to move a tag across assemblies.
/// @param _subId the identifier of the subassembly the tag is taken from.
AssemblyItem toSubAssemblyTag(size_t _subId) const;

View File

@ -93,6 +93,8 @@ std::map<std::string, Instruction> const solidity::evmasm::c_instructions =
{ "MSIZE", Instruction::MSIZE },
{ "GAS", Instruction::GAS },
{ "JUMPDEST", Instruction::JUMPDEST },
{ "RJUMP", Instruction::RJUMP },
{ "RJUMPI", Instruction::RJUMPI },
{ "PUSH1", Instruction::PUSH1 },
{ "PUSH2", Instruction::PUSH2 },
{ "PUSH3", Instruction::PUSH3 },
@ -240,6 +242,8 @@ static std::map<Instruction, InstructionInfo> const c_instructionInfo =
{ Instruction::MSIZE, { "MSIZE", 0, 0, 1, false, Tier::Base } },
{ Instruction::GAS, { "GAS", 0, 0, 1, false, Tier::Base } },
{ Instruction::JUMPDEST, { "JUMPDEST", 0, 0, 0, true, Tier::Special } },
{ Instruction::RJUMP, { "RJUMP", 0, 0, 0, true, Tier::Mid } },
{ Instruction::RJUMPI, { "RJUMPI", 0, 1, 0, true, Tier::High } },
{ Instruction::PUSH1, { "PUSH1", 1, 0, 1, false, Tier::VeryLow } },
{ Instruction::PUSH2, { "PUSH2", 2, 0, 1, false, Tier::VeryLow } },
{ Instruction::PUSH3, { "PUSH3", 3, 0, 1, false, Tier::VeryLow } },

View File

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