Go彙編學習 2.解構AMD64 bytes.Equal

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

上一篇學了記憶體結構基本知識,本文將學習符號(symbol)、語句的含義。我個人喜歡通過例子來學習,所以,我就從src/runtime/asm_amd64.s裡的bytes·Equal入手吧:)

對應代碼

TEXT bytes·Equal(SB),NOSPLIT,$0-49MOVQa_len+8(FP), BXMOVQb_len+32(FP), CXCMPQBX, CXJNEeqretMOVQa+0(FP), SIMOVQb+24(FP), DILEAQret+48(FP), AXJMPruntime·memeqbody(SB)eqret:MOVB$0, ret+48(FP)RET

預備知識

SB (static base)相關知識

以下是Go asm中的介紹

The SB pseudo-register can be thought of as the origin of memory, so the symbol foo(SB) is the name foo as an address in memory. This form is used to name global functions and data. Adding <>to the name, as in foo<>(SB), makes the name visible only in the current source file, like a top-level static declaration in a C file. Adding an offset to the name refers to that offset from the symbol’s address, so foo+4(SB) is four bytes past the start of foo.

大致翻譯一下,例如foo(SB)的符號,就對應了code segement中的地址,全域可見。當添加了 <> 符號後,就變為了當前檔案可見,類似於C檔案的static聲明,還可以通過添加位移量(offset)來訪問其他地址。

指令格式

例子中的TEXT指令就定義了一個叫bytes·Equal的符號(注意是中點號·),接下來就是對應的指令(可以理解成函數體),而最後RET則是返回指令(退出當前stack)。通常情況下,參數大小後跟隨著stack frame的大小,使用減號(-)分割。$0-49意味著這是一個0-byte的棧,並且有49-byte長的參數。NOSPLIT說明,不允許調度器調整stack frame的大小,這就意味著必須人工指定stack frame大小。但為什麼是49個byte?

因為我們可以看看bytes.Equal的定義

func Equal(a, b []byte) bool

a, b 分別為[]byte(不定長的byte slice),而slice的結構是:

type slice struct {    array unsafe.Pointer    len   int    lcap  int}

unsafe.Pointer 在amd64上是uintptr,即uint64。int在amd64上背後是int64。因此一個slice佔用了3個qword(word=2byte qual=4 即 2x4=8byte 8x8=64bit),即 3x8 = 24byte,然後又有兩個slice做為參數,再加上一個bool byte,因此,這個call stack frame應該有 24x2 ([]byte) + 1 (bool) = 49byte。又因為不需要局部變數,因此定義為0個.

$0-49

函數指令解構

彙編是門“死腦筋”+“瘋狂簡寫”的語言,接下來是對函數語句的解析,一旦理解了以後,語句是很簡單的。

MOVQa_len+8(FP), BX  // move qword, 把a slice的長度放入BX寄存器MOVQb_len+32(FP), CX // 把b slice的長度放入CX寄存器CMPQBX, CX  // compare qword, 對比BX,CXJNEeqret            // jump not equal, 如果不相等就跳轉至標籤eqret(equal ret)MOVQa+0(FP), SI // 把a的指標放入SI寄存器中MOVQb+24(FP), DI // 把b的指標放入DI寄存器中LEAQret+48(FP), AX // load effective address, 將傳回值的記憶體位址放入AX寄存器中JMPruntime·memeqbody(SB) // JUMP, 跳轉至 runtime·memeqbody(SB) 地址空間eqret:MOVB$0, ret+48(FP)          // move byte, 將$0 (意思是數字0, 而false = 0)傳入返回的參數中,即兩個slice不相等。RET

這裡出現了兩個新的概念:

位移量定義,例如a_len+8(FP),還記得上一篇中講過,FP是指在低記憶體位上的嗎?因此,這裡就定義了a_len,即a length = +8(FP),相對於FP位移8個byte(記得slice的結構吧),這個正好是a的長度所在的位置。不記得的話,可以參考

FP               +------------> b pointer                 |+                |    +-------> b length|                |    |v                |    |     +-> b capacityLow              |    |     |+----+----+----+-+--+-+--+--+-+-+|    |    |    |    |    |    | |+-+--+-+--+-+--+----+----+----+++  |    |    |                  |  |    |    +-> a capacity     +-> return value  |    |  |    +------> a length  |  +-----------> a uint64-pointer

每個空格相當於一個byte

另一個概念是label,彙編不同於進階語言,彙編的條件跳轉基本上都是靠label(標籤)實現的,例子中的eqret,就是個label。

AVX

接下來是精華hugeloop

AVX是Intel引以為傲的SIMD指令集,具體介紹在AVX,Go在字元比較中根據CPU的能力分別會使用SSE、AVX、AVX2,這種指令集最佳化就是我們為什麼要寫彙編的原因了。

// 64 bytes at a time using ymm registers (一次就能對比64個byte,64倍效能就問你怕不怕)hugeloop_avx2:CMPQBX, $64 // 對比字元長度JBbigloop_avx2 // 不夠64個位元組就用其他方法。VMOVDQU(SI), Y0// AVX2 專用載入資料的指令,將SI前32個byte載入進Y0寄存器(512bit)VMOVDQU(DI), Y1// ...VMOVDQU32(SI), Y2VMOVDQU32(DI), Y3VPCMPEQBY1, Y0, Y4  // 對比Y0 - Y1,把結果存入Y4中VPCMPEQBY2, Y3, Y5  // 同上VPANDY4, Y5, Y6// AND 操作VPMOVMSKB Y6, DX// MOVE BYTE MASK , 將Y6中的每8個bit做一個掩碼存入DX中(簡單點就是相同就都是0xf)ADDQ$64, SI// SI位移64個byteADDQ$64, DI// DI位移64個byteSUBQ$64, BX// BX 長度減64CMPLDX, $0xffffffff// 對比DX的低位JEQhugeloop_avx2// 相同則繼續對比VZEROUPPER// 清空Y寄存器MOVB$0, (AX)// 發現不同,返回RET

小結

現在對Golang的彙編比較熟悉了,下一篇會摘抄並翻譯一些注意事項。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.