Go函数调用:nop函数argsize为8字节及main栈帧8字节填充原因
Go函数调用的汇编相关问题
测试代码与环境
package main func main() { var x int32 = 1 nop(x) } //go:noinline func nop(x int32) {}
Go版本:go1.16.15 windows/amd64
为深入理解Go函数调用,使用命令go1.16.15 tool compile -S -N -l main.go将上述代码编译为汇编代码。
nop函数的汇编与问题1
nop函数的汇编代码如下:
""".nop STEXT nosplit size=1 args=0x8 locals=0x0 funcid=0x0 0x0000 00000 (main.go:9) TEXT """.nop(SB), NOSPLIT|ABIInternal, $0-8 0x0000 00000 (main.go:9) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (main.go:9) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0000 00000 (main.go:9) RET
显然nop函数仅接收一个int32类型参数且直接返回,但汇编中argsize显示为8字节:
TEXT """.nop(SB), NOSPLIT|ABIInternal, $0-8
问题1:为何argsize是8字节而非4字节?
main函数的汇编与问题2
main函数的汇编代码如下:
""".main STEXT size=73 args=0x0 locals=0x18 funcid=0x0 0x0000 00000 (main.go:3) TEXT """.main(SB), ABIInternal, $24-0 ;; ...省略栈拆分序言... 0x0016 00022 (main.go:3) SUBQ $24, SP 0x001a 00026 (main.go:3) MOVQ BP, 16(SP) 0x001f 00031 (main.go:3) LEAQ 16(SP), BP 0x0024 00036 (main.go:3) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0024 00036 (main.go:3) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0024 00036 (main.go:4) MOVL $1, """.x+12(SP) 0x002c 00044 (main.go:5) MOVL $1, (SP) 0x0033 00051 (main.go:5) PCDATA $1, $0 0x0033 00051 (main.go:5) CALL """.nop(SB) 0x0038 00056 (main.go:6) MOVQ 16(SP), BP 0x003d 00061 (main.go:6) ADDQ $24, SP 0x0041 00065 (main.go:6) RET ;; ...省略栈拆分尾声...
根据汇编代码分析,栈结构中存在8字节的填充区域。
问题2:栈中存在8字节的填充区域,其存在原因是什么?
我猜测该现象由内存对齐导致,但不确定。
问题解答
问题1:argsize为8字节的原因
这是由Go的**ABIInternal(内部应用二进制接口)**规则决定的:
- 在amd64架构下,Go的内部ABI要求所有栈上传递的参数以8字节(64位)为单位对齐。即使参数是4字节的
int32,也会被填充至8字节宽度,以此保证栈操作逻辑的一致性,同时契合amd64架构对内存访问效率的优化要求。 argsize表示函数在栈上占用的参数总空间,而非实际参数的字节数,因此会包含填充的字节。
问题2:栈填充区域的原因
你的猜测是正确的,这确实是内存对齐导致的:
- amd64架构要求栈指针SP始终保持16字节对齐:调用函数前,CALL指令会将8字节的返回地址压栈,因此调用前SP需要是16字节对齐,调用后SP会产生8字节偏移,函数内部需要调整回16字节对齐状态。
- 在main函数中,
SUBQ $24, SP的操作是为了满足整体栈帧的16字节对齐要求:局部变量、BP保存位置、函数参数区域的总长度需要凑齐16字节的倍数,因此需要填充额外字节,最终形成8字节的填充区域。 - 统一的内存对齐能让CPU访问内存时更高效,避免未对齐访问带来的性能损耗甚至错误,同时Go的运行时也依赖这种对齐规则来正确管理栈和执行垃圾回收。
内容的提问来源于stack exchange,提问作者tarorual
相关产品推荐
相关产品推荐

