.. index:: analyse, asm ############################# 分析编译器输出 ############################# 查看编译器生成的汇编代码通常是有用的。生成的二进制文件,即 ``solc --bin contract.sol`` 的输出,通常难以阅读。 建议使用标志 ``--asm`` 来分析汇编输出。 即使对于大型合约,查看更改前后的汇编可视化差异通常也非常有启发。 考虑以下合约(假设名为 ``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; } } 以下是 ``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 } 另外,上面的输出也可以通过 `Remix <https://remix.ethereum.org/>`_ 编译合约后,在“编译详情”选项下获得。 注意 ``asm`` 输出以创建/构造函数代码开始。 部署代码作为子对象的一部分提供(在上述示例中,它是子对象 ``sub_0`` 的一部分)。 ``auxdata`` 字段对应于合约 :ref:`metadata <encoding-of-the-metadata-hash-in-the-bytecode>`。 汇编输出中的注释指向源位置。请注意 ``#utility.yul`` 是一个内部生成的实用函数文件,可以使用标志 ``--combined-json generated-sources,generated-sources-runtime`` 获得。 同样,优化后的汇编可以通过命令 ``solc --optimize --asm contract.sol`` 获得。 通常,查看两个不同的 Solidity 源是否生成相同的优化代码是很有趣的。 例如,查看表达式 ``(a * b) / c`` 和 ``a * b / c`` 是否生成相同的字节码。 可以通过对相应的汇编输出进行 ``diff`` 来轻松完成,可能需要剥离引用源位置的注释。 .. note:: ``--asm`` 输出并不是为了机器可读而设计的。因此,在 solc 的小版本之间,输出可能会有重大变化。