/src/pkg/math/abs.go源碼閱讀兼談golang與彙編

來源:互聯網
上載者:User

開頭的碎碎念:

對接公眾平台的時候,開始有個字串排序,我接觸golang畢竟時間尚淺,很多東西都是能從網上找到就直接從網上找,結果就是找了好幾個範例程式碼都不好用,好容易一個好用的,從頭開始實現的,代碼太多了。我就想,google應該把這些玩意都封裝好了吧,不然一個新出的語言只有基礎文法,沒有強大的標準庫,誰用這玩意啊。也就是那時候第一次接觸src檔案夾,後來發現pkg裡的那些go檔案是絕好的學習資料。

那麼多檔案、檔案夾從哪開始看呢,我的原則,先找沒有依賴性的,也就是沒有import的,這麼尋摸著就找到了math檔案夾。笨方法,從a開始按順序來唄,這不就碰到了abs.go

難以理解的第12行:

// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package math// Abs returns the absolute value of x.//// Special cases are://    Abs(±Inf) = +Inf//    Abs(NaN) = NaNfunc Abs(x float64) float64func abs(x float64) float64 {    switch {    case x < 0:        return -x    case x == 0:        return 0 // return correctly abs(-0)    }    return x}

孤零零的一行,一個方法聲明,別的啥都沒有,完全不解其意。

下面那個abs()不用我說了吧,很簡單的,取絕對值。

不管了,先到math檔案夾看看,abs_386.s、abs_amd64.s、abs_arm.s有這三個檔案估計跟那行不知道哪來的代碼有關係,.s結尾的,組合語言檔案,繼續發動google的威力,golang、彙編混編,如此便找到了http://www.mikespook.com/2013/02/%E7%BF%BB%E8%AF%91go-%E5%92%8C%E6%B1%87%E7%BC%96/

讓程式跑起來:

先讓這段程式跑起來吧,因為我的機器是64位的,所以我把abs.go、abs_amd64.s兩個檔案拷貝到別處,abs.go的包改成了mymath,另外寫了一個簡單的測試程式

package mainimport(    "fmt"    "mymath")func main(){    fmt.Println(mymath.Abs(-12.00))}

在/pkg/tool/windows_amd64下有很多有用的工具,6g、6l啥的,不過常用的都被go命令給封裝了,直接go build、go install等命令就解決了。

涉及到彙編的,主要是6a,上面的代碼按如下順序編譯:

6a abs_amd64.s(產生abs_amd64.6)

6g –o _go_.6 abs.go(產生_go_.6)

pack grc abs.a  _go_.6 abs_amd64.6(產生abs.a)

本來是想直接讓主程式調用目錄下的庫的,import “./mymath”,不過,windows下提示出錯import path contains invalid characte ‘:’:”c:/xxx/xxx”,所以只得將abs.a扔到pkg/windows_amd64檔案夾中。

剩下的就是:

6g test.go(產生test.6)

6l test.6(產生6.out.exe)

從簡單的golang編譯器自動產生的彙編入手:

先看一個新的命令,golang編譯器自動產生彙編中間代碼的命令,go tool 6g –S XXX.go,其實上面的那些命令也都可以用go tool XXX來代替,go命令把那些命令都封裝進去了。

來個最簡單的代碼吧:

package asmfunc Asm(i int)int{    return i}

go tool 6g –S asm.go:

--- prog list "Asm" ---0000 (asm.go:3) TEXT    Asm+0(SB),$0-160001 (asm.go:3) LOCALS  ,$00002 (asm.go:3) TYPE    i+0(FP){int},$80003 (asm.go:3) TYPE    ~anon1+8(FP){int},$80004 (asm.go:4) MOVQ    i+0(FP),BX0005 (asm.go:4) MOVQ    BX,~anon1+8(FP)0006 (asm.go:4) RET     ,

plan9彙編,文法跟AT&T頗為類似,傳值是前面是源,後面是目的,這點跟masm、nasm啥的都是反的。

