From 7882a2a89daf0c0ea24c8fbe33e3396a002d00bc Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 6 Apr 2021 18:28:05 +0200 Subject: [PATCH] Added documentation about --asm flag --- docs/analysing-compilation-output.rst | 192 ++++++++++++++++++++++++++ docs/index.rst | 8 +- 2 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 docs/analysing-compilation-output.rst diff --git a/docs/analysing-compilation-output.rst b/docs/analysing-compilation-output.rst new file mode 100644 index 000000000..892b18b95 --- /dev/null +++ b/docs/analysing-compilation-output.rst @@ -0,0 +1,192 @@ +.. 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 `_, +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 +`. 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. diff --git a/docs/index.rst b/docs/index.rst index fb0d04ed2..1674248c1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -127,6 +127,13 @@ Contents cheatsheet.rst grammar.rst +.. toctree:: + :maxdepth: 2 + :caption: Compiler + + using-the-compiler.rst + analysing-compilation-output.rst + .. toctree:: :maxdepth: 2 :caption: Internals @@ -152,7 +159,6 @@ Contents security-considerations.rst smtchecker.rst resources.rst - using-the-compiler.rst yul.rst style-guide.rst common-patterns.rst