[libc] Rewrite setjmp() and longjmp()
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
d1f0e89e4e
commit
8ab4b00442
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Reference in New Issue