mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
193 lines
5.5 KiB
ReStructuredText
193 lines
5.5 KiB
ReStructuredText
|
.. index:: analyse, asm
|
||
|
|
||
|
#############################
|
||
|
Analysing the Compiler Output
|
||
|
#############################
|
||
|
|
||
|
It is often useful to look at the assembly code generated by the compiler. The generated binary,
|
||
|
i.e., the output of ``solc --bin contract.sol``, is generally difficult to read. It is recommended
|
||
|
to use the flag ``--asm`` to analyse the assembly output. Even for large contracts, looking at a
|
||
|
visual diff of the assembly before and after a change is often very enlightening.
|
||
|
|
||
|
Consider the following contract (named, say ``contract.sol``):
|
||
|
|
||
|
.. code-block:: Solidity
|
||
|
|
||
|
// SPDX-License-Identifier: GPL-3.0
|
||
|
pragma solidity >=0.5.0 <0.9.0;
|
||
|
contract C {
|
||
|
function one() public pure returns (uint) {
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
The following would be the output of ``solc --asm contract.sol``
|
||
|
|
||
|
.. code-block:: none
|
||
|
|
||
|
======= contract.sol:C =======
|
||
|
EVM assembly:
|
||
|
/* "contract.sol":0:86 contract C {... */
|
||
|
mstore(0x40, 0x80)
|
||
|
callvalue
|
||
|
dup1
|
||
|
iszero
|
||
|
tag_1
|
||
|
jumpi
|
||
|
0x00
|
||
|
dup1
|
||
|
revert
|
||
|
tag_1:
|
||
|
pop
|
||
|
dataSize(sub_0)
|
||
|
dup1
|
||
|
dataOffset(sub_0)
|
||
|
0x00
|
||
|
codecopy
|
||
|
0x00
|
||
|
return
|
||
|
stop
|
||
|
|
||
|
sub_0: assembly {
|
||
|
/* "contract.sol":0:86 contract C {... */
|
||
|
mstore(0x40, 0x80)
|
||
|
callvalue
|
||
|
dup1
|
||
|
iszero
|
||
|
tag_1
|
||
|
jumpi
|
||
|
0x00
|
||
|
dup1
|
||
|
revert
|
||
|
tag_1:
|
||
|
pop
|
||
|
jumpi(tag_2, lt(calldatasize, 0x04))
|
||
|
shr(0xe0, calldataload(0x00))
|
||
|
dup1
|
||
|
0x901717d1
|
||
|
eq
|
||
|
tag_3
|
||
|
jumpi
|
||
|
tag_2:
|
||
|
0x00
|
||
|
dup1
|
||
|
revert
|
||
|
/* "contract.sol":17:84 function one() public pure returns (uint) {... */
|
||
|
tag_3:
|
||
|
tag_4
|
||
|
tag_5
|
||
|
jump // in
|
||
|
tag_4:
|
||
|
mload(0x40)
|
||
|
tag_6
|
||
|
swap2
|
||
|
swap1
|
||
|
tag_7
|
||
|
jump // in
|
||
|
tag_6:
|
||
|
mload(0x40)
|
||
|
dup1
|
||
|
swap2
|
||
|
sub
|
||
|
swap1
|
||
|
return
|
||
|
tag_5:
|
||
|
/* "contract.sol":53:57 uint */
|
||
|
0x00
|
||
|
/* "contract.sol":76:77 1 */
|
||
|
0x01
|
||
|
/* "contract.sol":69:77 return 1 */
|
||
|
swap1
|
||
|
pop
|
||
|
/* "contract.sol":17:84 function one() public pure returns (uint) {... */
|
||
|
swap1
|
||
|
jump // out
|
||
|
/* "#utility.yul":7:125 */
|
||
|
tag_10:
|
||
|
/* "#utility.yul":94:118 */
|
||
|
tag_12
|
||
|
/* "#utility.yul":112:117 */
|
||
|
dup2
|
||
|
/* "#utility.yul":94:118 */
|
||
|
tag_13
|
||
|
jump // in
|
||
|
tag_12:
|
||
|
/* "#utility.yul":89:92 */
|
||
|
dup3
|
||
|
/* "#utility.yul":82:119 */
|
||
|
mstore
|
||
|
/* "#utility.yul":72:125 */
|
||
|
pop
|
||
|
pop
|
||
|
jump // out
|
||
|
/* "#utility.yul":131:353 */
|
||
|
tag_7:
|
||
|
0x00
|
||
|
/* "#utility.yul":262:264 */
|
||
|
0x20
|
||
|
/* "#utility.yul":251:260 */
|
||
|
dup3
|
||
|
/* "#utility.yul":247:265 */
|
||
|
add
|
||
|
/* "#utility.yul":239:265 */
|
||
|
swap1
|
||
|
pop
|
||
|
/* "#utility.yul":275:346 */
|
||
|
tag_15
|
||
|
/* "#utility.yul":343:344 */
|
||
|
0x00
|
||
|
/* "#utility.yul":332:341 */
|
||
|
dup4
|
||
|
/* "#utility.yul":328:345 */
|
||
|
add
|
||
|
/* "#utility.yul":319:325 */
|
||
|
dup5
|
||
|
/* "#utility.yul":275:346 */
|
||
|
tag_10
|
||
|
jump // in
|
||
|
tag_15:
|
||
|
/* "#utility.yul":229:353 */
|
||
|
swap3
|
||
|
swap2
|
||
|
pop
|
||
|
pop
|
||
|
jump // out
|
||
|
/* "#utility.yul":359:436 */
|
||
|
tag_13:
|
||
|
0x00
|
||
|
/* "#utility.yul":425:430 */
|
||
|
dup2
|
||
|
/* "#utility.yul":414:430 */
|
||
|
swap1
|
||
|
pop
|
||
|
/* "#utility.yul":404:436 */
|
||
|
swap2
|
||
|
swap1
|
||
|
pop
|
||
|
jump // out
|
||
|
|
||
|
auxdata: 0xa2646970667358221220a5874f19737ddd4c5d77ace1619e5160c67b3d4bedac75fce908fed32d98899864736f6c637827302e382e342d646576656c6f702e323032312e332e33302b636f6d6d69742e65613065363933380058
|
||
|
}
|
||
|
|
||
|
Alternatively, the above output can also be obtained from `Remix <https://remix.ethereum.org/>`_,
|
||
|
under the option "Compilation Details" after compiling a contract.
|
||
|
|
||
|
Notice that the ``asm`` output starts with the creation / constructor code. The deploy code is
|
||
|
provided as part of the sub object (in the above example, it is part of the sub-object ``sub_0``).
|
||
|
The ``auxdata`` field corresponds to the contract :ref:`metadata
|
||
|
<encoding-of-the-metadata-hash-in-the-bytecode>`. The comments in the assembly output point to the
|
||
|
source location. Note that ``#utility.yul`` is an internally generated file of utility functions
|
||
|
that can be obtained using the flags ``--combined-json
|
||
|
generated-sources,generated-sources-runtime``.
|
||
|
|
||
|
Similarly, the optimized assembly can be obtained with the command: ``solc --optimize --asm
|
||
|
contract.sol``. Often times, it is interesting to see if two different sources in Solidity result in
|
||
|
the same optimized code. For example, to see if the expressions ``(a * b) / c``, ``a * b / c``
|
||
|
generates the same bytecode. This can be easily done by taking a ``diff`` of the corresponding
|
||
|
assembly output, after potentially stripping comments that reference the source locations.
|
||
|
|
||
|
.. note::
|
||
|
|
||
|
The ``--asm`` output is not designed to be machine readable. Therefore, there may be breaking
|
||
|
changes on the output between minor versions of solc.
|