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

This blog post显示将GO编译到单独的.s文件并对其进行编辑,而不是像许多C编译器支持的那样将inline ASM作为GO函数的一部分.

推荐答案

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

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

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

你好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

主要的开始:

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

我在main.go中调用了两次hello(),只是为了再次判断hello()是否正确返回.

请注意,在Linux上直接调用中断80h并不被认为是一种好的风格,而调用用C编写的函数更多的是"future 证明".还要注意的是,这是专门针对64位Linux的汇编,并且在任何方式、形状或形式上都不是独立于平台的.

我知道这不是对你问题的直接回答,但这是我所知道的在GO中使用汇编的最简单的方法,因为没有内联.如果您确实需要内联,可以编写一个脚本,从源文件中提取内联程序集,并按照上述模式进行准备.够近了吗?:)

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

Update:更高版本的gccgo需要-g标志,只需要"main.hello"而不是"go.main.hello".下面是Go、C和Yasm:goyasm.tgz的更新示例

Go相关问答推荐

如何使用GRPC UnaryClientInterceptor中的`maily`参数?

如何使用我的 struct 化日志(log)记录格式使人panic ?

为什么(编码器).EncodeElement忽略";,innerxml";标记?

从 wincrypt API 到 Go 的 RC2 解密

我们如何保证取消的上下文会导致 goroutine 终止?

Docker 执行失败并显示cmd/ENTRYPOINT 中的命令未找到

为什么我只收到部分错误而不是我启动的 goroutines 的所有错误?

Yocto 无法交叉编译 GoLang Wails 应用程序

如何将 base64 编码的公钥转换为 crypto.PublicKey 或 ecdsa.PublicKey

CBC Decrypter 解密加密文本,但部分文本被随机字符替换

在 Golang 模板中计算时间/持续时间

在 Gorm 的 AfterFind() 钩子中获取智能 Select struct 的值

如何编写一个以字符串或错误为参数的通用函数?

GqlGen - 在字段解析器中访问查询输入参数

如何在Go中替换符号并使下一个字母大写

go 堆栈跟踪:在某些函数调用参数或返回值之后的问题(?)标记是什么意思?

golang 如何从字符串中查找表情符号?

Golang:每个键具有多个值的映射

在 Go 中将十六进制转换为带符号的 Int

如何解决在mac m1中运行gcc失败退出状态1?