2010-06-01 18 views

Respuesta

31

No hay soporte para ensamblaje en línea, pero puede vincular con código escrito en ensamble a través de C, compilando con cgo y usando import "C", como en gmp.go. Alternativamente, puede escribir en un estilo de ensamblaje que sea directamente compatible con Go, como en asm_linux_amd64.s, que requiere que los nombres de las funciones comiencen con "·".

O bien, puedes usar nasm y gccgo, mi forma favorita hasta ahora. (Tenga en cuenta que Nasm no parece soportar funciones que comiencen con "·").

Aquí hay un trabajo "hola mundo" ejemplo:

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

Y un Makefile útil:

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 

Llamo al hello() dos veces en main.go, solo para verificar que hello() regrese correctamente.

Tenga en cuenta que llamar a la interrupción 80h directamente no se considera un buen estilo en Linux, y llamar a las funciones escritas es C es más "a prueba de futuro". También tenga en cuenta que este es un ensamblaje específico para Linux de 64 bits, y no es independiente de la plataforma de ninguna manera, forma o forma.

Sé que no es una respuesta directa a su pregunta, pero es la ruta más fácil que conozco para utilizar el ensamblaje con Go, en ausencia de alineación. Si realmente necesita alineación, es posible escribir un script que extraiga el ensamblaje en línea de los archivos fuente y lo prepare de una manera que siga el patrón anterior. ¿Suficientemente cerca? :)

ejemplo

rápida para Go, C y Nasm: gonasm.tgz

Actualización: Las versiones posteriores de gccgo necesita que la -g y sólo "main.hello" se necesita en lugar de "go.main.hello ". Aquí hay un ejemplo actualizado para Go, C y Yasm: goyasm.tgz

23

No hay ninguna función en el lenguaje de programación Go para admitir el código del lenguaje del ensamblador en línea, y no hay planes para hacerlo. Go admite enlaces a rutinas escritas en assembler y C. Hay una función experimental que agrega SWIG support a Go.

+0

+1 en un vínculo de referencia podría hacer que esta respuesta perfecta;) – OscarRyz

+0

@OscarReyes: Hecho – peterSO

+0

1 Ahora bien, es perfecto! :) – OscarRyz

3

El pase de optimización en el compilador Go estándar (es decir, 8g + 8l, no gccgo) está trabajando básicamente con instrucciones sin formato en formato binario. Actualmente no hay forma (no está implementado) para que el compilador distinga el ensamblado generado por el compilador del código ensamblado en línea suministrado por el usuario - este es la razón principal por la cual el compilador Go no permite el ensamblaje en línea. En otras palabras, el compilador no admite el ensamblaje en línea debido a la arquitectura del compilador .

Por supuesto, no hay nada en el idioma Go que impida que otras implementaciones de Go language (es decir, otros compiladores Go) tengan soporte para el ensamblado en línea. El ensamblaje en línea es una decisión específica del compilador; tiene poco que ver con el idioma Go en sí.

En cualquier caso, el ensamblaje en línea no es seguro porque el sistema de tipos de Go no lo puede verificar. Parece que es mejor implementar cualquier función que requiera el uso del ensamblaje en línea en un lenguaje como C, y llamar a la función C desde Go.

+1

Es mejor no usar asm en línea en absoluto, la versión original de C y Unix no lo necesitaba o implementarlo, hace que el código sea inportable y – uriel

10

No, no puede, pero es fácil proporcionar una implementación de conjunto de una sola función mediante el uso del compilador go. No es necesario usar "Importar C" para usar el ensamblaje.

Tome un vistazo a un ejemplo de la biblioteca matemática:

http://golang.org/src/pkg/math/abs.go: La función ABS se declara en este archivo ir. (También hay una implementación de ABS en marcha en este archivo, pero esto no se exporta, ya que tiene un nombre en minúscula.)

package math 

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

Luego, en http://golang.org/src/pkg/math/abs_amd64.s, Abs se implementa para Intel de 64 bits en este archivo:

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