
Solidity 如何用 --asm 输出分析并 diff 编译产物的变化【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity编译 Solidity 合约时solc --bin输出的二进制串通常很难读不便于判断源码改动对产物的实际影响。Solidity 官方文档建议改用--asm标志查看汇编输出并且指出即使是大型合约对比改动前后的汇编视觉 diff 往往也很有参考价值docs/analysing-compilation-output.rst。本文围绕这条路径展开用--asm查看合约的汇编产物、区分其中的构造代码与部署代码并对改动前后的汇编输出做 diff判断两段 Solidity 源码最终是否生成相同的优化代码。前提是环境中已有solc命令行编译器可通过solc --help查看全部选项。先用 --asm 查看合约的汇编输出以下面的合约为例文档示例文件名为contract.sol// 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文档给出的输出文档示例大致如下开头是构造/创建代码随后是sub_0子对象中的部署代码 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) ... auxdata: 0xa2646970667358221220a5874f19737ddd4c... }读懂这份输出需要抓住文档明确给出的几个要点asm输出先给出创建/构造函数代码部署代码deploy code作为子对象出现示例中是sub_0。auxdata字段对应合约的元数据metadata其编码规则见 metadata 文档 中 Encoding of the Metadata Hash in the Bytecode 一节。输出中的注释指向源码位置例如/* contract.sol:76:77 1 */说明该行汇编由源码中对应区间生成。#utility.yul是编译器内部生成的工具函数文件如果需要查看它的原文可以用标志--combined-json generated-sources,generated-sources-runtime获取。除命令行外文档还提到同一份输出也可以在 Remix 的 Compilation Details 选项中看到编译合约之后。这是可选的替代查看方式命令行分析仍以solc --asm为准。获取优化后的汇编如果要对比优化对产物的影响加上--optimizesolc --optimize --asm contract.sol官方优化器文档docs/internals/optimizer.rst说明了非优化与优化输出的典型差异常数表达式会在编译期求值汇编层面还能看到等价或重复代码块被削减——文档建议直接对比--asm与--asm --optimize的输出。另外根据 using the compiler 文档优化器默认假设合约各操作码在其生命周期内约执行 200 次--optimize-runs可调整这一假设如--optimize-runs1偏向更小的部署成本因此对比两份汇编时除--optimize开与关之外--optimize-runs取值不同也可能导致产物不同。保存汇编文件并 diff 改动前后的产物文档给出的判断方法是对两份对应的汇编输出做diff必要时先剥离指向源码位置的注释。文档举的例子是验证两个不同 Solidity 表达式——(a * b) / c和a * b / c——是否生成相同的优化后字节码。把汇编落到文件、便于反复 diff官方命令行文档docs/using-the-compiler.rst给出的方式是让solc把各类输出分别写入目录solc -o outputDirectory --bin --ast-compact-json --asm sourceFile.sol其中outputDirectory是你要指定的输出目录sourceFile.sol是待编译文件。这样每次编译都在目录中留下汇编文件修改源码后再次编译再用diff比较两个版本的汇编文件即可diff before/contract.asm after/contract.asm执行时的操作顺序与判断依据在修改源码前编译一次并保存汇编如上-o写入before目录修改contract.sol例如把(a * b) / c改成a * b / c用相同参数再次编译到after目录对两份汇编执行diff。文档说明源码位置注释/* contract.sol:... */这类在源码改动后行号必然变化会让 diff 产生大量噪音因此建议剥离后再比较如果两份优化后汇编在去除注释后没有实质差异即可判断这两种写法生成了相同的优化代码。--optimize的 diff 与--optimize-runs同理保持两次编译的优化参数一致结论才可比。限制与注意事项官方文档明确警告--asm输出不是设计给机器解析使用的因此 solc 的小版本之间该输出格式可能有不兼容变化。跨 solc 版本对比汇编时必须保持编译器版本一致否则差异可能来自输出格式而非代码。汇编中的tag_N、jumpi、auxdata等属于编译器内部表示文档只说明了上述结构与注释含义没有给出逐指令语义的对照表需要理解具体指令行为时应回到 EVM 层面阅读本文不展开。若只想快速人工查看而不落盘solc --asm contract.sol直接打印到终端即可diff 场景才需要-o输出目录。完成上述步骤后你能得到的结论是某次源码改动或两种等价写法在优化前后的汇编层面到底改变了什么、是否生成了相同代码。若进一步需要追踪#utility.yul中工具函数的来源按前文说明使用--combined-json generated-sources,generated-sources-runtime获取即可。【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考