写点什么

汇编分析 golang 循环

  • 2020-02-26
  • 本文字数:1737 字

    阅读完需:约 6 分钟

汇编分析golang循环

今天小编为大家分享一篇关于 Golang 循环汇编分析的文章,文章中介绍了 golang 循环的汇编层面的处理,通过分析,我们可以更了解循环的实现。希望能对大家有所帮助。

循环是编程中很强大的一个概念,而且非常容易处理。但是,必须将其翻译成机器可理解的基本指令。它的编译方式也可能影响标准库中的其他组件。让我们开始分析一下范围循环。

循环汇编

范围循环可以迭代数组,切片或通道。下面函数展示了,对分片进行循环并将数字相加:


func main() {   l := []int{9, 45, 23, 67, 78}   t := 0
for _, v := range l { t += v }
println(t)}
复制代码


执行 go tool compile -S main.go 可以转储生成汇编代码,下面为范围循环的相关代码。


0x0041 00065 (main.go:4)   XORL   AX, AX0x0043 00067 (main.go:4)   XORL   CX, CX
0x0045 00069 (main.go:7) JMP 820x0047 00071 (main.go:7) MOVQ ""..autotmp_5+16(SP)(AX*8), DX0x004c 00076 (main.go:7) INCQ AX0x004f 00079 (main.go:8) ADDQ DX, CX0x0052 00082 (main.go:7) CMPQ AX, $50x0056 00086 (main.go:7) JLT 710x0058 00088 (main.go:11) MOVQ CX, "".t+8(SP)
复制代码


我们把指令分为两部分:初始化及循环本身。最开始两行指令用来初始化两个寄存器为 0。


0x0041 00065 (main.go:4)   XORL   AX, AX0x0043 00067 (main.go:4)   XORL   CX, CX
复制代码


寄存器 AX 包含循环中的当前位置,而 CX 包含变量 t 的值。下面是带有指令和通用寄存器的直观表示:



该循环指令 JMP 82 开始,表示跳转到指令 82。可以通过第二列来标识此目标指令:



下一条指令 CMPQ AX, $5 表示“比较寄存器 AX 和数值 5”。它实际上是从 AX 中减去寄存器 DX 的值,并将结果存储到另一个寄存器中。现在,可以在下一条指令 JLT 71 中使用该值,该指令表示“如果小于 0,则跳转到指令 71。”下面是更新后的图:



如果条件不满足,则程序将不会跳转执行循环后面的下一条指令。


因此,我们现在有了循环的结构。下面是转换回 Go 的循环:


goto endstart:   ?end:   if i < 5 {      goto start   }
println(t)
复制代码


该循环的主体是缺失的,下面是指令:


0x0047 00071 (main.go:7)   MOVQ   ""..autotmp_5+16(SP)(AX*8), DX0x004c 00076 (main.go:7)   INCQ   AX0x004f 00079 (main.go:8)   ADDQ   DX, CX
复制代码


第一个指令 MOVQ “”…autotmp_5+16(SP)(AX*8), DX 表示“将内存从源移动到目标”。由以下内容组成:


片段 “”…autotmp_5+16(SP) 其中 SP 是堆栈指针(我们当前的内存栈帧),而 autotmp_* 是自动生成的变量名称。


偏移量 8(在 64 位架构上,int 为 8 位)乘以寄存器 AX 的值,即循环中的当前位置。


由寄存器 DX 表示的,目标现在包含循环的当前值。


然后,INCQ 代表“递增”,并将递增循环的当前位置:


循环体的最后一条指令是 ADDQ DX, CX 表示“将 DX 添加到 CX”。之前我们已经看到 DX 包含循环的当前值,而 CX 是包含变量 t 内容的寄存器:



它将一直循环直到循环计数器到达 5。然后,循环之后的指令显示寄存器 CX 将其值移至 t :


0x0058 00088 (main.go:11) MOVQ CX, “”.t+8(SP)


这是处于最终状态的图:



我们还可以在 Go 中完成循环的翻译:


func main() {   l := []int{9, 45, 23, 67, 78}   t := 0   i := 0
var tmp int
goto endstart: tmp = l[i] i++ t += tmpend: if i < 5 { goto start }
println(t)}
复制代码


为这个新程序生成汇编代码,将提供完全相同的输出。

改进

内部转换循环的方式可能会对其他功能(例如 Go 调度程序)产生影响。在 Go 1.10 之前,编译的循环类似于以下代码:


