x86_64 align stack and recover without saving registers

旧街凉风 提交于 2019-12-09 06:32:02

问题


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?


回答1:


Here's my solution to the question as put:

pushq %rsp
pushq (%rsp)
andq $-0x10, %rsp
    call function
movq 8(%rsp), %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).




回答2:


There is no way doing it without a additional register, because the align operation is destructive to the rsp register. You need to do something along

push %rbp          ;save rbp for stack pointer
mov  %rsp, %rbp    ;move old sp to rbp
and  $-0x10, %rsp  ;align stack
...                
...                ;if you want to use %rbp here, save it on the stack before
...  
mov  %rbp, %rsp    ;old stack pointer
pop  %rbp
iret



回答3:


Probably slower than using %ebp as others have described, but how about:

    push %rsp
    test $0xf, %rsp
    jz aligned
    push (%rsp)   // duplicate the top of the stack
aligned:
    // now have 16-byte alignment with the original stack pointer
    // on the top of the stack, either once or twice
         :
    pop %rsp
    iret

This takes advantage of the fact that the stack is already 8-byte aligned, and that a push instruction can read the value to be pushed from memory.




回答4:


I suspect the only way to do it without using an additional register requires additional writing and reading to memory which would be the only point of not using an additional register.

I'll offer the current solution I have. I store rbp so I can use it for temporary storage and then restore it before the call to the function. This is similar to drhirsch's answer

movq    %rbp, -24(%rsp) //store original rbp 3 words beyond the stack
movq    %rsp, %rbp //store original rsp
subq    $8, %rsp //buy a word on the stack
andq    $-0x10, %rsp //16 byte align the stack (growing downwards)
//We now have 1 or 2 words free on the stack (depending on the original
// alignment). This is why we put rbp 3 words beyond the stack
movq    %rbp, (%rsp) //store the original rsp right here
movq    -24(%rbp), %rbp //restore original rbp
call    foo
movq    (%rsp), %rsp //restore original rsp
iretq


来源:https://stackoverflow.com/questions/9592345/x86-64-align-stack-and-recover-without-saving-registers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!