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
20 /* Minimize conditionalization for different OS naming schemes. */
21 #if defined __linux__ || defined __FreeBSD__ /* (but *not* OpenBSD) */
22 #define GNAME(var) var
24 #define GNAME(var) _##var
27 /* Get the right type of alignment. Linux and FreeBSD (but not OpenBSD)
28 * want alignment in bytes. */
29 #if defined(__linux__) || defined(__FreeBSD__)
32 #define align_16byte 16
36 #define align_16byte 4
40 .global GNAME(foreign_function_call_active)
44 * A call to call_into_c preserves esi, edi, and ebp.
45 * (The C function will preserve ebx, esi, edi, and ebp across its
46 * function call, but we trash ebx ourselves by using it to save the
47 * return Lisp address.)
49 * Return values are in eax and maybe edx for quads, or st(0) for
52 * This should work for Lisp calls C calls Lisp calls C..
55 .align align_16byte,0x90
56 .global GNAME(call_into_c)
57 .type GNAME(call_into_c),@function
59 movl $1,GNAME(foreign_function_call_active)
61 /* Save the return Lisp address in ebx. */
64 /* Setup the NPX for C */
74 call *%eax # normal callout using Lisp stack
76 movl %eax,%ecx # remember integer return value
78 /* Check for a return FP value. */
85 /* The return value is in eax, or eax,edx? */
86 /* Set up the NPX stack for Lisp. */
87 fldz # Ensure no regs are empty.
96 /* Restore the return value. */
97 movl %ecx,%eax # maybe return value
99 movl $0,GNAME(foreign_function_call_active)
104 /* The return result is in st(0). */
105 /* Set up the NPX stack for Lisp, placing the result in st(0). */
106 fldz # Ensure no regs are empty.
113 fxch %st(7) # Move the result back to st(0).
115 /* We don't need to restore eax, because the result is in st(0). */
117 movl $0,GNAME(foreign_function_call_active)
121 .size GNAME(call_into_c), . - GNAME(call_into_c)
125 .global GNAME(call_into_lisp)
126 .type GNAME(call_into_lisp),@function
128 /* The C conventions require that ebx, esi, edi, and ebp be preserved
129 * across function calls. */
130 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
131 * the stack changes. */
133 .align align_16byte,0x90
134 GNAME(call_into_lisp):
135 pushl %ebp # Save old frame pointer.
136 movl %esp,%ebp # Establish new frame.
138 /* Save the NPX state */
139 fwait # Catch any pending NPX exceptions.
140 subl $108,%esp # Make room for the NPX state.
141 fnsave (%esp) # resets NPX
143 movl (%esp),%eax # Load NPX control word.
144 andl $0xfffff3ff,%eax # Set rounding mode to nearest.
145 orl $0x00000300,%eax # Set precision to 64 bits.
147 fldcw (%esp) # Recover modes.
150 fldz # Ensure no FP regs are empty.
159 /* Save C regs: ebx esi edi. */
164 /* Clear descriptor regs. */
165 xorl %eax,%eax # lexenv
166 xorl %ebx,%ebx # available
167 xorl %ecx,%ecx # arg count
168 xorl %edx,%edx # first arg
169 xorl %edi,%edi # second arg
170 xorl %esi,%esi # third arg
172 /* no longer in function call */
173 movl %eax, GNAME(foreign_function_call_active)
175 movl %esp,%ebx # remember current stack
176 cmpl $CONTROL_STACK_START,%esp
177 jbe ChangeToLispStack
178 cmpl $CONTROL_STACK_END,%esp
181 /* Setup the *alien-stack* pointer */
182 movl %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
183 movl $CONTROL_STACK_END,%esp # new stack
185 pushl %ebx # Save entry stack on (maybe) new stack.
187 /* Establish Lisp args. */
188 movl 8(%ebp),%eax # lexenv?
189 movl 12(%ebp),%ebx # address of arg vec
190 movl 16(%ebp),%ecx # num args
191 shll $2,%ecx # Make num args into fixnum.
194 movl (%ebx),%edx # arg0
197 movl 4(%ebx),%edi # arg1
200 movl 8(%ebx),%esi # arg2
202 /* Registers eax, ecx, edx, edi, and esi are now live. */
204 /* Alloc new frame. */
205 mov %esp,%ebx # The current sp marks start of new frame.
206 push %ebp # fp in save location S0
207 sub $8,%esp # Ensure 3 slots are allocated, one above.
208 mov %ebx,%ebp # Switch to new frame.
210 /* Indirect the closure. */
211 call *CLOSURE_FUNCTION_OFFSET(%eax)
213 /* Multi-value return; blow off any extra values. */
215 /* single value return */
217 /* Restore the stack, in case there was a stack change. */
220 /* Restore C regs: ebx esi edi. */
225 /* Restore the NPX state. */
230 movl %edx,%eax # c-val
232 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
234 /* support for saving and restoring the NPX state from C */
236 .global GNAME(fpu_save)
237 .type GNAME(fpu_save),@function
241 fnsave (%eax) # Save the NPX state. (resets NPX)
243 .size GNAME(fpu_save),.-GNAME(fpu_save)
245 .global GNAME(fpu_restore)
246 .type GNAME(fpu_restore),@function
250 frstor (%eax) # Restore the NPX state.
252 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
255 * the undefined-function trampoline
258 .align align_4byte,0x90
259 .global GNAME(undefined_tramp)
260 .type GNAME(undefined_tramp),@function
261 GNAME(undefined_tramp):
265 #ifdef type_LongFloat
270 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
272 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
275 * the closure trampoline
278 .align align_4byte,0x90
279 .global GNAME(closure_tramp)
280 .type GNAME(closure_tramp),@function
281 GNAME(closure_tramp):
282 movl FDEFN_FUNCTION_OFFSET(%eax),%eax
283 /* FIXME: The '*' after "jmp" in the next line is from PVE's
284 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
285 * reasonable, and it certainly seems as though if CMU CL needs it,
286 * SBCL needs it too, but I haven't actually verified that it's
287 * right. It would be good to find a way to force the flow of
288 * control through here to test it. */
289 jmp *CLOSURE_FUNCTION_OFFSET(%eax)
290 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
293 * function-end breakpoint magic
296 .global GNAME(function_end_breakpoint_guts)
298 GNAME(function_end_breakpoint_guts):
299 /* Multiple Value return */
300 jmp multiple_value_return
301 /* Single value return: The eventual return will now use the
302 multiple values return convention but with a return values
304 movl %esp,%ebx # Setup ebx - the ofp.
305 subl $4,%esp # Allocate one stack slot for the return value
306 movl $4,%ecx # Setup ecx for one return value.
307 movl $NIL,%edi # default second value
308 movl $NIL,%esi # default third value
310 multiple_value_return:
312 .global GNAME(function_end_breakpoint_trap)
313 GNAME(function_end_breakpoint_trap):
315 .byte trap_FunctionEndBreakpoint
316 hlt # We should never return here.
318 .global GNAME(function_end_breakpoint_end)
319 GNAME(function_end_breakpoint_end):
322 .global GNAME(do_pending_interrupt)
323 .type GNAME(do_pending_interrupt),@function
324 .align align_4byte,0x90
325 GNAME(do_pending_interrupt):
327 .byte trap_PendingInterrupt
329 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
332 /* This is a copy function which is optimized for the Pentium and
333 * works OK on 486 as well. This assumes (does not check) that the
334 * input byte count is a multiple of 8 bytes (one Lisp object).
335 * This code takes advantage of pairing in the Pentium as well
336 * as the 128-bit cache line.
338 .global GNAME(fastcopy16)
339 .type GNAME(fastcopy16),@function
340 .align align_4byte,0x90
344 movl 8(%ebp), %edx # dst
345 movl 12(%ebp),%eax # src
346 movl 16(%ebp),%ecx # bytes
352 sarl $3,%ecx # number 8-byte units
361 Lquad: sarl $1,%ecx # count 16-byte units
363 movl %ecx,%ebp # use ebp for loop counter
364 .align align_16byte,0x90
366 movl (%edi),%eax # prefetch! MAJOR Pentium win..
378 jnz Ltop # non-prefixed jump saves cycles
385 .size GNAME(fastcopy16),.-GNAME(fastcopy16)
389 /* This is a fast bzero using the FPU. The first argument is the start
390 * address which needs to be aligned on an 8 byte boundary, the second
391 * argument is the number of bytes, which must be a nonzero multiple
394 .globl GNAME(i586_bzero)
395 .type GNAME(i586_bzero),@function
396 .align align_4byte,0x90
398 movl 4(%esp),%edx # Load the start address.
399 movl 8(%esp),%eax # Load the number of bytes.
407 .size GNAME(i586_bzero),.-GNAME(i586_bzero)
412 * Allocate bytes and return the start of the allocated space
413 * in the specified destination register.
415 * In the general case the size will be in the destination register.
417 * All registers must be preserved except the destination.
418 * The C conventions will preserve ebx, esi, edi, and ebp.
419 * So only eax, ecx, and edx need special care here.
422 .globl GNAME(alloc_to_eax)
423 .type GNAME(alloc_to_eax),@function
424 .align align_4byte,0x90
426 pushl %ecx # Save ecx and edx as C could destroy them.
428 pushl %eax # Push the size.
430 addl $4,%esp # Pop the size arg.
431 popl %edx # Restore ecx and edx.
434 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
436 .globl GNAME(alloc_8_to_eax)
437 .type GNAME(alloc_8_to_eax),@function
438 .align align_4byte,0x90
439 GNAME(alloc_8_to_eax):
440 pushl %ecx # Save ecx and edx as C could destroy them.
442 pushl $8 # Push the size.
444 addl $4,%esp # Pop the size arg.
445 popl %edx # Restore ecx and edx.
448 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
450 .globl GNAME(alloc_8_to_eax)
451 .type GNAME(alloc_8_to_eax),@function
452 .align align_4byte,0x90
454 .globl GNAME(alloc_16_to_eax)
455 .type GNAME(alloc_16_to_eax),@function
456 .align align_4byte,0x90
457 GNAME(alloc_16_to_eax):
458 pushl %ecx # Save ecx and edx as C could destroy them.
460 pushl $16 # Push the size.
462 addl $4,%esp # Pop the size arg.
463 popl %edx # Restore ecx and edx.
466 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
468 .globl GNAME(alloc_to_ecx)
469 .type GNAME(alloc_to_ecx),@function
470 .align align_4byte,0x90
472 pushl %eax # Save eax and edx as C could destroy them.
474 pushl %ecx # Push the size.
476 addl $4,%esp # Pop the size arg.
477 movl %eax,%ecx # Set up the destination.
478 popl %edx # Restore eax and edx.
481 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
483 .globl GNAME(alloc_8_to_ecx)
484 .type GNAME(alloc_8_to_ecx),@function
485 .align align_4byte,0x90
486 GNAME(alloc_8_to_ecx):
487 pushl %eax # Save eax and edx as C could destroy them.
489 pushl $8 # Push the size.
491 addl $4,%esp # Pop the size arg.
492 movl %eax,%ecx # Set up the destination.
493 popl %edx # Restore eax and edx.
496 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
498 .globl GNAME(alloc_16_to_ecx)
499 .type GNAME(alloc_16_to_ecx),@function
500 .align align_4byte,0x90
501 GNAME(alloc_16_to_ecx):
502 pushl %eax # Save eax and edx as C could destroy them.
504 pushl $16 # Push the size.
506 addl $4,%esp # Pop the size arg.
507 movl %eax,%ecx # Set up the destination.
508 popl %edx # Restore eax and edx.
511 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
514 .globl GNAME(alloc_to_edx)
515 .type GNAME(alloc_to_edx),@function
516 .align align_4byte,0x90
518 pushl %eax # Save eax and ecx as C could destroy them.
520 pushl %edx # Push the size.
522 addl $4,%esp # Pop the size arg.
523 movl %eax,%edx # Set up the destination.
524 popl %ecx # Restore eax and ecx.
527 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
529 .globl GNAME(alloc_8_to_edx)
530 .type GNAME(alloc_8_to_edx),@function
531 .align align_4byte,0x90
532 GNAME(alloc_8_to_edx):
533 pushl %eax # Save eax and ecx as C could destroy them.
535 pushl $8 # Push the size.
537 addl $4,%esp # Pop the size arg.
538 movl %eax,%edx # Set up the destination.
539 popl %ecx # Restore eax and ecx.
542 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
544 .globl GNAME(alloc_16_to_edx)
545 .type GNAME(alloc_16_to_edx),@function
546 .align align_4byte,0x90
547 GNAME(alloc_16_to_edx):
548 pushl %eax # Save eax and ecx as C could destroy them.
550 pushl $16 # Push the size.
552 addl $4,%esp # Pop the size arg.
553 movl %eax,%edx # Set up the destination.
554 popl %ecx # Restore eax and ecx.
557 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
561 .globl GNAME(alloc_to_ebx)
562 .type GNAME(alloc_to_ebx),@function
563 .align align_4byte,0x90
565 pushl %eax # Save eax, ecx, and edx as C could destroy them.
568 pushl %ebx # Push the size.
570 addl $4,%esp # Pop the size arg.
571 movl %eax,%ebx # Set up the destination.
572 popl %edx # Restore eax, ecx and edx.
576 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
578 .globl GNAME(alloc_8_to_ebx)
579 .type GNAME(alloc_8_to_ebx),@function
580 .align align_4byte,0x90
581 GNAME(alloc_8_to_ebx):
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,%ebx # Set up the destination.
589 popl %edx # Restore eax, ecx and edx.
593 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
595 .globl GNAME(alloc_16_to_ebx)
596 .type GNAME(alloc_16_to_ebx),@function
597 .align align_4byte,0x90
598 GNAME(alloc_16_to_ebx):
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,%ebx # setup the destination.
606 popl %edx # Restore eax, ecx and edx.
610 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
614 .globl GNAME(alloc_to_esi)
615 .type GNAME(alloc_to_esi),@function
616 .align align_4byte,0x90
618 pushl %eax # Save eax, ecx, and edx as C could destroy them.
621 pushl %esi # Push the size
623 addl $4,%esp # pop the size arg.
624 movl %eax,%esi # setup the destination.
625 popl %edx # Restore eax, ecx and edx.
629 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
631 .globl GNAME(alloc_8_to_esi)
632 .type GNAME(alloc_8_to_esi),@function
633 .align align_4byte,0x90
634 GNAME(alloc_8_to_esi):
635 pushl %eax # Save eax, ecx, and edx as C could destroy them.
638 pushl $8 # Push the size
640 addl $4,%esp # pop the size arg.
641 movl %eax,%esi # setup the destination.
642 popl %edx # Restore eax, ecx and edx.
646 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
648 .globl GNAME(alloc_16_to_esi)
649 .type GNAME(alloc_16_to_esi),@function
650 .align align_4byte,0x90
651 GNAME(alloc_16_to_esi):
652 pushl %eax # Save eax, ecx, and edx as C could destroy them.
655 pushl $16 # Push the size
657 addl $4,%esp # pop the size arg.
658 movl %eax,%esi # setup the destination.
659 popl %edx # Restore eax, ecx and edx.
663 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
666 .globl GNAME(alloc_to_edi)
667 .type GNAME(alloc_to_edi),@function
668 .align align_4byte,0x90
670 pushl %eax # Save eax, ecx, and edx as C could destroy them.
673 pushl %edi # Push the size
675 addl $4,%esp # pop the size arg.
676 movl %eax,%edi # setup the destination.
677 popl %edx # Restore eax, ecx and edx.
681 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
683 .globl GNAME(alloc_8_to_edi)
684 .type GNAME(alloc_8_to_edi),@function
685 .align align_4byte,0x90
686 GNAME(alloc_8_to_edi):
687 pushl %eax # Save eax, ecx, and edx as C could destroy them.
690 pushl $8 # Push the size
692 addl $4,%esp # pop the size arg.
693 movl %eax,%edi # setup the destination.
694 popl %edx # Restore eax, ecx and edx.
698 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
700 .globl GNAME(alloc_16_to_edi)
701 .type GNAME(alloc_16_to_edi),@function
702 .align align_4byte,0x90
703 GNAME(alloc_16_to_edi):
704 pushl %eax # Save eax, ecx, and edx as C could destroy them.
707 pushl $16 # Push the size
709 addl $4,%esp # pop the size arg.
710 movl %eax,%edi # setup the destination.
711 popl %edx # Restore eax, ecx and edx.
715 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
721 /* These routines are called from Lisp when an inline allocation
722 * overflows. Every register except the result needs to be preserved.
723 * We depend on C to preserve ebx, esi, edi, and ebp.
724 * But where necessary must save eax, ecx, edx. */
726 /* This routine handles an overflow with eax=crfp+size. So the
729 .globl GNAME(alloc_overflow_eax)
730 .type GNAME(alloc_overflow_eax),@function
731 GNAME(alloc_overflow_eax):
732 pushl %ecx # Save ecx
733 pushl %edx # Save edx
734 /* Calculate the size for the allocation. */
735 subl GNAME(current_region_free_pointer),%eax
736 pushl %eax # Push the size
738 addl $4,%esp # pop the size arg.
739 popl %edx # Restore edx.
740 popl %ecx # Restore ecx.
741 addl $6,(%esp) # Adjust the return address to skip the next inst.
743 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
745 /* This routine handles an overflow with ecx=crfp+size. So the
748 .globl GNAME(alloc_overflow_ecx)
749 .type GNAME(alloc_overflow_ecx),@function
750 GNAME(alloc_overflow_ecx):
751 pushl %eax # Save eax
752 pushl %edx # Save edx
753 /* Calculate the size for the allocation. */
754 subl GNAME(current_region_free_pointer),%ecx
755 pushl %ecx # Push the size
757 addl $4,%esp # pop the size arg.
758 movl %eax,%ecx # setup the destination.
759 popl %edx # Restore edx.
760 popl %eax # Restore eax.
761 addl $6,(%esp) # Adjust the return address to skip the next inst.
763 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
765 /* This routine handles an overflow with edx=crfp+size. So the
768 .globl GNAME(alloc_overflow_edx)
769 .type GNAME(alloc_overflow_edx),@function
770 GNAME(alloc_overflow_edx):
771 pushl %eax # Save eax
772 pushl %ecx # Save ecx
773 /* Calculate the size for the allocation. */
774 subl GNAME(current_region_free_pointer),%edx
775 pushl %edx # Push the size
777 addl $4,%esp # pop the size arg.
778 movl %eax,%edx # setup the destination.
779 popl %ecx # Restore ecx.
780 popl %eax # Restore eax.
781 addl $6,(%esp) # Adjust the return address to skip the next inst.
783 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
785 /* This routine handles an overflow with ebx=crfp+size. So the
788 .globl GNAME(alloc_overflow_ebx)
789 .type GNAME(alloc_overflow_ebx),@function
790 GNAME(alloc_overflow_ebx):
791 pushl %eax # Save eax
792 pushl %ecx # Save ecx
793 pushl %edx # Save edx
794 /* Calculate the size for the allocation. */
795 subl GNAME(current_region_free_pointer),%ebx
796 pushl %ebx # Push the size
798 addl $4,%esp # pop the size arg.
799 movl %eax,%ebx # setup the destination.
800 popl %edx # Restore edx.
801 popl %ecx # Restore ecx.
802 popl %eax # Restore eax.
803 addl $6,(%esp) # Adjust the return address to skip the next inst.
805 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
807 /* This routine handles an overflow with esi=crfp+size. So the
810 .globl GNAME(alloc_overflow_esi)
811 .type GNAME(alloc_overflow_esi),@function
812 GNAME(alloc_overflow_esi):
813 pushl %eax # Save eax
814 pushl %ecx # Save ecx
815 pushl %edx # Save edx
816 /* Calculate the size for the allocation. */
817 subl GNAME(current_region_free_pointer),%esi
818 pushl %esi # Push the size
820 addl $4,%esp # pop the size arg.
821 movl %eax,%esi # setup the destination.
822 popl %edx # Restore edx.
823 popl %ecx # Restore ecx.
824 popl %eax # Restore eax.
825 addl $6,(%esp) # Adjust the return address to skip the next inst.
827 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
829 /* This routine handles an overflow with edi=crfp+size. So the
832 .globl GNAME(alloc_overflow_edi)
833 .type GNAME(alloc_overflow_edi),@function
834 GNAME(alloc_overflow_edi):
835 pushl %eax # Save eax
836 pushl %ecx # Save ecx
837 pushl %edx # Save edx
838 /* Calculate the size for the allocation. */
839 subl GNAME(current_region_free_pointer),%edi
840 pushl %edi # Push the size
842 addl $4,%esp # pop the size arg.
843 movl %eax,%edi # setup the destination.
844 popl %edx # Restore edx.
845 popl %ecx # Restore ecx.
846 popl %eax # Restore eax.
847 addl $6,(%esp) # Adjust the return address to skip the next inst.
849 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)