C 的内联汇编

有些平台相关的指令在 C 语言中没有等价的语法,必须手写,因为 C 语言的语法和概念是对各种平台的抽象,而各种平台特有的一些东西就不会在 C 语言中出现。

  • 例如 x86 是端口 I/O,而 C 语言就没有这个概念,所以 in/out 指令必须用汇编来写。
  • gcc 提供了一种扩展语法可以在 C 代码中使用内联汇编(Inline Assembly)。

内联汇编最简单的格式是 __asm__("assembly code");

__asm__("nop");

__asm__("movl $1, %eax\n\t"
	"movl $4, %ebx\n\t"
	"int $0x80");
  • nop 这条指令什么都不做,只是让 CPU 空转一个指令执行周期;
  • 如果需要执行多条汇编指令,则应该用 \n\t 将各条指令分隔开。

Solidity 的内联汇编

You can interleave Solidity statements with inline assembly in a language close to the one of the EVM.

  • This gives you more fine-grained control, which is especially useful when you are enhancing the language by writing libraries.
  • Inline assembly is a way to access the EVM at a low level. This bypasses several important safety features and checks of Solidity.

The language used for inline assembly in Solidity is called Yul. An inline assembly block is marked by assembly { ... }, where the code inside the curly braces is code in the Yul language. Different inline assembly blocks share no namespace, i.e. it is not possible to call a Yul function or access a Yul variable defined in a different inline assembly block.

Reusable assembly libraries can enhance the Solidity language without a compiler change.

// Access the code of another contract and load it into a bytes variable.
// Plain Solidity <address>.code does this job too.
library GetCode {
    function at(address addr) public view returns (bytes memory code) {
        assembly {
            // retrieve the size of the code, this needs assembly
            let size := extcodesize(addr)
            // allocate output byte array - this could also be done without assembly
            // by using code = new bytes(size)
            code := mload(0x40)
            // new "memory end" including padding
            mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            // store length in memory
            mstore(code, size)
            // actually retrieve the code, this needs assembly
            extcodecopy(addr, add(code, 0x20), 0, size)
        }
    }
}
  • add(x, y): x + y
  • mload(p): mem[p…(p+32))
  • mstore(p, v): mem[p…(p+32)) := v
    • p: the offset in memory to write to
    • v: the data to write in memory

References