gcc生成的汇编和keil生成的汇编_查看 Golang、Lua、JS、Rust、Python等语言生成的汇编代码...

喜欢的话可以收藏转发加关注

为什么写这篇文章?

昨天在技术群上,有人问了个问题:

如果一个结构体, 只是读里面的成员, 在 golang 里面传值的时候, 不传递指针, golang 编译器会帮你优化成 const & 么?

随便一猜:golang 肯定是直接 copy 整个结构体。

为了确认是否真的是这样,最直白的方式就是直接看 golang 生成的汇编代码。

从图中的汇编代码中,我们可以清楚的看到:golang 的确是执行了完整的结构体 copy 。

78435b1fa86788692f698e1d7f568536.png

然后群友给了这样的反馈...

9af1372846ccd55e0b13ea3cd7265569.png

看着自己日益升高的发际线,我陷入了沉思...


好了,进入正题。

本文将以 1 + ... + 100 的代码为例,介绍以下几种语言查看“汇编代码”的方式。

(这里的“汇编代码”只是个统称,大家不用太计较)

  1. GolangLuaJavaScript(V8)RustPython等等 ...

1. Golang 生成汇编代码

源码

package mainfunc main(){var sum = 0for i:=1 ; i <= 100; i++ {sum = sum + i}}

查看方式

go tool compile -S .est.gogo tool objdump .est.o
56cf477752408eeb1da7f34f69ad26b9.png

分析

行 1 : 表示 将数值 1 放到 AX 中

行 2 : 表示 跳转到 行 4

行 3 : 表示 对 AX 中的数值执行 + 1 操作

行 4 : 比较 AX 是否在 100 以内。(0x64 是 数值 100 的 16 进制)

行 5 : 跳转到 行 3

嗯... 怎么感觉就是在空循环,我们的 sum 变量哪里去了?

事实上:golang 检测到 sum 没有被使用,直接就帮我们优化掉了,只留下一个空循环。

(但它没有彻底的帮我们把这个空循环也删掉...)

如果我们把代码改成这样子:

package mainfunc main(){}func getSum()int{var sum = 0for i:=1 ; i <= 100; i++ {sum = sum + i}return sum}

那么 sum 累加部分的汇编就是可以正常的显示出来,如图所示:

32577de0b6a0916e30b2841e1f2dba66.png

2. Lua 生成汇编代码

源码

function getSum() local sum = 0 for i=1, 100 do sum = sum + i end return sumend

查看方式

luac.exe -l test.lua 
fb8de345e4224b1a3662171409e75a01.png

分析

Lua 虚拟机是基于寄存器来实现的。这段汇编代码读起来,就不像golang那么好理解了。

(关于寄存器虚拟机的相关内容,我在文章的评论中补充了一些。有兴趣的话,可以看看)

这里我就简单的分析下:

行 1-4:将常量表里的 0,1,100,1分别加载到寄存器中。

LOADK 指令后面的跟着 2 个参数,分别是:参数1 寄存器索引,参数2 常量表索引

分号后面的数值是: 具体的常量值

这四个数字中:

第一个数字 0 ,就是 sum 的初始值 。

后面三个数(1, 100, 1):表示了循环从 1 开始,到 100 结束,步长为 1

( 也就是说 i 从 1 开始,每次循环自动+1,直到达到 100)

行 5-7:执行循环

Lua 通过 FORPREP、FORLOOP 两条指令来实现循环。

它们的第一个参数:表示指向 循环所需的三个数字 的起始寄存器索引,也就是 寄存器 1。

(这样虚拟机就知道了,循环所需的三个数字:1,100,1,从而准确的控制循环的逻辑)

它们的第二个参数,表示PC指令跳转的距离。

注意:FORLOOP 会把 i+1 的结果 放在寄存器 4 中,对应 add 的第 3 个参数

行 6:执行 Add 操作

Add 后面跟着 3 个参数。含义如下:

参数1:存放结果的寄存器索引

参数2、参数3: 分别是两个加数的索引位置

既然已经分析了 golang 和 lua 两个语言生成的汇编代码,后面的语言就不再详细的分析了,基本大同小异。

3. JavaScript 生成汇编代码

function getSum(){ let sum = 0; for(let i = 1 ; i <= 100; i++){ sum += i } return sum}

查看方式

node --print-bytecode .est.js
8e43fd50c8bc00b976827eae06d74077.png

4. Rust 生成汇编代码

rust 就比较有意思了(和 c++ 差不多),值得稍微提一下。

fn main() { println!("{}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值