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 fast bzero using the FPU. The first argument is the start
333 * address which needs to be aligned on an 8 byte boundary, the second
334 * argument is the number of bytes, which must be a nonzero multiple
337 .globl GNAME(i586_bzero)
338 .type GNAME(i586_bzero),@function
339 .align align_4byte,0x90
341 movl 4(%esp),%edx # Load the start address.
342 movl 8(%esp),%eax # Load the number of bytes.
350 .size GNAME(i586_bzero),.-GNAME(i586_bzero)
355 * Allocate bytes and return the start of the allocated space
356 * in the specified destination register.
358 * In the general case the size will be in the destination register.
360 * All registers must be preserved except the destination.
361 * The C conventions will preserve ebx, esi, edi, and ebp.
362 * So only eax, ecx, and edx need special care here.
365 .globl GNAME(alloc_to_eax)
366 .type GNAME(alloc_to_eax),@function
367 .align align_4byte,0x90
369 pushl %ecx # Save ecx and edx as C could destroy them.
371 pushl %eax # Push the size.
373 addl $4,%esp # Pop the size arg.
374 popl %edx # Restore ecx and edx.
377 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
379 .globl GNAME(alloc_8_to_eax)
380 .type GNAME(alloc_8_to_eax),@function
381 .align align_4byte,0x90
382 GNAME(alloc_8_to_eax):
383 pushl %ecx # Save ecx and edx as C could destroy them.
385 pushl $8 # Push the size.
387 addl $4,%esp # Pop the size arg.
388 popl %edx # Restore ecx and edx.
391 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
393 .globl GNAME(alloc_8_to_eax)
394 .type GNAME(alloc_8_to_eax),@function
395 .align align_4byte,0x90
397 .globl GNAME(alloc_16_to_eax)
398 .type GNAME(alloc_16_to_eax),@function
399 .align align_4byte,0x90
400 GNAME(alloc_16_to_eax):
401 pushl %ecx # Save ecx and edx as C could destroy them.
403 pushl $16 # Push the size.
405 addl $4,%esp # Pop the size arg.
406 popl %edx # Restore ecx and edx.
409 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
411 .globl GNAME(alloc_to_ecx)
412 .type GNAME(alloc_to_ecx),@function
413 .align align_4byte,0x90
415 pushl %eax # Save eax and edx as C could destroy them.
417 pushl %ecx # Push the size.
419 addl $4,%esp # Pop the size arg.
420 movl %eax,%ecx # Set up the destination.
421 popl %edx # Restore eax and edx.
424 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
426 .globl GNAME(alloc_8_to_ecx)
427 .type GNAME(alloc_8_to_ecx),@function
428 .align align_4byte,0x90
429 GNAME(alloc_8_to_ecx):
430 pushl %eax # Save eax and edx as C could destroy them.
432 pushl $8 # Push the size.
434 addl $4,%esp # Pop the size arg.
435 movl %eax,%ecx # Set up the destination.
436 popl %edx # Restore eax and edx.
439 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
441 .globl GNAME(alloc_16_to_ecx)
442 .type GNAME(alloc_16_to_ecx),@function
443 .align align_4byte,0x90
444 GNAME(alloc_16_to_ecx):
445 pushl %eax # Save eax and edx as C could destroy them.
447 pushl $16 # Push the size.
449 addl $4,%esp # Pop the size arg.
450 movl %eax,%ecx # Set up the destination.
451 popl %edx # Restore eax and edx.
454 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
457 .globl GNAME(alloc_to_edx)
458 .type GNAME(alloc_to_edx),@function
459 .align align_4byte,0x90
461 pushl %eax # Save eax and ecx as C could destroy them.
463 pushl %edx # Push the size.
465 addl $4,%esp # Pop the size arg.
466 movl %eax,%edx # Set up the destination.
467 popl %ecx # Restore eax and ecx.
470 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
472 .globl GNAME(alloc_8_to_edx)
473 .type GNAME(alloc_8_to_edx),@function
474 .align align_4byte,0x90
475 GNAME(alloc_8_to_edx):
476 pushl %eax # Save eax and ecx as C could destroy them.
478 pushl $8 # Push the size.
480 addl $4,%esp # Pop the size arg.
481 movl %eax,%edx # Set up the destination.
482 popl %ecx # Restore eax and ecx.
485 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
487 .globl GNAME(alloc_16_to_edx)
488 .type GNAME(alloc_16_to_edx),@function
489 .align align_4byte,0x90
490 GNAME(alloc_16_to_edx):
491 pushl %eax # Save eax and ecx as C could destroy them.
493 pushl $16 # Push the size.
495 addl $4,%esp # Pop the size arg.
496 movl %eax,%edx # Set up the destination.
497 popl %ecx # Restore eax and ecx.
500 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
504 .globl GNAME(alloc_to_ebx)
505 .type GNAME(alloc_to_ebx),@function
506 .align align_4byte,0x90
508 pushl %eax # Save eax, ecx, and edx as C could destroy them.
511 pushl %ebx # Push the size.
513 addl $4,%esp # Pop the size arg.
514 movl %eax,%ebx # Set up the destination.
515 popl %edx # Restore eax, ecx and edx.
519 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
521 .globl GNAME(alloc_8_to_ebx)
522 .type GNAME(alloc_8_to_ebx),@function
523 .align align_4byte,0x90
524 GNAME(alloc_8_to_ebx):
525 pushl %eax # Save eax, ecx, and edx as C could destroy them.
528 pushl $8 # Push the size.
530 addl $4,%esp # Pop the size arg.
531 movl %eax,%ebx # Set up the destination.
532 popl %edx # Restore eax, ecx and edx.
536 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
538 .globl GNAME(alloc_16_to_ebx)
539 .type GNAME(alloc_16_to_ebx),@function
540 .align align_4byte,0x90
541 GNAME(alloc_16_to_ebx):
542 pushl %eax # Save eax, ecx, and edx as C could destroy them.
545 pushl $16 # Push the size
547 addl $4,%esp # pop the size arg.
548 movl %eax,%ebx # setup the destination.
549 popl %edx # Restore eax, ecx and edx.
553 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
557 .globl GNAME(alloc_to_esi)
558 .type GNAME(alloc_to_esi),@function
559 .align align_4byte,0x90
561 pushl %eax # Save eax, ecx, and edx as C could destroy them.
564 pushl %esi # Push the size
566 addl $4,%esp # pop the size arg.
567 movl %eax,%esi # setup the destination.
568 popl %edx # Restore eax, ecx and edx.
572 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
574 .globl GNAME(alloc_8_to_esi)
575 .type GNAME(alloc_8_to_esi),@function
576 .align align_4byte,0x90
577 GNAME(alloc_8_to_esi):
578 pushl %eax # Save eax, ecx, and edx as C could destroy them.
581 pushl $8 # Push the size
583 addl $4,%esp # pop the size arg.
584 movl %eax,%esi # setup the destination.
585 popl %edx # Restore eax, ecx and edx.
589 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
591 .globl GNAME(alloc_16_to_esi)
592 .type GNAME(alloc_16_to_esi),@function
593 .align align_4byte,0x90
594 GNAME(alloc_16_to_esi):
595 pushl %eax # Save eax, ecx, and edx as C could destroy them.
598 pushl $16 # Push the size
600 addl $4,%esp # pop the size arg.
601 movl %eax,%esi # setup the destination.
602 popl %edx # Restore eax, ecx and edx.
606 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
609 .globl GNAME(alloc_to_edi)
610 .type GNAME(alloc_to_edi),@function
611 .align align_4byte,0x90
613 pushl %eax # Save eax, ecx, and edx as C could destroy them.
616 pushl %edi # Push the size
618 addl $4,%esp # pop the size arg.
619 movl %eax,%edi # setup the destination.
620 popl %edx # Restore eax, ecx and edx.
624 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
626 .globl GNAME(alloc_8_to_edi)
627 .type GNAME(alloc_8_to_edi),@function
628 .align align_4byte,0x90
629 GNAME(alloc_8_to_edi):
630 pushl %eax # Save eax, ecx, and edx as C could destroy them.
633 pushl $8 # Push the size
635 addl $4,%esp # pop the size arg.
636 movl %eax,%edi # setup the destination.
637 popl %edx # Restore eax, ecx and edx.
641 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
643 .globl GNAME(alloc_16_to_edi)
644 .type GNAME(alloc_16_to_edi),@function
645 .align align_4byte,0x90
646 GNAME(alloc_16_to_edi):
647 pushl %eax # Save eax, ecx, and edx as C could destroy them.
650 pushl $16 # Push the size
652 addl $4,%esp # pop the size arg.
653 movl %eax,%edi # setup the destination.
654 popl %edx # Restore eax, ecx and edx.
658 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
664 /* These routines are called from Lisp when an inline allocation
665 * overflows. Every register except the result needs to be preserved.
666 * We depend on C to preserve ebx, esi, edi, and ebp.
667 * But where necessary must save eax, ecx, edx. */
669 /* This routine handles an overflow with eax=crfp+size. So the
672 .globl GNAME(alloc_overflow_eax)
673 .type GNAME(alloc_overflow_eax),@function
674 GNAME(alloc_overflow_eax):
675 pushl %ecx # Save ecx
676 pushl %edx # Save edx
677 /* Calculate the size for the allocation. */
678 subl GNAME(current_region_free_pointer),%eax
679 pushl %eax # Push the size
681 addl $4,%esp # pop the size arg.
682 popl %edx # Restore edx.
683 popl %ecx # Restore ecx.
684 addl $6,(%esp) # Adjust the return address to skip the next inst.
686 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
688 /* This routine handles an overflow with ecx=crfp+size. So the
691 .globl GNAME(alloc_overflow_ecx)
692 .type GNAME(alloc_overflow_ecx),@function
693 GNAME(alloc_overflow_ecx):
694 pushl %eax # Save eax
695 pushl %edx # Save edx
696 /* Calculate the size for the allocation. */
697 subl GNAME(current_region_free_pointer),%ecx
698 pushl %ecx # Push the size
700 addl $4,%esp # pop the size arg.
701 movl %eax,%ecx # setup the destination.
702 popl %edx # Restore edx.
703 popl %eax # Restore eax.
704 addl $6,(%esp) # Adjust the return address to skip the next inst.
706 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
708 /* This routine handles an overflow with edx=crfp+size. So the
711 .globl GNAME(alloc_overflow_edx)
712 .type GNAME(alloc_overflow_edx),@function
713 GNAME(alloc_overflow_edx):
714 pushl %eax # Save eax
715 pushl %ecx # Save ecx
716 /* Calculate the size for the allocation. */
717 subl GNAME(current_region_free_pointer),%edx
718 pushl %edx # Push the size
720 addl $4,%esp # pop the size arg.
721 movl %eax,%edx # setup the destination.
722 popl %ecx # Restore ecx.
723 popl %eax # Restore eax.
724 addl $6,(%esp) # Adjust the return address to skip the next inst.
726 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
728 /* This routine handles an overflow with ebx=crfp+size. So the
731 .globl GNAME(alloc_overflow_ebx)
732 .type GNAME(alloc_overflow_ebx),@function
733 GNAME(alloc_overflow_ebx):
734 pushl %eax # Save 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),%ebx
739 pushl %ebx # Push the size
741 addl $4,%esp # pop the size arg.
742 movl %eax,%ebx # setup the destination.
743 popl %edx # Restore edx.
744 popl %ecx # Restore ecx.
745 popl %eax # Restore eax.
746 addl $6,(%esp) # Adjust the return address to skip the next inst.
748 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
750 /* This routine handles an overflow with esi=crfp+size. So the
753 .globl GNAME(alloc_overflow_esi)
754 .type GNAME(alloc_overflow_esi),@function
755 GNAME(alloc_overflow_esi):
756 pushl %eax # Save eax
757 pushl %ecx # Save ecx
758 pushl %edx # Save edx
759 /* Calculate the size for the allocation. */
760 subl GNAME(current_region_free_pointer),%esi
761 pushl %esi # Push the size
763 addl $4,%esp # pop the size arg.
764 movl %eax,%esi # setup the destination.
765 popl %edx # Restore edx.
766 popl %ecx # Restore ecx.
767 popl %eax # Restore eax.
768 addl $6,(%esp) # Adjust the return address to skip the next inst.
770 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
772 /* This routine handles an overflow with edi=crfp+size. So the
775 .globl GNAME(alloc_overflow_edi)
776 .type GNAME(alloc_overflow_edi),@function
777 GNAME(alloc_overflow_edi):
778 pushl %eax # Save eax
779 pushl %ecx # Save ecx
780 pushl %edx # Save edx
781 /* Calculate the size for the allocation. */
782 subl GNAME(current_region_free_pointer),%edi
783 pushl %edi # Push the size
785 addl $4,%esp # pop the size arg.
786 movl %eax,%edi # setup the destination.
787 popl %edx # Restore edx.
788 popl %ecx # Restore ecx.
789 popl %eax # Restore eax.
790 addl $6,(%esp) # Adjust the return address to skip the next inst.
792 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)