golang的伪寄存器
Go汇编为了简化汇编代码的编写,引入了PC、FP、SP、SB四个伪寄存器。四个伪寄存器加其它的通用寄存器就是Go汇编语言对CPU的重新抽象,该抽象的结构也适用于其它非X86类型的体系结构。
四个伪寄存器和X86/AMD64的内存和寄存器的相互关系如下图:
在AMD64环境,伪PC寄存器其实是IP指令计数器寄存器的别名。伪FP寄存器对应的是函数的帧指针,一般用来访问函数的参数和返回值。伪SP栈指针对应的是当前函数栈帧的底部(不包括参数和返回值部分),一般用于定位局部变量。伪SP是一个比较特殊的寄存器,因为还存在一个同名的SP真寄存器。真SP寄存器对应的是栈的顶部,一般用于定位调用其它函数的参数和返回值。
当需要区分伪寄存器和真寄存器的时候只需要记住一点:伪寄存器一般需要一个标识符和偏移量为前缀,如果没有标识符前缀则是真寄存器。比如(SP)、+8(SP)没有标识符前缀为真SP寄存器,而a(SP)、b+8(SP)有标识符为前缀表示伪寄存器。
总结:
伪FP和硬件SP使用最多
伪FP(Frame pointer): arguments and locals --->用于访问函数传入的参数
硬件SP(Stack pointer): top of stack --->栈顶地址
伪PC(Program counter): jumps and branches --->执行指令的地址
伪SP(Stack pointer): top of stack --->栈底地址
伪SB(Static base pointer): global symbols --->全局静态基指针,一般用来声明函数或全局变量
硬件BP(Base pointer): base pointer-->位置同伪SP
golang的stack布局
if framepoiner_enabled==true,那么framesize是包含 clller's BP 的
过程:
下面的SP指硬件SP
- CALL调用方法C,将PC地址压入return addr/parent return address
- 通过SUBQ操作SP扩张C的栈(需要额外开辟8bit保存当前的BP,即B的BP)
- 保存当前BP寄存器中的值到栈底
- 运行代码逻辑
- 恢复栈底的BP值到BP寄存器
- 通过ADDQ操作SP收缩栈至return addr/parent return address
- 执行RET,恢复return addr/parent return address的值到PC寄存器,继续其他逻辑
golang函数调用时栈例子
func main() {
printsum(1, 2)
}
func printsum(a, b int) {
var ret = sum(a, b)
println(ret)
}
func sum(a, b int) int {
return a+b
}
这里不包含BP是因为做了简化,更好的展示栈调用的过程
参考:
https://blog.csdn.net/hel12he/article/details/103271937
https://hezhiqiang8909.gitbook.io/go/ch3-asm/ch3-04-func#3.4.5-tiao-yong-qi-ta-han-shu
https://hezhiqiang8909.gitbook.io/go/ch3-asm/ch3-02-arch#3.2.4-go-hui-bian-zhong-de-wei-ji-cun-qi