时间:2021-05-19
女主宣言
今天小编为大家分享一篇关于Golang循环汇编分析的文章,文章中介绍了golang循环的汇编层面的处理,通过分析,我们可以更了解循环的实现。希望能对大家有所帮助。
PS:丰富的一线技术、多元化的表现形式,尽在“ 3 60云计算 ”,点关注哦!
循环是编程中很强大的一个概念,而且非常容易处理。 但是,必须将其翻译成机器可理解的基本指令。 它的编译方式也可能影响标准库中的其他组件。 让我们开始分析一下范围循环 。
1循环汇编
范围循环可以迭代数组,切片或通道。下面函数展示了,对分片进行循环并将数字相加:
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, CX0x0045 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 表示“将内存从源移动到目标”。由以下内容组成:
然后,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)}为这个新程序生成汇编代码,将提供完全相同的输出。
2改进
内部转换循环的方式可能会对其他功能(例如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调度程序中的非合作式抢占而进行了此改进。
总结
以上所述是小编给大家介绍的汇编分析 Golang 循环,希望对大家有所帮助,也非常感谢大家对网站的支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
Golang开发环境搭建Go语言开发包国外:https://golang.org/dl/国内(推荐):https://golang.google.cn/dl/编
CerberoSuiteAdvanced能够进行文件分析,拥有反汇编分析,字节码反汇编等等功能,使用方便,是不容错过的一款格式分析利器,感兴趣的朋友不要错过了。
前言for循环是Go语言唯一的循环结构,最近在做一个基于RabbitMQ的应用,由于官方的qos没有golang的版本,所以出了一点问题。问题代码如下:_,ch
针对Golang1.9的sync.RWMutex进行分析,与Golang1.10基本一样除了将panic改为了throw之外其他的都一样。RWMutex是读写互
前言golang不允许循环importpackage,如果检测到importcycle,会在编译时报错,通常importcycle是因为设计错误或包的规划问题。