可以在Go代码中包含内联汇编吗? [英] Is it possible to include inline assembly in Go code?

查看:490
本文介绍了可以在Go代码中包含内联汇编吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以在Go代码中包含内联汇编?

Is it possible to include inline assembly in Go code?

推荐答案

不支持内联汇编,但是您可以链接通过C用汇编语言编写的代码,使用cgo编译并使用import "C"进行链接,就像在 gmp.go .您也可以使用与Go直接兼容的汇编样式来编写,例如 asm_linux_amd64.s ,要求函数名称以·"开头.

There is no support for inline assembly, but you can link with code written in assembly through C, compiling with cgo and using import "C", like in gmp.go. You could alternatively write in a style of assembly that is directly compatible with Go, like in asm_linux_amd64.s, that requires that function names start with "·".

或者,您可以使用nasm和gccgo,这是我到目前为止最喜欢的方法. (请注意,Nasm似乎不支持以·"开头的功能.)

Or, you can use nasm and gccgo, my favorite way so far. (Note that Nasm does not seem to support functions starting with "·").

这是一个有效的"hello world"示例:

Here's a working "hello world" example:

hello.asm:

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:

And a handy 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

我在main.go中两次调用hello(),只是要仔细检查hello()是否正确返回.

I call hello() twice in main.go, just to double check that hello() returns properly.

请注意,在Linux上,直接调用中断80h并不被认为是好的方式,而调用C语言编写的函数则更具前瞻性".另外请注意,这是专门针对64位Linux的程序集,并且在任何形式,形状或形式上均与平台无关.

Note that calling interrupt 80h directly is not considered good style on Linux, and calling functions written is C is more "future proof". Also note that this is assembly specifically for 64-bit Linux, and is not platform-independent in any way, shape or form.

我知道这不是您问题的直接答案,但这是我知道在缺少内联的情况下将Go与汇编结合使用的最简单方法.如果确实需要内联,则可以编写一个脚本从源文件中提取内联程序集,并按照上述模式进行准备.足够接近? :)

I know it's not a direct answer to your question, but it's the easiest route I know for using assembly with Go, in lack of inlining. If you really need inlining, it's possible to write a script that extracts inline assembly from source files and prepares it in a way that follows the pattern above. Close enough? :)

Go,C和Nasm的快速示例: gonasm.tgz

Quick example for Go, C and Nasm: gonasm.tgz

更新:更高版本的gccgo需要使用-g标志,并且仅需要"main.hello"而不是"go.main.hello".这是Go,C和Yasm的更新示例: goyasm.tgz

Update: Later versions of gccgo needs the -g flag and only "main.hello" is needed instead of "go.main.hello". Here is an updated example for Go, C and Yasm: goyasm.tgz

这篇关于可以在Go代码中包含内联汇编吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