Dec
26
Go ASM:实现一个阶乘函数
先实现一个纯 Go 的版本:
修改上述 fac 方法,只保留函数定义(即声明存在该函数,由汇编代码实现):
新增 fac.s
编译运行:
$ 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
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。
// 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))
}
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
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
欢迎扫码关注:
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。