06-Solidity8.0汇编(Solidity Assembly)

本文深入介绍了Solidity8.0中的内联汇编,这是一种可以与Solidity源码混合使用的底层语言,用于实现更精细的控制。内联汇编提供了函数风格的操作码、局部变量、访问外部变量等功能,但同时也带来了安全风险和难度。文章通过实例展示了如何使用内联汇编进行循环、函数调用和变量赋值,并提醒开发者注意其潜在的陷阱。

Solidity8.0

06-Solidity8.0汇编(Solidity Assembly)


在这里插入图片描述


前言

Solidity汇编(Solidity Assembly)
Solidity定义了一个汇编语言,可以不同Solidity一起使用。这个汇编语言还可以嵌入到Solidity源码中,以内联汇编的方式使用。下面我们将从内联汇编如何使用着手,介绍其与独立使用的汇编语言的不同,最后再介绍这门汇编语言。

内联汇编(Inline Assembly)

通常我们通过库代码,来增强语言我,实现一些精细化的控制,Solidity为我们提供了一种接近于EVM底层的语言,内联汇编,允许与Solidity结合使用。由于EVM是栈式的,所以有时定位栈比较麻烦,Solidty的内联汇编为我们提供了下述的特性,来解决手写底层代码带来的各种问题:

允许函数风格的操作码:mul(1, add(2, 3))等同于push1 3 push1 2 add push1 1 mul
内联局部变量:let x := add(2, 3) let y := mload(0x40) x := add(x, y)
可访问外部变量:function f(uint x) { assembly { x := sub(x, 1) } }
标签:let x := 10 repeat: x := sub(x, 1) jumpi(repeat, eq(x, 0))
循环:for { let i := 0 } lt(i, x) { i := add(i, 1) } { y := mul(2, y) }
switch语句:switch x case 0 { y := mul(x, 2) } default { y := 0 }
函数调用:function f(x) -> y { switch x case 0 { y := 1 } default { y := mul(x, f(sub(x, 1))) } }
下面将详细介绍内联编译(inline assembly)语言。

警告
需要注意的是内联编译是一种非常底层的方式来访问EVM虚拟机。他没有Solidity提供的多种安全机制。
注解
TODO:待补充内联汇编的变量作用域的不同,尤其是使用含internal的函数的库时所引入的复杂度。另外,还需补充,编译器定义的符号(symbols)。


一、Solidity8.0汇编(Solidity Assembly)

1.汇编(Solidity Assembly)

代码如下(示例):
下面的例子提供了一个库函数来访问另一个合约,并把它写入到一个bytes变量中。有一些不能通过常规的Solidity语言完成,内联库可以用来在某些方面增强语言的能力。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

library GetCode {
   
   
    function at(address _addr) public view returns (bytes o_code) {
   
   
        assembly {
   
   
            // 取得代码的大小,这需要汇编
            let size := extcodesize(_addr)
            // 分配输出字节数组
            // 也可以不使用汇编完成——o_code = new bytes(size)
            o_code := mload(0x40)
            // new "memory end" including padding
            mstore(0x40,add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            // 存储长度在内存中
            mstore(o_code, size)
            // 实际取得代码,这需要汇编
            extcodecopy(_addr, add(o_code, 0x20), 0, size)
        }
    }
}

内联汇编在当编译器没办法得到有效率的代码时非常有用。但需要留意的是内联汇编写起来是比较难的,因为编译器不会进行一些检查,所以你应该只在复杂的,且你知道你在做什么的事情上使用它。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8;

library VectorSum {
   
   
    // 此函数效率较低,因为优化器当前无法
    // 移除数组访问中的边界检查。
    function sumSolidity(uint[] _data) public view returns (uint o_sum) {
   
   
        for (uint i = 0; i < _data.length; ++i)
            o_sum += _data[i];
    }

    // 我们知道我们只访问数组,所以我们可以避免检查。
    // 0x20需要添加到一个数组中,因为第一个位置包含
    // 数组长度。
    function sumAsm(uint[] _data) public view returns (uint o_sum) {
   
   
        for (uint i = 0; i < _data.length; ++i) {
   
   
            assembly {
   
   
                o_sum := add(o_sum, 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值