X86_64 align stack and restore without saving registers

I am writing interrupt routines for x86_64. ABI indicates that before calling function C, I must align the stack to 16 bytes. ISA x86_64 indicates that when I enter ISR, my stack is aligned by 8 bytes. So I need to align the stack pointer with 16 bytes. The problem is that when I return from my C function, I have to restore the (potentially) unrecognizable stack pointer so that I can correctly return from my interrupt.

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

+5
source share
4 answers

Here is my solution to the question of how to put:

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

, , %rsp (%rsp) 8(%rsp). andq - 16 , , 8 , 8 %rsp, , %rsp 8(%rsp) 16(%rsp). 8(%rsp).

+8

, rsp. -

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
+4

, , , , .

I offer the current solution that I have. I store rbp so I can use it for temporary storage and then restore it before calling the function. This is similar to drhirsch 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
0
source

Probably slower than using% ebp as described by others, but what 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 the push command can read the value that needs to be ejected from memory.

0
source

All Articles