匯編分析 Golang 循環(huán)(推薦)
女主宣言
今天小編為大家分享一篇關(guān)于Golang循環(huán)匯編分析的文章,文章中介紹了golang循環(huán)的匯編層面的處理,通過分析,我們可以更了解循環(huán)的實(shí)現(xiàn)。希望能對(duì)大家有所幫助。
PS:豐富的一線技術(shù)、多元化的表現(xiàn)形式,盡在“ 3 60云計(jì)算 ”,點(diǎn)關(guān)注哦!
循環(huán)是編程中很強(qiáng)大的一個(gè)概念,而且非常容易處理。 但是,必須將其翻譯成機(jī)器可理解的基本指令。 它的編譯方式也可能影響標(biāo)準(zhǔn)庫中的其他組件。 讓我們開始分析一下范圍循環(huán) 。
1循環(huán)匯編
范圍循環(huán)可以迭代數(shù)組,切片或通道。下面函數(shù)展示了,對(duì)分片進(jìn)行循環(huán)并將數(shù)字相加:
func main() { l := []int{9, 45, 23, 67, 78} t := 0 for _, v := range l { t += v } println(t) }
執(zhí)行 go tool compile -S main.go 可以轉(zhuǎn)儲(chǔ)生成匯編代碼,下面為范圍循環(huán)的相關(guān)代碼。
0x0041 00065 (main.go:4) XORL AX, AX 0x0043 00067 (main.go:4) XORL CX, CX 0x0045 00069 (main.go:7) JMP 82 0x0047 00071 (main.go:7) MOVQ ""..autotmp_5+16(SP)(AX*8), DX 0x004c 00076 (main.go:7) INCQ AX 0x004f 00079 (main.go:8) ADDQ DX, CX 0x0052 00082 (main.go:7) CMPQ AX, $5 0x0056 00086 (main.go:7) JLT 71 0x0058 00088 (main.go:11) MOVQ CX, "".t+8(SP)
我們把指令分為兩部分:初始化及循環(huán)本身。最開始兩行指令用來初始化兩個(gè)寄存器為0。
0x0041 00065 (main.go:4) XORL AX, AX 0x0043 00067 (main.go:4) XORL CX, CX
寄存器AX包含循環(huán)中的當(dāng)前位置,而CX包含變量 t 的值。下面是帶有指令和通用寄存器的直觀表示:
該循環(huán)指令 JMP 82 開始,表示跳轉(zhuǎn)到指令82??梢酝ㄟ^第二列來標(biāo)識(shí)此目標(biāo)指令:
下一條指令 CMPQ AX, $5 表示“比較寄存器AX和數(shù)值5”。它實(shí)際上是從AX中減去寄存器DX的值,并將結(jié)果存儲(chǔ)到另一個(gè)寄存器中?,F(xiàn)在,可以在下一條指令JLT 71中使用該值,該指令表示“如果小于0,則跳轉(zhuǎn)到指令71。”下面是更新后的圖:
如果條件不滿足,則程序?qū)⒉粫?huì)跳轉(zhuǎn)執(zhí)行循環(huán)后面的下一條指令。
因此,我們現(xiàn)在有了循環(huán)的結(jié)構(gòu)。下面是轉(zhuǎn)換回 Go 的循環(huán):
goto end start: ? end: if i < 5 { goto start } println(t)
該循環(huán)的主體是缺失的,下面是指令:
0x0047 00071 (main.go:7) MOVQ ""..autotmp_5+16(SP)(AX*8), DX 0x004c 00076 (main.go:7) INCQ AX 0x004f 00079 (main.go:8) ADDQ DX, CX
第一個(gè)指令 MOVQ ""..autotmp_5+16(SP)(AX*8), DX 表示“將內(nèi)存從源移動(dòng)到目標(biāo)”。由以下內(nèi)容組成:
- 片段 ""..autotmp_5+16(SP) 其中 SP 是堆棧指針(我們當(dāng)前的內(nèi)存棧幀),而 autotmp_* 是自動(dòng)生成的變量名稱。
- 偏移量8(在64位架構(gòu)上,int為8位)乘以寄存器AX的值,即循環(huán)中的當(dāng)前位置。
- 由寄存器DX表示的,目標(biāo)現(xiàn)在包含循環(huán)的當(dāng)前值。
然后,INCQ 代表“遞增”,并將遞增循環(huán)的當(dāng)前位置:
循環(huán)體的最后一條指令是 ADDQ DX, CX 表示“將DX添加到CX”。之前我們已經(jīng)看到DX包含循環(huán)的當(dāng)前值,而CX是包含變量 t 內(nèi)容的寄存器:
它將一直循環(huán)直到循環(huán)計(jì)數(shù)器到達(dá)5。然后,循環(huán)之后的指令顯示寄存器CX將其值移至 t :
0x0058 00088 (main.go:11) MOVQ CX, "".t+8(SP)
這是處于最終狀態(tài)的圖:
我們還可以在Go中完成循環(huán)的翻譯:
func main() { l := []int{9, 45, 23, 67, 78} t := 0 i := 0 var tmp int goto end start: tmp = l[i] i++ t += tmp end: if i < 5 { goto start } println(t) }
為這個(gè)新程序生成匯編代碼,將提供完全相同的輸出。
2改進(jìn)
內(nèi)部轉(zhuǎn)換循環(huán)的方式可能會(huì)對(duì)其他功能(例如Go調(diào)度程序)產(chǎn)生影響。在Go 1.10之前,編譯的循環(huán)類似于以下代碼:
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) }
這種實(shí)現(xiàn)方式的問題是,當(dāng)達(dá)到5時(shí),指針p超過了分配的末尾。這個(gè)問題使循環(huán)不容易被搶占,因?yàn)樗闹黧w不安全。循環(huán)編譯的優(yōu)化確保它不會(huì)創(chuàng)建任何過去的指針。為準(zhǔn)備Go調(diào)度程序中的非合作式搶占而進(jìn)行了此改進(jìn)。
總結(jié)
以上所述是小編給大家介紹的匯編分析 Golang 循環(huán),希望對(duì)大家有所幫助,也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
匯編語言實(shí)現(xiàn)在指定字符串中搜索字符''A''的方法
這篇文章主要介紹了匯編語言實(shí)現(xiàn)在指定字符串中搜索字符'A'的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02匯編語言基礎(chǔ)理解計(jì)算機(jī)底層技術(shù)原理
這篇文章主要為大家介紹了匯編語言基礎(chǔ),理解計(jì)算機(jī)底層原理,想要成為高級(jí)程序員,我們必須要學(xué)會(huì)匯編語言,匯編語言是非常重要的計(jì)算機(jī)底層技術(shù),一般用于底層的編寫2021-11-11