2010-06-01 64 views

回答

31

不支持內聯彙編,但是您可以使用匯編編寫的代碼通過C鏈接,使用cgo編譯並使用import "C",如gmp.go。您也可以使用與Go直接兼容的裝配樣式編寫代碼,如asm_linux_amd64.s,它要求函數名稱以「·」開頭。或者,您可以使用nasm和gccgo,這是我目前爲止最喜歡的方式。 (請注意,Nasm似乎不支持以「·」開頭的函數)。

這裏有一個工作的 「Hello World」 的例子:

hello.asm:

; Based on hello.asm from nasm 

    SECTION .data  ; data section 
msg: db "Hello World",10 ; the string to print, 10=cr 
len: equ $-msg  ; "$" means "here" 
       ; len is a value, not an address 

    SECTION .text  ; code section 

global go.main.hello  ; make label available to linker (Go) 
go.main.hello: 

    ; --- setup stack frame 
    push rbp   ; save old base pointer 
    mov rbp,rsp ; use stack pointer as new base pointer 

    ; --- print message 
    mov edx,len  ; arg3, length of string to print 
    mov ecx,msg  ; arg2, pointer to string 
    mov ebx,1  ; arg1, where to write, screen 
    mov eax,4  ; write sysout command to int 80 hex 
    int 0x80  ; interrupt 80 hex, call kernel 

    ; --- takedown stack frame 
    mov rsp,rbp ; use base pointer as new stack pointer 
    pop rbp  ; get the old base pointer 

    ; --- return 
    mov rax,0  ; error code 0, normal, no error 
    ret   ; return 

main.go:

package main 

func hello(); 

func main() { 
    hello() 
    hello() 
} 

和方便的Makefile:

main: main.go hello.o 
    gccgo hello.o main.go -o main 

hello.o: hello.asm 
    nasm -f elf64 -o hello.o hello.asm 

clean: 
    rm -rf _obj *.o *~ *.6 *.gch a.out main 

我致電hello()在main.go中兩次,只是爲了再次檢查hello()是否正確返回。

請注意,調用中斷80H直接不被認爲是在Linux上良好的作風,並要求寫的函數是C更「面向未來」。還要注意,這是針對64位Linux的程序集,並且不以任何方式,形狀或形式與平臺無關。

我知道這是不是直接回答你的問題,但它是使用裝配有圍棋,在缺乏內聯的,我知道最簡單的途徑。如果您真的需要內聯,可以編寫一個腳本從源文件中提取內聯彙編,並按照上述模式進行準備。足夠近? :)

用於圍棋,C和NASM

簡單的例子:gonasm.tgz

更新:gccgo的更高版本需要-g標誌,只有 「main.hello」 需要,而不是「go.main.hello 」。這裏是Go,C和Yasm的更新示例:goyasm.tgz

23

有在轉到編程語言,支持在線彙編語言代碼沒有設施,並且沒有計劃這樣做。 Go支持鏈接到在assemblerC中編寫的例程。有一個實驗性功能,將SWIG support添加到Go中。

+0

+1的鏈接的引用使得這個完美的答案;) – OscarRyz 2010-06-01 16:15:34

+0

@OscarReyes:完成 – peterSO 2010-06-01 16:43:47

+0

+1現在,它是完美的! :) – OscarRyz 2010-06-01 17:00:36

3

標準Go編譯器(即:8g + 8l,而不是gccgo)中的優化傳遞基本上使用二進制形式的原始指令。目前,編譯器無法(未實現)將編譯器生成的程序集與用戶提供的內聯彙編代碼區分開來 - 是Go編譯器不允許內聯彙編的主要原因。換句話說,由於編譯器體系結構,編譯器不支持內聯彙編。

還有就是在Go語言本身,這將阻止其他圍棋語言的實現當然不是什麼(即:其他圍棋編譯器),以有內聯彙編的支持。內聯彙編是一個編譯器特定的決定 - 它與Go語言本身無關。

在這兩種情況下,內聯彙編都是不安全的,因爲它的Go類型系統無法檢查其正確性。看起來最好是實現任何需要使用C語言內聯彙編的函數,並從Go中調用C函數。

+1

最好不要使用內聯asm,原始版本的C和Unix不需要它或實現它,它使代碼變得不可移植並且 – uriel 2012-06-15 12:01:28

10

不,您不能,但通過使用go編譯器很容易提供一個函數的彙編實現。沒有必要使用「導入C」來使用匯編。

看看一個例子來自數學庫:

http://golang.org/src/pkg/math/abs.go:ABS功能在這一點去文件中聲明。 (也有在往這個文件的ABS的實現,但這不出口,因爲它有一個小寫的名字。)

package math 

// Abs returns the absolute value of x. 
// 
// Special cases are: 
// Abs(±Inf) = +Inf 
// Abs(NaN) = NaN 
func Abs(x float64) float64 

然後,在http://golang.org/src/pkg/math/abs_amd64.s,ABS是在英特爾的64位執行本文件:

// func Abs(x float64) float64 
TEXT ·Abs(SB),NOSPLIT,$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