ARM64中栈指针的行为

5
由于在ARM64中缺乏PUSH和POP指令,我不太理解SP在ARM64中的工作原理。如果我要使用PUSH/POP指令,SP是按4、8还是16字节递减/递增?我阅读的文档说,堆栈帧必须按16字节对齐,但是在调试时,实际情况似乎并不完全如此。

简短回答,您可以使用标准的加载/存储指令来推送和弹出寄存器值,或者只需通过"add"或"subtract"从堆栈指针中对齐或腾出更大的分配空间。大多数指令都可以在不影响SP(IP也一样,但通常会有一定的性能损耗)的情况下运行。 - Michael Dorgan
我确认我能够将SP设置为不可用的值,并且仍然可以使用lldb逐步执行每个指令而没有问题。这是我的代码:<br> int main(int argc, char *argv[]) {<br> asm volatile("mov sp, 1"); asm volatile("mov sp, 2"); asm volatile("mov sp, 3"); return 0; }崩溃发生在return语句之后。看起来一个库函数试图访问错误地址的内存。 - user1766438
1个回答

13
无论堆栈向上还是向下增长,完全取决于您所查看的系统的ABI。也就是说,我所涉及的所有arm64代码都是向下增长的堆栈。
因此,一个常见的推送操作看起来像这样:
stp x29, x30, [sp, -0x10]!

而且还有一首像这样的流行歌曲:
ldp x29, x30, [sp], 0x10

这显然是一次同时推/弹出两个寄存器,因此每次修改堆栈指针16字节,这就引出了下一部分:
堆栈对齐检查。堆栈指针是否必须对齐到16字节边界也取决于你所使用的ABI,但这是一个实际的硬件特性,可以进行配置。 参见ARMv8参考手册SCTLR_EL[123]包含了打开或关闭每个异常级别的这个特性的位。例如,引用自SCTLR_EL1的内容如下: SA0, 位 [4] EL0级别的SP对齐检查使能。当设置为1时,如果在EL0级别执行的加载或存储指令使用SP作为基地址,并且SP未对齐到16字节边界,则会引发SP对齐错误异常。更多信息请参见第D1-2333页的SP对齐检查
当实现了ARMv8.1-VHE,并且HCR_EL2.{E2H, TGE}的值为{1, 1}时,该位对EL0级别的执行没有影响。
在一个PE重置为EL1的系统中,该字段将重置为一个架构上未知的值。 SA, 位 [3] SP对齐检查使能。当设置为1时,如果在EL1级别执行的加载或存储指令使用SP作为基地址,并且SP未对齐到16字节边界,则会引发SP对齐错误异常。更多信息请参见第D1-2333页的SP对齐检查
当实现了ARMv8.1-VHE,并且HCR_EL2.{E2H, TGE}的值为{1, 1}时,该位对PE没有影响。
在一个PE重置为EL1的系统中,该字段将重置为一个架构上未知的值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接