golang 數字比較 彙編分析golang迴圈

2021-10-13 17:28:09 字數 2980 閱讀 5190

女主宣言

ps:豐富的一線技術、多元化的表現形式,盡在「360雲計算」,點關注哦!

迴圈是程式設計中很強大的乙個概念,而且非常容易處理。但是,必須將其翻譯成機器可理解的基本指令。它的編譯方式也可能影響標準庫中的其他元件。讓我們開始分析一下範圍迴圈。

迴圈彙編

範圍迴圈可以迭代陣列,切片或通道。下面函式展示了,對分片進行迴圈並將數字相加:

func main() 

t := 0

for _, v := range l

println(t)

}

執行 go tool compile -s main.go 可以轉儲生成彙編**,下面為範圍迴圈的相關**。

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)

我們把指令分為兩部分:初始化及迴圈本身。最開始兩行指令用來初始化兩個暫存器為0。

0x0041 00065 (main.go:4)   xorl   ax, ax

0x0043 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 end

start:

?end:

if i < 5

println(t)

該迴圈的主體是缺失的,下面是指令:

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

第乙個指令 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() 

t := 0

i := 0

var tmp int

goto end

start:

tmp = l[i]

i++t += tmp

end:

if i < 5

println(t)

}

為這個新程式生成彙編**,將提供完全相同的輸出。

改進

內部轉換迴圈的方式可能會對其他功能(例如go排程程式)產生影響。在go 1.10之前,編譯的迴圈類似於以下**:

func main() 

t := 0

i := 0

var tmp int

p := uintptr(unsafe.pointer(&l[0]))

if i >= 5

body:

tmp = *(*int)(unsafe.pointer(p))

p += unsafe.sizeof(l[0])

i++t += tmp

if i < 5

end:

println(t)

}

這種實現方式的問題是,當達到5時,指標p超過了分配的末尾。這個問題使迴圈不容易被搶占,因為它的主體不安全。迴圈編譯的優化確保它不會建立任何過去的指標。為準備go排程程式中的非合作式搶占而進行了此改進。

360雲計算

Golang彙編快速指南

有些符號,例如pc,r0和sp,是預定義的並且是對乙個暫存器的引用。另外還有兩種預定義的符號,sb static base 和fp frame pointer 所有使用者定義的符號,除了標籤跳轉之外,都是對偽暫存器的offsets操作。1 sb偽暫存器可以想象成記憶體的位址,所以符號foo sb 是...

golang逃逸分析

帶gc語言給我們程式的編寫帶來了極大的便利,但是與此同時遮蔽了很多底層的細節,比如乙個物件是在棧上分配還是在堆上分配。對於普通的 來說雖然不需要關心這麼多,但是作為強迫症程式猿,還是希望能讓自己寫出來的 效能最優,所以還是需要了解什麼是逃逸,以及如何判斷是否發生了逃逸。首先需要知道,我們說的堆和棧是...

Golang中的struct比較

可比較的資料型別除了上述三種外,還有boolean,complex,pointer,channel,inte ce和array 不可比較的資料型別包括,slice,map,和function 不包含不可比較的成員變數 reflect.deepequal函式,指標和例項均可以比較 無論有沒有包含不可比...