david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[libc] Rewrite setjmp() and longjmp()

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2015-03-02 15:21:38 +00:00
parent d1f0e89e4e
commit 8ab4b00442
2 changed files with 81 additions and 49 deletions

View File

@ -1,42 +1,64 @@
/* setjmp and longjmp. Use of these functions is deprecated. */
FILE_LICENCE ( GPL2_OR_LATER )
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.arch i386
.code32
/**************************************************************************
SETJMP - Save stack context for non-local goto
**************************************************************************/
/* Must match jmp_buf structure layout */
.struct 0
env_retaddr: .long 0
env_stack: .long 0
env_ebx: .long 0
env_esi: .long 0
env_edi: .long 0
env_ebp: .long 0
.previous
/*
* Save stack context for non-local goto
*/
.globl setjmp
setjmp:
movl 4(%esp),%ecx /* jmpbuf */
movl 0(%esp),%edx /* return address */
movl %edx,0(%ecx)
movl %ebx,4(%ecx)
movl %esp,8(%ecx)
movl %ebp,12(%ecx)
movl %esi,16(%ecx)
movl %edi,20(%ecx)
movl $0,%eax
/* Get jmp_buf pointer in %edx */
movl 4(%esp),%edx
/* Save return address */
movl 0(%esp),%eax
movl %eax, env_retaddr(%edx)
/* Save stack pointer */
movl %esp, env_stack(%edx)
/* Save other registers */
movl %ebx, env_ebx(%edx)
movl %esi, env_esi(%edx)
movl %edi, env_edi(%edx)
movl %ebp, env_ebp(%edx)
/* Return 0 when returning as setjmp() */
xorl %eax, %eax
ret
.size setjmp, . - setjmp
/**************************************************************************
LONGJMP - Non-local jump to a saved stack context
**************************************************************************/
/*
* Non-local jump to a saved stack context
*/
.globl longjmp
longjmp:
movl 4(%esp),%edx /* jumpbuf */
movl 8(%esp),%eax /* result */
movl 0(%edx),%ecx
movl 4(%edx),%ebx
movl 8(%edx),%esp
movl 12(%edx),%ebp
movl 16(%edx),%esi
movl 20(%edx),%edi
cmpl $0,%eax
jne 1f
movl $1,%eax
1: movl %ecx,0(%esp)
/* Get jmp_buf pointer in %edx */
movl 4(%esp),%edx
/* Get result in %eax */
movl 8(%esp),%eax
/* Force result to non-zero */
testl %eax, %eax
jnz 1f
incl %eax
1: /* Restore stack pointer */
movl env_stack(%edx), %esp
/* Restore other registers */
movl env_ebx(%edx), %esp
movl env_esi(%edx), %esp
movl env_edi(%edx), %esp
movl env_ebp(%edx), %ebp
/* Replace return address on the new stack */
popl %ecx /* discard */
pushl env_retaddr(%edx)
/* Return to setjmp() caller */
ret
.size longjmp, . - longjmp

View File

@ -1,40 +1,50 @@
#ifndef ETHERBOOT_SETJMP_H
#define ETHERBOOT_SETJMP_H
#ifndef _SETJMP_H
#define _SETJMP_H
FILE_LICENCE ( GPL2_OR_LATER );
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <realmode.h>
/** A jump buffer */
typedef struct {
/** Saved return address */
uint32_t retaddr;
/** Saved stack pointer */
uint32_t stack;
/** Saved %ebx */
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
/** Saved %esi */
uint32_t esi;
/** Saved %edi */
uint32_t edi;
/** Saved %ebp */
uint32_t ebp;
} jmp_buf[1];
/** A real-mode-extended jump buffer */
typedef struct {
/** Jump buffer */
jmp_buf env;
uint16_t rm_ss;
uint16_t rm_sp;
/** Real-mode stack pointer */
segoff_t rm_stack;
} rmjmp_buf[1];
extern int __asmcall setjmp ( jmp_buf env );
extern void __asmcall longjmp ( jmp_buf env, int val );
extern int __asmcall __attribute__ (( returns_twice ))
setjmp ( jmp_buf env );
#define rmsetjmp( _env ) ( { \
(_env)->rm_ss = rm_ss; \
(_env)->rm_sp = rm_sp; \
setjmp ( (_env)->env ); } ) \
extern void __asmcall __attribute__ (( noreturn ))
longjmp ( jmp_buf env, int val );
#define rmlongjmp( _env, _val ) do { \
rm_ss = (_env)->rm_ss; \
rm_sp = (_env)->rm_sp; \
longjmp ( (_env)->env, (_val) ); \
#define rmsetjmp( _env ) ( { \
(_env)->rm_stack.segment = rm_ss; \
(_env)->rm_stack.offset = rm_sp; \
setjmp ( (_env)->env ); } ) \
#define rmlongjmp( _env, _val ) do { \
rm_ss = (_env)->rm_stack.segment; \
rm_sp = (_env)->rm_stack.offset; \
longjmp ( (_env)->env, (_val) ); \
} while ( 0 )
#endif /* ETHERBOOT_SETJMP_H */
#endif /* _SETJMP_H */