148 lines
3.4 KiB
Plaintext
148 lines
3.4 KiB
Plaintext
#
|
|
mes 2,EM_WSIZE,EM_PSIZE
|
|
|
|
exp $setjmp
|
|
pro $setjmp,2*EM_WSIZE
|
|
|
|
; setjmp saves the StackPointer and the LocalBase, and the chunk of
|
|
; memory between the StackPointer and the ArgumentBase, + its size in a
|
|
; buffer, pointed to by the parameter.
|
|
; longjump can then restore this buffer and return.
|
|
; Notice that this does not work on EM implementations in which every
|
|
; procedure frame has a different fragment in memory, because in this case
|
|
; the ArgumentBase will point into the fragment of the caller.
|
|
; What really is needed is a way to find out the size of the return
|
|
; status block.
|
|
; On EM-implementations in which the stack grows upwards it is untested,
|
|
; as there are no such implementations available now.
|
|
; This implementation of setjmp/longjmp
|
|
; depends on the assumption that the routine calling
|
|
; setjmp does not have register variables, and that it saves all registers
|
|
; that are available for variables.
|
|
|
|
loc 0
|
|
stl -2*EM_WSIZE
|
|
lor 1 ; load StackPointer
|
|
lal 0
|
|
loi EM_PSIZE
|
|
sti EM_PSIZE ; save it
|
|
lxl 0 ; load LocalBase
|
|
lal 0
|
|
loi EM_PSIZE
|
|
adp EM_PSIZE
|
|
sti EM_PSIZE ; save it
|
|
lxa 0 ; load ArgumentBase
|
|
lal 0
|
|
loi EM_PSIZE
|
|
loi EM_PSIZE ; load saved StackPointer
|
|
sbs EM_WSIZE ; gives size of block that is to be saved, or negative size
|
|
dup EM_WSIZE
|
|
zgt *5
|
|
ngi EM_WSIZE
|
|
loc 1
|
|
stl -2*EM_WSIZE; one if the stack grows upwards
|
|
5
|
|
stl -EM_WSIZE ; save size of block in local
|
|
lol -EM_WSIZE
|
|
lal 0
|
|
loi EM_PSIZE
|
|
adp 2*EM_PSIZE
|
|
sti EM_WSIZE ; and also in the buffer
|
|
lal 0
|
|
loi EM_PSIZE
|
|
loi EM_PSIZE ; load saved StackPointer
|
|
lol -2*EM_WSIZE; positive if the stack grows upwards
|
|
zle *6
|
|
asp EM_PSIZE
|
|
lxa 0
|
|
adp EM_WSIZE ; in this case the source address = ArgumentBase+EM_WSIZE
|
|
6
|
|
lal 0
|
|
loi EM_PSIZE
|
|
adp 2*EM_PSIZE+EM_WSIZE
|
|
; destination address
|
|
lol -EM_WSIZE ; count
|
|
bls EM_WSIZE ; block copy
|
|
loc 0
|
|
ret EM_WSIZE
|
|
end 2*EM_WSIZE
|
|
|
|
exp $longjmp
|
|
pro $longjmp,2*EM_WSIZE
|
|
|
|
; first, find out wether the stack grows upwards
|
|
loc 0
|
|
stl -2*EM_WSIZE
|
|
lxa 0
|
|
lxl 0
|
|
cmp
|
|
zge *7
|
|
loc 1
|
|
stl -2*EM_WSIZE; this local contains 1 if it does, otherwise it contains 0
|
|
7
|
|
; then, adjust StackPointer until it is below the saved StackPointer (or
|
|
; above if it grows upwards)
|
|
; then push parameters
|
|
; then copy the saved block in its proper place
|
|
; notice that the parameters can not be used anymore now
|
|
; then restore the LocalBase and the Stackpointer and return.
|
|
1
|
|
loc 0
|
|
2
|
|
lor 1
|
|
lal 0
|
|
loi EM_PSIZE
|
|
loi EM_PSIZE ; saved StackPointer
|
|
cmp ; compare with current one
|
|
lol -2*EM_WSIZE
|
|
zle *8
|
|
zlt *1
|
|
bra *10
|
|
8
|
|
zgt *1
|
|
10
|
|
lal 0
|
|
loi EM_PSIZE
|
|
loi EM_PSIZE ; push saved StackPointer
|
|
lol EM_PSIZE ; push value to be returned by longjmp
|
|
lal 0
|
|
loi EM_PSIZE
|
|
adp EM_PSIZE
|
|
loi EM_PSIZE ; push saved LocalBase
|
|
lal 0
|
|
loi EM_PSIZE
|
|
adp 2*EM_PSIZE+EM_WSIZE
|
|
; source address
|
|
lal 0
|
|
loi EM_PSIZE
|
|
loi EM_PSIZE ; saved stackpointer
|
|
lol -2*EM_WSIZE
|
|
zle *9 ; if not positive, this is the destination address,
|
|
; otherwise subtract the size of the saved area and add EM_WSIZE
|
|
adp EM_WSIZE
|
|
lal 0
|
|
loi EM_PSIZE
|
|
adp 2*EM_PSIZE
|
|
loi EM_WSIZE
|
|
ngi EM_WSIZE
|
|
ads EM_WSIZE
|
|
9 ; destination address
|
|
lal 0
|
|
loi EM_PSIZE
|
|
adp 2*EM_PSIZE
|
|
loi EM_WSIZE ; size
|
|
bls EM_WSIZE ; now we have a frame exactly as it was in setjmp,
|
|
; and exactly at the same place
|
|
str 0 ; restore LocalBase
|
|
stl -EM_WSIZE ; saves the return value
|
|
str 1 ; restores the StackPointer
|
|
lol -EM_WSIZE
|
|
dup EM_WSIZE
|
|
zne *3
|
|
; of course, longjmp may not return 0!
|
|
asp EM_WSIZE
|
|
loc 1
|
|
3
|
|
ret EM_WSIZE
|
|
end 2*EM_WSIZE
|