2 * very-low-level utilities for runtime support
8 * This software is part of the SBCL system. See the README file for
11 * This software is derived from the CMU CL system, which was
12 * written at Carnegie Mellon University and released into the
13 * public domain. The software is in the public domain and is
14 * provided with absolutely no warranty. See the COPYING and CREDITS
15 * files for more information.
18 #include "x86-validate.h"
20 #define LANGUAGE_ASSEMBLY
23 /* Minimize conditionalization for different OS naming schemes. */
24 #if defined __linux__ || defined __FreeBSD__ /* (but *not* OpenBSD) */
25 #define GNAME(var) var
27 #define GNAME(var) _##var
30 /* Get the right type of alignment. Linux and FreeBSD (but not OpenBSD)
31 * want alignment in bytes. */
32 #if defined(__linux__) || defined(__FreeBSD__)
35 #define align_16byte 16
39 #define align_16byte 4
43 .global GNAME(foreign_function_call_active)
47 * A call to call_into_c preserves esi, edi, and ebp.
48 * (The C function will preserve ebx, esi, edi, and ebp across its
49 * function call, but we trash ebx ourselves by using it to save the
50 * return Lisp address.)
52 * Return values are in eax and maybe edx for quads, or st(0) for
55 * This should work for Lisp calls C calls Lisp calls C..
58 .align align_16byte,0x90
59 .global GNAME(call_into_c)
60 .type GNAME(call_into_c),@function
62 movl $1,GNAME(foreign_function_call_active)
64 /* Save the return Lisp address in ebx. */
67 /* Setup the NPX for C */
77 call *%eax # normal callout using Lisp stack
79 movl %eax,%ecx # remember integer return value
81 /* Check for a return FP value. */
88 /* The return value is in eax, or eax,edx? */
89 /* Set up the NPX stack for Lisp. */
90 fldz # Ensure no regs are empty.
99 /* Restore the return value. */
100 movl %ecx,%eax # maybe return value
102 movl $0,GNAME(foreign_function_call_active)
107 /* The return result is in st(0). */
108 /* Set up the NPX stack for Lisp, placing the result in st(0). */
109 fldz # Ensure no regs are empty.
116 fxch %st(7) # Move the result back to st(0).
118 /* We don't need to restore eax, because the result is in st(0). */
120 movl $0,GNAME(foreign_function_call_active)
124 .size GNAME(call_into_c), . - GNAME(call_into_c)
128 .global GNAME(call_into_lisp)
129 .type GNAME(call_into_lisp),@function
131 /* The C conventions require that ebx, esi, edi, and ebp be preserved
132 * across function calls. */
133 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
134 * the stack changes. */
136 .align align_16byte,0x90
137 GNAME(call_into_lisp):
138 pushl %ebp # Save old frame pointer.
139 movl %esp,%ebp # Establish new frame.
141 /* Save the NPX state */
142 fwait # Catch any pending NPX exceptions.
143 subl $108,%esp # Make room for the NPX state.
144 fnsave (%esp) # resets NPX
146 movl (%esp),%eax # Load NPX control word.
147 andl $0xfffff3ff,%eax # Set rounding mode to nearest.
148 orl $0x00000300,%eax # Set precision to 64 bits.
150 fldcw (%esp) # Recover modes.
153 fldz # Ensure no FP regs are empty.
162 /* Save C regs: ebx esi edi. */
167 /* Clear descriptor regs. */
168 xorl %eax,%eax # lexenv
169 xorl %ebx,%ebx # available
170 xorl %ecx,%ecx # arg count
171 xorl %edx,%edx # first arg
172 xorl %edi,%edi # second arg
173 xorl %esi,%esi # third arg
175 /* no longer in function call */
176 movl %eax, GNAME(foreign_function_call_active)
178 movl %esp,%ebx # remember current stack
179 cmpl $CONTROL_STACK_START,%esp
180 jbe ChangeToLispStack
181 cmpl $CONTROL_STACK_END,%esp
184 /* Setup the *alien-stack* pointer */
185 movl %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
186 movl $CONTROL_STACK_END,%esp # new stack
188 pushl %ebx # Save entry stack on (maybe) new stack.
190 /* Establish Lisp args. */
191 movl 8(%ebp),%eax # lexenv?
192 movl 12(%ebp),%ebx # address of arg vec
193 movl 16(%ebp),%ecx # num args
194 shll $2,%ecx # Make num args into fixnum.
197 movl (%ebx),%edx # arg0
200 movl 4(%ebx),%edi # arg1
203 movl 8(%ebx),%esi # arg2
205 /* Registers eax, ecx, edx, edi, and esi are now live. */
207 /* Alloc new frame. */
208 mov %esp,%ebx # The current sp marks start of new frame.
209 push %ebp # fp in save location S0
210 sub $8,%esp # Ensure 3 slots are allocated, one above.
211 mov %ebx,%ebp # Switch to new frame.
213 /* Indirect the closure. */
214 call *CLOSURE_FUNCTION_OFFSET(%eax)
216 /* Multi-value return; blow off any extra values. */
218 /* single value return */
220 /* Restore the stack, in case there was a stack change. */
223 /* Restore C regs: ebx esi edi. */
228 /* Restore the NPX state. */
233 movl %edx,%eax # c-val
235 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
237 /* support for saving and restoring the NPX state from C */
239 .global GNAME(fpu_save)
240 .type GNAME(fpu_save),@function
244 fnsave (%eax) # Save the NPX state. (resets NPX)
246 .size GNAME(fpu_save),.-GNAME(fpu_save)
248 .global GNAME(fpu_restore)
249 .type GNAME(fpu_restore),@function
253 frstor (%eax) # Restore the NPX state.
255 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
258 * the undefined-function trampoline
261 .align align_4byte,0x90
262 .global GNAME(undefined_tramp)
263 .type GNAME(undefined_tramp),@function
264 GNAME(undefined_tramp):
268 #ifdef type_LongFloat
273 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
275 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
278 * the closure trampoline
281 .align align_4byte,0x90
282 .global GNAME(closure_tramp)
283 .type GNAME(closure_tramp),@function
284 GNAME(closure_tramp):
285 movl FDEFN_FUNCTION_OFFSET(%eax),%eax
286 /* FIXME: The '*' after "jmp" in the next line is from PVE's
287 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
288 * reasonable, and it certainly seems as though if CMU CL needs it,
289 * SBCL needs it too, but I haven't actually verified that it's
290 * right. It would be good to find a way to force the flow of
291 * control through here to test it. */
292 jmp *CLOSURE_FUNCTION_OFFSET(%eax)
293 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
296 * function-end breakpoint magic
299 .global GNAME(function_end_breakpoint_guts)
301 GNAME(function_end_breakpoint_guts):
302 /* Multiple Value return */
303 jmp multiple_value_return
304 /* Single value return: The eventual return will now use the
305 multiple values return convention but with a return values
307 movl %esp,%ebx # Setup ebx - the ofp.
308 subl $4,%esp # Allocate one stack slot for the return value
309 movl $4,%ecx # Setup ecx for one return value.
310 movl $NIL,%edi # default second value
311 movl $NIL,%esi # default third value
313 multiple_value_return:
315 .global GNAME(function_end_breakpoint_trap)
316 GNAME(function_end_breakpoint_trap):
318 .byte trap_FunctionEndBreakpoint
319 hlt # We should never return here.
321 .global GNAME(function_end_breakpoint_end)
322 GNAME(function_end_breakpoint_end):
325 .global GNAME(do_pending_interrupt)
326 .type GNAME(do_pending_interrupt),@function
327 .align align_4byte,0x90
328 GNAME(do_pending_interrupt):
330 .byte trap_PendingInterrupt
332 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
335 /* This is a copy function which is optimized for the Pentium and
336 * works OK on 486 as well. This assumes (does not check) that the
337 * input byte count is a multiple of 8 bytes (one Lisp object).
338 * This code takes advantage of pairing in the Pentium as well
339 * as the 128-bit cache line.
341 .global GNAME(fastcopy16)
342 .type GNAME(fastcopy16),@function
343 .align align_4byte,0x90
347 movl 8(%ebp), %edx # dst
348 movl 12(%ebp),%eax # src
349 movl 16(%ebp),%ecx # bytes
355 sarl $3,%ecx # number 8-byte units
364 Lquad: sarl $1,%ecx # count 16-byte units
366 movl %ecx,%ebp # use ebp for loop counter
367 .align align_16byte,0x90
369 movl (%edi),%eax # prefetch! MAJOR Pentium win..
381 jnz Ltop # non-prefixed jump saves cycles
388 .size GNAME(fastcopy16),.-GNAME(fastcopy16)
392 /* This is a fast bzero using the FPU. The first argument is the start
393 * address which needs to be aligned on an 8 byte boundary, the second
394 * argument is the number of bytes, which must be a nonzero multiple
397 .globl GNAME(i586_bzero)
398 .type GNAME(i586_bzero),@function
399 .align align_4byte,0x90
401 movl 4(%esp),%edx # Load the start address.
402 movl 8(%esp),%eax # Load the number of bytes.
410 .size GNAME(i586_bzero),.-GNAME(i586_bzero)
415 * Allocate bytes and return the start of the allocated space
416 * in the specified destination register.
418 * In the general case the size will be in the destination register.
420 * All registers must be preserved except the destination.
421 * The C conventions will preserve ebx, esi, edi, and ebp.
422 * So only eax, ecx, and edx need special care here.
425 .globl GNAME(alloc_to_eax)
426 .type GNAME(alloc_to_eax),@function
427 .align align_4byte,0x90
429 pushl %ecx # Save ecx and edx as C could destroy them.
431 pushl %eax # Push the size.
433 addl $4,%esp # Pop the size arg.
434 popl %edx # Restore ecx and edx.
437 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
439 .globl GNAME(alloc_8_to_eax)
440 .type GNAME(alloc_8_to_eax),@function
441 .align align_4byte,0x90
442 GNAME(alloc_8_to_eax):
443 pushl %ecx # Save ecx and edx as C could destroy them.
445 pushl $8 # Push the size.
447 addl $4,%esp # Pop the size arg.
448 popl %edx # Restore ecx and edx.
451 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
453 .globl GNAME(alloc_8_to_eax)
454 .type GNAME(alloc_8_to_eax),@function
455 .align align_4byte,0x90
457 .globl GNAME(alloc_16_to_eax)
458 .type GNAME(alloc_16_to_eax),@function
459 .align align_4byte,0x90
460 GNAME(alloc_16_to_eax):
461 pushl %ecx # Save ecx and edx as C could destroy them.
463 pushl $16 # Push the size.
465 addl $4,%esp # Pop the size arg.
466 popl %edx # Restore ecx and edx.
469 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
471 .globl GNAME(alloc_to_ecx)
472 .type GNAME(alloc_to_ecx),@function
473 .align align_4byte,0x90
475 pushl %eax # Save eax and edx as C could destroy them.
477 pushl %ecx # Push the size.
479 addl $4,%esp # Pop the size arg.
480 movl %eax,%ecx # Set up the destination.
481 popl %edx # Restore eax and edx.
484 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
486 .globl GNAME(alloc_8_to_ecx)
487 .type GNAME(alloc_8_to_ecx),@function
488 .align align_4byte,0x90
489 GNAME(alloc_8_to_ecx):
490 pushl %eax # Save eax and edx as C could destroy them.
492 pushl $8 # Push the size.
494 addl $4,%esp # Pop the size arg.
495 movl %eax,%ecx # Set up the destination.
496 popl %edx # Restore eax and edx.
499 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
501 .globl GNAME(alloc_16_to_ecx)
502 .type GNAME(alloc_16_to_ecx),@function
503 .align align_4byte,0x90
504 GNAME(alloc_16_to_ecx):
505 pushl %eax # Save eax and edx as C could destroy them.
507 pushl $16 # Push the size.
509 addl $4,%esp # Pop the size arg.
510 movl %eax,%ecx # Set up the destination.
511 popl %edx # Restore eax and edx.
514 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
517 .globl GNAME(alloc_to_edx)
518 .type GNAME(alloc_to_edx),@function
519 .align align_4byte,0x90
521 pushl %eax # Save eax and ecx as C could destroy them.
523 pushl %edx # Push the size.
525 addl $4,%esp # Pop the size arg.
526 movl %eax,%edx # Set up the destination.
527 popl %ecx # Restore eax and ecx.
530 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
532 .globl GNAME(alloc_8_to_edx)
533 .type GNAME(alloc_8_to_edx),@function
534 .align align_4byte,0x90
535 GNAME(alloc_8_to_edx):
536 pushl %eax # Save eax and ecx as C could destroy them.
538 pushl $8 # Push the size.
540 addl $4,%esp # Pop the size arg.
541 movl %eax,%edx # Set up the destination.
542 popl %ecx # Restore eax and ecx.
545 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
547 .globl GNAME(alloc_16_to_edx)
548 .type GNAME(alloc_16_to_edx),@function
549 .align align_4byte,0x90
550 GNAME(alloc_16_to_edx):
551 pushl %eax # Save eax and ecx as C could destroy them.
553 pushl $16 # Push the size.
555 addl $4,%esp # Pop the size arg.
556 movl %eax,%edx # Set up the destination.
557 popl %ecx # Restore eax and ecx.
560 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
564 .globl GNAME(alloc_to_ebx)
565 .type GNAME(alloc_to_ebx),@function
566 .align align_4byte,0x90
568 pushl %eax # Save eax, ecx, and edx as C could destroy them.
571 pushl %ebx # Push the size.
573 addl $4,%esp # Pop the size arg.
574 movl %eax,%ebx # Set up the destination.
575 popl %edx # Restore eax, ecx and edx.
579 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
581 .globl GNAME(alloc_8_to_ebx)
582 .type GNAME(alloc_8_to_ebx),@function
583 .align align_4byte,0x90
584 GNAME(alloc_8_to_ebx):
585 pushl %eax # Save eax, ecx, and edx as C could destroy them.
588 pushl $8 # Push the size.
590 addl $4,%esp # Pop the size arg.
591 movl %eax,%ebx # Set up the destination.
592 popl %edx # Restore eax, ecx and edx.
596 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
598 .globl GNAME(alloc_16_to_ebx)
599 .type GNAME(alloc_16_to_ebx),@function
600 .align align_4byte,0x90
601 GNAME(alloc_16_to_ebx):
602 pushl %eax # Save eax, ecx, and edx as C could destroy them.
605 pushl $16 # Push the size
607 addl $4,%esp # pop the size arg.
608 movl %eax,%ebx # setup the destination.
609 popl %edx # Restore eax, ecx and edx.
613 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
617 .globl GNAME(alloc_to_esi)
618 .type GNAME(alloc_to_esi),@function
619 .align align_4byte,0x90
621 pushl %eax # Save eax, ecx, and edx as C could destroy them.
624 pushl %esi # Push the size
626 addl $4,%esp # pop the size arg.
627 movl %eax,%esi # setup the destination.
628 popl %edx # Restore eax, ecx and edx.
632 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
634 .globl GNAME(alloc_8_to_esi)
635 .type GNAME(alloc_8_to_esi),@function
636 .align align_4byte,0x90
637 GNAME(alloc_8_to_esi):
638 pushl %eax # Save eax, ecx, and edx as C could destroy them.
641 pushl $8 # Push the size
643 addl $4,%esp # pop the size arg.
644 movl %eax,%esi # setup the destination.
645 popl %edx # Restore eax, ecx and edx.
649 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
651 .globl GNAME(alloc_16_to_esi)
652 .type GNAME(alloc_16_to_esi),@function
653 .align align_4byte,0x90
654 GNAME(alloc_16_to_esi):
655 pushl %eax # Save eax, ecx, and edx as C could destroy them.
658 pushl $16 # Push the size
660 addl $4,%esp # pop the size arg.
661 movl %eax,%esi # setup the destination.
662 popl %edx # Restore eax, ecx and edx.
666 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
669 .globl GNAME(alloc_to_edi)
670 .type GNAME(alloc_to_edi),@function
671 .align align_4byte,0x90
673 pushl %eax # Save eax, ecx, and edx as C could destroy them.
676 pushl %edi # Push the size
678 addl $4,%esp # pop the size arg.
679 movl %eax,%edi # setup the destination.
680 popl %edx # Restore eax, ecx and edx.
684 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
686 .globl GNAME(alloc_8_to_edi)
687 .type GNAME(alloc_8_to_edi),@function
688 .align align_4byte,0x90
689 GNAME(alloc_8_to_edi):
690 pushl %eax # Save eax, ecx, and edx as C could destroy them.
693 pushl $8 # Push the size
695 addl $4,%esp # pop the size arg.
696 movl %eax,%edi # setup the destination.
697 popl %edx # Restore eax, ecx and edx.
701 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
703 .globl GNAME(alloc_16_to_edi)
704 .type GNAME(alloc_16_to_edi),@function
705 .align align_4byte,0x90
706 GNAME(alloc_16_to_edi):
707 pushl %eax # Save eax, ecx, and edx as C could destroy them.
710 pushl $16 # Push the size
712 addl $4,%esp # pop the size arg.
713 movl %eax,%edi # setup the destination.
714 popl %edx # Restore eax, ecx and edx.
718 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
724 /* These routines are called from Lisp when an inline allocation
725 * overflows. Every register except the result needs to be preserved.
726 * We depend on C to preserve ebx, esi, edi, and ebp.
727 * But where necessary must save eax, ecx, edx. */
729 /* This routine handles an overflow with eax=crfp+size. So the
732 .globl GNAME(alloc_overflow_eax)
733 .type GNAME(alloc_overflow_eax),@function
734 GNAME(alloc_overflow_eax):
735 pushl %ecx # Save ecx
736 pushl %edx # Save edx
737 /* Calculate the size for the allocation. */
738 subl GNAME(current_region_free_pointer),%eax
739 pushl %eax # Push the size
741 addl $4,%esp # pop the size arg.
742 popl %edx # Restore edx.
743 popl %ecx # Restore ecx.
744 addl $6,(%esp) # Adjust the return address to skip the next inst.
746 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
748 /* This routine handles an overflow with ecx=crfp+size. So the
751 .globl GNAME(alloc_overflow_ecx)
752 .type GNAME(alloc_overflow_ecx),@function
753 GNAME(alloc_overflow_ecx):
754 pushl %eax # Save eax
755 pushl %edx # Save edx
756 /* Calculate the size for the allocation. */
757 subl GNAME(current_region_free_pointer),%ecx
758 pushl %ecx # Push the size
760 addl $4,%esp # pop the size arg.
761 movl %eax,%ecx # setup the destination.
762 popl %edx # Restore edx.
763 popl %eax # Restore eax.
764 addl $6,(%esp) # Adjust the return address to skip the next inst.
766 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
768 /* This routine handles an overflow with edx=crfp+size. So the
771 .globl GNAME(alloc_overflow_edx)
772 .type GNAME(alloc_overflow_edx),@function
773 GNAME(alloc_overflow_edx):
774 pushl %eax # Save eax
775 pushl %ecx # Save ecx
776 /* Calculate the size for the allocation. */
777 subl GNAME(current_region_free_pointer),%edx
778 pushl %edx # Push the size
780 addl $4,%esp # pop the size arg.
781 movl %eax,%edx # setup the destination.
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_edx),.-GNAME(alloc_overflow_edx)
788 /* This routine handles an overflow with ebx=crfp+size. So the
791 .globl GNAME(alloc_overflow_ebx)
792 .type GNAME(alloc_overflow_ebx),@function
793 GNAME(alloc_overflow_ebx):
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),%ebx
799 pushl %ebx # Push the size
801 addl $4,%esp # pop the size arg.
802 movl %eax,%ebx # 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_ebx),.-GNAME(alloc_overflow_ebx)
810 /* This routine handles an overflow with esi=crfp+size. So the
813 .globl GNAME(alloc_overflow_esi)
814 .type GNAME(alloc_overflow_esi),@function
815 GNAME(alloc_overflow_esi):
816 pushl %eax # Save eax
817 pushl %ecx # Save ecx
818 pushl %edx # Save edx
819 /* Calculate the size for the allocation. */
820 subl GNAME(current_region_free_pointer),%esi
821 pushl %esi # Push the size
823 addl $4,%esp # pop the size arg.
824 movl %eax,%esi # setup the destination.
825 popl %edx # Restore edx.
826 popl %ecx # Restore ecx.
827 popl %eax # Restore eax.
828 addl $6,(%esp) # Adjust the return address to skip the next inst.
830 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
832 /* This routine handles an overflow with edi=crfp+size. So the
835 .globl GNAME(alloc_overflow_edi)
836 .type GNAME(alloc_overflow_edi),@function
837 GNAME(alloc_overflow_edi):
838 pushl %eax # Save eax
839 pushl %ecx # Save ecx
840 pushl %edx # Save edx
841 /* Calculate the size for the allocation. */
842 subl GNAME(current_region_free_pointer),%edi
843 pushl %edi # Push the size
845 addl $4,%esp # pop the size arg.
846 movl %eax,%edi # setup the destination.
847 popl %edx # Restore edx.
848 popl %ecx # Restore ecx.
849 popl %eax # Restore eax.
850 addl $6,(%esp) # Adjust the return address to skip the next inst.
852 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)