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. */
26 #if defined __linux__ || defined __FreeBSD__ /* (but *not* OpenBSD) */
27 #define GNAME(var) var
29 #define GNAME(var) _##var
32 /* Get the right type of alignment. Linux and FreeBSD (but not OpenBSD)
33 * want alignment in bytes. */
34 #if defined(__linux__) || defined(__FreeBSD__)
37 #define align_16byte 16
41 #define align_16byte 4
45 .global GNAME(foreign_function_call_active)
46 .global GNAME(all_threads)
50 * A call to call_into_c preserves esi, edi, and ebp.
51 * (The C function will preserve ebx, esi, edi, and ebp across its
52 * function call, but we trash ebx ourselves by using it to save the
53 * return Lisp address.)
55 * Return values are in eax and maybe edx for quads, or st(0) for
58 * This should work for Lisp calls C calls Lisp calls C..
61 .align align_16byte,0x90
62 .global GNAME(call_into_c)
63 .type GNAME(call_into_c),@function
65 movl $1,GNAME(foreign_function_call_active)
67 /* Save the return Lisp address in ebx. */
70 /* Setup the NPX for C */
80 call *%eax # normal callout using Lisp stack
82 movl %eax,%ecx # remember integer return value
84 /* Check for a return FP value. */
91 /* The return value is in eax, or eax,edx? */
92 /* Set up the NPX stack for Lisp. */
93 fldz # Ensure no regs are empty.
102 /* Restore the return value. */
103 movl %ecx,%eax # maybe return value
105 movl $0,GNAME(foreign_function_call_active)
110 /* The return result is in st(0). */
111 /* Set up the NPX stack for Lisp, placing the result in st(0). */
112 fldz # Ensure no regs are empty.
119 fxch %st(7) # Move the result back to st(0).
121 /* We don't need to restore eax, because the result is in st(0). */
123 movl $0,GNAME(foreign_function_call_active)
127 .size GNAME(call_into_c), . - GNAME(call_into_c)
131 .global GNAME(call_into_lisp_first_time)
132 .type GNAME(call_into_lisp_first_time),@function
134 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
135 * the stack changes. We don't worry too much about saving registers
136 * here, because we never expect to return from the initial call to lisp
139 .align align_16byte,0x90
140 GNAME(call_into_lisp_first_time):
141 pushl %ebp # Save old frame pointer.
142 movl %esp,%ebp # Establish new frame.
143 movl %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
144 movl GNAME(all_threads),%eax
145 movl THREAD_CONTROL_STACK_START_OFFSET(%eax) ,%esp
146 /* don't think too hard about what happens if we get interrupted
148 addl $THREAD_CONTROL_STACK_SIZE-4,%esp
152 .global GNAME(call_into_lisp)
153 .type GNAME(call_into_lisp),@function
155 /* The C conventions require that ebx, esi, edi, and ebp be preserved
156 * across function calls. */
158 .align align_16byte,0x90
159 GNAME(call_into_lisp):
160 pushl %ebp # Save old frame pointer.
161 movl %esp,%ebp # Establish new frame.
163 /* Save the NPX state */
164 fwait # Catch any pending NPX exceptions.
165 subl $108,%esp # Make room for the NPX state.
166 fnsave (%esp) # save and reset NPX
168 movl (%esp),%eax # Load NPX control word.
169 andl $0xfffff3ff,%eax # Set rounding mode to nearest.
170 orl $0x00000300,%eax # Set precision to 64 bits.
172 fldcw (%esp) # Recover modes.
175 fldz # Ensure no FP regs are empty.
184 /* Save C regs: ebx esi edi. */
189 /* Clear descriptor regs. */
190 xorl %eax,%eax # lexenv
191 xorl %ebx,%ebx # available
192 xorl %ecx,%ecx # arg count
193 xorl %edx,%edx # first arg
194 xorl %edi,%edi # second arg
195 xorl %esi,%esi # third arg
197 /* no longer in function call */
198 movl %eax, GNAME(foreign_function_call_active)
200 movl %esp,%ebx # remember current stack
201 pushl %ebx # Save entry stack on (maybe) new stack.
203 /* Establish Lisp args. */
204 movl 8(%ebp),%eax # lexenv?
205 movl 12(%ebp),%ebx # address of arg vec
206 movl 16(%ebp),%ecx # num args
207 shll $2,%ecx # Make num args into fixnum.
210 movl (%ebx),%edx # arg0
213 movl 4(%ebx),%edi # arg1
216 movl 8(%ebx),%esi # arg2
218 /* Registers eax, ecx, edx, edi, and esi are now live. */
220 /* Alloc new frame. */
221 mov %esp,%ebx # The current sp marks start of new frame.
222 push %ebp # fp in save location S0
223 sub $8,%esp # Ensure 3 slots are allocated, one above.
224 mov %ebx,%ebp # Switch to new frame.
226 call *CLOSURE_FUN_OFFSET(%eax)
228 /* If the function returned multiple values, it will return to
229 this point. Lose them */
231 /* A singled value function returns here */
233 /* Restore the stack, in case there was a stack change. */
236 /* Restore C regs: ebx esi edi. */
241 /* Restore the NPX state. */
246 movl %edx,%eax # c-val
248 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
250 /* support for saving and restoring the NPX state from C */
252 .global GNAME(fpu_save)
253 .type GNAME(fpu_save),@function
257 fnsave (%eax) # Save the NPX state. (resets NPX)
259 .size GNAME(fpu_save),.-GNAME(fpu_save)
261 .global GNAME(fpu_restore)
262 .type GNAME(fpu_restore),@function
266 frstor (%eax) # Restore the NPX state.
268 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
271 * the undefined-function trampoline
274 .align align_4byte,0x90
275 .global GNAME(undefined_tramp)
276 .type GNAME(undefined_tramp),@function
277 GNAME(undefined_tramp):
281 .byte UNDEFINED_FUN_ERROR
282 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
284 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
287 * the closure trampoline
290 .align align_4byte,0x90
291 .global GNAME(closure_tramp)
292 .type GNAME(closure_tramp),@function
293 GNAME(closure_tramp):
294 movl FDEFN_FUN_OFFSET(%eax),%eax
295 /* FIXME: The '*' after "jmp" in the next line is from PVE's
296 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
297 * reasonable, and it certainly seems as though if CMU CL needs it,
298 * SBCL needs it too, but I haven't actually verified that it's
299 * right. It would be good to find a way to force the flow of
300 * control through here to test it. */
301 jmp *CLOSURE_FUN_OFFSET(%eax)
302 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
305 * fun-end breakpoint magic
308 .global GNAME(fun_end_breakpoint_guts)
310 GNAME(fun_end_breakpoint_guts):
311 /* Multiple Value return */
312 jmp multiple_value_return
313 /* Single value return: The eventual return will now use the
314 multiple values return convention but with a return values
316 movl %esp,%ebx # Setup ebx - the ofp.
317 subl $4,%esp # Allocate one stack slot for the return value
318 movl $4,%ecx # Setup ecx for one return value.
319 movl $NIL,%edi # default second value
320 movl $NIL,%esi # default third value
322 multiple_value_return:
324 .global GNAME(fun_end_breakpoint_trap)
325 GNAME(fun_end_breakpoint_trap):
327 .byte trap_FunEndBreakpoint
328 hlt # We should never return here.
330 .global GNAME(fun_end_breakpoint_end)
331 GNAME(fun_end_breakpoint_end):
334 .global GNAME(do_pending_interrupt)
335 .type GNAME(do_pending_interrupt),@function
336 .align align_4byte,0x90
337 GNAME(do_pending_interrupt):
339 .byte trap_PendingInterrupt
341 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
343 #ifdef LISP_FEATURE_GENCGC
344 /* This is a fast bzero using the FPU. The first argument is the start
345 * address which needs to be aligned on an 8 byte boundary, the second
346 * argument is the number of bytes, which must be a nonzero multiple
348 /* FIXME whether this is still faster than using the OS's bzero or
349 * equivalent, we don't know */
351 .globl GNAME(i586_bzero)
352 .type GNAME(i586_bzero),@function
353 .align align_4byte,0x90
355 movl 4(%esp),%edx # Load the start address.
356 movl 8(%esp),%eax # Load the number of bytes.
364 .size GNAME(i586_bzero),.-GNAME(i586_bzero)
369 * Allocate bytes and return the start of the allocated space
370 * in the specified destination register.
372 * In the general case the size will be in the destination register.
374 * All registers must be preserved except the destination.
375 * The C conventions will preserve ebx, esi, edi, and ebp.
376 * So only eax, ecx, and edx need special care here.
379 .globl GNAME(alloc_to_eax)
380 .type GNAME(alloc_to_eax),@function
381 .align align_4byte,0x90
383 pushl %ecx # Save ecx and edx as C could destroy them.
385 pushl %eax # Push the size.
387 addl $4,%esp # Pop the size arg.
388 popl %edx # Restore ecx and edx.
391 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
393 .globl GNAME(alloc_8_to_eax)
394 .type GNAME(alloc_8_to_eax),@function
395 .align align_4byte,0x90
396 GNAME(alloc_8_to_eax):
397 pushl %ecx # Save ecx and edx as C could destroy them.
399 pushl $8 # Push the size.
401 addl $4,%esp # Pop the size arg.
402 popl %edx # Restore ecx and edx.
405 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
407 .globl GNAME(alloc_8_to_eax)
408 .type GNAME(alloc_8_to_eax),@function
409 .align align_4byte,0x90
411 .globl GNAME(alloc_16_to_eax)
412 .type GNAME(alloc_16_to_eax),@function
413 .align align_4byte,0x90
414 GNAME(alloc_16_to_eax):
415 pushl %ecx # Save ecx and edx as C could destroy them.
417 pushl $16 # Push the size.
419 addl $4,%esp # Pop the size arg.
420 popl %edx # Restore ecx and edx.
423 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
425 .globl GNAME(alloc_to_ecx)
426 .type GNAME(alloc_to_ecx),@function
427 .align align_4byte,0x90
429 pushl %eax # Save eax and edx as C could destroy them.
431 pushl %ecx # Push the size.
433 addl $4,%esp # Pop the size arg.
434 movl %eax,%ecx # Set up the destination.
435 popl %edx # Restore eax and edx.
438 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
440 .globl GNAME(alloc_8_to_ecx)
441 .type GNAME(alloc_8_to_ecx),@function
442 .align align_4byte,0x90
443 GNAME(alloc_8_to_ecx):
444 pushl %eax # Save eax and edx as C could destroy them.
446 pushl $8 # Push the size.
448 addl $4,%esp # Pop the size arg.
449 movl %eax,%ecx # Set up the destination.
450 popl %edx # Restore eax and edx.
453 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
455 .globl GNAME(alloc_16_to_ecx)
456 .type GNAME(alloc_16_to_ecx),@function
457 .align align_4byte,0x90
458 GNAME(alloc_16_to_ecx):
459 pushl %eax # Save eax and edx as C could destroy them.
461 pushl $16 # Push the size.
463 addl $4,%esp # Pop the size arg.
464 movl %eax,%ecx # Set up the destination.
465 popl %edx # Restore eax and edx.
468 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
471 .globl GNAME(alloc_to_edx)
472 .type GNAME(alloc_to_edx),@function
473 .align align_4byte,0x90
475 pushl %eax # Save eax and ecx as C could destroy them.
477 pushl %edx # Push the size.
479 addl $4,%esp # Pop the size arg.
480 movl %eax,%edx # Set up the destination.
481 popl %ecx # Restore eax and ecx.
484 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
486 .globl GNAME(alloc_8_to_edx)
487 .type GNAME(alloc_8_to_edx),@function
488 .align align_4byte,0x90
489 GNAME(alloc_8_to_edx):
490 pushl %eax # Save eax and ecx as C could destroy them.
492 pushl $8 # Push the size.
494 addl $4,%esp # Pop the size arg.
495 movl %eax,%edx # Set up the destination.
496 popl %ecx # Restore eax and ecx.
499 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
501 .globl GNAME(alloc_16_to_edx)
502 .type GNAME(alloc_16_to_edx),@function
503 .align align_4byte,0x90
504 GNAME(alloc_16_to_edx):
505 pushl %eax # Save eax and ecx as C could destroy them.
507 pushl $16 # Push the size.
509 addl $4,%esp # Pop the size arg.
510 movl %eax,%edx # Set up the destination.
511 popl %ecx # Restore eax and ecx.
514 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
518 .globl GNAME(alloc_to_ebx)
519 .type GNAME(alloc_to_ebx),@function
520 .align align_4byte,0x90
522 pushl %eax # Save eax, ecx, and edx as C could destroy them.
525 pushl %ebx # Push the size.
527 addl $4,%esp # Pop the size arg.
528 movl %eax,%ebx # Set up the destination.
529 popl %edx # Restore eax, ecx and edx.
533 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
535 .globl GNAME(alloc_8_to_ebx)
536 .type GNAME(alloc_8_to_ebx),@function
537 .align align_4byte,0x90
538 GNAME(alloc_8_to_ebx):
539 pushl %eax # Save eax, ecx, and edx as C could destroy them.
542 pushl $8 # Push the size.
544 addl $4,%esp # Pop the size arg.
545 movl %eax,%ebx # Set up the destination.
546 popl %edx # Restore eax, ecx and edx.
550 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
552 .globl GNAME(alloc_16_to_ebx)
553 .type GNAME(alloc_16_to_ebx),@function
554 .align align_4byte,0x90
555 GNAME(alloc_16_to_ebx):
556 pushl %eax # Save eax, ecx, and edx as C could destroy them.
559 pushl $16 # Push the size
561 addl $4,%esp # pop the size arg.
562 movl %eax,%ebx # setup the destination.
563 popl %edx # Restore eax, ecx and edx.
567 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
571 .globl GNAME(alloc_to_esi)
572 .type GNAME(alloc_to_esi),@function
573 .align align_4byte,0x90
575 pushl %eax # Save eax, ecx, and edx as C could destroy them.
578 pushl %esi # Push the size
580 addl $4,%esp # pop the size arg.
581 movl %eax,%esi # setup the destination.
582 popl %edx # Restore eax, ecx and edx.
586 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
588 .globl GNAME(alloc_8_to_esi)
589 .type GNAME(alloc_8_to_esi),@function
590 .align align_4byte,0x90
591 GNAME(alloc_8_to_esi):
592 pushl %eax # Save eax, ecx, and edx as C could destroy them.
595 pushl $8 # Push the size
597 addl $4,%esp # pop the size arg.
598 movl %eax,%esi # setup the destination.
599 popl %edx # Restore eax, ecx and edx.
603 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
605 .globl GNAME(alloc_16_to_esi)
606 .type GNAME(alloc_16_to_esi),@function
607 .align align_4byte,0x90
608 GNAME(alloc_16_to_esi):
609 pushl %eax # Save eax, ecx, and edx as C could destroy them.
612 pushl $16 # Push the size
614 addl $4,%esp # pop the size arg.
615 movl %eax,%esi # setup the destination.
616 popl %edx # Restore eax, ecx and edx.
620 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
623 .globl GNAME(alloc_to_edi)
624 .type GNAME(alloc_to_edi),@function
625 .align align_4byte,0x90
627 pushl %eax # Save eax, ecx, and edx as C could destroy them.
630 pushl %edi # Push the size
632 addl $4,%esp # pop the size arg.
633 movl %eax,%edi # setup the destination.
634 popl %edx # Restore eax, ecx and edx.
638 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
640 .globl GNAME(alloc_8_to_edi)
641 .type GNAME(alloc_8_to_edi),@function
642 .align align_4byte,0x90
643 GNAME(alloc_8_to_edi):
644 pushl %eax # Save eax, ecx, and edx as C could destroy them.
647 pushl $8 # Push the size
649 addl $4,%esp # pop the size arg.
650 movl %eax,%edi # setup the destination.
651 popl %edx # Restore eax, ecx and edx.
655 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
657 .globl GNAME(alloc_16_to_edi)
658 .type GNAME(alloc_16_to_edi),@function
659 .align align_4byte,0x90
660 GNAME(alloc_16_to_edi):
661 pushl %eax # Save eax, ecx, and edx as C could destroy them.
664 pushl $16 # Push the size
666 addl $4,%esp # pop the size arg.
667 movl %eax,%edi # setup the destination.
668 popl %edx # Restore eax, ecx and edx.
672 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
675 .align align_4byte,0x90
676 .globl GNAME(post_signal_tramp)
677 .type GNAME(post_signal_tramp),@function
678 GNAME(post_signal_tramp):
679 /* this is notionally the second half of a function whose first half
680 * doesn't exist. This is where call_into_lisp returns when called
681 * using return_to_lisp_function */
682 addl $12,%esp /* clear call_into_lisp args from stack */
683 popa /* restore registers */
686 .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)
690 #ifdef GENCGC_INLINE_ALLOC /* LISP_FEATURE_GENCGC */
692 /* These routines are called from Lisp when an inline allocation
693 * overflows. Every register except the result needs to be preserved.
694 * We depend on C to preserve ebx, esi, edi, and ebp.
695 * But where necessary must save eax, ecx, edx. */
697 /* This routine handles an overflow with eax=crfp+size. So the
700 .globl GNAME(alloc_overflow_eax)
701 .type GNAME(alloc_overflow_eax),@function
702 GNAME(alloc_overflow_eax):
703 pushl %ecx # Save ecx
704 pushl %edx # Save edx
705 /* Calculate the size for the allocation. */
706 subl GNAME(current_region_free_pointer),%eax
707 pushl %eax # Push the size
709 addl $4,%esp # pop the size arg.
710 popl %edx # Restore edx.
711 popl %ecx # Restore ecx.
712 addl $6,(%esp) # Adjust the return address to skip the next inst.
714 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
716 /* This routine handles an overflow with ecx=crfp+size. So the
719 .globl GNAME(alloc_overflow_ecx)
720 .type GNAME(alloc_overflow_ecx),@function
721 GNAME(alloc_overflow_ecx):
722 pushl %eax # Save eax
723 pushl %edx # Save edx
724 /* Calculate the size for the allocation. */
725 subl GNAME(current_region_free_pointer),%ecx
726 pushl %ecx # Push the size
728 addl $4,%esp # pop the size arg.
729 movl %eax,%ecx # setup the destination.
730 popl %edx # Restore edx.
731 popl %eax # Restore eax.
732 addl $6,(%esp) # Adjust the return address to skip the next inst.
734 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
736 /* This routine handles an overflow with edx=crfp+size. So the
739 .globl GNAME(alloc_overflow_edx)
740 .type GNAME(alloc_overflow_edx),@function
741 GNAME(alloc_overflow_edx):
742 pushl %eax # Save eax
743 pushl %ecx # Save ecx
744 /* Calculate the size for the allocation. */
745 subl GNAME(current_region_free_pointer),%edx
746 pushl %edx # Push the size
748 addl $4,%esp # pop the size arg.
749 movl %eax,%edx # setup the destination.
750 popl %ecx # Restore ecx.
751 popl %eax # Restore eax.
752 addl $6,(%esp) # Adjust the return address to skip the next inst.
754 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
756 /* This routine handles an overflow with ebx=crfp+size. So the
759 .globl GNAME(alloc_overflow_ebx)
760 .type GNAME(alloc_overflow_ebx),@function
761 GNAME(alloc_overflow_ebx):
762 pushl %eax # Save eax
763 pushl %ecx # Save ecx
764 pushl %edx # Save edx
765 /* Calculate the size for the allocation. */
766 subl GNAME(current_region_free_pointer),%ebx
767 pushl %ebx # Push the size
769 addl $4,%esp # pop the size arg.
770 movl %eax,%ebx # setup the destination.
771 popl %edx # Restore edx.
772 popl %ecx # Restore ecx.
773 popl %eax # Restore eax.
774 addl $6,(%esp) # Adjust the return address to skip the next inst.
776 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
778 /* This routine handles an overflow with esi=crfp+size. So the
781 .globl GNAME(alloc_overflow_esi)
782 .type GNAME(alloc_overflow_esi),@function
783 GNAME(alloc_overflow_esi):
784 pushl %eax # Save eax
785 pushl %ecx # Save ecx
786 pushl %edx # Save edx
787 /* Calculate the size for the allocation. */
788 subl GNAME(current_region_free_pointer),%esi
789 pushl %esi # Push the size
791 addl $4,%esp # pop the size arg.
792 movl %eax,%esi # setup the destination.
793 popl %edx # Restore edx.
794 popl %ecx # Restore ecx.
795 popl %eax # Restore eax.
796 addl $6,(%esp) # Adjust the return address to skip the next inst.
798 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
800 /* This routine handles an overflow with edi=crfp+size. So the
803 .globl GNAME(alloc_overflow_edi)
804 .type GNAME(alloc_overflow_edi),@function
805 GNAME(alloc_overflow_edi):
806 pushl %eax # Save eax
807 pushl %ecx # Save ecx
808 pushl %edx # Save edx
809 /* Calculate the size for the allocation. */
810 subl GNAME(current_region_free_pointer),%edi
811 pushl %edi # Push the size
813 addl $4,%esp # pop the size arg.
814 movl %eax,%edi # setup the destination.
815 popl %edx # Restore edx.
816 popl %ecx # Restore ecx.
817 popl %eax # Restore eax.
818 addl $6,(%esp) # Adjust the return address to skip the next inst.
820 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)