doushang9172 2010-06-01 15:26
浏览 345
已采纳

Go代码中可以包含内联汇编吗?

Is it possible to include inline assembly in Go code?

  • 写回答

5条回答 默认 最新

  • doumenshi1475 2011-06-30 13:36
    关注

    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 "·".

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

    Here's a working "hello world" example:

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

    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
    

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

    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.

    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? :)

    Quick example for Go, C and Nasm: gonasm.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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

悬赏问题

  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿
  • ¥15 kafka 分区副本增加会导致消息丢失或者不可用吗?
  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