2 * very-low-level utilities for runtime support
6 * This software is part of the SBCL system. See the README file for
9 * This software is derived from the CMU CL system, which was
10 * written at Carnegie Mellon University and released into the
11 * public domain. The software is in the public domain and is
12 * provided with absolutely no warranty. See the COPYING and CREDITS
13 * files for more information.
16 #define LANGUAGE_ASSEMBLY
19 #include "genesis/closure.h"
20 #include "genesis/fdefn.h"
21 #include "genesis/static-symbols.h"
22 #include "genesis/symbol.h"
23 #include "genesis/thread.h"
25 /* Minimize conditionalization for different OS naming schemes.
27 * (As of sbcl-0.8.10, this seems no longer to be much of an issue,
28 * since everyone has converged on ELF. If this generality really
29 * turns out not to matter, perhaps it's just clutter we could get
30 * rid of? -- WHN 2004-04-18)
32 #if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
33 #define GNAME(var) var
35 #define GNAME(var) _##var
38 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
39 * want alignment in bytes.
41 * (As in the GNAME() definitions above, as of sbcl-0.8.10, this seems
42 * no longer to be much of an issue, since everyone has converged on
43 * the same value. If this generality really turns out not to
44 * matter any more, perhaps it's just clutter we could get
45 * rid of? -- WHN 2004-04-18)
47 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
50 #define align_16byte 16
54 #define align_16byte 4
58 .global GNAME(foreign_function_call_active)
59 .global GNAME(all_threads)
62 * A call to call_into_c preserves esi, edi, and ebp.
63 * (The C function will preserve ebx, esi, edi, and ebp across its
64 * function call, but we trash ebx ourselves by using it to save the
65 * return Lisp address.)
67 * Return values are in eax and maybe edx for quads, or st(0) for
70 * This should work for Lisp calls C calls Lisp calls C..
73 .align align_16byte,0x90
74 .global GNAME(call_into_c)
75 .type GNAME(call_into_c),@function
77 movl $1,GNAME(foreign_function_call_active)
79 /* Save the return Lisp address in ebx. */
82 /* Setup the NPX for C */
92 call *%eax # normal callout using Lisp stack
94 movl %eax,%ecx # remember integer return value
96 /* Check for a return FP value. */
103 /* The return value is in eax, or eax,edx? */
104 /* Set up the NPX stack for Lisp. */
105 fldz # Ensure no regs are empty.
114 /* Restore the return value. */
115 movl %ecx,%eax # maybe return value
117 movl $0,GNAME(foreign_function_call_active)
122 /* The return result is in st(0). */
123 /* Set up the NPX stack for Lisp, placing the result in st(0). */
124 fldz # Ensure no regs are empty.
131 fxch %st(7) # Move the result back to st(0).
133 /* We don't need to restore eax, because the result is in st(0). */
135 movl $0,GNAME(foreign_function_call_active)
139 .size GNAME(call_into_c), . - GNAME(call_into_c)
143 .global GNAME(call_into_lisp_first_time)
144 .type GNAME(call_into_lisp_first_time),@function
146 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
147 * the stack changes. We don't worry too much about saving registers
148 * here, because we never expect to return from the initial call to lisp
151 .align align_16byte,0x90
152 GNAME(call_into_lisp_first_time):
153 pushl %ebp # Save old frame pointer.
154 movl %esp,%ebp # Establish new frame.
155 movl %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
156 movl GNAME(all_threads),%eax
157 movl THREAD_CONTROL_STACK_START_OFFSET(%eax) ,%esp
158 /* don't think too hard about what happens if we get interrupted
160 addl $THREAD_CONTROL_STACK_SIZE-4,%esp
164 .global GNAME(call_into_lisp)
165 .type GNAME(call_into_lisp),@function
167 /* The C conventions require that ebx, esi, edi, and ebp be preserved
168 * across function calls. */
170 .align align_16byte,0x90
171 GNAME(call_into_lisp):
172 pushl %ebp # Save old frame pointer.
173 movl %esp,%ebp # Establish new frame.
175 /* Save the NPX state */
176 fwait # Catch any pending NPX exceptions.
177 subl $108,%esp # Make room for the NPX state.
178 fnsave (%esp) # save and reset NPX
180 movl (%esp),%eax # Load NPX control word.
181 andl $0xfffff2ff,%eax # Set rounding mode to nearest.
182 orl $0x00000200,%eax # Set precision to 64 bits. (53-bit mantissa)
184 fldcw (%esp) # Recover modes.
187 fldz # Ensure no FP regs are empty.
196 /* Save C regs: ebx esi edi. */
201 /* Clear descriptor regs. */
202 xorl %eax,%eax # lexenv
203 xorl %ebx,%ebx # available
204 xorl %ecx,%ecx # arg count
205 xorl %edx,%edx # first arg
206 xorl %edi,%edi # second arg
207 xorl %esi,%esi # third arg
209 /* no longer in function call */
210 movl %eax, GNAME(foreign_function_call_active)
212 movl %esp,%ebx # remember current stack
213 pushl %ebx # Save entry stack on (maybe) new stack.
215 /* Establish Lisp args. */
216 movl 8(%ebp),%eax # lexenv?
217 movl 12(%ebp),%ebx # address of arg vec
218 movl 16(%ebp),%ecx # num args
219 shll $2,%ecx # Make num args into fixnum.
222 movl (%ebx),%edx # arg0
225 movl 4(%ebx),%edi # arg1
228 movl 8(%ebx),%esi # arg2
230 /* Registers eax, ecx, edx, edi, and esi are now live. */
232 /* Alloc new frame. */
233 mov %esp,%ebx # The current sp marks start of new frame.
234 push %ebp # fp in save location S0
235 sub $8,%esp # Ensure 3 slots are allocated, one above.
236 mov %ebx,%ebp # Switch to new frame.
238 call *CLOSURE_FUN_OFFSET(%eax)
240 /* If the function returned multiple values, it will return to
241 this point. Lose them */
243 /* A singled value function returns here */
245 /* Restore the stack, in case there was a stack change. */
248 /* Restore C regs: ebx esi edi. */
253 /* Restore the NPX state. */
258 movl %edx,%eax # c-val
260 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
262 /* support for saving and restoring the NPX state from C */
264 .global GNAME(fpu_save)
265 .type GNAME(fpu_save),@function
269 fnsave (%eax) # Save the NPX state. (resets NPX)
271 .size GNAME(fpu_save),.-GNAME(fpu_save)
273 .global GNAME(fpu_restore)
274 .type GNAME(fpu_restore),@function
278 frstor (%eax) # Restore the NPX state.
280 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
283 * the undefined-function trampoline
286 .align align_4byte,0x90
287 .global GNAME(undefined_tramp)
288 .type GNAME(undefined_tramp),@function
289 .byte 0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
290 GNAME(undefined_tramp):
294 .byte UNDEFINED_FUN_ERROR
295 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
297 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
300 * the closure trampoline
303 .align align_4byte,0x90
304 .global GNAME(closure_tramp)
305 .type GNAME(closure_tramp),@function
306 .byte 0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
307 GNAME(closure_tramp):
308 movl FDEFN_FUN_OFFSET(%eax),%eax
309 /* FIXME: The '*' after "jmp" in the next line is from PVE's
310 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
311 * reasonable, and it certainly seems as though if CMU CL needs it,
312 * SBCL needs it too, but I haven't actually verified that it's
313 * right. It would be good to find a way to force the flow of
314 * control through here to test it. */
315 jmp *CLOSURE_FUN_OFFSET(%eax)
316 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
319 * fun-end breakpoint magic
322 .global GNAME(fun_end_breakpoint_guts)
324 GNAME(fun_end_breakpoint_guts):
325 /* Multiple Value return */
326 jmp multiple_value_return
327 /* Single value return: The eventual return will now use the
328 multiple values return convention but with a return values
330 movl %esp,%ebx # Setup ebx - the ofp.
331 subl $4,%esp # Allocate one stack slot for the return value
332 movl $4,%ecx # Setup ecx for one return value.
333 movl $NIL,%edi # default second value
334 movl $NIL,%esi # default third value
336 multiple_value_return:
338 .global GNAME(fun_end_breakpoint_trap)
339 GNAME(fun_end_breakpoint_trap):
341 .byte trap_FunEndBreakpoint
342 hlt # We should never return here.
344 .global GNAME(fun_end_breakpoint_end)
345 GNAME(fun_end_breakpoint_end):
348 .global GNAME(do_pending_interrupt)
349 .type GNAME(do_pending_interrupt),@function
350 .align align_4byte,0x90
351 GNAME(do_pending_interrupt):
353 .byte trap_PendingInterrupt
355 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
359 * Allocate bytes and return the start of the allocated space
360 * in the specified destination register.
362 * In the general case the size will be in the destination register.
364 * All registers must be preserved except the destination.
365 * The C conventions will preserve ebx, esi, edi, and ebp.
366 * So only eax, ecx, and edx need special care here.
369 .globl GNAME(alloc_to_eax)
370 .type GNAME(alloc_to_eax),@function
371 .align align_4byte,0x90
373 pushl %ecx # Save ecx and edx as C could destroy them.
375 pushl %eax # Push the size.
377 addl $4,%esp # Pop the size arg.
378 popl %edx # Restore ecx and edx.
381 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
383 .globl GNAME(alloc_8_to_eax)
384 .type GNAME(alloc_8_to_eax),@function
385 .align align_4byte,0x90
386 GNAME(alloc_8_to_eax):
387 pushl %ecx # Save ecx and edx as C could destroy them.
389 pushl $8 # Push the size.
391 addl $4,%esp # Pop the size arg.
392 popl %edx # Restore ecx and edx.
395 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
397 .globl GNAME(alloc_8_to_eax)
398 .type GNAME(alloc_8_to_eax),@function
399 .align align_4byte,0x90
401 .globl GNAME(alloc_16_to_eax)
402 .type GNAME(alloc_16_to_eax),@function
403 .align align_4byte,0x90
404 GNAME(alloc_16_to_eax):
405 pushl %ecx # Save ecx and edx as C could destroy them.
407 pushl $16 # Push the size.
409 addl $4,%esp # Pop the size arg.
410 popl %edx # Restore ecx and edx.
413 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
415 .globl GNAME(alloc_to_ecx)
416 .type GNAME(alloc_to_ecx),@function
417 .align align_4byte,0x90
419 pushl %eax # Save eax and edx as C could destroy them.
421 pushl %ecx # Push the size.
423 addl $4,%esp # Pop the size arg.
424 movl %eax,%ecx # Set up the destination.
425 popl %edx # Restore eax and edx.
428 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
430 .globl GNAME(alloc_8_to_ecx)
431 .type GNAME(alloc_8_to_ecx),@function
432 .align align_4byte,0x90
433 GNAME(alloc_8_to_ecx):
434 pushl %eax # Save eax and edx as C could destroy them.
436 pushl $8 # Push the size.
438 addl $4,%esp # Pop the size arg.
439 movl %eax,%ecx # Set up the destination.
440 popl %edx # Restore eax and edx.
443 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
445 .globl GNAME(alloc_16_to_ecx)
446 .type GNAME(alloc_16_to_ecx),@function
447 .align align_4byte,0x90
448 GNAME(alloc_16_to_ecx):
449 pushl %eax # Save eax and edx as C could destroy them.
451 pushl $16 # Push the size.
453 addl $4,%esp # Pop the size arg.
454 movl %eax,%ecx # Set up the destination.
455 popl %edx # Restore eax and edx.
458 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
461 .globl GNAME(alloc_to_edx)
462 .type GNAME(alloc_to_edx),@function
463 .align align_4byte,0x90
465 pushl %eax # Save eax and ecx as C could destroy them.
467 pushl %edx # Push the size.
469 addl $4,%esp # Pop the size arg.
470 movl %eax,%edx # Set up the destination.
471 popl %ecx # Restore eax and ecx.
474 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
476 .globl GNAME(alloc_8_to_edx)
477 .type GNAME(alloc_8_to_edx),@function
478 .align align_4byte,0x90
479 GNAME(alloc_8_to_edx):
480 pushl %eax # Save eax and ecx as C could destroy them.
482 pushl $8 # Push the size.
484 addl $4,%esp # Pop the size arg.
485 movl %eax,%edx # Set up the destination.
486 popl %ecx # Restore eax and ecx.
489 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
491 .globl GNAME(alloc_16_to_edx)
492 .type GNAME(alloc_16_to_edx),@function
493 .align align_4byte,0x90
494 GNAME(alloc_16_to_edx):
495 pushl %eax # Save eax and ecx as C could destroy them.
497 pushl $16 # Push the size.
499 addl $4,%esp # Pop the size arg.
500 movl %eax,%edx # Set up the destination.
501 popl %ecx # Restore eax and ecx.
504 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
508 .globl GNAME(alloc_to_ebx)
509 .type GNAME(alloc_to_ebx),@function
510 .align align_4byte,0x90
512 pushl %eax # Save eax, ecx, and edx as C could destroy them.
515 pushl %ebx # Push the size.
517 addl $4,%esp # Pop the size arg.
518 movl %eax,%ebx # Set up the destination.
519 popl %edx # Restore eax, ecx and edx.
523 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
525 .globl GNAME(alloc_8_to_ebx)
526 .type GNAME(alloc_8_to_ebx),@function
527 .align align_4byte,0x90
528 GNAME(alloc_8_to_ebx):
529 pushl %eax # Save eax, ecx, and edx as C could destroy them.
532 pushl $8 # Push the size.
534 addl $4,%esp # Pop the size arg.
535 movl %eax,%ebx # Set up the destination.
536 popl %edx # Restore eax, ecx and edx.
540 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
542 .globl GNAME(alloc_16_to_ebx)
543 .type GNAME(alloc_16_to_ebx),@function
544 .align align_4byte,0x90
545 GNAME(alloc_16_to_ebx):
546 pushl %eax # Save eax, ecx, and edx as C could destroy them.
549 pushl $16 # Push the size
551 addl $4,%esp # pop the size arg.
552 movl %eax,%ebx # setup the destination.
553 popl %edx # Restore eax, ecx and edx.
557 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
561 .globl GNAME(alloc_to_esi)
562 .type GNAME(alloc_to_esi),@function
563 .align align_4byte,0x90
565 pushl %eax # Save eax, ecx, and edx as C could destroy them.
568 pushl %esi # Push the size
570 addl $4,%esp # pop the size arg.
571 movl %eax,%esi # setup the destination.
572 popl %edx # Restore eax, ecx and edx.
576 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
578 .globl GNAME(alloc_8_to_esi)
579 .type GNAME(alloc_8_to_esi),@function
580 .align align_4byte,0x90
581 GNAME(alloc_8_to_esi):
582 pushl %eax # Save eax, ecx, and edx as C could destroy them.
585 pushl $8 # Push the size
587 addl $4,%esp # pop the size arg.
588 movl %eax,%esi # setup the destination.
589 popl %edx # Restore eax, ecx and edx.
593 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
595 .globl GNAME(alloc_16_to_esi)
596 .type GNAME(alloc_16_to_esi),@function
597 .align align_4byte,0x90
598 GNAME(alloc_16_to_esi):
599 pushl %eax # Save eax, ecx, and edx as C could destroy them.
602 pushl $16 # Push the size
604 addl $4,%esp # pop the size arg.
605 movl %eax,%esi # setup the destination.
606 popl %edx # Restore eax, ecx and edx.
610 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
613 .globl GNAME(alloc_to_edi)
614 .type GNAME(alloc_to_edi),@function
615 .align align_4byte,0x90
617 pushl %eax # Save eax, ecx, and edx as C could destroy them.
620 pushl %edi # Push the size
622 addl $4,%esp # pop the size arg.
623 movl %eax,%edi # setup the destination.
624 popl %edx # Restore eax, ecx and edx.
628 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
630 .globl GNAME(alloc_8_to_edi)
631 .type GNAME(alloc_8_to_edi),@function
632 .align align_4byte,0x90
633 GNAME(alloc_8_to_edi):
634 pushl %eax # Save eax, ecx, and edx as C could destroy them.
637 pushl $8 # Push the size
639 addl $4,%esp # pop the size arg.
640 movl %eax,%edi # setup the destination.
641 popl %edx # Restore eax, ecx and edx.
645 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
647 .globl GNAME(alloc_16_to_edi)
648 .type GNAME(alloc_16_to_edi),@function
649 .align align_4byte,0x90
650 GNAME(alloc_16_to_edi):
651 pushl %eax # Save eax, ecx, and edx as C could destroy them.
654 pushl $16 # Push the size
656 addl $4,%esp # pop the size arg.
657 movl %eax,%edi # setup the destination.
658 popl %edx # Restore eax, ecx and edx.
662 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
665 /* Called from lisp when an inline allocation overflows.
666 Every register except the result needs to be preserved.
667 We depend on C to preserve ebx, esi, edi, and ebp.
668 But where necessary must save eax, ecx, edx. */
670 #ifdef LISP_FEATURE_SB_THREAD
671 #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET
672 #define DISPLACEMENT $7
674 #define START_REGION boxed_region
675 #define DISPLACEMENT $6
678 /* This routine handles an overflow with eax=crfp+size. So the
681 .globl GNAME(alloc_overflow_eax)
682 .type GNAME(alloc_overflow_eax),@function
683 GNAME(alloc_overflow_eax):
684 pushl %ecx # Save ecx
685 pushl %edx # Save edx
686 /* Calculate the size for the allocation. */
687 subl START_REGION,%eax
688 pushl %eax # Push the size
690 addl $4,%esp # pop the size arg.
691 popl %edx # Restore edx.
692 popl %ecx # Restore ecx.
693 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
695 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
698 .globl GNAME(alloc_overflow_ecx)
699 .type GNAME(alloc_overflow_ecx),@function
700 GNAME(alloc_overflow_ecx):
701 pushl %eax # Save eax
702 pushl %edx # Save edx
703 /* Calculate the size for the allocation. */
704 subl START_REGION,%ecx
705 pushl %ecx # Push the size
707 addl $4,%esp # pop the size arg.
708 movl %eax,%ecx # setup the destination.
709 popl %edx # Restore edx.
710 popl %eax # Restore eax.
711 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
713 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
716 .globl GNAME(alloc_overflow_edx)
717 .type GNAME(alloc_overflow_edx),@function
718 GNAME(alloc_overflow_edx):
719 pushl %eax # Save eax
720 pushl %ecx # Save ecx
721 /* Calculate the size for the allocation. */
722 subl START_REGION,%edx
723 pushl %edx # Push the size
725 addl $4,%esp # pop the size arg.
726 movl %eax,%edx # setup the destination.
727 popl %ecx # Restore ecx.
728 popl %eax # Restore eax.
729 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
731 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
733 /* This routine handles an overflow with ebx=crfp+size. So the
736 .globl GNAME(alloc_overflow_ebx)
737 .type GNAME(alloc_overflow_ebx),@function
738 GNAME(alloc_overflow_ebx):
739 pushl %eax # Save eax
740 pushl %ecx # Save ecx
741 pushl %edx # Save edx
742 /* Calculate the size for the allocation. */
743 subl START_REGION,%ebx
744 pushl %ebx # Push the size
746 addl $4,%esp # pop the size arg.
747 movl %eax,%ebx # setup the destination.
748 popl %edx # Restore edx.
749 popl %ecx # Restore ecx.
750 popl %eax # Restore eax.
751 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
753 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
755 /* This routine handles an overflow with esi=crfp+size. So the
758 .globl GNAME(alloc_overflow_esi)
759 .type GNAME(alloc_overflow_esi),@function
760 GNAME(alloc_overflow_esi):
761 pushl %eax # Save eax
762 pushl %ecx # Save ecx
763 pushl %edx # Save edx
764 /* Calculate the size for the allocation. */
765 subl START_REGION,%esi
766 pushl %esi # Push the size
768 addl $4,%esp # pop the size arg.
769 movl %eax,%esi # setup the destination.
770 popl %edx # Restore edx.
771 popl %ecx # Restore ecx.
772 popl %eax # Restore eax.
773 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
775 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
778 .globl GNAME(alloc_overflow_edi)
779 .type GNAME(alloc_overflow_edi),@function
780 GNAME(alloc_overflow_edi):
781 pushl %eax # Save eax
782 pushl %ecx # Save ecx
783 pushl %edx # Save edx
784 /* Calculate the size for the allocation. */
785 subl START_REGION,%edi
786 pushl %edi # Push the size
788 addl $4,%esp # pop the size arg.
789 movl %eax,%edi # setup the destination.
790 popl %edx # Restore edx.
791 popl %ecx # Restore ecx.
792 popl %eax # Restore eax.
793 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
795 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)
797 .align align_4byte,0x90
798 .globl GNAME(post_signal_tramp)
799 .type GNAME(post_signal_tramp),@function
800 GNAME(post_signal_tramp):
801 /* this is notionally the second half of a function whose first half
802 * doesn't exist. This is where call_into_lisp returns when called
803 * using return_to_lisp_function */
804 addl $12,%esp /* clear call_into_lisp args from stack */
805 popa /* restore registers */
808 .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)