【笔记】golang plan9 汇编中,一个汇编函数调用另一个汇编函数

作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!


1. 调试方法

  • 把一个 test 程序编译为二进制
go test \
		  -c \
		  -gcflags="all=-N -l" \
		  -o xxhash.test \
		  github.com/cespare/xxhash/v2
  • 使用 gdb 来调试这个二进制
gdb --args ./xxhash.test \
		  -test.fullpath=true \
		  -test.run=^TestBatch1$
  • 在汇编函数上设置断点
(gdb) break github.com/cespare/xxhash/v2.BatchSum64String
  • 单步调试

    • step
    • s (或者简写为 s)
  • 查看寄存器的值

    • p/x $r8
  • 查看一个指针的内存区域的数据

x/16bx $r8  // 输出 16 字节的内容

2. 一句话总结

一个汇编函数 call 另一个汇编函数,则必然需要栈的空间来存放被调用函数的参数和返回值

// 我的函数
//go:noescape
func BatchSum64String(src []string, dst []uint64) int64

// 被调用的函数
//go:noescape
func Sum64(b []byte) uint64

可以发现

  • 主调函数:
    • 参数: src []string, 一共 24 字节
    • 参数:dst []string, 一共 24 字节
    • 参数: int64, 8 字节
  • 被调函数
    • 参数为: []byte,一共 24 字节
    • 返回值为:uint64, 8 字节

因此,需要这样定义函数原型:

// func BatchSum64String(src []string, dst []uint64) int64
// 栈空间 32 字节
// 参数, 56 字节
TEXT ·BatchSum64String(SB), NOSPLIT, $32-56

call 一个函数之前,参数要写到栈上;call 之后,要从栈上取得返回值

    // 把 Data 写到 Sum64 的参数区
	LEAQ +0(R8)(R11*8), R12
	MOVQ (R12), R13
    MOVQ R13, 0(SP)
    // Len
	LEAQ +8(R8)(R11*8), R12
	MOVQ (R12), R13
    MOVQ R13, 8(SP)
	MOVQ R13, 16(SP)  // cap
    // =========================
    // 2. 调用函数
    // =========================
    CALL ·Sum64(SB)

    // =========================
    // 3. 取返回值
    // =========================
    MOVQ 24(SP), R12
  • 如果有多个参数,则栈布局的顺序是:参数 1, 参数 2...参数 n, 返回值1, 返回值 2... 返回值 n

call 一个函数的时候,不会自动保存寄存器。需要开发者自己维护寄存器。

  • 寄存器保存到栈上,则需要更多栈空间
  • call 之前压栈,call 之后出栈。

posted on 2025-12-23 18:13  ahfuzhang  阅读(0)  评论(0)    收藏  举报