2010-06-01 10 views

Répondre

31

L'assembly en ligne n'est pas pris en charge, mais vous pouvez lier avec du code écrit en assembly via C, en compilant avec cgo et en utilisant import "C", comme dans gmp.go. Vous pouvez également écrire dans un style d'assemblage directement compatible avec Go, comme dans asm_linux_amd64.s, qui nécessite que les noms de fonctions commencent par "·".

Ou, vous pouvez utiliser nasm et gccgo, ma façon préférée jusqu'à présent. (Notez que Nasm ne semble pas supporter les fonctions commençant par "·").

est ici un travail "Bonjour tout le monde" exemple:

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() 
} 

Et un Makefile pratique:

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 

J'appelle hello() deux fois dans main.go, juste pour vérifier que hello() retourne correctement. Notez que l'appel direct de l'interruption 80h n'est pas considéré comme un bon style sous Linux, et que les fonctions d'appel écrites en C sont plus "futures". Notez également qu'il s'agit d'un assembly spécifique à Linux 64 bits et qu'il n'est pas indépendant de la plate-forme, de quelque manière que ce soit.

Je sais que ce n'est pas une réponse directe à votre question, mais c'est la route la plus facile que je connaisse pour utiliser l'assemblage avec Go, en l'absence d'inline. Si vous avez vraiment besoin d'inlining, il est possible d'écrire un script qui extrait l'assemblage en ligne des fichiers source et le prépare d'une manière qui suit le modèle ci-dessus. Assez proche? :)

exemple rapide pour Go, C et Nasm: gonasm.tgz

Mise à jour: Les versions ultérieures de gccgo a besoin le drapeau -g et que "main.hello" est nécessaire au lieu de « go.main.hello ". Voici un exemple mis à jour pour Go, C et Yasm: goyasm.tgz

23

Il n'y a pas d'installation dans le langage de programmation Go pour prendre en charge le code de langage assembleur en ligne, et il n'est pas prévu de le faire. Go prend en charge la liaison aux routines écrites en assembler et C. Il existe une fonctionnalité expérimentale qui ajoute SWIG support à Go.

+0

+1 un lien pour une référence rendrait cette réponse parfaite;) – OscarRyz

+0

@OscarReyes: Fait – peterSO

+0

+1 maintenant, il est parfait! :) – OscarRyz

3

Le passage d'optimisation dans le compilateur standard Go (c'est-à-dire: 8g + 8l, pas gccgo) fonctionne essentiellement avec des instructions brutes sous forme binaire. Il est actuellement impossible pour le compilateur de distinguer l'assemblage généré par le compilateur du code de l'assemblage en ligne fourni par l'utilisateur - cette est la principale raison pour laquelle le compilateur Go n'autorise pas l'assemblage en ligne. En d'autres termes, le compilateur ne prend pas en charge l'assemblage en ligne en raison de l'architecture du compilateur.

Il n'y a bien sûr rien dans le langage Go qui empêcherait d'autres implémentations de langage Go (c'est-à-dire: d'autres compilateurs Go) de prendre en charge l'assemblage en ligne. L'assemblage en ligne est une décision spécifique au compilateur - il a peu à voir avec le langage Go lui-même.

Dans les deux cas, l'assemblage en ligne n'est pas sûr, car le système de type Go ne permet pas de vérifier son exactitude. Il semble qu'il est préférable d'implémenter n'importe quelle fonction qui nécessite l'utilisation de l'assemblage en ligne dans un langage comme C, et d'appeler la fonction C de Go.

+1

Est préférable de ne pas utiliser inline asm du tout, la version originale de C et Unix n'a pas besoin ou l'implémenter, il rend le code nonportable et – uriel

10

Non, vous ne pouvez pas, mais il est facile de fournir une implémentation d'ensemble d'une seule fonction en utilisant le compilateur go. Il n'est pas nécessaire d'utiliser "Import C" pour utiliser l'assemblage.

Jetez un oeil à un exemple de la bibliothèque de mathématiques:

http://golang.org/src/pkg/math/abs.go: La fonction ABS est déclarée dans ce dossier aller. (Il y a aussi une mise en œuvre de l'ABS en aller dans ce dossier, mais ce n'est pas exporté car il a un nom minuscule.)

package math 

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

Puis, en http://golang.org/src/pkg/math/abs_amd64.s, Abs est mis en œuvre pour le bit intel 64 ce fichier:

// 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