#
mes 2,EM_WSIZE,EM_PSIZE
- exp $setjmp
- pro $setjmp,3*EM_WSIZE
+;
+; layout of a setjmp buffer:
+;
+; -----------------
+; | signal mask | (only for Berkeley 4.2)
+; -----------------
+; | PC of caller |
+; -----------------
+; | |
+; | GTO descriptor |
+; | (SP, LB, PC) |
+; | |
+; -----------------
+;
+; setjmp saves the signalmask, PC, SP, and LB of caller, and creates a
+; GTO descriptor with a program counter indicating a piece of code that
+; gets the return value right before jumping to the caller of setjmp in
+; the setjmp buffer, which has a layout as displayed above.
+; The big problem here is how to het the return address, i.e. the PC of
+; the caller; This problem is solved by the front-end, which must pass
+; it as an extra parameter to setjmp.
-; 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.
+gtobuf
+ bss 3*EM_PSIZE,0,0
+retval
+ bss EM_WSIZE,0,0
+jmpbuf_addr
+ bss EM_PSIZE,0,0
+ inp $fill_ret_area
+ exp $setjmp
+ pro $setjmp,0
+ mes 11
#ifdef __BSD4_2
loc 0
cal $sigblock
asp EM_WSIZE
lfr EM_WSIZE
- stl -3*EM_WSIZE
-#endif
- 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
+ stf 4*EM_PSIZE
+#endif
+ ; create GTO descriptor for longjmp
+ lxl 0
+ dch ; Local Base of caller
+ lxa 0 ; Stackpointer of caller
+.1
+ rom *1
+ lae .1
+ loi EM_PSIZE ; where the longjmp ends up
lal 0
loi EM_PSIZE
- adp 2*EM_PSIZE
- sti EM_WSIZE ; and also in the buffer
- lal 0
+ sti 3*EM_PSIZE ; stored in jmpbuf
+ ; also save return address, which has been supplied by the compiler
+ lal EM_PSIZE
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
+ adp 3*EM_PSIZE
+ sti EM_PSIZE
loc 0
ret EM_WSIZE
- end 3*EM_WSIZE
-
- exp $longjmp
- pro $longjmp,3*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
+ ; so, the longjmp returns here.
+ ; now, create a GTO descriptor for the final GTO
+ lae jmpbuf_addr
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
+ adp 3*EM_PSIZE
loi EM_PSIZE
- loi EM_PSIZE ; push saved StackPointer
- lol EM_PSIZE ; push value to be returned by longjmp
- lal 0
+ lae gtobuf
+ sti EM_PSIZE ; this is the return address
+ lae jmpbuf_addr
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
+ loi 2*EM_PSIZE
+ lae gtobuf+EM_PSIZE
+ sti 2*EM_PSIZE ; that's it, the GTO descriptor is ready;
+ ; now take care of the return value ...
+ cal $fill_ret_area
+ gto gtobuf ; there we go ...
+ end 0
+
+ pro $fill_ret_area,0
+ loe retval
+ ret EM_WSIZE
+ end 0
+
+ exp $longjmp
+ pro $longjmp,?
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
#ifdef __BSD4_2
- lol -3*EM_WSIZE
+ dup EM_PSIZE
+ lof 4*EM_PSIZE
cal $sigsetmask
asp EM_WSIZE
lfr EM_WSIZE
asp EM_WSIZE
#endif
- lol -EM_WSIZE
+ lae jmpbuf_addr
+ sti EM_PSIZE ; save address of jmpbuf
+ lol EM_PSIZE
dup EM_WSIZE
zne *3
; of course, longjmp may not return 0!
asp EM_WSIZE
loc 1
3
- ret EM_WSIZE
- end 3*EM_WSIZE
+ ste retval ; save return value
+ lal 0
+ loi EM_PSIZE
+ lae gtobuf
+ blm 3*EM_PSIZE ; create GTO descriptor
+ gto gtobuf ; and GTO
+ end 0