Skip to content

Commit 287b66a

Browse files
committed
Add instruction location info to eof assembly
1 parent 19db669 commit 287b66a

File tree

1 file changed

+63
-1
lines changed

1 file changed

+63
-1
lines changed

libevmasm/Assembly.cpp

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,54 @@ using namespace solidity::evmasm;
5353
using namespace solidity::langutil;
5454
using namespace solidity::util;
5555

56+
namespace
57+
{
58+
59+
/// Produces instruction location info in RAII style. When an assembly instruction is added to the bytecode,
60+
/// this class can be instantiated in that scope. It will record the current bytecode size (before addition)
61+
/// and, at destruction time, record the new bytecode size. This information is then added to an external
62+
/// instruction locations vector.
63+
/// If the instruction decomposes into multiple individual evm instructions, `emit` can be
64+
/// called for all but the last one (which will be emitted by the destructor).
65+
class InstructionLocationEmitter
66+
{
67+
public:
68+
InstructionLocationEmitter(
69+
std::vector<LinkerObject::InstructionLocation>& _instructionLocations,
70+
bytes const& _bytecode,
71+
size_t const _assemblyItemIndex
72+
):
73+
m_instructionLocations(_instructionLocations),
74+
m_bytecode(_bytecode),
75+
m_assemblyItemIndex(_assemblyItemIndex),
76+
m_instructionLocationStart(_bytecode.size())
77+
{}
78+
79+
~InstructionLocationEmitter()
80+
{
81+
emit();
82+
}
83+
84+
void emit()
85+
{
86+
auto const end = m_bytecode.size();
87+
m_instructionLocations.push_back(LinkerObject::InstructionLocation{
88+
.start = m_instructionLocationStart,
89+
.end = end,
90+
.assemblyItemIndex = m_assemblyItemIndex
91+
});
92+
m_instructionLocationStart = end;
93+
}
94+
95+
private:
96+
std::vector<LinkerObject::InstructionLocation>& m_instructionLocations;
97+
bytes const& m_bytecode;
98+
size_t const m_assemblyItemIndex{};
99+
size_t m_instructionLocationStart{};
100+
};
101+
102+
}
103+
56104
std::map<std::string, std::shared_ptr<std::string const>> Assembly::s_sharedSourceNames;
57105

58106
AssemblyItem const& Assembly::append(AssemblyItem _i)
@@ -1606,9 +1654,17 @@ LinkerObject const& Assembly::assembleEOF() const
16061654
for (auto&& [codeSectionIndex, codeSection]: m_codeSections | ranges::views::enumerate)
16071655
{
16081656
auto const sectionStart = ret.bytecode.size();
1657+
1658+
std::vector<LinkerObject::InstructionLocation> instructionLocations;
1659+
instructionLocations.reserve(codeSection.items.size());
1660+
16091661
solAssert(!codeSection.items.empty(), "Empty code section.");
1610-
for (AssemblyItem const& item: codeSection.items)
1662+
1663+
for (auto const& [assemblyItemIndex, item]: codeSection.items | ranges::views::enumerate)
16111664
{
1665+
// collect instruction locations via side effects
1666+
InstructionLocationEmitter instructionLocationEmitter {instructionLocations, ret.bytecode, assemblyItemIndex};
1667+
16121668
// store position of the invalid jump destination
16131669
if (item.type() != Tag && m_tagPositionsInBytecode[0] == std::numeric_limits<size_t>::max())
16141670
m_tagPositionsInBytecode[0] = ret.bytecode.size();
@@ -1724,6 +1780,12 @@ LinkerObject const& Assembly::assembleEOF() const
17241780
"Code section too large for EOF."
17251781
);
17261782
setBigEndianUint16(ret.bytecode, codeSectionSizePositions[codeSectionIndex], ret.bytecode.size() - sectionStart);
1783+
1784+
ret.codeSectionLocations.push_back(LinkerObject::CodeSectionLocation{
1785+
.start = sectionStart,
1786+
.end = ret.bytecode.size(),
1787+
.instructionLocations = std::move(instructionLocations)
1788+
});
17271789
}
17281790

17291791
for (auto const& [refPos, tagId]: tagRef)

0 commit comments

Comments
 (0)