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 GNAME(undefined_tramp):
293 .byte UNDEFINED_FUN_ERROR
294 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
296 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
299 * the closure trampoline
302 .align align_4byte,0x90
303 .global GNAME(closure_tramp)
304 .type GNAME(closure_tramp),@function
305 GNAME(closure_tramp):
306 movl FDEFN_FUN_OFFSET(%eax),%eax
307 /* FIXME: The '*' after "jmp" in the next line is from PVE's
308 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
309 * reasonable, and it certainly seems as though if CMU CL needs it,
310 * SBCL needs it too, but I haven't actually verified that it's
311 * right. It would be good to find a way to force the flow of
312 * control through here to test it. */
313 jmp *CLOSURE_FUN_OFFSET(%eax)
314 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
317 * fun-end breakpoint magic
320 .global GNAME(fun_end_breakpoint_guts)
322 GNAME(fun_end_breakpoint_guts):
323 /* Multiple Value return */
324 jmp multiple_value_return
325 /* Single value return: The eventual return will now use the
326 multiple values return convention but with a return values
328 movl %esp,%ebx # Setup ebx - the ofp.
329 subl $4,%esp # Allocate one stack slot for the return value
330 movl $4,%ecx # Setup ecx for one return value.
331 movl $NIL,%edi # default second value
332 movl $NIL,%esi # default third value
334 multiple_value_return:
336 .global GNAME(fun_end_breakpoint_trap)
337 GNAME(fun_end_breakpoint_trap):
339 .byte trap_FunEndBreakpoint
340 hlt # We should never return here.
342 .global GNAME(fun_end_breakpoint_end)
343 GNAME(fun_end_breakpoint_end):
346 .global GNAME(do_pending_interrupt)
347 .type GNAME(do_pending_interrupt),@function
348 .align align_4byte,0x90
349 GNAME(do_pending_interrupt):
351 .byte trap_PendingInterrupt
353 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
357 * Allocate bytes and return the start of the allocated space
358 * in the specified destination register.
360 * In the general case the size will be in the destination register.
362 * All registers must be preserved except the destination.
363 * The C conventions will preserve ebx, esi, edi, and ebp.
364 * So only eax, ecx, and edx need special care here.
367 .globl GNAME(alloc_to_eax)
368 .type GNAME(alloc_to_eax),@function
369 .align align_4byte,0x90
371 pushl %ecx # Save ecx and edx as C could destroy them.
373 pushl %eax # Push the size.
375 addl $4,%esp # Pop the size arg.
376 popl %edx # Restore ecx and edx.
379 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
381 .globl GNAME(alloc_8_to_eax)
382 .type GNAME(alloc_8_to_eax),@function
383 .align align_4byte,0x90
384 GNAME(alloc_8_to_eax):
385 pushl %ecx # Save ecx and edx as C could destroy them.
387 pushl $8 # Push the size.
389 addl $4,%esp # Pop the size arg.
390 popl %edx # Restore ecx and edx.
393 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
395 .globl GNAME(alloc_8_to_eax)
396 .type GNAME(alloc_8_to_eax),@function
397 .align align_4byte,0x90
399 .globl GNAME(alloc_16_to_eax)
400 .type GNAME(alloc_16_to_eax),@function
401 .align align_4byte,0x90
402 GNAME(alloc_16_to_eax):
403 pushl %ecx # Save ecx and edx as C could destroy them.
405 pushl $16 # Push the size.
407 addl $4,%esp # Pop the size arg.
408 popl %edx # Restore ecx and edx.
411 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
413 .globl GNAME(alloc_to_ecx)
414 .type GNAME(alloc_to_ecx),@function
415 .align align_4byte,0x90
417 pushl %eax # Save eax and edx as C could destroy them.
419 pushl %ecx # Push the size.
421 addl $4,%esp # Pop the size arg.
422 movl %eax,%ecx # Set up the destination.
423 popl %edx # Restore eax and edx.
426 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
428 .globl GNAME(alloc_8_to_ecx)
429 .type GNAME(alloc_8_to_ecx),@function
430 .align align_4byte,0x90
431 GNAME(alloc_8_to_ecx):
432 pushl %eax # Save eax and edx as C could destroy them.
434 pushl $8 # Push the size.
436 addl $4,%esp # Pop the size arg.
437 movl %eax,%ecx # Set up the destination.
438 popl %edx # Restore eax and edx.
441 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
443 .globl GNAME(alloc_16_to_ecx)
444 .type GNAME(alloc_16_to_ecx),@function
445 .align align_4byte,0x90
446 GNAME(alloc_16_to_ecx):
447 pushl %eax # Save eax and edx as C could destroy them.
449 pushl $16 # Push the size.
451 addl $4,%esp # Pop the size arg.
452 movl %eax,%ecx # Set up the destination.
453 popl %edx # Restore eax and edx.
456 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
459 .globl GNAME(alloc_to_edx)
460 .type GNAME(alloc_to_edx),@function
461 .align align_4byte,0x90
463 pushl %eax # Save eax and ecx as C could destroy them.
465 pushl %edx # Push the size.
467 addl $4,%esp # Pop the size arg.
468 movl %eax,%edx # Set up the destination.
469 popl %ecx # Restore eax and ecx.
472 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
474 .globl GNAME(alloc_8_to_edx)
475 .type GNAME(alloc_8_to_edx),@function
476 .align align_4byte,0x90
477 GNAME(alloc_8_to_edx):
478 pushl %eax # Save eax and ecx as C could destroy them.
480 pushl $8 # Push the size.
482 addl $4,%esp # Pop the size arg.
483 movl %eax,%edx # Set up the destination.
484 popl %ecx # Restore eax and ecx.
487 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
489 .globl GNAME(alloc_16_to_edx)
490 .type GNAME(alloc_16_to_edx),@function
491 .align align_4byte,0x90
492 GNAME(alloc_16_to_edx):
493 pushl %eax # Save eax and ecx as C could destroy them.
495 pushl $16 # Push the size.
497 addl $4,%esp # Pop the size arg.
498 movl %eax,%edx # Set up the destination.
499 popl %ecx # Restore eax and ecx.
502 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
506 .globl GNAME(alloc_to_ebx)
507 .type GNAME(alloc_to_ebx),@function
508 .align align_4byte,0x90
510 pushl %eax # Save eax, ecx, and edx as C could destroy them.
513 pushl %ebx # Push the size.
515 addl $4,%esp # Pop the size arg.
516 movl %eax,%ebx # Set up the destination.
517 popl %edx # Restore eax, ecx and edx.
521 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
523 .globl GNAME(alloc_8_to_ebx)
524 .type GNAME(alloc_8_to_ebx),@function
525 .align align_4byte,0x90
526 GNAME(alloc_8_to_ebx):
527 pushl %eax # Save eax, ecx, and edx as C could destroy them.
530 pushl $8 # Push the size.
532 addl $4,%esp # Pop the size arg.
533 movl %eax,%ebx # Set up the destination.
534 popl %edx # Restore eax, ecx and edx.
538 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
540 .globl GNAME(alloc_16_to_ebx)
541 .type GNAME(alloc_16_to_ebx),@function
542 .align align_4byte,0x90
543 GNAME(alloc_16_to_ebx):
544 pushl %eax # Save eax, ecx, and edx as C could destroy them.
547 pushl $16 # Push the size
549 addl $4,%esp # pop the size arg.
550 movl %eax,%ebx # setup the destination.
551 popl %edx # Restore eax, ecx and edx.
555 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
559 .globl GNAME(alloc_to_esi)
560 .type GNAME(alloc_to_esi),@function
561 .align align_4byte,0x90
563 pushl %eax # Save eax, ecx, and edx as C could destroy them.
566 pushl %esi # Push the size
568 addl $4,%esp # pop the size arg.
569 movl %eax,%esi # setup the destination.
570 popl %edx # Restore eax, ecx and edx.
574 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
576 .globl GNAME(alloc_8_to_esi)
577 .type GNAME(alloc_8_to_esi),@function
578 .align align_4byte,0x90
579 GNAME(alloc_8_to_esi):
580 pushl %eax # Save eax, ecx, and edx as C could destroy them.
583 pushl $8 # Push the size
585 addl $4,%esp # pop the size arg.
586 movl %eax,%esi # setup the destination.
587 popl %edx # Restore eax, ecx and edx.
591 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
593 .globl GNAME(alloc_16_to_esi)
594 .type GNAME(alloc_16_to_esi),@function
595 .align align_4byte,0x90
596 GNAME(alloc_16_to_esi):
597 pushl %eax # Save eax, ecx, and edx as C could destroy them.
600 pushl $16 # Push the size
602 addl $4,%esp # pop the size arg.
603 movl %eax,%esi # setup the destination.
604 popl %edx # Restore eax, ecx and edx.
608 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
611 .globl GNAME(alloc_to_edi)
612 .type GNAME(alloc_to_edi),@function
613 .align align_4byte,0x90
615 pushl %eax # Save eax, ecx, and edx as C could destroy them.
618 pushl %edi # Push the size
620 addl $4,%esp # pop the size arg.
621 movl %eax,%edi # setup the destination.
622 popl %edx # Restore eax, ecx and edx.
626 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
628 .globl GNAME(alloc_8_to_edi)
629 .type GNAME(alloc_8_to_edi),@function
630 .align align_4byte,0x90
631 GNAME(alloc_8_to_edi):
632 pushl %eax # Save eax, ecx, and edx as C could destroy them.
635 pushl $8 # Push the size
637 addl $4,%esp # pop the size arg.
638 movl %eax,%edi # setup the destination.
639 popl %edx # Restore eax, ecx and edx.
643 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
645 .globl GNAME(alloc_16_to_edi)
646 .type GNAME(alloc_16_to_edi),@function
647 .align align_4byte,0x90
648 GNAME(alloc_16_to_edi):
649 pushl %eax # Save eax, ecx, and edx as C could destroy them.
652 pushl $16 # Push the size
654 addl $4,%esp # pop the size arg.
655 movl %eax,%edi # setup the destination.
656 popl %edx # Restore eax, ecx and edx.
660 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
663 .align align_4byte,0x90
664 .globl GNAME(post_signal_tramp)
665 .type GNAME(post_signal_tramp),@function
666 GNAME(post_signal_tramp):
667 /* this is notionally the second half of a function whose first half
668 * doesn't exist. This is where call_into_lisp returns when called
669 * using return_to_lisp_function */
670 addl $12,%esp /* clear call_into_lisp args from stack */
671 popa /* restore registers */
674 .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)
678 #ifdef GENCGC_INLINE_ALLOC /* LISP_FEATURE_GENCGC */
680 /* These routines are called from Lisp when an inline allocation
681 * overflows. Every register except the result needs to be preserved.
682 * We depend on C to preserve ebx, esi, edi, and ebp.
683 * But where necessary must save eax, ecx, edx. */
685 /* This routine handles an overflow with eax=crfp+size. So the
688 .globl GNAME(alloc_overflow_eax)
689 .type GNAME(alloc_overflow_eax),@function
690 GNAME(alloc_overflow_eax):
691 pushl %ecx # Save ecx
692 pushl %edx # Save edx
693 /* Calculate the size for the allocation. */
694 subl GNAME(current_region_free_pointer),%eax
695 pushl %eax # Push the size
697 addl $4,%esp # pop the size arg.
698 popl %edx # Restore edx.
699 popl %ecx # Restore ecx.
700 addl $6,(%esp) # Adjust the return address to skip the next inst.
702 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
704 /* This routine handles an overflow with ecx=crfp+size. So the
707 .globl GNAME(alloc_overflow_ecx)
708 .type GNAME(alloc_overflow_ecx),@function
709 GNAME(alloc_overflow_ecx):
710 pushl %eax # Save eax
711 pushl %edx # Save edx
712 /* Calculate the size for the allocation. */
713 subl GNAME(current_region_free_pointer),%ecx
714 pushl %ecx # Push the size
716 addl $4,%esp # pop the size arg.
717 movl %eax,%ecx # setup the destination.
718 popl %edx # Restore edx.
719 popl %eax # Restore eax.
720 addl $6,(%esp) # Adjust the return address to skip the next inst.
722 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
724 /* This routine handles an overflow with edx=crfp+size. So the
727 .globl GNAME(alloc_overflow_edx)
728 .type GNAME(alloc_overflow_edx),@function
729 GNAME(alloc_overflow_edx):
730 pushl %eax # Save eax
731 pushl %ecx # Save ecx
732 /* Calculate the size for the allocation. */
733 subl GNAME(current_region_free_pointer),%edx
734 pushl %edx # Push the size
736 addl $4,%esp # pop the size arg.
737 movl %eax,%edx # setup the destination.
738 popl %ecx # Restore ecx.
739 popl %eax # Restore eax.
740 addl $6,(%esp) # Adjust the return address to skip the next inst.
742 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
744 /* This routine handles an overflow with ebx=crfp+size. So the
747 .globl GNAME(alloc_overflow_ebx)
748 .type GNAME(alloc_overflow_ebx),@function
749 GNAME(alloc_overflow_ebx):
750 pushl %eax # Save eax
751 pushl %ecx # Save ecx
752 pushl %edx # Save edx
753 /* Calculate the size for the allocation. */
754 subl GNAME(current_region_free_pointer),%ebx
755 pushl %ebx # Push the size
757 addl $4,%esp # pop the size arg.
758 movl %eax,%ebx # setup the destination.
759 popl %edx # Restore edx.
760 popl %ecx # Restore ecx.
761 popl %eax # Restore eax.
762 addl $6,(%esp) # Adjust the return address to skip the next inst.
764 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
766 /* This routine handles an overflow with esi=crfp+size. So the
769 .globl GNAME(alloc_overflow_esi)
770 .type GNAME(alloc_overflow_esi),@function
771 GNAME(alloc_overflow_esi):
772 pushl %eax # Save eax
773 pushl %ecx # Save ecx
774 pushl %edx # Save edx
775 /* Calculate the size for the allocation. */
776 subl GNAME(current_region_free_pointer),%esi
777 pushl %esi # Push the size
779 addl $4,%esp # pop the size arg.
780 movl %eax,%esi # setup the destination.
781 popl %edx # Restore edx.
782 popl %ecx # Restore ecx.
783 popl %eax # Restore eax.
784 addl $6,(%esp) # Adjust the return address to skip the next inst.
786 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
788 /* This routine handles an overflow with edi=crfp+size. So the
791 .globl GNAME(alloc_overflow_edi)
792 .type GNAME(alloc_overflow_edi),@function
793 GNAME(alloc_overflow_edi):
794 pushl %eax # Save eax
795 pushl %ecx # Save ecx
796 pushl %edx # Save edx
797 /* Calculate the size for the allocation. */
798 subl GNAME(current_region_free_pointer),%edi
799 pushl %edi # Push the size
801 addl $4,%esp # pop the size arg.
802 movl %eax,%edi # setup the destination.
803 popl %edx # Restore edx.
804 popl %ecx # Restore ecx.
805 popl %eax # Restore eax.
806 addl $6,(%esp) # Adjust the return address to skip the next inst.
808 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)