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
19 #include "genesis/closure.h"
20 #include "genesis/fdefn.h"
21 #include "genesis/static-symbols.h"
22 #include "genesis/symbol.h"
23 #include "genesis/thread.h"
25 /* Minimize conditionalization for different OS naming schemes. */
26 #if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ /* (but *not* OpenBSD) */
27 #define GNAME(var) var
29 #define GNAME(var) _##var
32 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
33 * want alignment in bytes. */
34 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
37 #define align_16byte 16
41 #define align_16byte 4
45 .global GNAME(foreign_function_call_active)
46 .global GNAME(all_threads)
50 * A call to call_into_c preserves esi, edi, and ebp.
51 * (The C function will preserve ebx, esi, edi, and ebp across its
52 * function call, but we trash ebx ourselves by using it to save the
53 * return Lisp address.)
55 * Return values are in eax and maybe edx for quads, or st(0) for
58 * This should work for Lisp calls C calls Lisp calls C..
61 .align align_16byte,0x90
62 .global GNAME(call_into_c)
63 .type GNAME(call_into_c),@function
65 movl $1,GNAME(foreign_function_call_active)
67 /* Save the return Lisp address in ebx. */
70 /* Setup the NPX for C */
80 call *%eax # normal callout using Lisp stack
82 movl %eax,%ecx # remember integer return value
84 /* Check for a return FP value. */
91 /* The return value is in eax, or eax,edx? */
92 /* Set up the NPX stack for Lisp. */
93 fldz # Ensure no regs are empty.
102 /* Restore the return value. */
103 movl %ecx,%eax # maybe return value
105 movl $0,GNAME(foreign_function_call_active)
110 /* The return result is in st(0). */
111 /* Set up the NPX stack for Lisp, placing the result in st(0). */
112 fldz # Ensure no regs are empty.
119 fxch %st(7) # Move the result back to st(0).
121 /* We don't need to restore eax, because the result is in st(0). */
123 movl $0,GNAME(foreign_function_call_active)
127 .size GNAME(call_into_c), . - GNAME(call_into_c)
131 .global GNAME(call_into_lisp_first_time)
132 .type GNAME(call_into_lisp_first_time),@function
134 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
135 * the stack changes. We don't worry too much about saving registers
136 * here, because we never expect to return from the initial call to lisp
139 .align align_16byte,0x90
140 GNAME(call_into_lisp_first_time):
141 pushl %ebp # Save old frame pointer.
142 movl %esp,%ebp # Establish new frame.
143 movl %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
144 movl GNAME(all_threads),%eax
145 movl THREAD_CONTROL_STACK_START_OFFSET(%eax) ,%esp
146 /* don't think too hard about what happens if we get interrupted
148 addl $THREAD_CONTROL_STACK_SIZE-4,%esp
152 .global GNAME(call_into_lisp)
153 .type GNAME(call_into_lisp),@function
155 /* The C conventions require that ebx, esi, edi, and ebp be preserved
156 * across function calls. */
158 .align align_16byte,0x90
159 GNAME(call_into_lisp):
160 pushl %ebp # Save old frame pointer.
161 movl %esp,%ebp # Establish new frame.
163 /* Save the NPX state */
164 fwait # Catch any pending NPX exceptions.
165 subl $108,%esp # Make room for the NPX state.
166 fnsave (%esp) # save and reset NPX
168 movl (%esp),%eax # Load NPX control word.
169 andl $0xfffff3ff,%eax # Set rounding mode to nearest.
170 orl $0x00000300,%eax # Set precision to 64 bits.
172 fldcw (%esp) # Recover modes.
175 fldz # Ensure no FP regs are empty.
184 /* Save C regs: ebx esi edi. */
189 /* Clear descriptor regs. */
190 xorl %eax,%eax # lexenv
191 xorl %ebx,%ebx # available
192 xorl %ecx,%ecx # arg count
193 xorl %edx,%edx # first arg
194 xorl %edi,%edi # second arg
195 xorl %esi,%esi # third arg
197 /* no longer in function call */
198 movl %eax, GNAME(foreign_function_call_active)
200 movl %esp,%ebx # remember current stack
201 pushl %ebx # Save entry stack on (maybe) new stack.
203 /* Establish Lisp args. */
204 movl 8(%ebp),%eax # lexenv?
205 movl 12(%ebp),%ebx # address of arg vec
206 movl 16(%ebp),%ecx # num args
207 shll $2,%ecx # Make num args into fixnum.
210 movl (%ebx),%edx # arg0
213 movl 4(%ebx),%edi # arg1
216 movl 8(%ebx),%esi # arg2
218 /* Registers eax, ecx, edx, edi, and esi are now live. */
220 /* Alloc new frame. */
221 mov %esp,%ebx # The current sp marks start of new frame.
222 push %ebp # fp in save location S0
223 sub $8,%esp # Ensure 3 slots are allocated, one above.
224 mov %ebx,%ebp # Switch to new frame.
226 call *CLOSURE_FUN_OFFSET(%eax)
228 /* If the function returned multiple values, it will return to
229 this point. Lose them */
231 /* A singled value function returns here */
233 /* Restore the stack, in case there was a stack change. */
236 /* Restore C regs: ebx esi edi. */
241 /* Restore the NPX state. */
246 movl %edx,%eax # c-val
248 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
250 /* support for saving and restoring the NPX state from C */
252 .global GNAME(fpu_save)
253 .type GNAME(fpu_save),@function
257 fnsave (%eax) # Save the NPX state. (resets NPX)
259 .size GNAME(fpu_save),.-GNAME(fpu_save)
261 .global GNAME(fpu_restore)
262 .type GNAME(fpu_restore),@function
266 frstor (%eax) # Restore the NPX state.
268 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
271 * the undefined-function trampoline
274 .align align_4byte,0x90
275 .global GNAME(undefined_tramp)
276 .type GNAME(undefined_tramp),@function
277 GNAME(undefined_tramp):
281 .byte UNDEFINED_FUN_ERROR
282 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
284 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
287 * the closure trampoline
290 .align align_4byte,0x90
291 .global GNAME(closure_tramp)
292 .type GNAME(closure_tramp),@function
293 GNAME(closure_tramp):
294 movl FDEFN_FUN_OFFSET(%eax),%eax
295 /* FIXME: The '*' after "jmp" in the next line is from PVE's
296 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
297 * reasonable, and it certainly seems as though if CMU CL needs it,
298 * SBCL needs it too, but I haven't actually verified that it's
299 * right. It would be good to find a way to force the flow of
300 * control through here to test it. */
301 jmp *CLOSURE_FUN_OFFSET(%eax)
302 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
305 * fun-end breakpoint magic
308 .global GNAME(fun_end_breakpoint_guts)
310 GNAME(fun_end_breakpoint_guts):
311 /* Multiple Value return */
312 jmp multiple_value_return
313 /* Single value return: The eventual return will now use the
314 multiple values return convention but with a return values
316 movl %esp,%ebx # Setup ebx - the ofp.
317 subl $4,%esp # Allocate one stack slot for the return value
318 movl $4,%ecx # Setup ecx for one return value.
319 movl $NIL,%edi # default second value
320 movl $NIL,%esi # default third value
322 multiple_value_return:
324 .global GNAME(fun_end_breakpoint_trap)
325 GNAME(fun_end_breakpoint_trap):
327 .byte trap_FunEndBreakpoint
328 hlt # We should never return here.
330 .global GNAME(fun_end_breakpoint_end)
331 GNAME(fun_end_breakpoint_end):
334 .global GNAME(do_pending_interrupt)
335 .type GNAME(do_pending_interrupt),@function
336 .align align_4byte,0x90
337 GNAME(do_pending_interrupt):
339 .byte trap_PendingInterrupt
341 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
345 * Allocate bytes and return the start of the allocated space
346 * in the specified destination register.
348 * In the general case the size will be in the destination register.
350 * All registers must be preserved except the destination.
351 * The C conventions will preserve ebx, esi, edi, and ebp.
352 * So only eax, ecx, and edx need special care here.
355 .globl GNAME(alloc_to_eax)
356 .type GNAME(alloc_to_eax),@function
357 .align align_4byte,0x90
359 pushl %ecx # Save ecx and edx as C could destroy them.
361 pushl %eax # Push the size.
363 addl $4,%esp # Pop the size arg.
364 popl %edx # Restore ecx and edx.
367 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
369 .globl GNAME(alloc_8_to_eax)
370 .type GNAME(alloc_8_to_eax),@function
371 .align align_4byte,0x90
372 GNAME(alloc_8_to_eax):
373 pushl %ecx # Save ecx and edx as C could destroy them.
375 pushl $8 # Push the size.
377 addl $4,%esp # Pop the size arg.
378 popl %edx # Restore ecx and edx.
381 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
383 .globl GNAME(alloc_8_to_eax)
384 .type GNAME(alloc_8_to_eax),@function
385 .align align_4byte,0x90
387 .globl GNAME(alloc_16_to_eax)
388 .type GNAME(alloc_16_to_eax),@function
389 .align align_4byte,0x90
390 GNAME(alloc_16_to_eax):
391 pushl %ecx # Save ecx and edx as C could destroy them.
393 pushl $16 # Push the size.
395 addl $4,%esp # Pop the size arg.
396 popl %edx # Restore ecx and edx.
399 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
401 .globl GNAME(alloc_to_ecx)
402 .type GNAME(alloc_to_ecx),@function
403 .align align_4byte,0x90
405 pushl %eax # Save eax and edx as C could destroy them.
407 pushl %ecx # Push the size.
409 addl $4,%esp # Pop the size arg.
410 movl %eax,%ecx # Set up the destination.
411 popl %edx # Restore eax and edx.
414 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
416 .globl GNAME(alloc_8_to_ecx)
417 .type GNAME(alloc_8_to_ecx),@function
418 .align align_4byte,0x90
419 GNAME(alloc_8_to_ecx):
420 pushl %eax # Save eax and edx as C could destroy them.
422 pushl $8 # Push the size.
424 addl $4,%esp # Pop the size arg.
425 movl %eax,%ecx # Set up the destination.
426 popl %edx # Restore eax and edx.
429 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
431 .globl GNAME(alloc_16_to_ecx)
432 .type GNAME(alloc_16_to_ecx),@function
433 .align align_4byte,0x90
434 GNAME(alloc_16_to_ecx):
435 pushl %eax # Save eax and edx as C could destroy them.
437 pushl $16 # Push the size.
439 addl $4,%esp # Pop the size arg.
440 movl %eax,%ecx # Set up the destination.
441 popl %edx # Restore eax and edx.
444 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
447 .globl GNAME(alloc_to_edx)
448 .type GNAME(alloc_to_edx),@function
449 .align align_4byte,0x90
451 pushl %eax # Save eax and ecx as C could destroy them.
453 pushl %edx # Push the size.
455 addl $4,%esp # Pop the size arg.
456 movl %eax,%edx # Set up the destination.
457 popl %ecx # Restore eax and ecx.
460 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
462 .globl GNAME(alloc_8_to_edx)
463 .type GNAME(alloc_8_to_edx),@function
464 .align align_4byte,0x90
465 GNAME(alloc_8_to_edx):
466 pushl %eax # Save eax and ecx as C could destroy them.
468 pushl $8 # Push the size.
470 addl $4,%esp # Pop the size arg.
471 movl %eax,%edx # Set up the destination.
472 popl %ecx # Restore eax and ecx.
475 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
477 .globl GNAME(alloc_16_to_edx)
478 .type GNAME(alloc_16_to_edx),@function
479 .align align_4byte,0x90
480 GNAME(alloc_16_to_edx):
481 pushl %eax # Save eax and ecx as C could destroy them.
483 pushl $16 # Push the size.
485 addl $4,%esp # Pop the size arg.
486 movl %eax,%edx # Set up the destination.
487 popl %ecx # Restore eax and ecx.
490 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
494 .globl GNAME(alloc_to_ebx)
495 .type GNAME(alloc_to_ebx),@function
496 .align align_4byte,0x90
498 pushl %eax # Save eax, ecx, and edx as C could destroy them.
501 pushl %ebx # Push the size.
503 addl $4,%esp # Pop the size arg.
504 movl %eax,%ebx # Set up the destination.
505 popl %edx # Restore eax, ecx and edx.
509 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
511 .globl GNAME(alloc_8_to_ebx)
512 .type GNAME(alloc_8_to_ebx),@function
513 .align align_4byte,0x90
514 GNAME(alloc_8_to_ebx):
515 pushl %eax # Save eax, ecx, and edx as C could destroy them.
518 pushl $8 # Push the size.
520 addl $4,%esp # Pop the size arg.
521 movl %eax,%ebx # Set up the destination.
522 popl %edx # Restore eax, ecx and edx.
526 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
528 .globl GNAME(alloc_16_to_ebx)
529 .type GNAME(alloc_16_to_ebx),@function
530 .align align_4byte,0x90
531 GNAME(alloc_16_to_ebx):
532 pushl %eax # Save eax, ecx, and edx as C could destroy them.
535 pushl $16 # Push the size
537 addl $4,%esp # pop the size arg.
538 movl %eax,%ebx # setup the destination.
539 popl %edx # Restore eax, ecx and edx.
543 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
547 .globl GNAME(alloc_to_esi)
548 .type GNAME(alloc_to_esi),@function
549 .align align_4byte,0x90
551 pushl %eax # Save eax, ecx, and edx as C could destroy them.
554 pushl %esi # Push the size
556 addl $4,%esp # pop the size arg.
557 movl %eax,%esi # setup the destination.
558 popl %edx # Restore eax, ecx and edx.
562 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
564 .globl GNAME(alloc_8_to_esi)
565 .type GNAME(alloc_8_to_esi),@function
566 .align align_4byte,0x90
567 GNAME(alloc_8_to_esi):
568 pushl %eax # Save eax, ecx, and edx as C could destroy them.
571 pushl $8 # Push the size
573 addl $4,%esp # pop the size arg.
574 movl %eax,%esi # setup the destination.
575 popl %edx # Restore eax, ecx and edx.
579 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
581 .globl GNAME(alloc_16_to_esi)
582 .type GNAME(alloc_16_to_esi),@function
583 .align align_4byte,0x90
584 GNAME(alloc_16_to_esi):
585 pushl %eax # Save eax, ecx, and edx as C could destroy them.
588 pushl $16 # Push the size
590 addl $4,%esp # pop the size arg.
591 movl %eax,%esi # setup the destination.
592 popl %edx # Restore eax, ecx and edx.
596 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
599 .globl GNAME(alloc_to_edi)
600 .type GNAME(alloc_to_edi),@function
601 .align align_4byte,0x90
603 pushl %eax # Save eax, ecx, and edx as C could destroy them.
606 pushl %edi # Push the size
608 addl $4,%esp # pop the size arg.
609 movl %eax,%edi # setup the destination.
610 popl %edx # Restore eax, ecx and edx.
614 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
616 .globl GNAME(alloc_8_to_edi)
617 .type GNAME(alloc_8_to_edi),@function
618 .align align_4byte,0x90
619 GNAME(alloc_8_to_edi):
620 pushl %eax # Save eax, ecx, and edx as C could destroy them.
623 pushl $8 # Push the size
625 addl $4,%esp # pop the size arg.
626 movl %eax,%edi # setup the destination.
627 popl %edx # Restore eax, ecx and edx.
631 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
633 .globl GNAME(alloc_16_to_edi)
634 .type GNAME(alloc_16_to_edi),@function
635 .align align_4byte,0x90
636 GNAME(alloc_16_to_edi):
637 pushl %eax # Save eax, ecx, and edx as C could destroy them.
640 pushl $16 # Push the size
642 addl $4,%esp # pop the size arg.
643 movl %eax,%edi # setup the destination.
644 popl %edx # Restore eax, ecx and edx.
648 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
651 .align align_4byte,0x90
652 .globl GNAME(post_signal_tramp)
653 .type GNAME(post_signal_tramp),@function
654 GNAME(post_signal_tramp):
655 /* this is notionally the second half of a function whose first half
656 * doesn't exist. This is where call_into_lisp returns when called
657 * using return_to_lisp_function */
658 addl $12,%esp /* clear call_into_lisp args from stack */
659 popa /* restore registers */
662 .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)
666 #ifdef GENCGC_INLINE_ALLOC /* LISP_FEATURE_GENCGC */
668 /* These routines are called from Lisp when an inline allocation
669 * overflows. Every register except the result needs to be preserved.
670 * We depend on C to preserve ebx, esi, edi, and ebp.
671 * But where necessary must save eax, ecx, edx. */
673 /* This routine handles an overflow with eax=crfp+size. So the
676 .globl GNAME(alloc_overflow_eax)
677 .type GNAME(alloc_overflow_eax),@function
678 GNAME(alloc_overflow_eax):
679 pushl %ecx # Save ecx
680 pushl %edx # Save edx
681 /* Calculate the size for the allocation. */
682 subl GNAME(current_region_free_pointer),%eax
683 pushl %eax # Push the size
685 addl $4,%esp # pop the size arg.
686 popl %edx # Restore edx.
687 popl %ecx # Restore ecx.
688 addl $6,(%esp) # Adjust the return address to skip the next inst.
690 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
692 /* This routine handles an overflow with ecx=crfp+size. So the
695 .globl GNAME(alloc_overflow_ecx)
696 .type GNAME(alloc_overflow_ecx),@function
697 GNAME(alloc_overflow_ecx):
698 pushl %eax # Save eax
699 pushl %edx # Save edx
700 /* Calculate the size for the allocation. */
701 subl GNAME(current_region_free_pointer),%ecx
702 pushl %ecx # Push the size
704 addl $4,%esp # pop the size arg.
705 movl %eax,%ecx # setup the destination.
706 popl %edx # Restore edx.
707 popl %eax # Restore eax.
708 addl $6,(%esp) # Adjust the return address to skip the next inst.
710 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
712 /* This routine handles an overflow with edx=crfp+size. So the
715 .globl GNAME(alloc_overflow_edx)
716 .type GNAME(alloc_overflow_edx),@function
717 GNAME(alloc_overflow_edx):
718 pushl %eax # Save eax
719 pushl %ecx # Save ecx
720 /* Calculate the size for the allocation. */
721 subl GNAME(current_region_free_pointer),%edx
722 pushl %edx # Push the size
724 addl $4,%esp # pop the size arg.
725 movl %eax,%edx # setup the destination.
726 popl %ecx # Restore ecx.
727 popl %eax # Restore eax.
728 addl $6,(%esp) # Adjust the return address to skip the next inst.
730 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
732 /* This routine handles an overflow with ebx=crfp+size. So the
735 .globl GNAME(alloc_overflow_ebx)
736 .type GNAME(alloc_overflow_ebx),@function
737 GNAME(alloc_overflow_ebx):
738 pushl %eax # Save eax
739 pushl %ecx # Save ecx
740 pushl %edx # Save edx
741 /* Calculate the size for the allocation. */
742 subl GNAME(current_region_free_pointer),%ebx
743 pushl %ebx # Push the size
745 addl $4,%esp # pop the size arg.
746 movl %eax,%ebx # setup the destination.
747 popl %edx # Restore edx.
748 popl %ecx # Restore ecx.
749 popl %eax # Restore eax.
750 addl $6,(%esp) # Adjust the return address to skip the next inst.
752 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
754 /* This routine handles an overflow with esi=crfp+size. So the
757 .globl GNAME(alloc_overflow_esi)
758 .type GNAME(alloc_overflow_esi),@function
759 GNAME(alloc_overflow_esi):
760 pushl %eax # Save eax
761 pushl %ecx # Save ecx
762 pushl %edx # Save edx
763 /* Calculate the size for the allocation. */
764 subl GNAME(current_region_free_pointer),%esi
765 pushl %esi # Push the size
767 addl $4,%esp # pop the size arg.
768 movl %eax,%esi # setup the destination.
769 popl %edx # Restore edx.
770 popl %ecx # Restore ecx.
771 popl %eax # Restore eax.
772 addl $6,(%esp) # Adjust the return address to skip the next inst.
774 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
776 /* This routine handles an overflow with edi=crfp+size. So the
779 .globl GNAME(alloc_overflow_edi)
780 .type GNAME(alloc_overflow_edi),@function
781 GNAME(alloc_overflow_edi):
782 pushl %eax # Save eax
783 pushl %ecx # Save ecx
784 pushl %edx # Save edx
785 /* Calculate the size for the allocation. */
786 subl GNAME(current_region_free_pointer),%edi
787 pushl %edi # Push the size
789 addl $4,%esp # pop the size arg.
790 movl %eax,%edi # setup the destination.
791 popl %edx # Restore edx.
792 popl %ecx # Restore ecx.
793 popl %eax # Restore eax.
794 addl $6,(%esp) # Adjust the return address to skip the next inst.
796 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)