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.
27 * (As of sbcl-0.8.10, this seems no longer to be much of an issue,
28 * since everyone has converged on ELF. If this generality really
29 * turns out not to matter, perhaps it's just clutter we could get
30 * rid of? -- WHN 2004-04-18)
32 #if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
33 #define GNAME(var) var
35 #define GNAME(var) _##var
38 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
39 * want alignment in bytes.
41 * (As in the GNAME() definitions above, as of sbcl-0.8.10, this seems
42 * no longer to be much of an issue, since everyone has converged on
43 * the same value. If this generality really turns out not to
44 * matter any more, perhaps it's just clutter we could get
45 * rid of? -- WHN 2004-04-18)
47 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
50 #define align_16byte 16
54 #define align_16byte 4
58 .global GNAME(foreign_function_call_active)
59 .global GNAME(all_threads)
62 * A call to call_into_c preserves esi, edi, and ebp.
63 * (The C function will preserve ebx, esi, edi, and ebp across its
64 * function call, but we trash ebx ourselves by using it to save the
65 * return Lisp address.)
67 * Return values are in eax and maybe edx for quads, or st(0) for
70 * This should work for Lisp calls C calls Lisp calls C..
73 .align align_16byte,0x90
74 .global GNAME(call_into_c)
75 .type GNAME(call_into_c),@function
77 movl $1,GNAME(foreign_function_call_active)
79 /* Save the return Lisp address in ebx. */
82 /* Setup the NPX for C */
92 call *%eax # normal callout using Lisp stack
94 movl %eax,%ecx # remember integer return value
96 /* Check for a return FP value. */
103 /* The return value is in eax, or eax,edx? */
104 /* Set up the NPX stack for Lisp. */
105 fldz # Ensure no regs are empty.
114 /* Restore the return value. */
115 movl %ecx,%eax # maybe return value
117 movl $0,GNAME(foreign_function_call_active)
122 /* The return result is in st(0). */
123 /* Set up the NPX stack for Lisp, placing the result in st(0). */
124 fldz # Ensure no regs are empty.
131 fxch %st(7) # Move the result back to st(0).
133 /* We don't need to restore eax, because the result is in st(0). */
135 movl $0,GNAME(foreign_function_call_active)
139 .size GNAME(call_into_c), . - GNAME(call_into_c)
143 .global GNAME(call_into_lisp_first_time)
144 .type GNAME(call_into_lisp_first_time),@function
146 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
147 * the stack changes. We don't worry too much about saving registers
148 * here, because we never expect to return from the initial call to lisp
151 .align align_16byte,0x90
152 GNAME(call_into_lisp_first_time):
153 pushl %ebp # Save old frame pointer.
154 movl %esp,%ebp # Establish new frame.
155 movl %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
156 movl GNAME(all_threads),%eax
157 movl THREAD_CONTROL_STACK_START_OFFSET(%eax) ,%esp
158 /* don't think too hard about what happens if we get interrupted
160 addl $THREAD_CONTROL_STACK_SIZE-4,%esp
164 .global GNAME(call_into_lisp)
165 .type GNAME(call_into_lisp),@function
167 /* The C conventions require that ebx, esi, edi, and ebp be preserved
168 * across function calls. */
170 .align align_16byte,0x90
171 GNAME(call_into_lisp):
172 pushl %ebp # Save old frame pointer.
173 movl %esp,%ebp # Establish new frame.
175 /* Save the NPX state */
176 fwait # Catch any pending NPX exceptions.
177 subl $108,%esp # Make room for the NPX state.
178 fnsave (%esp) # save and reset NPX
180 movl (%esp),%eax # Load NPX control word.
181 andl $0xfffff2ff,%eax # Set rounding mode to nearest.
182 orl $0x00000200,%eax # Set precision to 64 bits. (53-bit mantissa)
184 fldcw (%esp) # Recover modes.
187 fldz # Ensure no FP regs are empty.
196 /* Save C regs: ebx esi edi. */
201 /* Clear descriptor regs. */
202 xorl %eax,%eax # lexenv
203 xorl %ebx,%ebx # available
204 xorl %ecx,%ecx # arg count
205 xorl %edx,%edx # first arg
206 xorl %edi,%edi # second arg
207 xorl %esi,%esi # third arg
209 /* no longer in function call */
210 movl %eax, GNAME(foreign_function_call_active)
212 movl %esp,%ebx # remember current stack
213 pushl %ebx # Save entry stack on (maybe) new stack.
215 /* Establish Lisp args. */
216 movl 8(%ebp),%eax # lexenv?
217 movl 12(%ebp),%ebx # address of arg vec
218 movl 16(%ebp),%ecx # num args
219 shll $2,%ecx # Make num args into fixnum.
222 movl (%ebx),%edx # arg0
225 movl 4(%ebx),%edi # arg1
228 movl 8(%ebx),%esi # arg2
230 /* Registers eax, ecx, edx, edi, and esi are now live. */
232 /* Alloc new frame. */
233 mov %esp,%ebx # The current sp marks start of new frame.
234 push %ebp # fp in save location S0
235 sub $8,%esp # Ensure 3 slots are allocated, one above.
236 mov %ebx,%ebp # Switch to new frame.
238 call *CLOSURE_FUN_OFFSET(%eax)
240 /* If the function returned multiple values, it will return to
241 this point. Lose them */
243 /* A singled value function returns here */
245 /* Restore the stack, in case there was a stack change. */
248 /* Restore C regs: ebx esi edi. */
253 /* Restore the NPX state. */
258 movl %edx,%eax # c-val
260 .size GNAME(call_into_lisp), . - GNAME(call_into_lisp)
262 /* support for saving and restoring the NPX state from C */
264 .global GNAME(fpu_save)
265 .type GNAME(fpu_save),@function
269 fnsave (%eax) # Save the NPX state. (resets NPX)
271 .size GNAME(fpu_save),.-GNAME(fpu_save)
273 .global GNAME(fpu_restore)
274 .type GNAME(fpu_restore),@function
278 frstor (%eax) # Restore the NPX state.
280 .size GNAME(fpu_restore),.-GNAME(fpu_restore)
283 * the undefined-function trampoline
286 .align align_4byte,0x90
287 .global GNAME(undefined_tramp)
288 .type GNAME(undefined_tramp),@function
289 GNAME(undefined_tramp):
293 .byte UNDEFINED_FUN_ERROR
294 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
296 .size GNAME(undefined_tramp), .-GNAME(undefined_tramp)
299 * the closure trampoline
302 .align align_4byte,0x90
303 .global GNAME(closure_tramp)
304 .type GNAME(closure_tramp),@function
305 GNAME(closure_tramp):
306 movl FDEFN_FUN_OFFSET(%eax),%eax
307 /* FIXME: The '*' after "jmp" in the next line is from PVE's
308 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
309 * reasonable, and it certainly seems as though if CMU CL needs it,
310 * SBCL needs it too, but I haven't actually verified that it's
311 * right. It would be good to find a way to force the flow of
312 * control through here to test it. */
313 jmp *CLOSURE_FUN_OFFSET(%eax)
314 .size GNAME(closure_tramp), .-GNAME(closure_tramp)
317 * fun-end breakpoint magic
320 .global GNAME(fun_end_breakpoint_guts)
322 GNAME(fun_end_breakpoint_guts):
323 /* Multiple Value return */
324 jmp multiple_value_return
325 /* Single value return: The eventual return will now use the
326 multiple values return convention but with a return values
328 movl %esp,%ebx # Setup ebx - the ofp.
329 subl $4,%esp # Allocate one stack slot for the return value
330 movl $4,%ecx # Setup ecx for one return value.
331 movl $NIL,%edi # default second value
332 movl $NIL,%esi # default third value
334 multiple_value_return:
336 .global GNAME(fun_end_breakpoint_trap)
337 GNAME(fun_end_breakpoint_trap):
339 .byte trap_FunEndBreakpoint
340 hlt # We should never return here.
342 .global GNAME(fun_end_breakpoint_end)
343 GNAME(fun_end_breakpoint_end):
346 .global GNAME(do_pending_interrupt)
347 .type GNAME(do_pending_interrupt),@function
348 .align align_4byte,0x90
349 GNAME(do_pending_interrupt):
351 .byte trap_PendingInterrupt
353 .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
357 * Allocate bytes and return the start of the allocated space
358 * in the specified destination register.
360 * In the general case the size will be in the destination register.
362 * All registers must be preserved except the destination.
363 * The C conventions will preserve ebx, esi, edi, and ebp.
364 * So only eax, ecx, and edx need special care here.
367 .globl GNAME(alloc_to_eax)
368 .type GNAME(alloc_to_eax),@function
369 .align align_4byte,0x90
371 pushl %ecx # Save ecx and edx as C could destroy them.
373 pushl %eax # Push the size.
375 addl $4,%esp # Pop the size arg.
376 popl %edx # Restore ecx and edx.
379 .size GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
381 .globl GNAME(alloc_8_to_eax)
382 .type GNAME(alloc_8_to_eax),@function
383 .align align_4byte,0x90
384 GNAME(alloc_8_to_eax):
385 pushl %ecx # Save ecx and edx as C could destroy them.
387 pushl $8 # Push the size.
389 addl $4,%esp # Pop the size arg.
390 popl %edx # Restore ecx and edx.
393 .size GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
395 .globl GNAME(alloc_8_to_eax)
396 .type GNAME(alloc_8_to_eax),@function
397 .align align_4byte,0x90
399 .globl GNAME(alloc_16_to_eax)
400 .type GNAME(alloc_16_to_eax),@function
401 .align align_4byte,0x90
402 GNAME(alloc_16_to_eax):
403 pushl %ecx # Save ecx and edx as C could destroy them.
405 pushl $16 # Push the size.
407 addl $4,%esp # Pop the size arg.
408 popl %edx # Restore ecx and edx.
411 .size GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
413 .globl GNAME(alloc_to_ecx)
414 .type GNAME(alloc_to_ecx),@function
415 .align align_4byte,0x90
417 pushl %eax # Save eax and edx as C could destroy them.
419 pushl %ecx # Push the size.
421 addl $4,%esp # Pop the size arg.
422 movl %eax,%ecx # Set up the destination.
423 popl %edx # Restore eax and edx.
426 .size GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
428 .globl GNAME(alloc_8_to_ecx)
429 .type GNAME(alloc_8_to_ecx),@function
430 .align align_4byte,0x90
431 GNAME(alloc_8_to_ecx):
432 pushl %eax # Save eax and edx as C could destroy them.
434 pushl $8 # Push the size.
436 addl $4,%esp # Pop the size arg.
437 movl %eax,%ecx # Set up the destination.
438 popl %edx # Restore eax and edx.
441 .size GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
443 .globl GNAME(alloc_16_to_ecx)
444 .type GNAME(alloc_16_to_ecx),@function
445 .align align_4byte,0x90
446 GNAME(alloc_16_to_ecx):
447 pushl %eax # Save eax and edx as C could destroy them.
449 pushl $16 # Push the size.
451 addl $4,%esp # Pop the size arg.
452 movl %eax,%ecx # Set up the destination.
453 popl %edx # Restore eax and edx.
456 .size GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
459 .globl GNAME(alloc_to_edx)
460 .type GNAME(alloc_to_edx),@function
461 .align align_4byte,0x90
463 pushl %eax # Save eax and ecx as C could destroy them.
465 pushl %edx # Push the size.
467 addl $4,%esp # Pop the size arg.
468 movl %eax,%edx # Set up the destination.
469 popl %ecx # Restore eax and ecx.
472 .size GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
474 .globl GNAME(alloc_8_to_edx)
475 .type GNAME(alloc_8_to_edx),@function
476 .align align_4byte,0x90
477 GNAME(alloc_8_to_edx):
478 pushl %eax # Save eax and ecx as C could destroy them.
480 pushl $8 # Push the size.
482 addl $4,%esp # Pop the size arg.
483 movl %eax,%edx # Set up the destination.
484 popl %ecx # Restore eax and ecx.
487 .size GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
489 .globl GNAME(alloc_16_to_edx)
490 .type GNAME(alloc_16_to_edx),@function
491 .align align_4byte,0x90
492 GNAME(alloc_16_to_edx):
493 pushl %eax # Save eax and ecx as C could destroy them.
495 pushl $16 # Push the size.
497 addl $4,%esp # Pop the size arg.
498 movl %eax,%edx # Set up the destination.
499 popl %ecx # Restore eax and ecx.
502 .size GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
506 .globl GNAME(alloc_to_ebx)
507 .type GNAME(alloc_to_ebx),@function
508 .align align_4byte,0x90
510 pushl %eax # Save eax, ecx, and edx as C could destroy them.
513 pushl %ebx # Push the size.
515 addl $4,%esp # Pop the size arg.
516 movl %eax,%ebx # Set up the destination.
517 popl %edx # Restore eax, ecx and edx.
521 .size GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
523 .globl GNAME(alloc_8_to_ebx)
524 .type GNAME(alloc_8_to_ebx),@function
525 .align align_4byte,0x90
526 GNAME(alloc_8_to_ebx):
527 pushl %eax # Save eax, ecx, and edx as C could destroy them.
530 pushl $8 # Push the size.
532 addl $4,%esp # Pop the size arg.
533 movl %eax,%ebx # Set up the destination.
534 popl %edx # Restore eax, ecx and edx.
538 .size GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
540 .globl GNAME(alloc_16_to_ebx)
541 .type GNAME(alloc_16_to_ebx),@function
542 .align align_4byte,0x90
543 GNAME(alloc_16_to_ebx):
544 pushl %eax # Save eax, ecx, and edx as C could destroy them.
547 pushl $16 # Push the size
549 addl $4,%esp # pop the size arg.
550 movl %eax,%ebx # setup the destination.
551 popl %edx # Restore eax, ecx and edx.
555 .size GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
559 .globl GNAME(alloc_to_esi)
560 .type GNAME(alloc_to_esi),@function
561 .align align_4byte,0x90
563 pushl %eax # Save eax, ecx, and edx as C could destroy them.
566 pushl %esi # Push the size
568 addl $4,%esp # pop the size arg.
569 movl %eax,%esi # setup the destination.
570 popl %edx # Restore eax, ecx and edx.
574 .size GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
576 .globl GNAME(alloc_8_to_esi)
577 .type GNAME(alloc_8_to_esi),@function
578 .align align_4byte,0x90
579 GNAME(alloc_8_to_esi):
580 pushl %eax # Save eax, ecx, and edx as C could destroy them.
583 pushl $8 # Push the size
585 addl $4,%esp # pop the size arg.
586 movl %eax,%esi # setup the destination.
587 popl %edx # Restore eax, ecx and edx.
591 .size GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
593 .globl GNAME(alloc_16_to_esi)
594 .type GNAME(alloc_16_to_esi),@function
595 .align align_4byte,0x90
596 GNAME(alloc_16_to_esi):
597 pushl %eax # Save eax, ecx, and edx as C could destroy them.
600 pushl $16 # Push the size
602 addl $4,%esp # pop the size arg.
603 movl %eax,%esi # setup the destination.
604 popl %edx # Restore eax, ecx and edx.
608 .size GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
611 .globl GNAME(alloc_to_edi)
612 .type GNAME(alloc_to_edi),@function
613 .align align_4byte,0x90
615 pushl %eax # Save eax, ecx, and edx as C could destroy them.
618 pushl %edi # Push the size
620 addl $4,%esp # pop the size arg.
621 movl %eax,%edi # setup the destination.
622 popl %edx # Restore eax, ecx and edx.
626 .size GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
628 .globl GNAME(alloc_8_to_edi)
629 .type GNAME(alloc_8_to_edi),@function
630 .align align_4byte,0x90
631 GNAME(alloc_8_to_edi):
632 pushl %eax # Save eax, ecx, and edx as C could destroy them.
635 pushl $8 # Push the size
637 addl $4,%esp # pop the size arg.
638 movl %eax,%edi # setup the destination.
639 popl %edx # Restore eax, ecx and edx.
643 .size GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
645 .globl GNAME(alloc_16_to_edi)
646 .type GNAME(alloc_16_to_edi),@function
647 .align align_4byte,0x90
648 GNAME(alloc_16_to_edi):
649 pushl %eax # Save eax, ecx, and edx as C could destroy them.
652 pushl $16 # Push the size
654 addl $4,%esp # pop the size arg.
655 movl %eax,%edi # setup the destination.
656 popl %edx # Restore eax, ecx and edx.
660 .size GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
663 /* Called from lisp when an inline allocation overflows.
664 Every register except the result needs to be preserved.
665 We depend on C to preserve ebx, esi, edi, and ebp.
666 But where necessary must save eax, ecx, edx. */
668 #ifdef LISP_FEATURE_SB_THREAD
669 #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET
670 #define DISPLACEMENT $7
672 #define START_REGION boxed_region
673 #define DISPLACEMENT $6
676 /* This routine handles an overflow with eax=crfp+size. So the
679 .globl GNAME(alloc_overflow_eax)
680 .type GNAME(alloc_overflow_eax),@function
681 GNAME(alloc_overflow_eax):
682 pushl %ecx # Save ecx
683 pushl %edx # Save edx
684 /* Calculate the size for the allocation. */
685 subl START_REGION,%eax
686 pushl %eax # Push the size
688 addl $4,%esp # pop the size arg.
689 popl %edx # Restore edx.
690 popl %ecx # Restore ecx.
691 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
693 .size GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
696 .globl GNAME(alloc_overflow_ecx)
697 .type GNAME(alloc_overflow_ecx),@function
698 GNAME(alloc_overflow_ecx):
699 pushl %eax # Save eax
700 pushl %edx # Save edx
701 /* Calculate the size for the allocation. */
702 subl START_REGION,%ecx
703 pushl %ecx # Push the size
705 addl $4,%esp # pop the size arg.
706 movl %eax,%ecx # setup the destination.
707 popl %edx # Restore edx.
708 popl %eax # Restore eax.
709 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
711 .size GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
714 .globl GNAME(alloc_overflow_edx)
715 .type GNAME(alloc_overflow_edx),@function
716 GNAME(alloc_overflow_edx):
717 pushl %eax # Save eax
718 pushl %ecx # Save ecx
719 /* Calculate the size for the allocation. */
720 subl START_REGION,%edx
721 pushl %edx # Push the size
723 addl $4,%esp # pop the size arg.
724 movl %eax,%edx # setup the destination.
725 popl %ecx # Restore ecx.
726 popl %eax # Restore eax.
727 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
729 .size GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
731 /* This routine handles an overflow with ebx=crfp+size. So the
734 .globl GNAME(alloc_overflow_ebx)
735 .type GNAME(alloc_overflow_ebx),@function
736 GNAME(alloc_overflow_ebx):
737 pushl %eax # Save eax
738 pushl %ecx # Save ecx
739 pushl %edx # Save edx
740 /* Calculate the size for the allocation. */
741 subl START_REGION,%ebx
742 pushl %ebx # Push the size
744 addl $4,%esp # pop the size arg.
745 movl %eax,%ebx # setup the destination.
746 popl %edx # Restore edx.
747 popl %ecx # Restore ecx.
748 popl %eax # Restore eax.
749 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
751 .size GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
753 /* This routine handles an overflow with esi=crfp+size. So the
756 .globl GNAME(alloc_overflow_esi)
757 .type GNAME(alloc_overflow_esi),@function
758 GNAME(alloc_overflow_esi):
759 pushl %eax # Save eax
760 pushl %ecx # Save ecx
761 pushl %edx # Save edx
762 /* Calculate the size for the allocation. */
763 subl START_REGION,%esi
764 pushl %esi # Push the size
766 addl $4,%esp # pop the size arg.
767 movl %eax,%esi # setup the destination.
768 popl %edx # Restore edx.
769 popl %ecx # Restore ecx.
770 popl %eax # Restore eax.
771 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
773 .size GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
776 .globl GNAME(alloc_overflow_edi)
777 .type GNAME(alloc_overflow_edi),@function
778 GNAME(alloc_overflow_edi):
779 pushl %eax # Save eax
780 pushl %ecx # Save ecx
781 pushl %edx # Save edx
782 /* Calculate the size for the allocation. */
783 subl START_REGION,%edi
784 pushl %edi # Push the size
786 addl $4,%esp # pop the size arg.
787 movl %eax,%edi # setup the destination.
788 popl %edx # Restore edx.
789 popl %ecx # Restore ecx.
790 popl %eax # Restore eax.
791 addl DISPLACEMENT,(%esp) # Adjust the return address to skip the next inst.
793 .size GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)
795 .align align_4byte,0x90
796 .globl GNAME(post_signal_tramp)
797 .type GNAME(post_signal_tramp),@function
798 GNAME(post_signal_tramp):
799 /* this is notionally the second half of a function whose first half
800 * doesn't exist. This is where call_into_lisp returns when called
801 * using return_to_lisp_function */
802 addl $12,%esp /* clear call_into_lisp args from stack */
803 popa /* restore registers */
806 .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)