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 #include "x86-validate.h"
18 #define LANGUAGE_ASSEMBLY
21 /* Minimize conditionalization for different OS naming schemes. */
22 #if defined __linux__ || defined __FreeBSD__ /* (but *not* OpenBSD) */
23 #define GNAME(var) var
25 #define GNAME(var) _##var
28 /* Get the right type of alignment. Linux and FreeBSD (but not OpenBSD)
29 * want alignment in bytes. */
30 #if defined(__linux__) || defined(__FreeBSD__)
33 #define align_16byte 16
37 #define align_16byte 4
41 .global GNAME(foreign_function_call_active)
45 * A call to call_into_c preserves esi, edi, and ebp.
46 * (The C function will preserve ebx, esi, edi, and ebp across its
47 * function call, but we trash ebx ourselves by using it to save the
48 * return Lisp address.)
50 * Return values are in eax and maybe edx for quads, or st(0) for
53 * This should work for Lisp calls C calls Lisp calls C..
56 .align align_16byte,0x90
57 .global GNAME(call_into_c)
58 .type GNAME(call_into_c),@function
60 movl $1,GNAME(foreign_function_call_active)
62 /* Save the return Lisp address in ebx. */
65 /* Setup the NPX for C */
75 call *%eax # normal callout using Lisp stack
77 movl %eax,%ecx # remember integer return value
79 /* Check for a return FP value. */
86 /* The return value is in eax, or eax,edx? */
87 /* Set up the NPX stack for Lisp. */
88 fldz # Ensure no regs are empty.
97 /* Restore the return value. */
98 movl %ecx,%eax # maybe return value
100 movl $0,GNAME(foreign_function_call_active)
105 /* The return result is in st(0). */
106 /* Set up the NPX stack for Lisp, placing the result in st(0). */
107 fldz # Ensure no regs are empty.
114 fxch %st(7) # Move the result back to st(0).
116 /* We don't need to restore eax, because the result is in st(0). */
118 movl $0,GNAME(foreign_function_call_active)
122 .size GNAME(call_into_c), . - GNAME(call_into_c)
126 .global GNAME(call_into_lisp)
127 .type GNAME(call_into_lisp),@function
129 /* The C conventions require that ebx, esi, edi, and ebp be preserved
130 * across function calls. */
131 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
132 * the stack changes. */
134 .align align_16byte,0x90
135 GNAME(call_into_lisp):
136 pushl %ebp # Save old frame pointer.
137 movl %esp,%ebp # Establish new frame.
139 /* Save the NPX state */
140 fwait # Catch any pending NPX exceptions.
141 subl $108,%esp # Make room for the NPX state.
142 fnsave (%esp) # resets NPX
144 movl (%esp),%eax # Load NPX control word.
145 andl $0xfffff3ff,%eax # Set rounding mode to nearest.
146 orl $0x00000300,%eax # Set precision to 64 bits.
148 fldcw (%esp) # Recover modes.
151 fldz # Ensure no FP regs are empty.
160 /* Save C regs: ebx esi edi. */
165 /* Clear descriptor regs. */
166 xorl %eax,%eax # lexenv
167 xorl %ebx,%ebx # available
168 xorl %ecx,%ecx # arg count
169 xorl %edx,%edx # first arg
170 xorl %edi,%edi # second arg
171 xorl %esi,%esi # third arg
173 /* no longer in function call */
174 movl %eax, GNAME(foreign_function_call_active)
176 movl %esp,%ebx # remember current stack
177 cmpl $CONTROL_STACK_START,%esp
178 jbe ChangeToLispStack
179 cmpl $CONTROL_STACK_END,%esp
182 /* Setup the *alien-stack* pointer */
183 movl %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
184 movl $CONTROL_STACK_END,%esp # new stack
186 pushl %ebx # Save entry stack on (maybe) new stack.
188 /* Establish Lisp args. */
189 movl 8(%ebp),%eax # lexenv?
190 movl 12(%ebp),%ebx # address of arg vec
191 movl 16(%ebp),%ecx # num args
192 shll $2,%ecx # Make num args into fixnum.
195 movl (%ebx),%edx # arg0
198 movl 4(%ebx),%edi # arg1
201 movl 8(%ebx),%esi # arg2
203 /* Registers eax, ecx, edx, edi, and esi are now live. */
205 /* Alloc new frame. */
206 mov %esp,%ebx # The current sp marks start of new frame.
207 push %ebp # fp in save location S0
208 sub $8,%esp # Ensure 3 slots are allocated, one above.
209 mov %ebx,%ebp # Switch to new frame.
211 /* Indirect the closure. */
212 call *CLOSURE_FUNCTION_OFFSET(%eax)
214 /* Multi-value return; blow off any extra values. */
216 /* single value return */
218 /* Restore the stack, in case there was a stack change. */
221 /* Restore C regs: ebx esi edi. */
226 /* Restore the NPX state. */
231 movl %edx,%eax # c-val
233 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
235 /* support for saving and restoring the NPX state from C */
237 .global GNAME(fpu_save)
238 .type GNAME(fpu_save),@function
242 fnsave (%eax) # Save the NPX state. (resets NPX)
244 .size GNAME(fpu_save),.-GNAME(fpu_save)
246 .global GNAME(fpu_restore)
247 .type GNAME(fpu_restore),@function
251 frstor (%eax) # Restore the NPX state.
253 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
256 * the undefined-function trampoline
259 .align align_4byte,0x90
260 .global GNAME(undefined_tramp)
261 .type GNAME(undefined_tramp),@function
262 GNAME(undefined_tramp):
266 #ifdef type_LongFloat
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_FUNCTION_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_FUNCTION_OFFSET(%eax)
291 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
294 * function-end breakpoint magic
297 .global GNAME(function_end_breakpoint_guts)
299 GNAME(function_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(function_end_breakpoint_trap)
314 GNAME(function_end_breakpoint_trap):
316 .byte trap_FunctionEndBreakpoint
317 hlt # We should never return here.
319 .global GNAME(function_end_breakpoint_end)
320 GNAME(function_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)
333 /* This is a copy function which is optimized for the Pentium and
334 * works OK on 486 as well. This assumes (does not check) that the
335 * input byte count is a multiple of 8 bytes (one Lisp object).
336 * This code takes advantage of pairing in the Pentium as well
337 * as the 128-bit cache line.
339 .global GNAME(fastcopy16)
340 .type GNAME(fastcopy16),@function
341 .align align_4byte,0x90
345 movl 8(%ebp), %edx # dst
346 movl 12(%ebp),%eax # src
347 movl 16(%ebp),%ecx # bytes
353 sarl $3,%ecx # number 8-byte units
362 Lquad: sarl $1,%ecx # count 16-byte units
364 movl %ecx,%ebp # use ebp for loop counter
365 .align align_16byte,0x90
367 movl (%edi),%eax # prefetch! MAJOR Pentium win..
379 jnz Ltop # non-prefixed jump saves cycles
386 .size GNAME(fastcopy16),.-GNAME(fastcopy16)
390 /* This is a fast bzero using the FPU. The first argument is the start
391 * address which needs to be aligned on an 8 byte boundary, the second
392 * argument is the number of bytes, which must be a nonzero multiple
395 .globl GNAME(i586_bzero)
396 .type GNAME(i586_bzero),@function
397 .align align_4byte,0x90
399 movl 4(%esp),%edx # Load the start address.
400 movl 8(%esp),%eax # Load the number of bytes.
408 .size GNAME(i586_bzero),.-GNAME(i586_bzero)
413 * Allocate bytes and return the start of the allocated space
414 * in the specified destination register.
416 * In the general case the size will be in the destination register.
418 * All registers must be preserved except the destination.
419 * The C conventions will preserve ebx, esi, edi, and ebp.
420 * So only eax, ecx, and edx need special care here.
423 .globl GNAME(alloc_to_eax)
424 .type GNAME(alloc_to_eax),@function
425 .align align_4byte,0x90
427 pushl %ecx # Save ecx and edx as C could destroy them.
429 pushl %eax # Push the size.
431 addl $4,%esp # Pop the size arg.
432 popl %edx # Restore ecx and edx.
435 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
437 .globl GNAME(alloc_8_to_eax)
438 .type GNAME(alloc_8_to_eax),@function
439 .align align_4byte,0x90
440 GNAME(alloc_8_to_eax):
441 pushl %ecx # Save ecx and edx as C could destroy them.
443 pushl $8 # Push the size.
445 addl $4,%esp # Pop the size arg.
446 popl %edx # Restore ecx and edx.
449 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
451 .globl GNAME(alloc_8_to_eax)
452 .type GNAME(alloc_8_to_eax),@function
453 .align align_4byte,0x90
455 .globl GNAME(alloc_16_to_eax)
456 .type GNAME(alloc_16_to_eax),@function
457 .align align_4byte,0x90
458 GNAME(alloc_16_to_eax):
459 pushl %ecx # Save ecx and edx as C could destroy them.
461 pushl $16 # Push the size.
463 addl $4,%esp # Pop the size arg.
464 popl %edx # Restore ecx and edx.
467 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
469 .globl GNAME(alloc_to_ecx)
470 .type GNAME(alloc_to_ecx),@function
471 .align align_4byte,0x90
473 pushl %eax # Save eax and edx as C could destroy them.
475 pushl %ecx # Push the size.
477 addl $4,%esp # Pop the size arg.
478 movl %eax,%ecx # Set up the destination.
479 popl %edx # Restore eax and edx.
482 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
484 .globl GNAME(alloc_8_to_ecx)
485 .type GNAME(alloc_8_to_ecx),@function
486 .align align_4byte,0x90
487 GNAME(alloc_8_to_ecx):
488 pushl %eax # Save eax and edx as C could destroy them.
490 pushl $8 # Push the size.
492 addl $4,%esp # Pop the size arg.
493 movl %eax,%ecx # Set up the destination.
494 popl %edx # Restore eax and edx.
497 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
499 .globl GNAME(alloc_16_to_ecx)
500 .type GNAME(alloc_16_to_ecx),@function
501 .align align_4byte,0x90
502 GNAME(alloc_16_to_ecx):
503 pushl %eax # Save eax and edx as C could destroy them.
505 pushl $16 # Push the size.
507 addl $4,%esp # Pop the size arg.
508 movl %eax,%ecx # Set up the destination.
509 popl %edx # Restore eax and edx.
512 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
515 .globl GNAME(alloc_to_edx)
516 .type GNAME(alloc_to_edx),@function
517 .align align_4byte,0x90
519 pushl %eax # Save eax and ecx as C could destroy them.
521 pushl %edx # Push the size.
523 addl $4,%esp # Pop the size arg.
524 movl %eax,%edx # Set up the destination.
525 popl %ecx # Restore eax and ecx.
528 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
530 .globl GNAME(alloc_8_to_edx)
531 .type GNAME(alloc_8_to_edx),@function
532 .align align_4byte,0x90
533 GNAME(alloc_8_to_edx):
534 pushl %eax # Save eax and ecx as C could destroy them.
536 pushl $8 # Push the size.
538 addl $4,%esp # Pop the size arg.
539 movl %eax,%edx # Set up the destination.
540 popl %ecx # Restore eax and ecx.
543 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
545 .globl GNAME(alloc_16_to_edx)
546 .type GNAME(alloc_16_to_edx),@function
547 .align align_4byte,0x90
548 GNAME(alloc_16_to_edx):
549 pushl %eax # Save eax and ecx as C could destroy them.
551 pushl $16 # Push the size.
553 addl $4,%esp # Pop the size arg.
554 movl %eax,%edx # Set up the destination.
555 popl %ecx # Restore eax and ecx.
558 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
562 .globl GNAME(alloc_to_ebx)
563 .type GNAME(alloc_to_ebx),@function
564 .align align_4byte,0x90
566 pushl %eax # Save eax, ecx, and edx as C could destroy them.
569 pushl %ebx # Push the size.
571 addl $4,%esp # Pop the size arg.
572 movl %eax,%ebx # Set up the destination.
573 popl %edx # Restore eax, ecx and edx.
577 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
579 .globl GNAME(alloc_8_to_ebx)
580 .type GNAME(alloc_8_to_ebx),@function
581 .align align_4byte,0x90
582 GNAME(alloc_8_to_ebx):
583 pushl %eax # Save eax, ecx, and edx as C could destroy them.
586 pushl $8 # Push the size.
588 addl $4,%esp # Pop the size arg.
589 movl %eax,%ebx # Set up the destination.
590 popl %edx # Restore eax, ecx and edx.
594 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
596 .globl GNAME(alloc_16_to_ebx)
597 .type GNAME(alloc_16_to_ebx),@function
598 .align align_4byte,0x90
599 GNAME(alloc_16_to_ebx):
600 pushl %eax # Save eax, ecx, and edx as C could destroy them.
603 pushl $16 # Push the size
605 addl $4,%esp # pop the size arg.
606 movl %eax,%ebx # setup the destination.
607 popl %edx # Restore eax, ecx and edx.
611 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
615 .globl GNAME(alloc_to_esi)
616 .type GNAME(alloc_to_esi),@function
617 .align align_4byte,0x90
619 pushl %eax # Save eax, ecx, and edx as C could destroy them.
622 pushl %esi # Push the size
624 addl $4,%esp # pop the size arg.
625 movl %eax,%esi # setup the destination.
626 popl %edx # Restore eax, ecx and edx.
630 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
632 .globl GNAME(alloc_8_to_esi)
633 .type GNAME(alloc_8_to_esi),@function
634 .align align_4byte,0x90
635 GNAME(alloc_8_to_esi):
636 pushl %eax # Save eax, ecx, and edx as C could destroy them.
639 pushl $8 # Push the size
641 addl $4,%esp # pop the size arg.
642 movl %eax,%esi # setup the destination.
643 popl %edx # Restore eax, ecx and edx.
647 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
649 .globl GNAME(alloc_16_to_esi)
650 .type GNAME(alloc_16_to_esi),@function
651 .align align_4byte,0x90
652 GNAME(alloc_16_to_esi):
653 pushl %eax # Save eax, ecx, and edx as C could destroy them.
656 pushl $16 # Push the size
658 addl $4,%esp # pop the size arg.
659 movl %eax,%esi # setup the destination.
660 popl %edx # Restore eax, ecx and edx.
664 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
667 .globl GNAME(alloc_to_edi)
668 .type GNAME(alloc_to_edi),@function
669 .align align_4byte,0x90
671 pushl %eax # Save eax, ecx, and edx as C could destroy them.
674 pushl %edi # Push the size
676 addl $4,%esp # pop the size arg.
677 movl %eax,%edi # setup the destination.
678 popl %edx # Restore eax, ecx and edx.
682 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
684 .globl GNAME(alloc_8_to_edi)
685 .type GNAME(alloc_8_to_edi),@function
686 .align align_4byte,0x90
687 GNAME(alloc_8_to_edi):
688 pushl %eax # Save eax, ecx, and edx as C could destroy them.
691 pushl $8 # Push the size
693 addl $4,%esp # pop the size arg.
694 movl %eax,%edi # setup the destination.
695 popl %edx # Restore eax, ecx and edx.
699 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
701 .globl GNAME(alloc_16_to_edi)
702 .type GNAME(alloc_16_to_edi),@function
703 .align align_4byte,0x90
704 GNAME(alloc_16_to_edi):
705 pushl %eax # Save eax, ecx, and edx as C could destroy them.
708 pushl $16 # Push the size
710 addl $4,%esp # pop the size arg.
711 movl %eax,%edi # setup the destination.
712 popl %edx # Restore eax, ecx and edx.
716 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
722 /* These routines are called from Lisp when an inline allocation
723 * overflows. Every register except the result needs to be preserved.
724 * We depend on C to preserve ebx, esi, edi, and ebp.
725 * But where necessary must save eax, ecx, edx. */
727 /* This routine handles an overflow with eax=crfp+size. So the
730 .globl GNAME(alloc_overflow_eax)
731 .type GNAME(alloc_overflow_eax),@function
732 GNAME(alloc_overflow_eax):
733 pushl %ecx # Save ecx
734 pushl %edx # Save edx
735 /* Calculate the size for the allocation. */
736 subl GNAME(current_region_free_pointer),%eax
737 pushl %eax # Push the size
739 addl $4,%esp # pop the size arg.
740 popl %edx # Restore edx.
741 popl %ecx # Restore ecx.
742 addl $6,(%esp) # Adjust the return address to skip the next inst.
744 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
746 /* This routine handles an overflow with ecx=crfp+size. So the
749 .globl GNAME(alloc_overflow_ecx)
750 .type GNAME(alloc_overflow_ecx),@function
751 GNAME(alloc_overflow_ecx):
752 pushl %eax # Save eax
753 pushl %edx # Save edx
754 /* Calculate the size for the allocation. */
755 subl GNAME(current_region_free_pointer),%ecx
756 pushl %ecx # Push the size
758 addl $4,%esp # pop the size arg.
759 movl %eax,%ecx # setup the destination.
760 popl %edx # Restore edx.
761 popl %eax # Restore eax.
762 addl $6,(%esp) # Adjust the return address to skip the next inst.
764 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
766 /* This routine handles an overflow with edx=crfp+size. So the
769 .globl GNAME(alloc_overflow_edx)
770 .type GNAME(alloc_overflow_edx),@function
771 GNAME(alloc_overflow_edx):
772 pushl %eax # Save eax
773 pushl %ecx # Save ecx
774 /* Calculate the size for the allocation. */
775 subl GNAME(current_region_free_pointer),%edx
776 pushl %edx # Push the size
778 addl $4,%esp # pop the size arg.
779 movl %eax,%edx # setup the destination.
780 popl %ecx # Restore ecx.
781 popl %eax # Restore eax.
782 addl $6,(%esp) # Adjust the return address to skip the next inst.
784 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
786 /* This routine handles an overflow with ebx=crfp+size. So the
789 .globl GNAME(alloc_overflow_ebx)
790 .type GNAME(alloc_overflow_ebx),@function
791 GNAME(alloc_overflow_ebx):
792 pushl %eax # Save eax
793 pushl %ecx # Save ecx
794 pushl %edx # Save edx
795 /* Calculate the size for the allocation. */
796 subl GNAME(current_region_free_pointer),%ebx
797 pushl %ebx # Push the size
799 addl $4,%esp # pop the size arg.
800 movl %eax,%ebx # setup the destination.
801 popl %edx # Restore edx.
802 popl %ecx # Restore ecx.
803 popl %eax # Restore eax.
804 addl $6,(%esp) # Adjust the return address to skip the next inst.
806 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
808 /* This routine handles an overflow with esi=crfp+size. So the
811 .globl GNAME(alloc_overflow_esi)
812 .type GNAME(alloc_overflow_esi),@function
813 GNAME(alloc_overflow_esi):
814 pushl %eax # Save eax
815 pushl %ecx # Save ecx
816 pushl %edx # Save edx
817 /* Calculate the size for the allocation. */
818 subl GNAME(current_region_free_pointer),%esi
819 pushl %esi # Push the size
821 addl $4,%esp # pop the size arg.
822 movl %eax,%esi # setup the destination.
823 popl %edx # Restore edx.
824 popl %ecx # Restore ecx.
825 popl %eax # Restore eax.
826 addl $6,(%esp) # Adjust the return address to skip the next inst.
828 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
830 /* This routine handles an overflow with edi=crfp+size. So the
833 .globl GNAME(alloc_overflow_edi)
834 .type GNAME(alloc_overflow_edi),@function
835 GNAME(alloc_overflow_edi):
836 pushl %eax # Save eax
837 pushl %ecx # Save ecx
838 pushl %edx # Save edx
839 /* Calculate the size for the allocation. */
840 subl GNAME(current_region_free_pointer),%edi
841 pushl %edi # Push the size
843 addl $4,%esp # pop the size arg.
844 movl %eax,%edi # setup the destination.
845 popl %edx # Restore edx.
846 popl %ecx # Restore ecx.
847 popl %eax # Restore eax.
848 addl $6,(%esp) # Adjust the return address to skip the next inst.
850 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)