Skip to content

Commit 3aa86bf

Browse files
committed
Add instruction location info to eof assembly
1 parent 53e732b commit 3aa86bf

File tree

1 file changed

+76
-1
lines changed

1 file changed

+76
-1
lines changed

Diff for: libevmasm/Assembly.cpp

+76-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,65 @@ 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 AddInstructionLocation
66+
{
67+
public:
68+
AddInstructionLocation(
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+
~AddInstructionLocation()
80+
{
81+
emit();
82+
}
83+
84+
void emit()
85+
{
86+
// deals with EOF tag instructions that do not have any meaningful source location and also don't contribute
87+
// to the bytecode
88+
if (m_skip)
89+
return;
90+
91+
auto const end = m_bytecode.size();
92+
m_instructionLocations.emplace_back(LinkerObject::InstructionLocation{
93+
.start = m_instructionLocationStart,
94+
.end = end,
95+
.assemblyItemIndex = m_assemblyItemIndex
96+
});
97+
m_instructionLocationStart = end;
98+
}
99+
100+
void skip()
101+
{
102+
m_skip = true;
103+
}
104+
105+
private:
106+
std::vector<LinkerObject::InstructionLocation>& m_instructionLocations;
107+
bytes const& m_bytecode;
108+
size_t const m_assemblyItemIndex;
109+
size_t m_instructionLocationStart;
110+
bool m_skip = false;
111+
};
112+
113+
}
114+
56115
std::map<std::string, std::shared_ptr<std::string const>> Assembly::s_sharedSourceNames;
57116

58117
AssemblyItem const& Assembly::append(AssemblyItem _i)
@@ -1607,9 +1666,17 @@ LinkerObject const& Assembly::assembleEOF() const
16071666
for (auto&& [codeSectionIndex, codeSection]: m_codeSections | ranges::views::enumerate)
16081667
{
16091668
auto const sectionStart = ret.bytecode.size();
1669+
1670+
std::vector<LinkerObject::InstructionLocation> instructionLocations;
1671+
instructionLocations.reserve(codeSection.items.size());
1672+
16101673
solAssert(!codeSection.items.empty(), "Empty code section.");
1611-
for (AssemblyItem const& item: codeSection.items)
1674+
1675+
for (auto const& [assemblyItemIndex, item]: codeSection.items | ranges::views::enumerate)
16121676
{
1677+
// collect instruction locations via side effects
1678+
AddInstructionLocation addInstructionLocation {instructionLocations, ret.bytecode, assemblyItemIndex};
1679+
16131680
// store position of the invalid jump destination
16141681
if (item.type() != Tag && m_tagPositionsInBytecode[0] == std::numeric_limits<size_t>::max())
16151682
m_tagPositionsInBytecode[0] = ret.bytecode.size();
@@ -1676,6 +1743,8 @@ LinkerObject const& Assembly::assembleEOF() const
16761743
break;
16771744
case Tag:
16781745
ret.bytecode += assembleTag(item, ret.bytecode.size(), false);
1746+
// since no jumpdest is added, these tags do not contribute to the bytecode
1747+
addInstructionLocation.skip();
16791748
break;
16801749
case AuxDataLoadN:
16811750
{
@@ -1725,6 +1794,12 @@ LinkerObject const& Assembly::assembleEOF() const
17251794
"Code section too large for EOF."
17261795
);
17271796
setBigEndianUint16(ret.bytecode, codeSectionSizePositions[codeSectionIndex], ret.bytecode.size() - sectionStart);
1797+
1798+
ret.codeSectionLocations.emplace_back(LinkerObject::CodeSectionLocation{
1799+
.start = sectionStart,
1800+
.end = ret.bytecode.size(),
1801+
.instructionLocations = std::move(instructionLocations)
1802+
});
17281803
}
17291804

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

0 commit comments

Comments
 (0)