]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[libc] Add x86_64 versions of setjmp() and longjmp()
authorMichael Brown <mcb30@ipxe.org>
Tue, 7 Apr 2015 05:40:42 +0000 (06:40 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 7 Apr 2015 05:40:42 +0000 (06:40 +0100)
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>
src/arch/x86_64/Makefile
src/arch/x86_64/core/setjmp.S [new file with mode: 0644]
src/arch/x86_64/include/setjmp.h [new file with mode: 0644]

index b687f3407970eba6fd343810125ecf42fc7d05c1..48c0aa1af88cbf50abaad49e2742ea00e797d5aa 100644 (file)
@@ -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 (file)
index 0000000..e43200d
--- /dev/null
@@ -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 (file)
index 0000000..69835d9
--- /dev/null
@@ -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 */