func main() {   l := []int{9, 45, 23, 67, 78}   t := 0   i := 0
var tmp int p := uintptr(unsafe.Pointer(&l[0]))
if i >= 5 { goto end }body: tmp = *(*int)(unsafe.Pointer(p)) p += unsafe.Sizeof(l[0]) i++ t += tmp if i < 5 { goto body }end: println(t)}
复制代码


这种实现方式的问题是,当达到 5 时,指针 p 超过了分配的末尾。这个问题使循环不容易被抢占,因为它的主体不安全。循环编译的优化确保它不会创建任何过去的指针。为准备 Go 调度程序中的非合作式抢占而进行了此改进。


本文转载自 360 云计算公众号。


原文链接:https://mp.weixin.qq.com/s/J37BmlWhEEeuwVnPck0rIA


2020-02-26 23:001046

评论

发布
暂无评论
发现更多内容

共话开源,为热爱而聚!2023开放原子全球开源峰会“开发者之夜”节目征集进行中!

开放原子开源基金会

开源

可以免费使用的ChatGPT-4,微软开放Bing Chat功能,供用户体验

炜娓道来程序人生

AI AIGC ChatGPT

数字化转型应该如何去做?(方法篇)

数字随行

数字化转型

开源赋能 普惠未来|QUICKPOOL诚邀您参与2023开放原子全球开源峰会

开放原子开源基金会

开源

为什么 HashMap 会死循环?

javacn.site

【腾讯云 Finops Crane 集训营】安装使用及EHPA弹性演示

指剑

腾讯云 Kubernetes 降本增效 FinOps crane

开源赋能 普惠未来|OpenNJet诚邀您参与2023开放原子全球开源峰会

开放原子开源基金会

面试官:你能和我说一下 CMS 垃圾回收器吗?

Java你猿哥

Java 算法 CMS 垃圾回收器 垃圾收集器

开源模式新探索!卡奥斯工业互联网开源开放社区再升级

Openlab_cosmoplat

开源 工业互联网 天工开物

Java开发分析用什么软件好?

真大的脸盆

Mac JAVA开发 Mac 软件 Java开发分析工具

扩展可能性:发挥React Native与小程序集成的优势

FinFish

React Native 跨端开发 小程序容器 跨端框架 小程序技术

名侦探白洞(一):智能家居灵异事件

白洞计划

AI

2023-05-22:给定一个长度为 n 的字符串 s ,其中 s[i] 是: D 意味着减少; I 意味着增加。 有效排列 是对有 n + 1 个在 [0, n] 范围内的整数的一个排列 perm

福大大架构师每日一题

Go 算法 rust 福大大

如何使用Go实现原型设计模式

Jack

golang 设计模式 架构设计 golang 面试

PoseiSwap:为何青睐 Layer3?又为何选择 Celestia 作为技术伙伴?

西柚子

MobTech MobPush|ChatGPT辅助消息推送,实现文案千人千版

MobTech袤博科技

打卡智能中国(五):博士都去哪儿了?

脑极体

AI 智能中国

记一次redis主从切换导致的数据丢失与陷入只读状态故障

Java你猿哥

redis sentinel ssm 高可用架构

Transformer模型的基础演算

OneFlow

人工智能 AI

即时通讯(IM)开源项目OpenIM对WebAssembly支持,提升web端体验

Geek_1ef48b

AIGC产业研究报告2023——分子发现与电路设计篇

易观分析

产业 AIGC

JavaScript作用域深度剖析:动态作用域

沉浸式趣谈

SpringWeb服务构建轻量级Web技术体系:SpringHATEOAS

Java你猿哥

Java spring RESTful Web ssm

2023开放原子全球开源峰会分论坛即将来袭,Pick你最关注的峰会话题!

开放原子开源基金会

利用 DynamoDB 和 S3 结合 gzip 压缩,最大化存储玩家数据

亚马逊云科技 (Amazon Web Services)

存储

iOS MachineLearning 系列(17)—— 几个常用的对象识别 CoreML 模型

珲少

C/C++项目构建指南:如何使用Makefile提高开发效率

小万哥

c++ 程序员 面试 后端 开发

Last Week in Milvus

Zilliz

PoseiSwap:为何青睐 Layer3?又为何选择 Celestia 作为技术伙伴?

股市老人

汇编分析golang循环_文化 & 方法_360云计算_InfoQ精选文章