写点什么

Solidity 之旅(十八)内联汇编 [inline assembly]

作者:BSN研习社
  • 2024-01-12
    浙江
  • 本文字数:1765 字

    阅读完需:约 6 分钟

Solidity之旅(十八)内联汇编 [inline assembly]

概要

自从 C 语言问世,而后类 C 语言犹如雨后春笋般地搅动着 IT 界,而这些语言有别于汇编语言那样。它们就是更贴切自然语言的高级编程语言,可这些高级编程语言最终还是要编译成机器语言(汇编语言)。


EVM(Ethereum Virtual Machine)是一种栈(Stack)结构,我们知道栈是一种先进后出(LIFO)的数据结构。


为什么要用汇编来编写呢?


借您所问,既然 Solidity 可以编写出优秀的智能合约,那为什么还要使用低级的汇编语言呢?


在回答这个问题之前,我们来看看每个新的编程语言诞生都是为了解决当前编程语言无法解决,或者说使用当前编程语言解决起来比较麻烦,那么,新的编程语言就在这样的环境下应运而生,当然咯,并不是所有新编程语言都是为了解决当前编程语言不能解决的问题,才被开发出来,而是……(此处不便说出缘由,毕竟它也不是本文的重点)。


细粒度控制


Assembly 允许您执行一些仅仅靠 Solidity 无法实现的逻辑,比如,指向特定的内存插槽(Memory Slot)。


当我们在编写库(library)时,细粒度控制特别有用,因为它们会被重复使用。


节省 gas


在 Solidity 中使用 Assembly 的主要好处之一是节省 gas。让我们尝试通过创建一个将 2 个值 x 和 y 相加并返回结果的函数来比较 Solidity 和 Assembly 之间的 gas 成本。


// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.8.0;
contract AssemblyExample { function addAssembly(uint x, uint y) public pure returns (uint) { assembly { let result := add(x, y) mstore(0x0, result) return(0x0, 32) } } function addSolidity(uint x, uint y) public pure returns (uint) { return x + y; } }
复制代码



Solidity 中两种方式实现 Assembly

1、内联汇编:也可以在 Solidity 代码中使用。2、独立程序集:无需编写 Solidity 代码即可使用。

怎么使用 Assembly?

正如上面的例子那样,汇编代码运行在 assembly{...}汇编块中的。而汇编代码是使用 YUL 语言来编写的!内联汇编块不共享命名空间,即不能在一个汇编块调用另一个汇编块中定义的变量。

assembly {   // some assembly code here}
复制代码


以下是一个简单的示例,函数接受两个参数,并将它们的和作为返回值,看看使用 Assembly 是怎么实现的?了解它们在 EVM 的工作方式。


// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.8.0;
contract AssemblyExample { function addition(uint x, uint y) public pure returns (uint) { assembly { //声明一个 result 变量,并将 x,y之和赋值给它 let result := add(x, y) // x + y //使用 mstore 操作码将 result存在 memory 中,地址是 0x0 mstore(0x0, result) // store result in memory //返回 32 字节的 memory 地址 return(0x0, 32) }} }
复制代码



数据存储


让我们来看看一个简单的例子。我们将数据存放在 storage(存储)中,然后再去调用它。

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.8.0;
contract StorageDataExample {
function setData(uint256 newValue) public { assembly { sstore(0, newValue) } }
function getData() public view returns(uint256) { assembly { let v := sload(0) mstore(0x80, v) return(0x80, 32) } }}
复制代码



setData 函数使用了 sstore 操作码将变量 newValue 写入 storage(存储)中。getData 函数先是用了 sload 操作码来加载 storage(存储)中的数据,它并不能从 storage 中直接返回。所以才需要 mstore 操作码将其写入 memory(内存)中,最后我们返回引用 memory(内存)中存放数据的地址和 32 字节长度的数据。


https://docs.soliditylang.org/en/latest/yul.html


版权声明:本文为 CSDN 博主「甄齐才」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:

https://blog.csdn.net/coco2d_x2014/article/details/128473584


文章来源:CSDN 博主「甄齐才」

文章原标题:《玩以太坊链上项目的必备技能(内联汇编 [inline assembly]-Solidity 之旅十八)》

旨在传播区块链相关技术,如有侵权请与我们联系删除。

用户头像

BSN研习社

关注

还未添加个人签名 2021-11-05 加入

还未添加个人简介

评论

发布
暂无评论
Solidity之旅(十八)内联汇编 [inline assembly]_BSN研习社_InfoQ写作社区