Dec 26

Go ASM:实现一个阶乘函数 不指定

felix021 @ 2022-12-26 00:32 [IT » 程序设计] 评论(0) , 引用(0) , 阅读(990) | Via 本站原创 | |
先实现一个纯 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



欢迎扫码关注:




转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   *非必须
网址   电邮   [注册]