好久没有写博客了,上一篇写的汇编只是简单的调试了一下,这段时间又看了下,做一个简单的汇总。
两个代码
汇编代码,1_amd64.s
TEXT ·add(SB),$0-0 MOVQ a+0(FP),AX MOVQ b+8(FP),BX ADDQ AX,BX MOVQ BX,c+16(FP) RET
主函数1.go
package main func add(a, b int) int func main() { sum := add(1, 2) println(sum) }
主要对这两个简单的代码进行调试,实现的功能也比较简单:计算两个数之和。
main函数的初始化
注意:上面的汇编代码是使用未优化的。
main函数是被系统调用的,首先将SP拉伸到40字节,然后将BP寄存器入栈,接着再调整BP到该位置,当前BP所在的位置应该算是栈空间的开始!
main函数的一些变量如何分配?
在go语言汇编里面,当A调用B时,在A的栈上准备参数(和返回值,如果有),图示展示了这一点。main函数调用add,因此它准备了两个实参和一个返回值,一共24字节,同时还有一个局部变量sum。
可见它也没有把sum优化,也就是说本来是什么就是什么,按部就班的将各个参数和局部变量排布好。
在执行call调用时,会将PC压栈,同时SP再往下前进8字节。
1_amd64.s分析
分析完了main.go,接着看1_amd64.s文件,这部分代码是由人工写的,所以考虑的比较简单。
FP寄存器
FP伪寄存器按照书本的说法就是提供一个快捷的方式访问函数参数,它的位置应该在:
由图可见,伪FP直接对着函数参数,因此a+0(FP)就对应实参a,b+8(FP)就对应实参b,同理,c+16(FP)就对应返回值c。
因此高亮的汇编代码意思是:
1和2搬到栈中,然后执行call调用,将结果搬到add返回值空间,再接着将该返回值复制一份到局部变量sum!
伪SP寄存器
按书本上说,伪SP寄存器对应当前栈帧的底部。此时,请读者注意,在1_amd64.s文件中,我没有进行SP的拉伸和BP的移动,因为这个代码是我写的,不是编译器写的。
因此当前相当于只移动了真SP,原因是真SP会随着call的执行必须移动。
那么这样说,意思就是进入到add函数时,当前栈的分布还是像上图一样没变化。因此当前的栈底就是真SP所在的位置。
由于伪SP对应当前栈的栈底,因此它的一个特性是固定不变,可以用做计算局部变量的位置。
BP到底会不会压栈?
我们在X86的汇编中知道,一般情况下BP会入栈的,但是GO中似乎提到可以简化,这个问题先搁置在这里,后面再说明。
当前的1_amd64.s并没有将BP入栈,因为这是人工写的。
下面我们在程序中再写一个简单的减法函数,然后编译查看一下。
func sub(a, b int) int { c := a - b return c }
编译之后得到:
"".sub STEXT nosplit size=52 args=0x18 locals=0x10 0x0000 00000 (1.go:4) TEXT "".sub(SB), NOSPLIT|ABIInternal, $16-24 0x0000 00000 (1.go:4) SUBQ $16, SP 0x0004 00004 (1.go:4) MOVQ BP, 8(SP) 0x0009 00009 (1.go:4) LEAQ 8(SP), BP 0x000e 00014 (1.go:4) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x000e 00014 (1.go:4) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x000e 00014 (1.go:4) MOVQ $0, "".~r2+40(SP) 0x0017 00023 (1.go:5) MOVQ "".a+24(SP), AX 0x001c 00028 (1.go:5) SUBQ "".b+32(SP), AX 0x0021 00033 (1.go:5) MOVQ AX, "".c(SP) 0x0025 00037 (1.go:6) MOVQ AX, "".~r2+40(SP) 0x002a 00042 (1.go:6) MOVQ 8(SP), BP 0x002f 00047 (1.go:6) ADDQ $16, SP 0x0033 00051 (1.go:6) RET 0x0000 48 83 ec 10 48 89 6c 24 08 48 8d 6c 24 08 48 c7 H...H.l$.H.l$.H. 0x0010 44 24 28 00 00 00 00 48 8b 44 24 18 48 2b 44 24 D$(....H.D$.H+D$ 0x0020 20 48 89 04 24 48 89 44 24 28 48 8b 6c 24 08 48 H..$H.D$(H.l$.H 0x0030 83 c4 10 c3
从结果可以看到:BP被入栈了,这是未优化的代码
其实BP入不入栈并没有什么影响,只要计算相对位置就行
总结
这篇文章详细说明了伪SP,伪FP,BP是否入栈,以及各个参数的空间安排,了解这些细节对于常见的汇编阅读已经足够。
标签:24,汇编,48,SP,FP,golang,BP,寄存器,go From: https://www.cnblogs.com/tinaluo/p/17521578.html