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"
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)
49 * A call to call_into_c preserves esi, edi, and ebp.
50 * (The C function will preserve ebx, esi, edi, and ebp across its
51 * function call, but we trash ebx ourselves by using it to save the
52 * return Lisp address.)
54 * Return values are in eax and maybe edx for quads, or st(0) for
57 * This should work for Lisp calls C calls Lisp calls C..
60 .align align_16byte,0x90
61 .global GNAME(call_into_c)
62 .type GNAME(call_into_c),@function
64 movl $1,GNAME(foreign_function_call_active)
66 /* Save the return Lisp address in ebx. */
69 /* Setup the NPX for C */
79 call *%eax # normal callout using Lisp stack
81 movl %eax,%ecx # remember integer return value
83 /* Check for a return FP value. */
90 /* The return value is in eax, or eax,edx? */
91 /* Set up the NPX stack for Lisp. */
92 fldz # Ensure no regs are empty.
101 /* Restore the return value. */
102 movl %ecx,%eax # maybe return value
104 movl $0,GNAME(foreign_function_call_active)
109 /* The return result is in st(0). */
110 /* Set up the NPX stack for Lisp, placing the result in st(0). */
111 fldz # Ensure no regs are empty.
118 fxch %st(7) # Move the result back to st(0).
120 /* We don't need to restore eax, because the result is in st(0). */
122 movl $0,GNAME(foreign_function_call_active)
126 .size GNAME(call_into_c), . - GNAME(call_into_c)
130 .global GNAME(call_into_lisp)
131 .type GNAME(call_into_lisp),@function
133 /* The C conventions require that ebx, esi, edi, and ebp be preserved
134 * across function calls. */
135 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
136 * the stack changes. */
138 .align align_16byte,0x90
139 GNAME(call_into_lisp):
140 pushl %ebp # Save old frame pointer.
141 movl %esp,%ebp # Establish new frame.
143 /* Save the NPX state */
144 fwait # Catch any pending NPX exceptions.
145 subl $108,%esp # Make room for the NPX state.
146 fnsave (%esp) # resets NPX
148 movl (%esp),%eax # Load NPX control word.
149 andl $0xfffff3ff,%eax # Set rounding mode to nearest.
150 orl $0x00000300,%eax # Set precision to 64 bits.
152 fldcw (%esp) # Recover modes.
155 fldz # Ensure no FP regs are empty.
164 /* Save C regs: ebx esi edi. */
169 /* Clear descriptor regs. */
170 xorl %eax,%eax # lexenv
171 xorl %ebx,%ebx # available
172 xorl %ecx,%ecx # arg count
173 xorl %edx,%edx # first arg
174 xorl %edi,%edi # second arg
175 xorl %esi,%esi # third arg
177 /* no longer in function call */
178 movl %eax, GNAME(foreign_function_call_active)
180 movl %esp,%ebx # remember current stack
181 cmpl $CONTROL_STACK_START,%esp
182 jbe ChangeToLispStack
183 cmpl $CONTROL_STACK_END,%esp
186 /* Setup the *alien-stack* pointer */
187 movl %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
188 movl $CONTROL_STACK_END,%esp # new stack
190 pushl %ebx # Save entry stack on (maybe) new stack.
192 /* Establish Lisp args. */
193 movl 8(%ebp),%eax # lexenv?
194 movl 12(%ebp),%ebx # address of arg vec
195 movl 16(%ebp),%ecx # num args
196 shll $2,%ecx # Make num args into fixnum.
199 movl (%ebx),%edx # arg0
202 movl 4(%ebx),%edi # arg1
205 movl 8(%ebx),%esi # arg2
207 /* Registers eax, ecx, edx, edi, and esi are now live. */
209 /* Alloc new frame. */
210 mov %esp,%ebx # The current sp marks start of new frame.
211 push %ebp # fp in save location S0
212 sub $8,%esp # Ensure 3 slots are allocated, one above.
213 mov %ebx,%ebp # Switch to new frame.
215 /* Indirect the closure. */
216 call *CLOSURE_FUN_OFFSET(%eax)
218 /* Multi-value return; blow off any extra values. */
220 /* single value return */
222 /* Restore the stack, in case there was a stack change. */
225 /* Restore C regs: ebx esi edi. */
230 /* Restore the NPX state. */
235 movl %edx,%eax # c-val
237 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
239 /* support for saving and restoring the NPX state from C */
241 .global GNAME(fpu_save)
242 .type GNAME(fpu_save),@function
246 fnsave (%eax) # Save the NPX state. (resets NPX)
248 .size GNAME(fpu_save),.-GNAME(fpu_save)
250 .global GNAME(fpu_restore)
251 .type GNAME(fpu_restore),@function
255 frstor (%eax) # Restore the NPX state.
257 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
260 * the undefined-function trampoline
263 .align align_4byte,0x90
264 .global GNAME(undefined_tramp)
265 .type GNAME(undefined_tramp),@function
266 GNAME(undefined_tramp):
270 .byte UNDEFINED_FUN_ERROR
271 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
273 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
276 * the closure trampoline
279 .align align_4byte,0x90
280 .global GNAME(closure_tramp)
281 .type GNAME(closure_tramp),@function
282 GNAME(closure_tramp):
283 movl FDEFN_FUN_OFFSET(%eax),%eax
284 /* FIXME: The '*' after "jmp" in the next line is from PVE's
285 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
286 * reasonable, and it certainly seems as though if CMU CL needs it,
287 * SBCL needs it too, but I haven't actually verified that it's
288 * right. It would be good to find a way to force the flow of
289 * control through here to test it. */
290 jmp *CLOSURE_FUN_OFFSET(%eax)
291 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
294 * fun-end breakpoint magic
297 .global GNAME(fun_end_breakpoint_guts)
299 GNAME(fun_end_breakpoint_guts):
300 /* Multiple Value return */
301 jmp multiple_value_return
302 /* Single value return: The eventual return will now use the
303 multiple values return convention but with a return values
305 movl %esp,%ebx # Setup ebx - the ofp.
306 subl $4,%esp # Allocate one stack slot for the return value
307 movl $4,%ecx # Setup ecx for one return value.
308 movl $NIL,%edi # default second value
309 movl $NIL,%esi # default third value
311 multiple_value_return:
313 .global GNAME(fun_end_breakpoint_trap)
314 GNAME(fun_end_breakpoint_trap):
316 .byte trap_FunEndBreakpoint
317 hlt # We should never return here.
319 .global GNAME(fun_end_breakpoint_end)
320 GNAME(fun_end_breakpoint_end):
323 .global GNAME(do_pending_interrupt)
324 .type GNAME(do_pending_interrupt),@function
325 .align align_4byte,0x90
326 GNAME(do_pending_interrupt):
328 .byte trap_PendingInterrupt
330 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
332 #ifdef LISP_FEATURE_GENCGC
333 /* This is a fast bzero using the FPU. The first argument is the start
334 * address which needs to be aligned on an 8 byte boundary, the second
335 * argument is the number of bytes, which must be a nonzero multiple
337 /* FIXME whether this is still faster than using the OS's bzero or
338 * equivalent, we don't know */
340 .globl GNAME(i586_bzero)
341 .type GNAME(i586_bzero),@function
342 .align align_4byte,0x90
344 movl 4(%esp),%edx # Load the start address.
345 movl 8(%esp),%eax # Load the number of bytes.
353 .size GNAME(i586_bzero),.-GNAME(i586_bzero)
358 * Allocate bytes and return the start of the allocated space
359 * in the specified destination register.
361 * In the general case the size will be in the destination register.
363 * All registers must be preserved except the destination.
364 * The C conventions will preserve ebx, esi, edi, and ebp.
365 * So only eax, ecx, and edx need special care here.
368 .globl GNAME(alloc_to_eax)
369 .type GNAME(alloc_to_eax),@function
370 .align align_4byte,0x90
372 pushl %ecx # Save ecx and edx as C could destroy them.
374 pushl %eax # Push the size.
376 addl $4,%esp # Pop the size arg.
377 popl %edx # Restore ecx and edx.
380 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
382 .globl GNAME(alloc_8_to_eax)
383 .type GNAME(alloc_8_to_eax),@function
384 .align align_4byte,0x90
385 GNAME(alloc_8_to_eax):
386 pushl %ecx # Save ecx and edx as C could destroy them.
388 pushl $8 # Push the size.
390 addl $4,%esp # Pop the size arg.
391 popl %edx # Restore ecx and edx.
394 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
396 .globl GNAME(alloc_8_to_eax)
397 .type GNAME(alloc_8_to_eax),@function
398 .align align_4byte,0x90
400 .globl GNAME(alloc_16_to_eax)
401 .type GNAME(alloc_16_to_eax),@function
402 .align align_4byte,0x90
403 GNAME(alloc_16_to_eax):
404 pushl %ecx # Save ecx and edx as C could destroy them.
406 pushl $16 # Push the size.
408 addl $4,%esp # Pop the size arg.
409 popl %edx # Restore ecx and edx.
412 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
414 .globl GNAME(alloc_to_ecx)
415 .type GNAME(alloc_to_ecx),@function
416 .align align_4byte,0x90
418 pushl %eax # Save eax and edx as C could destroy them.
420 pushl %ecx # Push the size.
422 addl $4,%esp # Pop the size arg.
423 movl %eax,%ecx # Set up the destination.
424 popl %edx # Restore eax and edx.
427 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
429 .globl GNAME(alloc_8_to_ecx)
430 .type GNAME(alloc_8_to_ecx),@function
431 .align align_4byte,0x90
432 GNAME(alloc_8_to_ecx):
433 pushl %eax # Save eax and edx as C could destroy them.
435 pushl $8 # Push the size.
437 addl $4,%esp # Pop the size arg.
438 movl %eax,%ecx # Set up the destination.
439 popl %edx # Restore eax and edx.
442 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
444 .globl GNAME(alloc_16_to_ecx)
445 .type GNAME(alloc_16_to_ecx),@function
446 .align align_4byte,0x90
447 GNAME(alloc_16_to_ecx):
448 pushl %eax # Save eax and edx as C could destroy them.
450 pushl $16 # Push the size.
452 addl $4,%esp # Pop the size arg.
453 movl %eax,%ecx # Set up the destination.
454 popl %edx # Restore eax and edx.
457 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
460 .globl GNAME(alloc_to_edx)
461 .type GNAME(alloc_to_edx),@function
462 .align align_4byte,0x90
464 pushl %eax # Save eax and ecx as C could destroy them.
466 pushl %edx # Push the size.
468 addl $4,%esp # Pop the size arg.
469 movl %eax,%edx # Set up the destination.
470 popl %ecx # Restore eax and ecx.
473 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
475 .globl GNAME(alloc_8_to_edx)
476 .type GNAME(alloc_8_to_edx),@function
477 .align align_4byte,0x90
478 GNAME(alloc_8_to_edx):
479 pushl %eax # Save eax and ecx as C could destroy them.
481 pushl $8 # Push the size.
483 addl $4,%esp # Pop the size arg.
484 movl %eax,%edx # Set up the destination.
485 popl %ecx # Restore eax and ecx.
488 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
490 .globl GNAME(alloc_16_to_edx)
491 .type GNAME(alloc_16_to_edx),@function
492 .align align_4byte,0x90
493 GNAME(alloc_16_to_edx):
494 pushl %eax # Save eax and ecx as C could destroy them.
496 pushl $16 # Push the size.
498 addl $4,%esp # Pop the size arg.
499 movl %eax,%edx # Set up the destination.
500 popl %ecx # Restore eax and ecx.
503 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
507 .globl GNAME(alloc_to_ebx)
508 .type GNAME(alloc_to_ebx),@function
509 .align align_4byte,0x90
511 pushl %eax # Save eax, ecx, and edx as C could destroy them.
514 pushl %ebx # Push the size.
516 addl $4,%esp # Pop the size arg.
517 movl %eax,%ebx # Set up the destination.
518 popl %edx # Restore eax, ecx and edx.
522 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
524 .globl GNAME(alloc_8_to_ebx)
525 .type GNAME(alloc_8_to_ebx),@function
526 .align align_4byte,0x90
527 GNAME(alloc_8_to_ebx):
528 pushl %eax # Save eax, ecx, and edx as C could destroy them.
531 pushl $8 # Push the size.
533 addl $4,%esp # Pop the size arg.
534 movl %eax,%ebx # Set up the destination.
535 popl %edx # Restore eax, ecx and edx.
539 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
541 .globl GNAME(alloc_16_to_ebx)
542 .type GNAME(alloc_16_to_ebx),@function
543 .align align_4byte,0x90
544 GNAME(alloc_16_to_ebx):
545 pushl %eax # Save eax, ecx, and edx as C could destroy them.
548 pushl $16 # Push the size
550 addl $4,%esp # pop the size arg.
551 movl %eax,%ebx # setup the destination.
552 popl %edx # Restore eax, ecx and edx.
556 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
560 .globl GNAME(alloc_to_esi)
561 .type GNAME(alloc_to_esi),@function
562 .align align_4byte,0x90
564 pushl %eax # Save eax, ecx, and edx as C could destroy them.
567 pushl %esi # Push the size
569 addl $4,%esp # pop the size arg.
570 movl %eax,%esi # setup the destination.
571 popl %edx # Restore eax, ecx and edx.
575 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
577 .globl GNAME(alloc_8_to_esi)
578 .type GNAME(alloc_8_to_esi),@function
579 .align align_4byte,0x90
580 GNAME(alloc_8_to_esi):
581 pushl %eax # Save eax, ecx, and edx as C could destroy them.
584 pushl $8 # Push the size
586 addl $4,%esp # pop the size arg.
587 movl %eax,%esi # setup the destination.
588 popl %edx # Restore eax, ecx and edx.
592 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
594 .globl GNAME(alloc_16_to_esi)
595 .type GNAME(alloc_16_to_esi),@function
596 .align align_4byte,0x90
597 GNAME(alloc_16_to_esi):
598 pushl %eax # Save eax, ecx, and edx as C could destroy them.
601 pushl $16 # Push the size
603 addl $4,%esp # pop the size arg.
604 movl %eax,%esi # setup the destination.
605 popl %edx # Restore eax, ecx and edx.
609 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
612 .globl GNAME(alloc_to_edi)
613 .type GNAME(alloc_to_edi),@function
614 .align align_4byte,0x90
616 pushl %eax # Save eax, ecx, and edx as C could destroy them.
619 pushl %edi # Push the size
621 addl $4,%esp # pop the size arg.
622 movl %eax,%edi # setup the destination.
623 popl %edx # Restore eax, ecx and edx.
627 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
629 .globl GNAME(alloc_8_to_edi)
630 .type GNAME(alloc_8_to_edi),@function
631 .align align_4byte,0x90
632 GNAME(alloc_8_to_edi):
633 pushl %eax # Save eax, ecx, and edx as C could destroy them.
636 pushl $8 # Push the size
638 addl $4,%esp # pop the size arg.
639 movl %eax,%edi # setup the destination.
640 popl %edx # Restore eax, ecx and edx.
644 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
646 .globl GNAME(alloc_16_to_edi)
647 .type GNAME(alloc_16_to_edi),@function
648 .align align_4byte,0x90
649 GNAME(alloc_16_to_edi):
650 pushl %eax # Save eax, ecx, and edx as C could destroy them.
653 pushl $16 # Push the size
655 addl $4,%esp # pop the size arg.
656 movl %eax,%edi # setup the destination.
657 popl %edx # Restore eax, ecx and edx.
661 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
665 #ifdef LISP_FEATURE_GENCGC_INLINE_ALLOC /* disabled at present */
667 /* These routines are called from Lisp when an inline allocation
668 * overflows. Every register except the result needs to be preserved.
669 * We depend on C to preserve ebx, esi, edi, and ebp.
670 * But where necessary must save eax, ecx, edx. */
672 /* This routine handles an overflow with eax=crfp+size. So the
675 .globl GNAME(alloc_overflow_eax)
676 .type GNAME(alloc_overflow_eax),@function
677 GNAME(alloc_overflow_eax):
678 pushl %ecx # Save ecx
679 pushl %edx # Save edx
680 /* Calculate the size for the allocation. */
681 subl GNAME(current_region_free_pointer),%eax
682 pushl %eax # Push the size
684 addl $4,%esp # pop the size arg.
685 popl %edx # Restore edx.
686 popl %ecx # Restore ecx.
687 addl $6,(%esp) # Adjust the return address to skip the next inst.
689 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
691 /* This routine handles an overflow with ecx=crfp+size. So the
694 .globl GNAME(alloc_overflow_ecx)
695 .type GNAME(alloc_overflow_ecx),@function
696 GNAME(alloc_overflow_ecx):
697 pushl %eax # Save eax
698 pushl %edx # Save edx
699 /* Calculate the size for the allocation. */
700 subl GNAME(current_region_free_pointer),%ecx
701 pushl %ecx # Push the size
703 addl $4,%esp # pop the size arg.
704 movl %eax,%ecx # setup the destination.
705 popl %edx # Restore edx.
706 popl %eax # Restore eax.
707 addl $6,(%esp) # Adjust the return address to skip the next inst.
709 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
711 /* This routine handles an overflow with edx=crfp+size. So the
714 .globl GNAME(alloc_overflow_edx)
715 .type GNAME(alloc_overflow_edx),@function
716 GNAME(alloc_overflow_edx):
717 pushl %eax # Save eax
718 pushl %ecx # Save ecx
719 /* Calculate the size for the allocation. */
720 subl GNAME(current_region_free_pointer),%edx
721 pushl %edx # Push the size
723 addl $4,%esp # pop the size arg.
724 movl %eax,%edx # setup the destination.
725 popl %ecx # Restore ecx.
726 popl %eax # Restore eax.
727 addl $6,(%esp) # Adjust the return address to skip the next inst.
729 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
731 /* This routine handles an overflow with ebx=crfp+size. So the
734 .globl GNAME(alloc_overflow_ebx)
735 .type GNAME(alloc_overflow_ebx),@function
736 GNAME(alloc_overflow_ebx):
737 pushl %eax # Save eax
738 pushl %ecx # Save ecx
739 pushl %edx # Save edx
740 /* Calculate the size for the allocation. */
741 subl GNAME(current_region_free_pointer),%ebx
742 pushl %ebx # Push the size
744 addl $4,%esp # pop the size arg.
745 movl %eax,%ebx # setup the destination.
746 popl %edx # Restore edx.
747 popl %ecx # Restore ecx.
748 popl %eax # Restore eax.
749 addl $6,(%esp) # Adjust the return address to skip the next inst.
751 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
753 /* This routine handles an overflow with esi=crfp+size. So the
756 .globl GNAME(alloc_overflow_esi)
757 .type GNAME(alloc_overflow_esi),@function
758 GNAME(alloc_overflow_esi):
759 pushl %eax # Save eax
760 pushl %ecx # Save ecx
761 pushl %edx # Save edx
762 /* Calculate the size for the allocation. */
763 subl GNAME(current_region_free_pointer),%esi
764 pushl %esi # Push the size
766 addl $4,%esp # pop the size arg.
767 movl %eax,%esi # setup the destination.
768 popl %edx # Restore edx.
769 popl %ecx # Restore ecx.
770 popl %eax # Restore eax.
771 addl $6,(%esp) # Adjust the return address to skip the next inst.
773 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
775 /* This routine handles an overflow with edi=crfp+size. So the
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 GNAME(current_region_free_pointer),%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 $6,(%esp) # Adjust the return address to skip the next inst.
795 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)