solidity智能合约[50]-assembly内联汇编-创新互联

内联汇编

对于普通的solidity智能合约来说,通过solc编译器的优化操作,将源代码转换为以太坊能够识别的二进制文件。但是solc编译器不是万能的,在某些情况下,例如循环操作的时候,并不能达到最佳的执行方式。通过在solidity智能合约中内嵌汇编代码,可以阻止编译器的优化,在某些时候能够到达节约gas的作用。同时,内嵌汇编代码可以增加solidity语言的功能。例如在判断账户地址为合约地址还是外部地址的时候,只能够通过汇编代码来实现。

目前创新互联已为上1000家的企业提供了网站建设、域名、虚拟主机网站运营、企业网站设计、禹会网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。

内联汇编语法

1
2
3
assembly{
 内联汇编语句
}

将for循环转换变为内联汇编

let指令定义变量。
add函数是内联汇编中内置的加法操作,solidity内联汇编中有很多内置的函数。jumpi为跳转函数,跳转到loop语句执行。
It函数为小于函数,lt(i,9)判断i是否小于9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function nativeLoop() public returns(uint _r){

  for(uint i = 0;i<10;i++){
    _r += i;
  }
}


function asmloop() public returns(uint _r){

  assembly{

    let i :=0
    loop:
       i:=add(i,1)
       _r := add(_r,i)
       jumpi(loop,lt(i,9))
  }
}

条件语句转换为内联汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function nativeConditional(uint _v) returns(uint _r){

  if(5==_v){
    _r =  55;
  }
  else if(6 ==_v){
    _r =  66;
  }

  _r =  11;
}

function asmConditional(uint _v) public returns(uint _r){

  assembly{

    switch _v

    case 5{
      _r:=55
    }
    case 6{
       _r:=66
    }
    default{
      _r:=11
    }
  }
}

内联汇编解析1

下面的合约中,msize()代表的是当前已经使用的memory空间的大位置。加1之后,代表的是可用的指针所在的位置。
mstore代表将值_v赋值给_ptr。 return (ptr,0x20)代表的是从位置_ptr开始,往下读取0x20也就是32个字节

1
2
3
4
5
6
7
function asmReturens(uint _v) public returns(uint){
   assembly{
     let _ptr :=add(msize(),1)
     mstore(_ptr,_v)
     return (_ptr,0x20)
   }
 }

内联汇编解析2

mload(40)代表获取0x40位置往下32个字节存储的数据。0x40位置非常特殊,其存储的是最小的可用的memory内存的地址。
例如为0x80.
mstore(add(freemem_pointer,0x00),“36e5236fcd4c610449678014f0d085”) 存储字符串到"36e5236fcd4c610449678014f0d085" 到0x80往下32个字节的空间中。
mstore(add(freemem_pointer,0x20),“36e5236fcd4c610449678014f0d086”) 首先将0x80加上32个字节,变为了0xa0。之后便加上32个字节,存储字符串"36e5236fcd4c610449678014f0d086" 到0xa0往下32个字节的空间中。
let arr1:=mload(freemem_pointer)定义了变量arr1. 获取freemem_pointer往下32个字节。由于freemem_pointer当前仍然为0x80,因此arr1的值为字符串"36e5236fcd4c610449678014f0d085"。 最后的语句mstore(add(freemem_pointer,0x40),arr1)。存储了arr1到0xc0地址往下的32个字节的空间中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pragma solidity ^0.4.23;

contract cat{

  function test(){

    assembly{
      let freemem_pointer :=mload(0x40) //0x80

      mstore(add(freemem_pointer,0x00),"36e5236fcd4c610449678014f0d085")
      mstore(add(freemem_pointer,0x20),"36e5236fcd4c610449678014f0d086")
      let arr1:=mload(freemem_pointer)
      mstore(add(freemem_pointer,0x40),arr1)
    }
  }
}

内联汇编解析3

下面的函数,实现了将地址转换为动态字节数组的操作。
let m := mload(0x40)获取0x40位置往下32个字节存储的数据。0x40位置非常特殊,其存储的是最小的可用的memory内存的地址。例如为0x80. add(m, 20) 将0x80加上了20个字节(0x14),到达0x94.
xor为位运算的异或操作。相等为0,不等为1。0x140000000000000000000000000000000000000000的长度为168位,币地址多了6位。假设地址为0xca35b7d915458ef540ade6068dfe2f44e8fa733c。那么异或之后,变为了0x14ca35b7d915458ef540ade6068dfe2f44e8fa733c,一共有21个字节。填充为32个字节之后变为了0x000000000000000000000014ca35b7d915458ef540ade6068dfe2f44e8fa733c,通过mstore存储到0x94地址之后的32个字节中。

在memory空间中
0x80 0x0000000000000000000000000000000000000000000000000000000000000014
0xa0 0xca35b7d915458ef540ade6068dfe2f44e8fa733c000000000000000000000000

从而14代表长度为20个字节。其后面是地址。将0x80的地址赋值给动态长度字节变量b。由于动态长度字节数组首先32个字节存储长度,后面存储内容。因此将地址转换为了动态长度数组。

1
2
3
4
5
6
7
8
9
10
11
contract dog{

 function toBytes(address a) constant returns (bytes b){
 assembly {
    let m := mload(0x40)
    mstore(add(m, 20), xor(0x140000000000000000000000000000000000000000, a))
    mstore(0x40, add(m, 52))
    b := m
 }
}
}
  • 本文链接: https://dreamerjonson.com/2018/11/24/solidity-50-assembly/

  • 版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0 CN协议 许可协议。转载请注明出处!

solidity智能合约[50]-assembly内联汇编

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


当前文章:solidity智能合约[50]-assembly内联汇编-创新互联
分享地址:http://pwwzsj.com/article/cscccs.html