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_FUN_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 .byte UNDEFINED_FUN_ERROR
266 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
268 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
271 * the closure trampoline
274 .align align_4byte,0x90
275 .global GNAME(closure_tramp)
276 .type GNAME(closure_tramp),@function
277 GNAME(closure_tramp):
278 movl FDEFN_FUN_OFFSET(%eax),%eax
279 /* FIXME: The '*' after "jmp" in the next line is from PVE's
280 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
281 * reasonable, and it certainly seems as though if CMU CL needs it,
282 * SBCL needs it too, but I haven't actually verified that it's
283 * right. It would be good to find a way to force the flow of
284 * control through here to test it. */
285 jmp *CLOSURE_FUN_OFFSET(%eax)
286 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
289 * fun-end breakpoint magic
292 .global GNAME(fun_end_breakpoint_guts)
294 GNAME(fun_end_breakpoint_guts):
295 /* Multiple Value return */
296 jmp multiple_value_return
297 /* Single value return: The eventual return will now use the
298 multiple values return convention but with a return values
300 movl %esp,%ebx # Setup ebx - the ofp.
301 subl $4,%esp # Allocate one stack slot for the return value
302 movl $4,%ecx # Setup ecx for one return value.
303 movl $NIL,%edi # default second value
304 movl $NIL,%esi # default third value
306 multiple_value_return:
308 .global GNAME(fun_end_breakpoint_trap)
309 GNAME(fun_end_breakpoint_trap):
311 .byte trap_FunEndBreakpoint
312 hlt # We should never return here.
314 .global GNAME(fun_end_breakpoint_end)
315 GNAME(fun_end_breakpoint_end):
318 .global GNAME(do_pending_interrupt)
319 .type GNAME(do_pending_interrupt),@function
320 .align align_4byte,0x90
321 GNAME(do_pending_interrupt):
323 .byte trap_PendingInterrupt
325 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
327 #ifdef LISP_FEATURE_GENCGC
328 /* This is a fast bzero using the FPU. The first argument is the start
329 * address which needs to be aligned on an 8 byte boundary, the second
330 * argument is the number of bytes, which must be a nonzero multiple
332 /* FIXME whether this is still faster than using the OS's bzero or
333 * equivalent, we don't know */
335 .globl GNAME(i586_bzero)
336 .type GNAME(i586_bzero),@function
337 .align align_4byte,0x90
339 movl 4(%esp),%edx # Load the start address.
340 movl 8(%esp),%eax # Load the number of bytes.
348 .size GNAME(i586_bzero),.-GNAME(i586_bzero)
353 * Allocate bytes and return the start of the allocated space
354 * in the specified destination register.
356 * In the general case the size will be in the destination register.
358 * All registers must be preserved except the destination.
359 * The C conventions will preserve ebx, esi, edi, and ebp.
360 * So only eax, ecx, and edx need special care here.
363 .globl GNAME(alloc_to_eax)
364 .type GNAME(alloc_to_eax),@function
365 .align align_4byte,0x90
367 pushl %ecx # Save ecx and edx as C could destroy them.
369 pushl %eax # Push the size.
371 addl $4,%esp # Pop the size arg.
372 popl %edx # Restore ecx and edx.
375 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
377 .globl GNAME(alloc_8_to_eax)
378 .type GNAME(alloc_8_to_eax),@function
379 .align align_4byte,0x90
380 GNAME(alloc_8_to_eax):
381 pushl %ecx # Save ecx and edx as C could destroy them.
383 pushl $8 # Push the size.
385 addl $4,%esp # Pop the size arg.
386 popl %edx # Restore ecx and edx.
389 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
391 .globl GNAME(alloc_8_to_eax)
392 .type GNAME(alloc_8_to_eax),@function
393 .align align_4byte,0x90
395 .globl GNAME(alloc_16_to_eax)
396 .type GNAME(alloc_16_to_eax),@function
397 .align align_4byte,0x90
398 GNAME(alloc_16_to_eax):
399 pushl %ecx # Save ecx and edx as C could destroy them.
401 pushl $16 # Push the size.
403 addl $4,%esp # Pop the size arg.
404 popl %edx # Restore ecx and edx.
407 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
409 .globl GNAME(alloc_to_ecx)
410 .type GNAME(alloc_to_ecx),@function
411 .align align_4byte,0x90
413 pushl %eax # Save eax and edx as C could destroy them.
415 pushl %ecx # Push the size.
417 addl $4,%esp # Pop the size arg.
418 movl %eax,%ecx # Set up the destination.
419 popl %edx # Restore eax and edx.
422 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
424 .globl GNAME(alloc_8_to_ecx)
425 .type GNAME(alloc_8_to_ecx),@function
426 .align align_4byte,0x90
427 GNAME(alloc_8_to_ecx):
428 pushl %eax # Save eax and edx as C could destroy them.
430 pushl $8 # Push the size.
432 addl $4,%esp # Pop the size arg.
433 movl %eax,%ecx # Set up the destination.
434 popl %edx # Restore eax and edx.
437 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
439 .globl GNAME(alloc_16_to_ecx)
440 .type GNAME(alloc_16_to_ecx),@function
441 .align align_4byte,0x90
442 GNAME(alloc_16_to_ecx):
443 pushl %eax # Save eax and edx as C could destroy them.
445 pushl $16 # Push the size.
447 addl $4,%esp # Pop the size arg.
448 movl %eax,%ecx # Set up the destination.
449 popl %edx # Restore eax and edx.
452 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
455 .globl GNAME(alloc_to_edx)
456 .type GNAME(alloc_to_edx),@function
457 .align align_4byte,0x90
459 pushl %eax # Save eax and ecx as C could destroy them.
461 pushl %edx # Push the size.
463 addl $4,%esp # Pop the size arg.
464 movl %eax,%edx # Set up the destination.
465 popl %ecx # Restore eax and ecx.
468 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
470 .globl GNAME(alloc_8_to_edx)
471 .type GNAME(alloc_8_to_edx),@function
472 .align align_4byte,0x90
473 GNAME(alloc_8_to_edx):
474 pushl %eax # Save eax and ecx as C could destroy them.
476 pushl $8 # Push the size.
478 addl $4,%esp # Pop the size arg.
479 movl %eax,%edx # Set up the destination.
480 popl %ecx # Restore eax and ecx.
483 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
485 .globl GNAME(alloc_16_to_edx)
486 .type GNAME(alloc_16_to_edx),@function
487 .align align_4byte,0x90
488 GNAME(alloc_16_to_edx):
489 pushl %eax # Save eax and ecx as C could destroy them.
491 pushl $16 # Push the size.
493 addl $4,%esp # Pop the size arg.
494 movl %eax,%edx # Set up the destination.
495 popl %ecx # Restore eax and ecx.
498 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
502 .globl GNAME(alloc_to_ebx)
503 .type GNAME(alloc_to_ebx),@function
504 .align align_4byte,0x90
506 pushl %eax # Save eax, ecx, and edx as C could destroy them.
509 pushl %ebx # Push the size.
511 addl $4,%esp # Pop the size arg.
512 movl %eax,%ebx # Set up the destination.
513 popl %edx # Restore eax, ecx and edx.
517 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
519 .globl GNAME(alloc_8_to_ebx)
520 .type GNAME(alloc_8_to_ebx),@function
521 .align align_4byte,0x90
522 GNAME(alloc_8_to_ebx):
523 pushl %eax # Save eax, ecx, and edx as C could destroy them.
526 pushl $8 # Push the size.
528 addl $4,%esp # Pop the size arg.
529 movl %eax,%ebx # Set up the destination.
530 popl %edx # Restore eax, ecx and edx.
534 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
536 .globl GNAME(alloc_16_to_ebx)
537 .type GNAME(alloc_16_to_ebx),@function
538 .align align_4byte,0x90
539 GNAME(alloc_16_to_ebx):
540 pushl %eax # Save eax, ecx, and edx as C could destroy them.
543 pushl $16 # Push the size
545 addl $4,%esp # pop the size arg.
546 movl %eax,%ebx # setup the destination.
547 popl %edx # Restore eax, ecx and edx.
551 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
555 .globl GNAME(alloc_to_esi)
556 .type GNAME(alloc_to_esi),@function
557 .align align_4byte,0x90
559 pushl %eax # Save eax, ecx, and edx as C could destroy them.
562 pushl %esi # Push the size
564 addl $4,%esp # pop the size arg.
565 movl %eax,%esi # setup the destination.
566 popl %edx # Restore eax, ecx and edx.
570 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
572 .globl GNAME(alloc_8_to_esi)
573 .type GNAME(alloc_8_to_esi),@function
574 .align align_4byte,0x90
575 GNAME(alloc_8_to_esi):
576 pushl %eax # Save eax, ecx, and edx as C could destroy them.
579 pushl $8 # Push the size
581 addl $4,%esp # pop the size arg.
582 movl %eax,%esi # setup the destination.
583 popl %edx # Restore eax, ecx and edx.
587 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
589 .globl GNAME(alloc_16_to_esi)
590 .type GNAME(alloc_16_to_esi),@function
591 .align align_4byte,0x90
592 GNAME(alloc_16_to_esi):
593 pushl %eax # Save eax, ecx, and edx as C could destroy them.
596 pushl $16 # Push the size
598 addl $4,%esp # pop the size arg.
599 movl %eax,%esi # setup the destination.
600 popl %edx # Restore eax, ecx and edx.
604 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
607 .globl GNAME(alloc_to_edi)
608 .type GNAME(alloc_to_edi),@function
609 .align align_4byte,0x90
611 pushl %eax # Save eax, ecx, and edx as C could destroy them.
614 pushl %edi # Push the size
616 addl $4,%esp # pop the size arg.
617 movl %eax,%edi # setup the destination.
618 popl %edx # Restore eax, ecx and edx.
622 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
624 .globl GNAME(alloc_8_to_edi)
625 .type GNAME(alloc_8_to_edi),@function
626 .align align_4byte,0x90
627 GNAME(alloc_8_to_edi):
628 pushl %eax # Save eax, ecx, and edx as C could destroy them.
631 pushl $8 # Push the size
633 addl $4,%esp # pop the size arg.
634 movl %eax,%edi # setup the destination.
635 popl %edx # Restore eax, ecx and edx.
639 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
641 .globl GNAME(alloc_16_to_edi)
642 .type GNAME(alloc_16_to_edi),@function
643 .align align_4byte,0x90
644 GNAME(alloc_16_to_edi):
645 pushl %eax # Save eax, ecx, and edx as C could destroy them.
648 pushl $16 # Push the size
650 addl $4,%esp # pop the size arg.
651 movl %eax,%edi # setup the destination.
652 popl %edx # Restore eax, ecx and edx.
656 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
660 #ifdef LISP_FEATURE_GENCGC
662 /* These routines are called from Lisp when an inline allocation
663 * overflows. Every register except the result needs to be preserved.
664 * We depend on C to preserve ebx, esi, edi, and ebp.
665 * But where necessary must save eax, ecx, edx. */
667 /* This routine handles an overflow with eax=crfp+size. So the
670 .globl GNAME(alloc_overflow_eax)
671 .type GNAME(alloc_overflow_eax),@function
672 GNAME(alloc_overflow_eax):
673 pushl %ecx # Save ecx
674 pushl %edx # Save edx
675 /* Calculate the size for the allocation. */
676 subl GNAME(current_region_free_pointer),%eax
677 pushl %eax # Push the size
679 addl $4,%esp # pop the size arg.
680 popl %edx # Restore edx.
681 popl %ecx # Restore ecx.
682 addl $6,(%esp) # Adjust the return address to skip the next inst.
684 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
686 /* This routine handles an overflow with ecx=crfp+size. So the
689 .globl GNAME(alloc_overflow_ecx)
690 .type GNAME(alloc_overflow_ecx),@function
691 GNAME(alloc_overflow_ecx):
692 pushl %eax # Save eax
693 pushl %edx # Save edx
694 /* Calculate the size for the allocation. */
695 subl GNAME(current_region_free_pointer),%ecx
696 pushl %ecx # Push the size
698 addl $4,%esp # pop the size arg.
699 movl %eax,%ecx # setup the destination.
700 popl %edx # Restore edx.
701 popl %eax # Restore eax.
702 addl $6,(%esp) # Adjust the return address to skip the next inst.
704 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
706 /* This routine handles an overflow with edx=crfp+size. So the
709 .globl GNAME(alloc_overflow_edx)
710 .type GNAME(alloc_overflow_edx),@function
711 GNAME(alloc_overflow_edx):
712 pushl %eax # Save eax
713 pushl %ecx # Save ecx
714 /* Calculate the size for the allocation. */
715 subl GNAME(current_region_free_pointer),%edx
716 pushl %edx # Push the size
718 addl $4,%esp # pop the size arg.
719 movl %eax,%edx # setup the destination.
720 popl %ecx # Restore ecx.
721 popl %eax # Restore eax.
722 addl $6,(%esp) # Adjust the return address to skip the next inst.
724 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
726 /* This routine handles an overflow with ebx=crfp+size. So the
729 .globl GNAME(alloc_overflow_ebx)
730 .type GNAME(alloc_overflow_ebx),@function
731 GNAME(alloc_overflow_ebx):
732 pushl %eax # Save 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),%ebx
737 pushl %ebx # Push the size
739 addl $4,%esp # pop the size arg.
740 movl %eax,%ebx # setup the destination.
741 popl %edx # Restore edx.
742 popl %ecx # Restore ecx.
743 popl %eax # Restore eax.
744 addl $6,(%esp) # Adjust the return address to skip the next inst.
746 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
748 /* This routine handles an overflow with esi=crfp+size. So the
751 .globl GNAME(alloc_overflow_esi)
752 .type GNAME(alloc_overflow_esi),@function
753 GNAME(alloc_overflow_esi):
754 pushl %eax # Save eax
755 pushl %ecx # Save ecx
756 pushl %edx # Save edx
757 /* Calculate the size for the allocation. */
758 subl GNAME(current_region_free_pointer),%esi
759 pushl %esi # Push the size
761 addl $4,%esp # pop the size arg.
762 movl %eax,%esi # setup the destination.
763 popl %edx # Restore edx.
764 popl %ecx # Restore ecx.
765 popl %eax # Restore eax.
766 addl $6,(%esp) # Adjust the return address to skip the next inst.
768 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
770 /* This routine handles an overflow with edi=crfp+size. So the
773 .globl GNAME(alloc_overflow_edi)
774 .type GNAME(alloc_overflow_edi),@function
775 GNAME(alloc_overflow_edi):
776 pushl %eax # Save eax
777 pushl %ecx # Save ecx
778 pushl %edx # Save edx
779 /* Calculate the size for the allocation. */
780 subl GNAME(current_region_free_pointer),%edi
781 pushl %edi # Push the size
783 addl $4,%esp # pop the size arg.
784 movl %eax,%edi # setup the destination.
785 popl %edx # Restore edx.
786 popl %ecx # Restore ecx.
787 popl %eax # Restore eax.
788 addl $6,(%esp) # Adjust the return address to skip the next inst.
790 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)