标题:Go ASM:实现一个阶乘函数 出处:Felix021 时间:Mon, 26 Dec 2022 00:32:27 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?2243 内容: 先实现一个纯 Go 的版本: // main.go package main import "fmt" func fac(n uint) uint { var result uint = 1 for n > 0 { result = result * n n -= 1 } return result } func main() { fmt.Println(fac(10)) } 修改上述 fac 方法,只保留函数定义(即声明存在该函数,由汇编代码实现): func fac(n uint) uint 新增 fac.s TEXT ·fac(SB), $0-8 MOVQ n+0(FP), CX MOVQ $1, DX LOOP: IMULQ CX, DX DECQ CX JNZ LOOP MOVQ DX, result+8(FP) RET 编译运行: 引用 $ go run . 3628800 说明: 1. TEXT ·fac(SB), $0-8 - TEXT 表示这个方法在 TEXT 段中 - · 是Unicode的「中点」(中文输入法,1左边的按键),前面省略了包名,表示这是 main 包的 fac 函数 - SB 是 stack base pointer,Go ASM 中的「伪寄存器」(不是硬件寄存器),大致等同于程序的起始地址 - $0-8:0 表示这个函数没有局部变量,8 表示返回值占用8个字节 2. MOVQ n+0(FP), CX - MOVQ 的 Q 表示 8 个字节 - n+0(FP) 表示变量 n 在 FP(Frame Pointer,伪寄存器,表示这个函数的栈帧起始位置) + 0 的位置(即第一个参数)。注意这个写法形式上是必须得,但是变量名n没有实际意义,只是用来注记。 - CX 即 x86/x86_64 的 CX(16bit),ECX(32bit),RCX(64bit) 寄存器,具体多长取决于前面的指令(MOVQ是64bit) - 这句的意思是把第一个参数的值写入 RCX 3. MOVQ $1, DX - $1:$开头的是立即数 - 这句的意思是给 RDX 赋值为 1 4. IMULQ CX, DX - DX = DX * CX 5. DECQ CX - CX = CX - 1 6. JNZ LOOP - JNZ: Jump if Not Zero - 当 CX 不等于 0 时跳转到 LOOP 7. MOVQ DX, result+8(FP) - 将 RDX 的值写入到 FP+8 的位置。 8. RET - 返回到调用方。 p.s. 这个汇编版本的实现并不等同于原来 Go 版本,只是这样写会更简单(只要一个jump)。 参考: - Golang ASM 简明教程:https://jiajunhuang.com/articles/2020_04_22-go_asm.md.html - A Quick Guide to Go's Assembler:https://go.dev/doc/asm Generated by Bo-blog 2.1.0