| # Kernel implementations for a slim setjmp/longjmp. |
| # |
| # int setjmp(struct jmpbuf *env); |
| # void longjmp(struct jmpbuf *env, int val); |
| # |
| # Callers *must* clobber all callee-saved registers first, e.g.: |
| # asm volatile ("" : : : "rbx", "r12", "r13", "r14", "r15"); |
| |
| # The jmpbuf struct is defined as below: |
| # struct jmpbuf { |
| # uintptr_t retaddr; // return address |
| # uintreg_t rsp; // post-return rsp |
| # uintreg_t rbp; |
| # }; |
| |
| .text |
| .align 4 |
| .globl slim_setjmp |
| .type slim_setjmp, @function |
| slim_setjmp: |
| xorl %eax,%eax # Zero out the return value for our first return |
| pop %rsi # Temporarily grab the return address and adjust %rsp |
| movq %rsi,(%rdi) # Save the return address |
| movq %rsp,8(%rdi) # The adjusted %rsp is the post-return %rsp |
| # (see longjmp) |
| movq %rbp,16(%rdi) |
| push %rsi # Restore stuff to make the call/return stack happy |
| ret |
| |
| .size slim_setjmp,.-slim_setjmp |
| |
| .text |
| .align 4 |
| .globl longjmp |
| .type longjmp, @function |
| longjmp: |
| movl %esi,%eax # Set the return value to val (32-bit int) |
| movq 16(%rdi),%rbp |
| movq 8(%rdi),%rsp # Set the post-return %rsp |
| jmp *(%rdi) # Jump back to setjmp callsite (no ret necessary) |
| |
| .size longjmp,.-longjmp |