Go彙編實戰的坑

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

為啥寫

Go的彙編一直是我感興趣的地方,為了驗證之前所學的彙編知識和好玩 ,我決定往Go官方提交一個效能patch。所以到官方的標準庫裡搜了一圈,發現adler32並沒有硬體加速的實現,而Intel已經公布了相關的SSE加速實現https://github.com/01org/isa-l/

所以我決定把Intel的抄過來,結果不停地掉坑和爬出來,終於提交了patch(撒花)

https://go-review.googlesource.com/c/51850

希望在Go 1.10發布的時候能進入官方源:)

  1. 寫法的區別
  2. Go彙編不支援
  3. 難以調試
  4. 記憶體越界與LEA
  5. 向官方提交代碼需要注意的地方,保證Change ID一致

坑一:Intel和AT&T的寫法的區別

Intel寫法是:opcode source destination

AT&T 也就是Go官方組合語言的寫法正好是反過來的:opcode destination source

抄代碼的時候有點繞

坑二 Go彙編不支援:

Go的維護者們對於新添加彙編opcode一直是很保守的,比如2001年前後就有的SSE2 裡的PSHLLW()竟然不支援(= =||)。所以得自己填BYTE,比如官方文檔中的MOVQ用BYTE方式編寫 https://golang.org/doc/asm

BYTE $0x0f; BYTE $0x6f; BYTE $0x00 // MOVQ (AX), M0

但這裡就有一個坑,比如PSHLLD和PSHRQ的Opcode是一樣的……只是按/r 寄存器類型進行區別。需要注意

坑三:調試困難

一般代碼測試時,都可以直接輸出日誌,協助定位問題,但是彙編不行,所以我是通過把需要的值放入某個不用的寄存器, 例如

#define debug R15// min(a, b int) intTEXT min(SB), NOSPLIT, $0

在需要的時候,提前把函數返回

MOVQ debug, ret+16(FP)RET

當然應該有更好的方法,可以把所有寄存器列印出來,不過這個方法夠我自己調試用了。

坑四:記憶體越界與LEA

一般程式中都是指標,或者直接結構體。不過,彙編這裡迴歸本真,只有記憶體位址和寄存器。所以一定要小心訪問資料的邊界和跳轉的記憶體位址。這裡學到了一個LEA的用法,地址計算機,把記憶體位址到目標寄存器裡。

LEAQ  0(data)(size*1), end

具體用法

  • 0: 寫死的位移量
  • data: 位移值
  • size: 動態位移量,可以用乘法

坑五:

提交代碼到gerrit要保持Change ID相同,要不然算一個新的Change。

附錄:opcode坑

  • MOVOU: O=oct, U=unaligned, 指的是八個word,即128位,用於XXM寄存器的移動。
  • TESTQ: 對比值,並影響FLAG
  • DIVL:低位除,如果高位有資料就會出錯

資料:Go官方介紹: https://golang.org/doc/asm

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.