Assembly 为什么下面的x86_64程序集会给我一个分段错误?
到目前为止,我一直在学习编写一些x86_64程序集。我读到可以减去RSP来向下扩展堆栈并分配空间,因此我编写了以下代码:Assembly 为什么下面的x86_64程序集会给我一个分段错误?,assembly,x86-64,x86,Assembly,X86 64,X86,到目前为止,我一直在学习编写一些x86_64程序集。我读到可以减去RSP来向下扩展堆栈并分配空间,因此我编写了以下代码: push %rbp movq %rsp, %rbp subq $16, %rsp movq $200, -8(%rsp) movq $300, -16(%rsp) popq %rbp retq 据我所知,这将生成一个函数,在该函数中,它在堆栈帧上设置一个值,然后在堆栈上分配16个字节,并将值分别设置为-8和-16到200和300。 然而,当我用gcc运行这个程序时,我得到了
push %rbp
movq %rsp, %rbp
subq $16, %rsp
movq $200, -8(%rsp)
movq $300, -16(%rsp)
popq %rbp
retq
据我所知,这将生成一个函数,在该函数中,它在堆栈帧上设置一个值,然后在堆栈上分配16个字节,并将值分别设置为-8和-16到200和300。
然而,当我用gcc运行这个程序时,我得到了一个分段错误。虽然如果我删除程序的
子部分
,它仍能正常工作。我想我误解了什么,那么这里到底发生了什么?正如Jester所说,问题是当你pop%rbp
/ret
时,堆栈指针指向其他地方,所以你没有得到旧的%rbp
和返回地址。(由于另一个潜在的错误,您从不向弹出的位置写信,因此我无法确切地告诉您将ret
发送到哪个无效地址。)
如果您制作了一个堆栈帧(mov%rsp,%rbp
),那么使用相对于%rbp
的偏移量是正常的。有趣的事实:movq$200,-8(%rbp)
比同等的movq$200,8(%rsp)
花费更多。(遗憾的是,使用%rsp
作为基址寄存器总是需要SIB字节来编码有效地址。)
使用%rbp
还意味着引用任何给定堆栈地址的表达式即使在推/弹出内容时也不会更改(在32位代码中,堆栈参数ABI很常见,但在64位代码中很少见。64位gcc在32位之前切换为-fomit帧指针)
您的
movq$200,-8(%rsp)
使用您保留的16B之外的空间。这就是我前面提到的“其他潜在bug”
在当前的%rsp
下使用最多128B实际上并不是SysV ABI中的一个错误:异步事件(信号处理程序等)避免阻塞,因此不调用任何其他函数的小函数可以避免花费指令修改%rsp
以保留空间。x86-64有15个通用寄存器(不计算堆栈指针),因此中小型函数通常不需要使用堆栈,而只需要保存/恢复调用保留的寄存器。或用于本地阵列
Windows ABI不使用红色区域,因此%rsp
下面的内存可能会被踩到,即使您自己不使用调用
有关调用约定/ABI的链接,请参见tag wiki。正如Jester所说,问题是当您pop%rbp
/ret
时,堆栈指针指向其他地方,因此无法获取旧的%rbp
和返回地址。(由于另一个潜在的错误,您从不向弹出的位置写信,因此我无法确切地告诉您将ret
发送到哪个无效地址。)
如果您制作了一个堆栈帧(mov%rsp,%rbp
),那么使用相对于%rbp
的偏移量是正常的。有趣的事实:movq$200,-8(%rbp)
比同等的movq$200,8(%rsp)
花费更多。(遗憾的是,使用%rsp
作为基址寄存器总是需要SIB字节来编码有效地址。)
使用%rbp
还意味着引用任何给定堆栈地址的表达式即使在推/弹出内容时也不会更改(在32位代码中,堆栈参数ABI很常见,但在64位代码中很少见。64位gcc在32位之前切换为-fomit帧指针)
您的movq$200,-8(%rsp)
使用您保留的16B之外的空间。这就是我前面提到的“其他潜在bug”
在当前的%rsp
下使用最多128B实际上并不是SysV ABI中的一个错误:异步事件(信号处理程序等)避免阻塞,因此不调用任何其他函数的小函数可以避免花费指令修改%rsp
以保留空间。x86-64有15个通用寄存器(不计算堆栈指针),因此中小型函数通常不需要使用堆栈,而只需要保存/恢复调用保留的寄存器。或用于本地阵列
Windows ABI不使用红色区域,因此%rsp
下面的内存可能会被踩到,即使您自己不使用调用
有关调用约定/ABI的链接,请参见标记wiki。您需要释放分配的空间。通过将rbp
移回rsp
或撤消sub
@Jester,我可以在rsp上做与减法和加16相反的操作吗?是的,如果不使用帧指针,这是通常的方法。当你有一个帧指针时,它通常会移回rsp
。哇!这里不是指(%rBp)
吗?如果要将这些值写入刚刚分配的堆栈部分,您是指-8(%rBp)
和-16(%rBp)
。您需要释放分配的空间。通过将rbp
移回rsp
或撤消sub
@Jester,我可以在rsp上做与减法和加16相反的操作吗?是的,如果不使用帧指针,这是通常的方法。当你有一个帧指针时,它通常会移回rsp
。哇!这里您不是指(%rBp)
吗?如果您打算将这些值写入刚刚分配的堆栈部分,您是指-8(%rBp)
和-16(%rBp)
。