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 * (Except Win32, which is unlikely ever to be ELF, sorry. -- AB 2005-12-08)
34 #if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __sun
35 #define GNAME(var) var
37 #define GNAME(var) _##var
40 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
41 * want alignment in bytes.
43 * (As in the GNAME() definitions above, as of sbcl-0.8.10, this seems
44 * no longer to be much of an issue, since everyone has converged on
45 * the same value. If this generality really turns out not to
46 * matter any more, perhaps it's just clutter we could get
47 * rid of? -- WHN 2004-04-18)
49 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun) || defined(LISP_FEATURE_WIN32)
52 #define align_16byte 16
56 #define align_16byte 4
60 * The assembler used for win32 doesn't like .type or .size directives,
61 * so we want to conditionally kill them out. So let's wrap them in macros
62 * that are defined to be no-ops on win32. Hopefully this still works on
65 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
66 #define TYPE(name) .type name,@function
67 #define SIZE(name) .size name,.-name
74 * x86/darwin (as of MacOS X 10.4.5) doesn't reliably file signal
75 * handlers (SIGTRAP or Mach exception handlers) for 0xCC, wo we have
76 * to use ud2 instead. ud2 is an undefined opcode, #x0b0f, or
77 * 0F 0B in low-endian notation, that causes SIGILL to fire. We check
78 * for this instruction in the SIGILL handler and if we see it, we
79 * advance the EIP by two bytes to skip over ud2 instruction and
80 * call sigtrap_handler. */
81 #if defined(LISP_FEATURE_DARWIN)
90 .globl GNAME(foreign_function_call_active)
91 .globl GNAME(all_threads)
94 * A call to call_into_c preserves esi, edi, and ebp.
95 * (The C function will preserve ebx, esi, edi, and ebp across its
96 * function call, but we trash ebx ourselves by using it to save the
97 * return Lisp address.)
99 * Return values are in eax and maybe edx for quads, or st(0) for
102 * This should work for Lisp calls C calls Lisp calls C..
105 .align align_16byte,0x90
106 .globl GNAME(call_into_c)
107 TYPE(GNAME(call_into_c))
109 movl $1,GNAME(foreign_function_call_active)
111 /* Save the return Lisp address in ebx. */
114 /* Setup the NPX for C */
124 #ifdef LISP_FEATURE_WIN32
128 #ifdef LISP_FEATURE_DARWIN
129 andl $0xfffffff0,%esp # align stack to 16-byte boundary before calling C
131 call *%eax # normal callout using Lisp stack
133 movl %eax,%ecx # remember integer return value
135 /* Check for a return FP value. */
142 /* The return value is in eax, or eax,edx? */
143 /* Set up the NPX stack for Lisp. */
144 fldz # Ensure no regs are empty.
153 /* Restore the return value. */
154 movl %ecx,%eax # maybe return value
156 movl $0,GNAME(foreign_function_call_active)
161 /* The return result is in st(0). */
162 /* Set up the NPX stack for Lisp, placing the result in st(0). */
163 fldz # Ensure no regs are empty.
170 fxch %st(7) # Move the result back to st(0).
172 /* We don't need to restore eax, because the result is in st(0). */
174 movl $0,GNAME(foreign_function_call_active)
178 SIZE(GNAME(call_into_c))
182 .globl GNAME(call_into_lisp_first_time)
183 TYPE(GNAME(call_into_lisp_first_time))
185 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
186 * the stack changes. We don't worry too much about saving registers
187 * here, because we never expect to return from the initial call to lisp
190 .align align_16byte,0x90
191 GNAME(call_into_lisp_first_time):
192 pushl %ebp # Save old frame pointer.
193 movl %esp,%ebp # Establish new frame.
194 #ifndef LISP_FEATURE_WIN32
195 movl %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
196 movl GNAME(all_threads),%eax
197 movl THREAD_CONTROL_STACK_START_OFFSET(%eax) ,%esp
198 /* don't think too hard about what happens if we get interrupted
200 addl $(THREAD_CONTROL_STACK_SIZE),%esp
202 /* Win32 -really- doesn't like you switching stacks out from under it. */
203 movl GNAME(all_threads),%eax
208 .globl GNAME(call_into_lisp)
209 TYPE(GNAME(call_into_lisp))
211 /* The C conventions require that ebx, esi, edi, and ebp be preserved
212 * across function calls. */
214 .align align_16byte,0x90
215 GNAME(call_into_lisp):
216 pushl %ebp # Save old frame pointer.
217 movl %esp,%ebp # Establish new frame.
219 /* Save the NPX state */
220 fwait # Catch any pending NPX exceptions.
221 subl $108,%esp # Make room for the NPX state.
222 fnsave (%esp) # save and reset NPX
224 movl (%esp),%eax # Load NPX control word.
225 andl $0xfffff2ff,%eax # Set rounding mode to nearest.
226 orl $0x00000200,%eax # Set precision to 64 bits. (53-bit mantissa)
228 fldcw (%esp) # Recover modes.
231 fldz # Ensure no FP regs are empty.
240 /* Save C regs: ebx esi edi. */
245 /* Clear descriptor regs. */
246 xorl %eax,%eax # lexenv
247 xorl %ebx,%ebx # available
248 xorl %ecx,%ecx # arg count
249 xorl %edx,%edx # first arg
250 xorl %edi,%edi # second arg
251 xorl %esi,%esi # third arg
253 /* no longer in function call */
254 movl %eax, GNAME(foreign_function_call_active)
256 movl %esp,%ebx # remember current stack
257 pushl %ebx # Save entry stack on (maybe) new stack.
259 /* Establish Lisp args. */
260 movl 8(%ebp),%eax # lexenv?
261 movl 12(%ebp),%ebx # address of arg vec
262 movl 16(%ebp),%ecx # num args
263 shll $2,%ecx # Make num args into fixnum.
266 movl (%ebx),%edx # arg0
269 movl 4(%ebx),%edi # arg1
272 movl 8(%ebx),%esi # arg2
274 /* Registers eax, ecx, edx, edi, and esi are now live. */
276 /* Alloc new frame. */
277 mov %esp,%ebx # The current sp marks start of new frame.
278 push %ebp # fp in save location S0
279 sub $8,%esp # Ensure 3 slots are allocated, one above.
280 mov %ebx,%ebp # Switch to new frame.
282 call *CLOSURE_FUN_OFFSET(%eax)
284 /* If the function returned multiple values, it will return to
285 this point. Lose them */
289 /* A singled value function returns here */
291 /* Restore the stack, in case there was a stack change. */
294 /* Restore C regs: ebx esi edi. */
299 /* Restore the NPX state. */
304 movl %edx,%eax # c-val
306 SIZE(GNAME(call_into_lisp))
308 /* support for saving and restoring the NPX state from C */
310 .globl GNAME(fpu_save)
311 TYPE(GNAME(fpu_save))
315 fnsave (%eax) # Save the NPX state. (resets NPX)
317 SIZE(GNAME(fpu_save))
319 .globl GNAME(fpu_restore)
320 TYPE(GNAME(fpu_restore))
324 frstor (%eax) # Restore the NPX state.
326 SIZE(GNAME(fpu_restore))
329 * the undefined-function trampoline
332 .align align_4byte,0x90
333 .globl GNAME(undefined_tramp)
334 TYPE(GNAME(undefined_tramp))
335 .byte 0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
336 GNAME(undefined_tramp):
340 .byte UNDEFINED_FUN_ERROR
341 .byte sc_DescriptorReg # eax in the Descriptor-reg SC
343 SIZE(GNAME(undefined_tramp))
346 * the closure trampoline
349 .align align_4byte,0x90
350 .globl GNAME(closure_tramp)
351 TYPE(GNAME(closure_tramp))
352 .byte 0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
353 GNAME(closure_tramp):
354 movl FDEFN_FUN_OFFSET(%eax),%eax
355 /* FIXME: The '*' after "jmp" in the next line is from PVE's
356 * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
357 * reasonable, and it certainly seems as though if CMU CL needs it,
358 * SBCL needs it too, but I haven't actually verified that it's
359 * right. It would be good to find a way to force the flow of
360 * control through here to test it. */
361 jmp *CLOSURE_FUN_OFFSET(%eax)
362 SIZE(GNAME(closure_tramp))
365 .align align_4byte,0x90
366 .global GNAME(funcallable_instance_tramp)
367 .type GNAME(funcallable_instance_tramp),@function
368 GNAME(funcallable_instance_tramp):
369 movl FUNCALLABLE_INSTANCE_FUNCTION_OFFSET(%eax),%eax
370 /* KLUDGE: on this platform, whatever kind of function is in %rax
371 * now, the first word of it contains the address to jump to. */
372 jmp *CLOSURE_FUN_OFFSET(%eax)
373 .size GNAME(funcallable_instance_tramp), .-GNAME(funcallable_instance_tramp)
376 * fun-end breakpoint magic
379 .globl GNAME(fun_end_breakpoint_guts)
381 GNAME(fun_end_breakpoint_guts):
382 /* Multiple Value return */
383 jc multiple_value_return
384 /* Single value return: The eventual return will now use the
385 multiple values return convention but with a return values
387 movl %esp,%ebx # Setup ebx - the ofp.
388 subl $4,%esp # Allocate one stack slot for the return value
389 movl $4,%ecx # Setup ecx for one return value.
390 movl $(NIL),%edi # default second value
391 movl $(NIL),%esi # default third value
393 multiple_value_return:
395 .globl GNAME(fun_end_breakpoint_trap)
396 GNAME(fun_end_breakpoint_trap):
398 .byte trap_FunEndBreakpoint
399 hlt # We should never return here.
401 .globl GNAME(fun_end_breakpoint_end)
402 GNAME(fun_end_breakpoint_end):
405 .globl GNAME(do_pending_interrupt)
406 TYPE(GNAME(do_pending_interrupt))
407 .align align_4byte,0x90
408 GNAME(do_pending_interrupt):
410 .byte trap_PendingInterrupt
412 SIZE(GNAME(do_pending_interrupt))
416 * Allocate bytes and return the start of the allocated space
417 * in the specified destination register.
419 * In the general case the size will be in the destination register.
421 * All registers must be preserved except the destination.
422 * The C conventions will preserve ebx, esi, edi, and ebp.
423 * So only eax, ecx, and edx need special care here.
426 .globl GNAME(alloc_to_eax)
427 TYPE(GNAME(alloc_to_eax))
428 .align align_4byte,0x90
430 pushl %ecx # Save ecx and edx as C could destroy them.
432 pushl %eax # Push the size.
434 addl $4,%esp # Pop the size arg.
435 popl %edx # Restore ecx and edx.
438 SIZE(GNAME(alloc_to_eax))
440 .globl GNAME(alloc_8_to_eax)
441 TYPE(GNAME(alloc_8_to_eax))
442 .align align_4byte,0x90
443 GNAME(alloc_8_to_eax):
444 pushl %ecx # Save ecx and edx as C could destroy them.
446 pushl $8 # Push the size.
448 addl $4,%esp # Pop the size arg.
449 popl %edx # Restore ecx and edx.
452 SIZE(GNAME(alloc_8_to_eax))
454 .globl GNAME(alloc_8_to_eax)
455 TYPE(GNAME(alloc_8_to_eax))
456 .align align_4byte,0x90
458 .globl GNAME(alloc_16_to_eax)
459 TYPE(GNAME(alloc_16_to_eax))
460 .align align_4byte,0x90
461 GNAME(alloc_16_to_eax):
462 pushl %ecx # Save ecx and edx as C could destroy them.
464 pushl $16 # Push the size.
466 addl $4,%esp # Pop the size arg.
467 popl %edx # Restore ecx and edx.
470 SIZE(GNAME(alloc_16_to_eax))
472 .globl GNAME(alloc_to_ecx)
473 TYPE(GNAME(alloc_to_ecx))
474 .align align_4byte,0x90
476 pushl %eax # Save eax and edx as C could destroy them.
478 pushl %ecx # Push the size.
480 addl $4,%esp # Pop the size arg.
481 movl %eax,%ecx # Set up the destination.
482 popl %edx # Restore eax and edx.
485 SIZE(GNAME(alloc_to_ecx))
487 .globl GNAME(alloc_8_to_ecx)
488 TYPE(GNAME(alloc_8_to_ecx))
489 .align align_4byte,0x90
490 GNAME(alloc_8_to_ecx):
491 pushl %eax # Save eax and edx as C could destroy them.
493 pushl $8 # Push the size.
495 addl $4,%esp # Pop the size arg.
496 movl %eax,%ecx # Set up the destination.
497 popl %edx # Restore eax and edx.
500 SIZE(GNAME(alloc_8_to_ecx))
502 .globl GNAME(alloc_16_to_ecx)
503 TYPE(GNAME(alloc_16_to_ecx))
504 .align align_4byte,0x90
505 GNAME(alloc_16_to_ecx):
506 pushl %eax # Save eax and edx as C could destroy them.
508 pushl $16 # Push the size.
510 addl $4,%esp # Pop the size arg.
511 movl %eax,%ecx # Set up the destination.
512 popl %edx # Restore eax and edx.
515 SIZE(GNAME(alloc_16_to_ecx))
518 .globl GNAME(alloc_to_edx)
519 TYPE(GNAME(alloc_to_edx))
520 .align align_4byte,0x90
522 pushl %eax # Save eax and ecx as C could destroy them.
524 pushl %edx # Push the size.
526 addl $4,%esp # Pop the size arg.
527 movl %eax,%edx # Set up the destination.
528 popl %ecx # Restore eax and ecx.
531 SIZE(GNAME(alloc_to_edx))
533 .globl GNAME(alloc_8_to_edx)
534 TYPE(GNAME(alloc_8_to_edx))
535 .align align_4byte,0x90
536 GNAME(alloc_8_to_edx):
537 pushl %eax # Save eax and ecx as C could destroy them.
539 pushl $8 # Push the size.
541 addl $4,%esp # Pop the size arg.
542 movl %eax,%edx # Set up the destination.
543 popl %ecx # Restore eax and ecx.
546 SIZE(GNAME(alloc_8_to_edx))
548 .globl GNAME(alloc_16_to_edx)
549 TYPE(GNAME(alloc_16_to_edx))
550 .align align_4byte,0x90
551 GNAME(alloc_16_to_edx):
552 pushl %eax # Save eax and ecx as C could destroy them.
554 pushl $16 # Push the size.
556 addl $4,%esp # Pop the size arg.
557 movl %eax,%edx # Set up the destination.
558 popl %ecx # Restore eax and ecx.
561 SIZE(GNAME(alloc_16_to_edx))
565 .globl GNAME(alloc_to_ebx)
566 TYPE(GNAME(alloc_to_ebx))
567 .align align_4byte,0x90
569 pushl %eax # Save eax, ecx, and edx as C could destroy them.
572 pushl %ebx # Push the size.
574 addl $4,%esp # Pop the size arg.
575 movl %eax,%ebx # Set up the destination.
576 popl %edx # Restore eax, ecx and edx.
580 SIZE(GNAME(alloc_to_ebx))
582 .globl GNAME(alloc_8_to_ebx)
583 TYPE(GNAME(alloc_8_to_ebx))
584 .align align_4byte,0x90
585 GNAME(alloc_8_to_ebx):
586 pushl %eax # Save eax, ecx, and edx as C could destroy them.
589 pushl $8 # Push the size.
591 addl $4,%esp # Pop the size arg.
592 movl %eax,%ebx # Set up the destination.
593 popl %edx # Restore eax, ecx and edx.
597 SIZE(GNAME(alloc_8_to_ebx))
599 .globl GNAME(alloc_16_to_ebx)
600 TYPE(GNAME(alloc_16_to_ebx))
601 .align align_4byte,0x90
602 GNAME(alloc_16_to_ebx):
603 pushl %eax # Save eax, ecx, and edx as C could destroy them.
606 pushl $16 # Push the size
608 addl $4,%esp # pop the size arg.
609 movl %eax,%ebx # setup the destination.
610 popl %edx # Restore eax, ecx and edx.
614 SIZE(GNAME(alloc_16_to_ebx))
618 .globl GNAME(alloc_to_esi)
619 TYPE(GNAME(alloc_to_esi))
620 .align align_4byte,0x90
622 pushl %eax # Save eax, ecx, and edx as C could destroy them.
625 pushl %esi # Push the size
627 addl $4,%esp # pop the size arg.
628 movl %eax,%esi # setup the destination.
629 popl %edx # Restore eax, ecx and edx.
633 SIZE(GNAME(alloc_to_esi))
635 .globl GNAME(alloc_8_to_esi)
636 TYPE(GNAME(alloc_8_to_esi))
637 .align align_4byte,0x90
638 GNAME(alloc_8_to_esi):
639 pushl %eax # Save eax, ecx, and edx as C could destroy them.
642 pushl $8 # Push the size
644 addl $4,%esp # pop the size arg.
645 movl %eax,%esi # setup the destination.
646 popl %edx # Restore eax, ecx and edx.
650 SIZE(GNAME(alloc_8_to_esi))
652 .globl GNAME(alloc_16_to_esi)
653 TYPE(GNAME(alloc_16_to_esi))
654 .align align_4byte,0x90
655 GNAME(alloc_16_to_esi):
656 pushl %eax # Save eax, ecx, and edx as C could destroy them.
659 pushl $16 # Push the size
661 addl $4,%esp # pop the size arg.
662 movl %eax,%esi # setup the destination.
663 popl %edx # Restore eax, ecx and edx.
667 SIZE(GNAME(alloc_16_to_esi))
670 .globl GNAME(alloc_to_edi)
671 TYPE(GNAME(alloc_to_edi))
672 .align align_4byte,0x90
674 pushl %eax # Save eax, ecx, and edx as C could destroy them.
677 pushl %edi # Push the size
679 addl $4,%esp # pop the size arg.
680 movl %eax,%edi # setup the destination.
681 popl %edx # Restore eax, ecx and edx.
685 SIZE(GNAME(alloc_to_edi))
687 .globl GNAME(alloc_8_to_edi)
688 TYPE(GNAME(alloc_8_to_edi))
689 .align align_4byte,0x90
690 GNAME(alloc_8_to_edi):
691 pushl %eax # Save eax, ecx, and edx as C could destroy them.
694 pushl $8 # Push the size
696 addl $4,%esp # pop the size arg.
697 movl %eax,%edi # setup the destination.
698 popl %edx # Restore eax, ecx and edx.
702 SIZE(GNAME(alloc_8_to_edi))
704 .globl GNAME(alloc_16_to_edi)
705 TYPE(GNAME(alloc_16_to_edi))
706 .align align_4byte,0x90
707 GNAME(alloc_16_to_edi):
708 pushl %eax # Save eax, ecx, and edx as C could destroy them.
711 pushl $16 # Push the size
713 addl $4,%esp # pop the size arg.
714 movl %eax,%edi # setup the destination.
715 popl %edx # Restore eax, ecx and edx.
719 SIZE(GNAME(alloc_16_to_edi))
722 /* Called from lisp when an inline allocation overflows.
723 Every register except the result needs to be preserved.
724 We depend on C to preserve ebx, esi, edi, and ebp.
725 But where necessary must save eax, ecx, edx. */
727 #ifdef LISP_FEATURE_SB_THREAD
728 #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET
730 #define START_REGION GNAME(boxed_region)
733 /* This routine handles an overflow with eax=crfp+size. So the
736 .globl GNAME(alloc_overflow_eax)
737 TYPE(GNAME(alloc_overflow_eax))
738 GNAME(alloc_overflow_eax):
739 pushl %ecx # Save ecx
740 pushl %edx # Save edx
741 /* Calculate the size for the allocation. */
742 subl START_REGION,%eax
743 pushl %eax # Push the size
745 addl $4,%esp # pop the size arg.
746 popl %edx # Restore edx.
747 popl %ecx # Restore ecx.
749 SIZE(GNAME(alloc_overflow_eax))
752 .globl GNAME(alloc_overflow_ecx)
753 TYPE(GNAME(alloc_overflow_ecx))
754 GNAME(alloc_overflow_ecx):
755 pushl %eax # Save eax
756 pushl %edx # Save edx
757 /* Calculate the size for the allocation. */
758 subl START_REGION,%ecx
759 pushl %ecx # Push the size
761 addl $4,%esp # pop the size arg.
762 movl %eax,%ecx # setup the destination.
763 popl %edx # Restore edx.
764 popl %eax # Restore eax.
766 SIZE(GNAME(alloc_overflow_ecx))
769 .globl GNAME(alloc_overflow_edx)
770 TYPE(GNAME(alloc_overflow_edx))
771 GNAME(alloc_overflow_edx):
772 pushl %eax # Save eax
773 pushl %ecx # Save ecx
774 /* Calculate the size for the allocation. */
775 subl START_REGION,%edx
776 pushl %edx # Push the size
778 addl $4,%esp # pop the size arg.
779 movl %eax,%edx # setup the destination.
780 popl %ecx # Restore ecx.
781 popl %eax # Restore eax.
783 SIZE(GNAME(alloc_overflow_edx))
785 /* This routine handles an overflow with ebx=crfp+size. So the
788 .globl GNAME(alloc_overflow_ebx)
789 TYPE(GNAME(alloc_overflow_ebx))
790 GNAME(alloc_overflow_ebx):
791 pushl %eax # Save eax
792 pushl %ecx # Save ecx
793 pushl %edx # Save edx
794 /* Calculate the size for the allocation. */
795 subl START_REGION,%ebx
796 pushl %ebx # Push the size
798 addl $4,%esp # pop the size arg.
799 movl %eax,%ebx # setup the destination.
800 popl %edx # Restore edx.
801 popl %ecx # Restore ecx.
802 popl %eax # Restore eax.
804 SIZE(GNAME(alloc_overflow_ebx))
806 /* This routine handles an overflow with esi=crfp+size. So the
809 .globl GNAME(alloc_overflow_esi)
810 TYPE(GNAME(alloc_overflow_esi))
811 GNAME(alloc_overflow_esi):
812 pushl %eax # Save eax
813 pushl %ecx # Save ecx
814 pushl %edx # Save edx
815 /* Calculate the size for the allocation. */
816 subl START_REGION,%esi
817 pushl %esi # Push the size
819 addl $4,%esp # pop the size arg.
820 movl %eax,%esi # setup the destination.
821 popl %edx # Restore edx.
822 popl %ecx # Restore ecx.
823 popl %eax # Restore eax.
825 SIZE(GNAME(alloc_overflow_esi))
828 .globl GNAME(alloc_overflow_edi)
829 TYPE(GNAME(alloc_overflow_edi))
830 GNAME(alloc_overflow_edi):
831 pushl %eax # Save eax
832 pushl %ecx # Save ecx
833 pushl %edx # Save edx
834 /* Calculate the size for the allocation. */
835 subl START_REGION,%edi
836 pushl %edi # Push the size
838 addl $4,%esp # pop the size arg.
839 movl %eax,%edi # setup the destination.
840 popl %edx # Restore edx.
841 popl %ecx # Restore ecx.
842 popl %eax # Restore eax.
844 SIZE(GNAME(alloc_overflow_edi))
847 #ifdef LISP_FEATURE_DARWIN
849 .globl GNAME(call_into_lisp_tramp)
850 TYPE(GNAME(call_into_lisp_tramp))
851 GNAME(call_into_lisp_tramp):
852 /* 1. build the stack frame from the block that's pointed to by ECX
855 4. call the function via call_into_lisp
857 pushl 0(%ecx) /* return address */
862 pushl 32(%ecx) /* eflags */
863 pushl 28(%ecx) /* EAX */
864 pushl 20(%ecx) /* ECX */
865 pushl 16(%ecx) /* EDX */
866 pushl 24(%ecx) /* EBX */
867 pushl $0 /* popal is going to ignore esp */
868 pushl %ebp /* is this right?? */
869 pushl 12(%ecx) /* ESI */
870 pushl 8(%ecx) /* EDI */
871 pushl $0 /* args for call_into_lisp */
873 pushl 4(%ecx) /* function to call */
875 /* free our save block */
876 pushl %ecx /* reserve sufficient space on stack for args */
878 andl $0xfffffff0, %esp /* align stack */
881 call GNAME(os_invalidate)
883 /* call call_into_lisp */
885 call GNAME(call_into_lisp)
887 /* Clean up our mess */
894 SIZE(call_into_lisp_tramp)
897 .align align_4byte,0x90
898 .globl GNAME(post_signal_tramp)
899 TYPE(GNAME(post_signal_tramp))
900 GNAME(post_signal_tramp):
901 /* this is notionally the second half of a function whose first half
902 * doesn't exist. This is where call_into_lisp returns when called
903 * using return_to_lisp_function */
904 addl $12,%esp /* clear call_into_lisp args from stack */
905 popal /* restore registers */
907 #ifdef LISP_FEATURE_DARWIN
908 /* skip two padding words */
913 SIZE(GNAME(post_signal_tramp))
915 #ifdef LISP_FEATURE_WIN32
917 * This is part of the funky magic for exception handling on win32.
918 * see sigtrap_emulator() in win32-os.c for details.
920 .globl GNAME(sigtrap_trampoline)
921 GNAME(sigtrap_trampoline):
925 call GNAME(sigtrap_wrapper)
929 .byte trap_ContextRestore
930 hlt # We should never return here.
933 * This is part of the funky magic for exception handling on win32.
934 * see handle_exception() in win32-os.c for details.
936 .globl GNAME(exception_trampoline)
937 GNAME(exception_trampoline):
941 call GNAME(handle_win32_exception_wrapper)
945 .byte trap_ContextRestore
946 hlt # We should never return here.
949 /* fast_bzero implementations and code to detect which implementation
953 .globl GNAME(fast_bzero_pointer)
956 GNAME(fast_bzero_pointer):
957 /* Variable containing a pointer to the bzero function to use.
958 * Initially points to a basic function. Change this variable
959 * to fast_bzero_detect if OS supports SSE. */
960 .long GNAME(fast_bzero_base)
963 .align align_8byte,0x90
964 .globl GNAME(fast_bzero)
965 TYPE(GNAME(fast_bzero))
967 /* Indirect function call */
968 jmp *GNAME(fast_bzero_pointer)
969 SIZE(GNAME(fast_bzero))
973 .align align_8byte,0x90
974 .globl GNAME(fast_bzero_detect)
975 TYPE(GNAME(fast_bzero_detect))
976 GNAME(fast_bzero_detect):
977 /* Decide whether to use SSE, MMX or REP version */
978 push %eax /* CPUID uses EAX-EDX */
984 test $0x04000000, %edx /* SSE2 needed for MOVNTDQ */
986 /* Originally there was another case here for using the
987 * MOVNTQ instruction for processors that supported MMX but
988 * not SSE2. This turned out to be a loss especially on
989 * Athlons (where this instruction is apparently microcoded
990 * somewhat slowly). So for simplicity revert to REP STOSL
991 * for all non-SSE2 processors.
994 movl $(GNAME(fast_bzero_base)), GNAME(fast_bzero_pointer)
997 movl $(GNAME(fast_bzero_sse)), GNAME(fast_bzero_pointer)
1005 jmp *GNAME(fast_bzero_pointer)
1007 SIZE(GNAME(fast_bzero_detect))
1011 .align align_8byte,0x90
1012 .globl GNAME(fast_bzero_sse)
1013 TYPE(GNAME(fast_bzero_sse))
1015 GNAME(fast_bzero_sse):
1016 /* A fast routine for zero-filling blocks of memory that are
1017 * guaranteed to start and end at a 4096-byte aligned address.
1019 push %esi /* Save temporary registers */
1021 mov 16(%esp), %esi /* Parameter: amount of bytes to fill */
1022 mov 12(%esp), %edi /* Parameter: start address */
1023 shr $6, %esi /* Amount of 64-byte blocks to copy */
1024 jz Lend_sse /* If none, stop */
1025 movups %xmm7, -16(%esp) /* Save XMM register */
1026 xorps %xmm7, %xmm7 /* Zero the XMM register */
1031 /* Copy the 16 zeroes from xmm7 to memory, 4 times. MOVNTDQ is the
1032 * non-caching double-quadword moving variant, i.e. the memory areas
1033 * we're touching are not fetched into the L1 cache, since we're just
1034 * going to overwrite the memory soon anyway.
1036 movntdq %xmm7, 0(%edi)
1037 movntdq %xmm7, 16(%edi)
1038 movntdq %xmm7, 32(%edi)
1039 movntdq %xmm7, 48(%edi)
1041 add $64, %edi /* Advance pointer */
1042 dec %esi /* Decrement 64-byte block count */
1044 movups -16(%esp), %xmm7 /* Restore the XMM register */
1045 sfence /* Ensure that weakly ordered writes are flushed. */
1047 mov 12(%esp), %esi /* Parameter: start address */
1048 prefetcht0 0(%esi) /* Prefetch the start of the block into cache,
1049 * since it's likely to be used immediately. */
1050 pop %edi /* Restore temp registers */
1053 SIZE(GNAME(fast_bzero_sse))
1057 .align align_8byte,0x90
1058 .globl GNAME(fast_bzero_base)
1059 TYPE(GNAME(fast_bzero_base))
1061 GNAME(fast_bzero_base):
1062 /* A fast routine for zero-filling blocks of memory that are
1063 * guaranteed to start and end at a 4096-byte aligned address.
1065 push %eax /* Save temporary registers */
1068 mov 20(%esp), %ecx /* Parameter: amount of bytes to fill */
1069 mov 16(%esp), %edi /* Parameter: start address */
1070 xor %eax, %eax /* Zero EAX */
1071 shr $2, %ecx /* Amount of 4-byte blocks to copy */
1073 cld /* Set direction of STOSL to increment */
1076 stosl /* Store EAX to *EDI, ECX times, incrementing
1077 * EDI by 4 after each store */
1080 pop %edi /* Restore temp registers */
1084 SIZE(GNAME(fast_bzero_base))