x86_64 对齐堆栈并在不保存寄存器的情况下恢复寄存器、堆栈、并在、不保存

2023-09-07 03:36:32 作者:九尘

我正在为 x86_64 编写中断处理例程.ABI 规定,在调用 C 函数之前,我必须将堆栈对齐到 16 个字节.x86_64 ISA 指定在进入 ISR 时,我的堆栈是 8 字节对齐的.因此,我需要将堆栈指针对齐到 16 个字节.问题是从我的 C 函数返回时,我必须恢复(可能)未对齐的堆栈指针,以便我可以正确地从中断中返回.

I'm writing interrupt handling routines for x86_64. The ABI specifies that before calling a C function I must align the stack to 16 bytes. The x86_64 ISA specifies that on entry to an ISR, my stack is 8 byte aligned. I need to align my stack pointer to 16 bytes therefore. The issue is that on return from my C function, I must recover the (potentially) unaligned stack pointer so that I can return from my interrupt correctly.

我想知道是否有办法在不使用通用寄存器的情况下做到这一点?

I wonder if there is a way to do this without using a general purpose register?

推荐答案

这是我对问题的解决方案:

Here's my solution to the question as put:

pushq %rsp
pushq (%rsp)
andq $-0x10, %rsp
    call function
movq 8(%rsp), %rsp

两次推送离开堆栈时保持与原来相同的对齐方式,并在 (%rsp)8(%rsp).andq 然后对齐堆栈 - 如果它已经是 16 字节对齐,则没有任何变化,如果它是 8 字节对齐,则它从 %rsp 中减去 8,这意味着原始 %rsp 现在位于 8(%rsp)16(%rsp).所以我们可以无条件的从8(%rsp)恢复它.

The two pushes leave the stack with the same alignment it had originally, and a copy of the original %rsp at (%rsp) and 8(%rsp). The andq then aligns the stack - if it was already 16 byte aligned nothing changes, if it was 8 byte aligned then it subtracts 8 from %rsp, meaning that the original %rsp is now at 8(%rsp) and 16(%rsp). So we can unconditionally restore it from 8(%rsp).