@@ -53,6 +53,54 @@ using namespace solidity::evmasm;
53
53
using namespace solidity ::langutil;
54
54
using namespace solidity ::util;
55
55
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
+
56
104
std::map<std::string, std::shared_ptr<std::string const >> Assembly::s_sharedSourceNames;
57
105
58
106
AssemblyItem const & Assembly::append (AssemblyItem _i)
@@ -1606,9 +1654,17 @@ LinkerObject const& Assembly::assembleEOF() const
1606
1654
for (auto && [codeSectionIndex, codeSection]: m_codeSections | ranges::views::enumerate)
1607
1655
{
1608
1656
auto const sectionStart = ret.bytecode .size ();
1657
+
1658
+ std::vector<LinkerObject::InstructionLocation> instructionLocations;
1659
+ instructionLocations.reserve (codeSection.items .size ());
1660
+
1609
1661
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)
1611
1664
{
1665
+ // collect instruction locations via side effects
1666
+ InstructionLocationEmitter instructionLocationEmitter {instructionLocations, ret.bytecode , assemblyItemIndex};
1667
+
1612
1668
// store position of the invalid jump destination
1613
1669
if (item.type () != Tag && m_tagPositionsInBytecode[0 ] == std::numeric_limits<size_t >::max ())
1614
1670
m_tagPositionsInBytecode[0 ] = ret.bytecode .size ();
@@ -1724,6 +1780,12 @@ LinkerObject const& Assembly::assembleEOF() const
1724
1780
" Code section too large for EOF."
1725
1781
);
1726
1782
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
+ });
1727
1789
}
1728
1790
1729
1791
for (auto const & [refPos, tagId]: tagRef)
0 commit comments