diff options
author | Michael Brown <mcb30@ipxe.org> | 2015-04-07 06:40:42 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2015-04-07 06:40:42 +0100 |
commit | fb2bedcff3ab30ca2a4bed1aa821d1b1c8f9cfae (patch) | |
tree | 32ef3704cf0266ce3846566ae09a7aaa36a05418 | |
parent | 00ff3d8bb3af0831ced99e8b6f226291ca236883 (diff) | |
download | ipxe-fb2bedcff3ab30ca2a4bed1aa821d1b1c8f9cfae.tar.gz |
[libc] Add x86_64 versions of setjmp() and longjmp()
None of the x86_64 builds currently have any way of invoking these
functions. They are included only to avoid introducing unnecessary
architecture-specific dependencies into the self-test suite.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/arch/x86_64/Makefile | 1 | ||||
-rw-r--r-- | src/arch/x86_64/core/setjmp.S | 65 | ||||
-rw-r--r-- | src/arch/x86_64/include/setjmp.h | 34 |
3 files changed, 100 insertions, 0 deletions
diff --git a/src/arch/x86_64/Makefile b/src/arch/x86_64/Makefile index b687f340..48c0aa1a 100644 --- a/src/arch/x86_64/Makefile +++ b/src/arch/x86_64/Makefile @@ -40,6 +40,7 @@ endif # x86_64-specific directories containing source files # +SRCDIRS += arch/x86_64/core SRCDIRS += arch/x86_64/prefix # Include common x86 Makefile diff --git a/src/arch/x86_64/core/setjmp.S b/src/arch/x86_64/core/setjmp.S new file mode 100644 index 00000000..e43200d7 --- /dev/null +++ b/src/arch/x86_64/core/setjmp.S @@ -0,0 +1,65 @@ +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + + .text + .code64 + + /* Must match jmp_buf structure layout */ + .struct 0 +env_retaddr: .quad 0 +env_stack: .quad 0 +env_rbx: .quad 0 +env_rbp: .quad 0 +env_r12: .quad 0 +env_r13: .quad 0 +env_r14: .quad 0 +env_r15: .quad 0 + .previous + +/* + * Save stack context for non-local goto + */ + .globl setjmp +setjmp: + /* Save return address */ + movq 0(%rsp), %rax + movq %rax, env_retaddr(%rdi) + /* Save stack pointer */ + movq %rsp, env_stack(%rdi) + /* Save other registers */ + movq %rbx, env_rbx(%rdi) + movq %rbp, env_rbp(%rdi) + movq %r12, env_r12(%rdi) + movq %r13, env_r13(%rdi) + movq %r14, env_r14(%rdi) + movq %r15, env_r15(%rdi) + /* Return 0 when returning as setjmp() */ + xorq %rax, %rax + ret + .size setjmp, . - setjmp + +/* + * Non-local jump to a saved stack context + */ + .globl longjmp +longjmp: + /* Get result in %rax */ + movq %rsi, %rax + /* Force result to non-zero */ + testq %rax, %rax + jnz 1f + incq %rax +1: /* Restore stack pointer */ + movq env_stack(%rdi), %rsp + /* Restore other registers */ + movq env_rbx(%rdi), %rbx + movq env_rbp(%rdi), %rbp + movq env_r12(%rdi), %r12 + movq env_r13(%rdi), %r13 + movq env_r14(%rdi), %r14 + movq env_r15(%rdi), %r15 + /* Replace return address on the new stack */ + popq %rcx /* discard */ + pushq env_retaddr(%rdi) + /* Return to setjmp() caller */ + ret + .size longjmp, . - longjmp diff --git a/src/arch/x86_64/include/setjmp.h b/src/arch/x86_64/include/setjmp.h new file mode 100644 index 00000000..69835d9f --- /dev/null +++ b/src/arch/x86_64/include/setjmp.h @@ -0,0 +1,34 @@ +#ifndef _SETJMP_H +#define _SETJMP_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> + +/** A jump buffer */ +typedef struct { + /** Saved return address */ + uint64_t retaddr; + /** Saved stack pointer */ + uint64_t stack; + /** Saved %rbx */ + uint64_t rbx; + /** Saved %rbp */ + uint64_t rbp; + /** Saved %r12 */ + uint64_t r12; + /** Saved %r13 */ + uint64_t r13; + /** Saved %r14 */ + uint64_t r14; + /** Saved %r15 */ + uint64_t r15; +} jmp_buf[1]; + +extern int __asmcall __attribute__ (( returns_twice )) +setjmp ( jmp_buf env ); + +extern void __asmcall __attribute__ (( noreturn )) +longjmp ( jmp_buf env, int val ); + +#endif /* _SETJMP_H */ |