gint/src/setjmp/setjmp.s

80 lines
1.8 KiB
ArmAsm

/*
standard library module: setjmp
Long jumps. The register contents are saved in a buffer when setjmp()
is called and restored at any time when longjmp() performs the jump.
This is based on a trick that uses pr ; the user program is resumed
after the setjmp() call when longjmp() is invoked but this is not
setjmp() that returns. longjmp() restores the pr value that was saved
by setjmp() and performs an rts instruction.
setjmp() returns 0 when called to set up the jump point and a non-zero
value when invoked through a long jump. If 0 is given as return value
to longjmp(), then 1 is returned.
*/
.global _setjmp
.global _longjmp
_setjmp:
/* Getting some free space. */
add #64, r4
/* Saving general-purpose registers. */
mov.l r15, @-r4
mov.l r14, @-r4
mov.l r13, @-r4
mov.l r12, @-r4
mov.l r11, @-r4
mov.l r10, @-r4
mov.l r9, @-r4
mov.l r8, @-r4
/* Saving control and system registers. */
stc.l sr, @-r4
stc.l ssr, @-r4
stc.l spc, @-r4
stc.l gbr, @-r4
stc.l vbr, @-r4
sts.l mach, @-r4
sts.l macl, @-r4
sts.l pr, @-r4
/* This function always return 0. The cases where setjmp() seems to
return non-zero values, when a long jump has just been performed, is
actually handled by longjmp(). */
rts
mov #0, r0
_longjmp:
/* Restoring the system and control registers. Restoring pr is actually
what performs the jump -- and makes the user program think that
setjmp() has returned. */
lds.l @r4+, pr
lds.l @r4+, macl
lds.l @r4+, mach
ldc.l @r4+, vbr
ldc.l @r4+, gbr
ldc.l @r4+, spc
ldc.l @r4+, ssr
ldc.l @r4+, sr
/* Restoring the general-purpose registers. */
mov.l @r4+, r8
mov.l @r4+, r9
mov.l @r4+, r10
mov.l @r4+, r11
mov.l @r4+, r12
mov.l @r4+, r13
mov.l @r4+, r14
mov.l @r4+, r15
/* Preventing return value from being 0 (must be at least 1). */
tst r5, r5
movt r0
rts
add r5, r0