因为只是玩一玩,所以走的路线是:用C写代码,把C编译成AT&T格式汇编,把AT&T格式转换成plan9格式,在golang中调用plan9汇编。

c代码

函数

在clib/c/add.c中:

int add(int a, int b){  //实现一个两个整形相加的简单函数
    return a + b;
}

编译

用clang编译C代码。注意:一定要用clang,且一定要用x86的处理器,苹果的M1不行。

clang -mno-red-zone -fno-asynchronous-unwind-tables -fno-builtin -fno-exceptions \
      -fno-rtti -fno-stack-protector -nostdlib -O3 -msse4 -mavx -mno-avx2 -DUSE_AVX=1 \
      -DUSE_AVX2=0 -S add.c -o add.s

删除不必要的内容

add.s的内容为:

.text
	.file	"add.c"
	.globl	add                     # -- Begin function add
	.p2align	4, 0x90
	.type	add,@function
add:                                    # @add
# %bb.0:
                                        # kill: def $esi killed $esi def $rsi
                                        # kill: def $edi killed $edi def $rdi
	leal	(%rdi,%rsi), %eax
	retq
.Lfunc_end0:
	.size	add, .Lfunc_end0-add
                                        # -- End function
	.ident	"clang version 10.0.1"
	.section	".note.GNU-stack","",@progbits
	.addrsig

我们只需要add函数,因此删除add函数以外的代码:

add:                                    # @add
# %bb.0:
                                        # kill: def $esi killed $esi def $rsi
                                        # kill: def $edi killed $edi def $rdi
	leal	(%rdi,%rsi), %eax
	retq

转换为plan9汇编

安装工具

这个工具可以把AT&T汇编转换成plan9汇编:

  1. 要安装python3.8版本,低于这个版本无法使用
  2. 安装依赖的库:
pip install --upgrade git+https://github.com/Maratyszcza/PeachPy
  1. python脚本的使用方法为:python3 asm2asm.py 目的路径/add.s 源路径/add.s

准备go函数的定义文件

在 clib/add.go 中写入:

package clib

//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func _add(a int, b int) (ret int)

为了便于导出这个函数,还可以增加导出的文件: clib/export.go

package clib

func AddInt(a int, b int) int {
	return _add(a, b)
}

执行转换

cd clib/c
python3 asm2asm.py ../add.s add.s

然后在 clib 目录生成了文件:add.s add_subr.go

调用

在上层目录建立文件go.mod:

module github.com/ahfuzhang/example

go 1.18

入口文件:main.go

package main

import (
	"fmt"

	"github.com/ahfuzhang/example/clib"
)

func main() {
	fmt.Println(clib.AddInt(1, 2))
}

整体目录结构为:

example
  clib
    add.s
    add.go
    add_subr.go
    export.go
    c
       add.c
       add.s
  main.go
  go.mod

运行:

go run main.go

结果为3,成功了!
have fun!