000行:TEXT相當於定義了一個函數,Asm函數名,+0(SB)golang產生的都有這玩意;$0-16,經過我的反覆嘗試,起碼對於int、float64這兩者而言,是(參數個數+傳回值個數)*8(這都是我自己驗證的,沒啥科學依據,相關文檔我也翻閱過一些,不過鳥語不過關,將把能看懂的東西裡沒有我需要的,大膽假設,小心論證現在還做不到)。

001行:我估計是執行指令的位置,不過這都不重要,關鍵是後頭的。

002、003行:i是變數名,~anon1其實也是變數名(系統自動產生的)

稍微修改下

func Asm(i int) (j int){    j=i    return}

則003行,就變成了j+8(FP)

至於0(FP)、8(FP),對於int來說,每個數字佔8個位元組(64位下),所以傳入的參數,第一個就是+0(FP),第二個+8(FP),第三個+16(FP),第四個+24(FP)…

傳回值,如果有多個傳回值,第一個+(8+最後一個傳入參數的數值)(FP),後面都是依次+8

{int}標明了資料類型,$8表明佔據8個位元組

004行:將參數值傳給寄存器BX,MOVQ,傳遞四字

005行:將BX中的值傳給傳回值

006行:RET

看看float64又是啥樣的:

package asmfunc Asm(f float64)float64{    return f}
--- prog list "Asm" ---0000 (asm.go:3) TEXT    Asm+0(SB),$0-160001 (asm.go:3) LOCALS  ,$00002 (asm.go:3) TYPE    i+0(FP){int},$80003 (asm.go:3) TYPE    ~anon1+8(FP){float64},$80004 (asm.go:4) MOVQ    i+0(FP),X00005 (asm.go:4) MOVQ    X0,~anon1+8(FP)0006 (asm.go:4) RET     ,

可以看出與前面用int去嘗試大致相同,只是BX寄存器變成了X0,可以推測X0就是浮點數寄存器,有X0,大膽推測會有X1、X2、X3…

試試吧

package asmfunc Asm(f1,f2 float64) float64{    return f1+f2}
--- prog list "Asm" ---0000 (asm.go:3) TEXT    Asm+0(SB),$0-240001 (asm.go:3) LOCALS  ,$00002 (asm.go:3) TYPE    f1+0(FP){float64},$80003 (asm.go:3) TYPE    f2+8(FP){float64},$80004 (asm.go:3) TYPE    ~anon2+16(FP){float64},$80005 (asm.go:4) MOVSD   f1+0(FP),X00006 (asm.go:4) MOVSD   f2+8(FP),X10007 (asm.go:4) ADDSD   X1,X00008 (asm.go:4) MOVSD   X0,~anon2+16(FP)0009 (asm.go:4) RET     ,

abs_amd64.s:

// Copyright 2010 The Go Authors.  All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// func Abs(x float64) float64TEXT ·Abs(SB),7,$0        MOVQ   $(1<<63), BX        MOVQ   BX, X0 // movsd $(-0.0), x0        MOVSD  x+0(FP), X1    ANDNPD X1, X0    MOVSD  X0, ret+8(FP)    RET

折騰一番終於到這了。

第一行就當固定格式吧,函數名替換下就好。

MOVQ   $(1<<63), BXMOVQ   BX, X0

1右移動63位,傳給X0,此時X0二進位表示是1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

MOVSD  x+0(FP), X1

MOVSD移動標量雙精確度浮點值,將參數x的值傳給X1

ANDNPD X1, X0

ANDNPD壓縮雙精確度浮點值邏輯位與非,將目標運算元的取反,再與源運算元執行邏輯位“與”操作,結果儲存到目標運算元

即對X0取反,再與X1相與,最後結果儲存到X0中

以上操作所完成的也就是將符號位置0,由此完成取絕對值的任務。

相關文章

聯繫我們

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