Skip a test.
[sbcl.git] / src / runtime / x86-assem.S
blob69cea570858637308d3b7ce2d18211393d7e0804
1 /*
2  * very-low-level utilities for runtime support
3  */
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
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.
14  */
16 #ifdef __ELF__
17 // Mark the object as not requiring an executable stack.
18 .section .note.GNU-stack,"",%progbits
19 #endif
21 #include "genesis/sbcl.h"
22 #include "genesis/closure.h"
23 #include "genesis/static-symbols.h"
24 #include "genesis/symbol.h"
25 #include "genesis/thread.h"
27 /* Minimize conditionalization for different OS naming schemes.
28  *
29  * (As of sbcl-0.8.10, this seems no longer to be much of an issue,
30  * since everyone has converged on ELF. If this generality really
31  * turns out not to matter, perhaps it's just clutter we could get
32  * rid of? -- WHN 2004-04-18)
33  *
34  * (Except Win32, which is unlikely ever to be ELF, sorry. -- AB 2005-12-08)
35  */
36 #if defined __linux__  || defined LISP_FEATURE_FREEBSD || defined __NetBSD__ || defined __OpenBSD__ || \
37         defined __sun || defined __DragonFly__
38 #define GNAME(var) var
39 #else
40 #define GNAME(var) _##var
41 #endif
43 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
44  * want alignment in bytes.
45  *
46  * (As in the GNAME() definitions above, as of sbcl-0.8.10, this seems
47  * no longer to be much of an issue, since everyone has converged on
48  * the same value. If this generality really turns out not to
49  * matter any more, perhaps it's just clutter we could get
50  * rid of? -- WHN 2004-04-18)
51  */
52 #if defined(__linux__) || defined(LISP_FEATURE_FREEBSD) || defined(__NetBSD__) || defined(__OpenBSD__) || \
53         defined(__sun) || defined(LISP_FEATURE_WIN32) || defined(__DragonFly__)
54 #define align_16byte    16
55 #else
56 #define align_16byte    4
57 #endif
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
63  * other platforms.
64  */
65 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
66 #define TYPE(name) .type name,@function
67 #define SIZE(name) .size name,.-name
68 #else
69 #define TYPE(name)
70 #define SIZE(name)
71 #endif
73 /* Helper macros for access to thread-locals slots for both OS types:
74  * ------------------------------------------------------------------------
75  *
76  *                          Windows TEB block
77  * ==================        __________
78  * | Win32 %FS base | ---->  |        | 0
79  * ==================        |        | 1
80  *                           z        z
81  *     TLS slots start here> |XXXXXXXX| e10 = TEB_STATIC_TLS_SLOTS_OFFSET
82  *                           |XXXXXXXX| e11
83  *                           z   ...  z
84  *                           |XXXXXXXX| e4e
85  *     TLS ends here>     ,- |XXXXXXXX| e4f = TEB_STATIC_TLS_SLOTS_OFFSET+63
86  *                       /   z        z
87  *                       |   ----------                    "os_address" ----.
88  *                       |                                                   |
89  *                       |   big blob of SBCL-specific thread-local data     |
90  *                       |     |----------------------------------------| <--'
91  *                       |     |   CONTROL, BINDING, ALIEN STACK        |
92  *                       |     z                                        z
93  * ==================    |     |----------------------------------------|
94  * | Linux %FS base | -->|     |   FFI stack pointer                    |
95  * ==================    |     |    (extra page for mprotect)           |
96  *                        \    |----------------------------------------|
97  *   (union p_t_d) ----->  \-> | struct thread {   | dynamic_values[0]  |
98  *   .                         |   ...             |               [1]  |
99  *   .                         z   ...             z               ...  z
100  *   [tls data begins]         | }                 |               ...  | <-
101  *   [declared end of p_t_d]   |----------------------------------------| . |
102  *   .                         |                                   ...  | . |
103  *   .                         |                           [TLS_SIZE-1] | <-|
104  *   [tls data actually ends]  |----------------------------------------|   |
105  *   .                         | ALTSTACK                               |   |
106  *   .                         |----------------------------------------|   |
107  *   .                         | struct nonpointer_thread_data { }      |   |
108  *   .                         ------------------------------------------   |
109  *   [blob actually ends]                                                   |
110  *                                                                         /
111  *                                                                        /
112  *                                                                       /
113  *          ______________________                                      /
114  *          | struct symbol {    |                                     /
115  *          z   ...              z                                    /
116  *          |   fixnum tls_index;  // fixnum value relative to union /
117  *          | }                  |           (< TLS_SIZE = 4096)
118  *          ---------------------|
119  */
120 #ifdef LISP_FEATURE_WIN32
121 # define TEB_STATIC_TLS_SLOTS_OFFSET 0xE10
122 # define TEB_SBCL_THREAD_BASE_OFFSET (TEB_STATIC_TLS_SLOTS_OFFSET+(63*4))
123 # define SBCL_THREAD_BASE_EA %fs:TEB_SBCL_THREAD_BASE_OFFSET
124 # define MAYBE_FS(addr) addr
125 # define LoadTlSymbolValueAddress(symbol,reg) ;         \
126         movl    SBCL_THREAD_BASE_EA, reg ;              \
127         addl    (symbol+SYMBOL_TLS_INDEX_OFFSET), reg ;
128 # define LoadCurrentThreadSlot(offset,reg);     \
129         movl    SBCL_THREAD_BASE_EA, reg ;      \
130         movl    offset(reg), reg ;
131 #elif !defined(LISP_FEATURE_SB_THREAD)
132   /* so that we don't have to rewrite the safepoint logic */
133 # define SBCL_THREAD_BASE_EA GNAME(all_threads)
134 # define MAYBE_FS(addr) addr
135 #elif defined(LISP_FEATURE_LINUX) || defined(LISP_FEATURE_SUNOS) || defined(LISP_FEATURE_FREEBSD) || \
136         defined(LISP_FEATURE_DRAGONFLY)
137     /* %fs:0 refers to the current thread.  Useful!  Less usefully,
138      * Linux/x86 isn't capable of reporting a faulting si_addr on a
139      * segment as defined above (whereas faults on the segment that %gs
140      * usually points are reported just fine...).
141      * But we have the thread's address stored in the THIS slot,
142      * so that within the thread
143      *   movl %fs:THIS_OFFSET,x
144      * stores the absolute address of %fs:0 into x.
145      */
146 # define SBCL_THREAD_BASE_EA %fs:THREAD_THIS_OFFSET
147 # define MAYBE_FS(addr) addr
148 #else
149   /* perhaps there's an OS out there that actually supports %fs without
150    * jumping through hoops, so just in case, here a default definition: */
151 # define SBCL_THREAD_BASE_EA $0
152 # define MAYBE_FS(addr) %fs:addr
153 #endif
156 /* the CSP page sits right before the thread */
157 #define THREAD_SAVED_CSP_OFFSET (-N_WORD_BYTES)
159 #ifdef LISP_FEATURE_UD2_BREAKPOINTS
160 #define TRAP ud2
161 #else
162 #define TRAP int3
163 #endif
165         .text
166         .globl  GNAME(all_threads)
169  * A call to call_into_c preserves esi, edi, and ebp.
170  * (The C function will preserve ebx, esi, edi, and ebp across its
171  * function call, but we trash ebx ourselves by using it to save the
172  * return Lisp address.)
174  * Return values are in eax and maybe edx for quads, or st(0) for
175  * floats.
177  * This should work for Lisp calls C calls Lisp calls C..
179  * FIXME & OAOOM: This duplicates call-out in src/compiler/x86/c-call.lisp,
180  * so if you tweak this, change that too!
181  */
183  * Note on sections specific to LISP_FEATURE_SB_SAFEPOINT:
185  * The code below is essential to safepoint-based garbage collection,
186  * and several details need to be considered for correct implementation.
188  * The stack spilling approach:
189  *   On SB-SAFEPOINT platforms, the CALL-OUT vop is defined to spill all
190  *   live Lisp TNs to the stack to provide information for conservative
191  *   GC cooperatively (avoiding the need to retrieve register values
192  *   from POSIX signal contexts or Windows GetThreadContext()).
194  * Finding the SP at all:
195  *   The main remaining value needed by GC is the stack pointer (SP) at
196  *   the moment of entering the foreign function.  For this purpose, a
197  *   thread-local field for the SP is used.  Two stores to that field
198  *   are done for each C call, one to save the SP before calling out and
199  *   and one to undo that store afterwards.
201  * Stores as synchronization points:
202  *   These two stores delimit the C call: While the SP is set, our
203  *   thread is known not to run Lisp code: During GC, memory protection
204  *   ensures that no thread proceeds across stores.
206  * The return PC issue:
207  *   (Note that CALL-OUT has, in principle, two versions: Inline
208  *   assembly in the VOP -or- alternatively the out-of-line version you
209  *   are currently reading.  In reality, safepoint builds currently
210  *   lack the inline code entirely.)
212  *   Both versions need to take special care with the return PC:
213  *   - In the inline version of the code (if it existed), the two stores
214  *     would be done directly in the CALL-OUT vop.  In that theoretical
215  *     implementation, even though the CALL instruction pushes the return
216  *     address to the stack, it is outside of the range preserved by the
217  *     GC as possible heap pointers.
218  *   - In this out-of-line version, the stores are done during
219  *     call_into_c's frame, but an equivalent problem arises: In order
220  *     to present the stack of arguments as our foreign function expects
221  *     them, call_into_c has to pop the Lisp return address into a
222  *     register.
223  *   In both cases, stack scanning would not normally find the return
224  *   address, so we arrange to store it in a slot within our calling
225  *   frame.  The address of this slot is passed to us in EDI.
227  * Note on look-alike accessor macros with vastly different behaviour:
228  *   THREAD_PC_AROUND_FOREIGN_CALL_OFFSET was an "ordinary" field of the
229  *   struct thread, whereas THREAD_SAVED_CSP_OFFSET is a synchronization
230  *   point on a potentially write-protected page.
233         .text
234         .align  align_16byte,0x90
235         .globl GNAME(call_into_c)
236         TYPE(GNAME(call_into_c))
237 GNAME(call_into_c):
238 /* Save the return Lisp address in ebx. */
239         popl    %ebx
241 /* Setup the NPX for C */
242         /* The VOP says regarding CLD: "Clear out DF: Darwin, Windows,
243          * and Solaris at least require this, and it should not hurt
244          * others either." call_into_c didn't have it, but better safe than
245          * sorry. */
246         cld
247         fstp    %st(0)
248         fstp    %st(0)
249         fstp    %st(0)
250         fstp    %st(0)
251         fstp    %st(0)
252         fstp    %st(0)
253         fstp    %st(0)
254         fstp    %st(0)
256 #ifdef LISP_FEATURE_SB_SAFEPOINT
257         /* Save our return PC in the allocated slot (address passed in EDI) */
258         movl    %ebx,(%edi)
259         /* enter safe region: store SP */
260         movl    SBCL_THREAD_BASE_EA,%edi
261         movl    %esp,MAYBE_FS(THREAD_SAVED_CSP_OFFSET(%edi))
262 #endif
264         /* foreign call, preserving ESI, EDI, and EBX */
265         call    *%eax             # normal callout using Lisp stack
266         /* return values now in eax/edx OR st(0) */
268 #ifdef LISP_FEATURE_SB_SAFEPOINT
269         /* leave region: clear the SP! */
270         xorl    %ecx,%ecx
271         movl    %ecx,MAYBE_FS(THREAD_SAVED_CSP_OFFSET(%edi))
272 #endif
274         movl    %eax,%ecx         # remember integer return value
276 /* Check for a return FP value. */
277         fxam
278         fnstsw  %ax
279         andl    $0x4500,%eax
280         cmpl    $0x4100,%eax
281         jne     Lfp_rtn_value
283 /* The return value is in eax, or eax,edx? */
284 /* Set up the NPX stack for Lisp. */
285         fldz                    # Ensure no regs are empty.
286         fldz
287         fldz
288         fldz
289         fldz
290         fldz
291         fldz
292         fldz
294 /* Restore the return value. */
295         movl    %ecx,%eax       # maybe return value
297 /* Return. */
298         jmp     *%ebx
300 Lfp_rtn_value:
301 /* The return result is in st(0). */
302 /* Set up the NPX stack for Lisp, placing the result in st(0). */
303         fldz                    # Ensure no regs are empty.
304         fldz
305         fldz
306         fldz
307         fldz
308         fldz
309         fldz
310         fxch    %st(7)          # Move the result back to st(0).
312 /* We don't need to restore eax, because the result is in st(0). */
314 /* Return. FIXME: It would be nice to restructure this to use RET. */
315         jmp     *%ebx
317         SIZE(GNAME(call_into_c))
320 #ifdef LISP_FEATURE_OS_THREAD_STACK
321         .text
322         .globl  GNAME(funcall1_switching_stack)
323         TYPE(GNAME(funcall1_switching_stack))
324         .align  align_16byte,0x90
325 GNAME(funcall1_switching_stack):
326         /* The arguments are switched, funcall1_switching_stack(arg, function)
327            to avoid shuffling registers on x86-64
328         */
329         push    %ebp
330         mov     %esp,%ebp
332         movl    8(%ebp),%eax    # arg
333         movl    12(%ebp),%edx   # function
335         mov     THREAD_CONTROL_STACK_END_OFFSET(%eax),%esp
336         push    %edx
337         push    %eax
338         call    *%edx
340         mov     %ebp, %esp
341         pop     %ebp
342         ret
343         SIZE(GNAME(funcall1_switching_stack))
344 #endif
346         .text
347         .globl GNAME(call_into_lisp_first_time)
348         TYPE(GNAME(call_into_lisp_first_time))
350 /* We don't worry too much about saving registers
351  * here, because we never expect to return from the initial call to lisp
352  * anyway */
354         .align  align_16byte,0x90
355 GNAME(call_into_lisp_first_time):
356 GNAME(lspmain):
357         pushl   %ebp            # Save old frame pointer.
358         movl    %esp,%ebp       # Establish new frame.
359 #ifndef LISP_FEATURE_WIN32
360         movl    GNAME(all_threads),%eax
361         /* pthread machinery takes care of this for other threads */
362         movl    THREAD_CONTROL_STACK_END_OFFSET(%eax) ,%esp
363 #else
364 /* Win32 -really- doesn't like you switching stacks out from under it. */
365         movl    GNAME(all_threads),%eax
366 #endif
367         jmp     Lstack
369         .text
370         .globl GNAME(call_into_lisp)
371         TYPE(GNAME(call_into_lisp))
373 /* The C conventions require that ebx, esi, edi, and ebp be preserved
374  * across function calls. */
376         .align  align_16byte,0x90
377 GNAME(call_into_lisp):
378         pushl   %ebp            # Save old frame pointer.
379         movl    %esp,%ebp       # Establish new frame.
381 Lstack:
382 /* Save the NPX state */
383         fwait                   # Catch any pending NPX exceptions.
384         subl    $108,%esp       # Make room for the NPX state.
385         fnsave  (%esp)          # save and reset NPX
387         movl    (%esp),%eax     # Load NPX control word.
388         andl    $0xfffff2ff,%eax        # Set rounding mode to nearest.
389         orl     $0x00000200,%eax        # Set precision to 64 bits.  (53-bit mantissa)
390         pushl   %eax
391         fldcw   (%esp)          # Recover modes.
392         popl    %eax
394         fldz                    # Ensure no FP regs are empty.
395         fldz
396         fldz
397         fldz
398         fldz
399         fldz
400         fldz
401         fldz
403 /* Save C regs: ebx esi edi. */
404         pushl   %ebx
405         pushl   %esi
406         pushl   %edi
408 /* Clear descriptor regs. */
409         xorl    %eax,%eax       # lexenv
410         xorl    %ebx,%ebx       # available
411         xorl    %ecx,%ecx       # arg count
412         xorl    %edx,%edx       # first arg
413         xorl    %edi,%edi       # second arg
414         xorl    %esi,%esi       # third arg
416         /* Establish Lisp args. */
417         movl     8(%ebp),%eax   # lexenv?
418         movl    12(%ebp),%ebx   # address of arg vec
419         movl    16(%ebp),%ecx   # num args
420         shll    $2,%ecx         # Make num args into fixnum.
421         cmpl    $0,%ecx
422         je      Ldone
423         movl    (%ebx),%edx     # arg0
424         cmpl    $4,%ecx
425         je      Ldone
426         movl    4(%ebx),%edi    # arg1
427         cmpl    $8,%ecx
428         je      Ldone
429         movl    8(%ebx),%esi    # arg2
430 Ldone:
431         /* Registers eax, ecx, edx, edi, and esi are now live. */
433 #ifdef LISP_FEATURE_WIN32
434         /* Establish an SEH frame. */
435 #ifdef LISP_FEATURE_SB_THREAD
436         /* Save binding stack pointer */
437         subl $4, %esp
438         pushl %eax
439         movl SBCL_THREAD_BASE_EA, %eax
440         movl THREAD_BINDING_STACK_POINTER_OFFSET(%eax), %eax
441         movl %eax, 4(%esp)
442         popl %eax
443 #else
444         pushl   BINDING_STACK_POINTER + SYMBOL_VALUE_OFFSET
445 #endif
446         pushl   $GNAME(exception_handler_wrapper)
447         pushl   %fs:0
448         movl    %esp, %fs:0
449 #endif
451         /* Alloc new frame. */
452         push    %ebp            # Dummy for return address
453         push    %ebp            # fp in save location S1
454         mov     %esp,%ebp       # The current sp marks start of new frame.
455         sub     $4,%esp         # Ensure 3 slots are allocated, two above.
457         call    *CLOSURE_FUN_OFFSET(%eax)
459         /* If the function returned multiple values, it will return to
460            this point.  Lose them */
461         jnc     LsingleValue
462         mov     %ebx, %esp
463 LsingleValue:
464         /* A singled value function returns here */
466 #ifdef LISP_FEATURE_WIN32
467         /* Remove our SEH frame. */
468         mov     %fs:0,%esp
469         popl    %fs:0
470         add     $8, %esp
471 #endif
473 /* Restore C regs: ebx esi edi. */
474         popl    %edi
475         popl    %esi
476         popl    %ebx
478 /* Restore the NPX state. */
479         frstor  (%esp)
480         addl    $108, %esp
482         popl    %ebp            # c-sp
483         movl    %edx,%eax       # c-val
484         ret
485         SIZE(GNAME(call_into_lisp))
487 /* support for saving and restoring the NPX state from C */
488         .text
489         .globl  GNAME(fpu_save)
490         TYPE(GNAME(fpu_save))
491         .align  2,0x90
492 GNAME(fpu_save):
493         movl    4(%esp),%eax
494         fnsave  (%eax)          # Save the NPX state. (resets NPX)
495         ret
496         SIZE(GNAME(fpu_save))
498         .globl  GNAME(fpu_restore)
499         TYPE(GNAME(fpu_restore))
500         .align  2,0x90
501 GNAME(fpu_restore):
502         movl    4(%esp),%eax
503         frstor  (%eax)          # Restore the NPX state.
504         ret
505         SIZE(GNAME(fpu_restore))
508  * fun-end breakpoint magic
509  */
512  * For an explanation of the magic involved in function-end
513  * breakpoints, see the implementation in ppc-assem.S.
514  */
516         .text
517         .globl  GNAME(fun_end_breakpoint_guts)
518         .align  align_16byte
519 GNAME(fun_end_breakpoint_guts):
520         /* Multiple Value return */
521         jc      multiple_value_return
522         /* Single value return: The eventual return will now use the
523            multiple values return convention but with a return values
524            count of one. */
525         movl    %esp,%ebx       # Setup ebx - the ofp.
526         subl    $4,%esp         # Allocate one stack slot for the return value
527         movl    $(1 << N_FIXNUM_TAG_BITS),%ecx          # Setup ecx for one return value.
528         movl    $(NIL),%edi     # default second value
529         movl    $(NIL),%esi     # default third value
531 multiple_value_return:
533         .globl GNAME(fun_end_breakpoint_trap)
534 GNAME(fun_end_breakpoint_trap):
535         TRAP
536         .byte   trap_FunEndBreakpoint
537         hlt                     # We should never return here.
539         .globl GNAME(fun_end_breakpoint_end)
540 GNAME(fun_end_breakpoint_end):
543         .globl  GNAME(do_pending_interrupt)
544         TYPE(GNAME(do_pending_interrupt))
545         .align  align_16byte,0x90
546 GNAME(do_pending_interrupt):
547         TRAP
548         .byte   trap_PendingInterrupt
549         ret
550         SIZE(GNAME(do_pending_interrupt))
552 #ifdef LISP_FEATURE_SB_SAFEPOINT
553         .globl  GNAME(handle_global_safepoint_violation)
554         TYPE(GNAME(handle_global_safepoint_violation))
555         .align  align_16byte,0x90
556 GNAME(handle_global_safepoint_violation):
557         TRAP
558         .byte   trap_GlobalSafepoint
559         ret
560         SIZE(GNAME(handle_global_safepoint_violation))
562         .globl  GNAME(handle_csp_safepoint_violation)
563         TYPE(GNAME(handle_csp_safepoint_violation))
564         .align  align_16byte,0x90
565 GNAME(handle_csp_safepoint_violation):
566         TRAP
567         .byte   trap_CspSafepoint
568         ret
569         SIZE(GNAME(handle_csp_safepoint_violation))
570 #endif /* SB-SAFEPOINT */
572         .globl  GNAME(memory_fault_emulation_trap)
573         TYPE(GNAME(memory_fault_emulation_trap))
574         .align  align_16byte,0x90
575 GNAME(memory_fault_emulation_trap):
576         TRAP
577         .byte   trap_MemoryFaultEmulation
578         SIZE(GNAME(memory_fault_emulation_trap))
580 #ifdef LISP_FEATURE_WIN32
581         /* The guts of the exception-handling system doesn't use
582          * frame pointers, which manages to throw off backtraces
583          * rather badly.  So here we grab the (known-good) EBP
584          * and EIP from the exception context and use it to fake
585          * up a stack frame which will skip over the system SEH
586          * code. */
587         .align  align_16byte
588         .globl  GNAME(exception_handler_wrapper)
589         TYPE(GNAME(exception_handler_wrapper))
590 GNAME(exception_handler_wrapper):
591         /* Context layout is: */
592         /* 7 dwords before FSA. (0x1c) */
593         /* 8 dwords and 0x50 bytes in the FSA. (0x70/0x8c) */
594         /* 4 dwords segregs. (0x10/0x9c) */
595         /* 6 dwords non-stack GPRs. (0x18/0xb4) */
596         /* EBP (at 0xb4) */
597         /* EIP (at 0xb8) */
598 #define CONTEXT_EBP_OFFSET 0xb4
599 #define CONTEXT_EIP_OFFSET 0xb8
600         /* some other stuff we don't care about. */
601         pushl   %ebp
602         movl    0x10(%esp), %ebp        /* context */
603         pushl   CONTEXT_EIP_OFFSET(%ebp)
604         pushl   CONTEXT_EBP_OFFSET(%ebp)
605         movl    %esp, %ebp
606         pushl   0x1c(%esp)
607         pushl   0x1c(%esp)
608         pushl   0x1c(%esp)
609         pushl   0x1c(%esp)
610         call    GNAME(handle_exception)
611         lea     8(%ebp), %esp
612         popl    %ebp
613         ret
614         SIZE(GNAME(exception_handler_wrapper))
615 #endif
617 #ifdef LISP_FEATURE_DARWIN
618         .align align_16byte
619         .globl GNAME(call_into_lisp_tramp)
620         TYPE(GNAME(call_into_lisp_tramp))
621 GNAME(call_into_lisp_tramp):
622         /* 1. build the stack frame from the block that's pointed to by ECX
623            2. free the block
624            3. set ECX to 0
625            4. call the function via call_into_lisp
626         */
627         pushl   0(%ecx)          /* return address */
629         pushl   %ebp
630         movl    %esp, %ebp
632         pushl   32(%ecx)         /* eflags */
633         pushl   28(%ecx)         /* EAX */
634         pushl   20(%ecx)         /* ECX */
635         pushl   16(%ecx)         /* EDX */
636         pushl   24(%ecx)         /* EBX */
637         pushl   $0                /* popal is going to ignore esp */
638         pushl   %ebp              /* is this right?? */
639         pushl   12(%ecx)         /* ESI */
640         pushl   8(%ecx)          /* EDI */
641         pushl   $0                /* args for call_into_lisp */
642         pushl   $0
643         pushl   4(%ecx)          /* function to call */
645         /* free our save block */
646         pushl   %ecx              /* reserve sufficient space on stack for args */
647         pushl   %ecx
648         andl    $0xfffffff0, %esp  /* align stack */
649         movl    $0x40, 4(%esp)
650         movl    %ecx, (%esp)
651         call    GNAME(os_alloc_gc_space)
653         /* call call_into_lisp */
654         leal    -48(%ebp), %esp
655         call    GNAME(call_into_lisp)
657         /* Clean up our mess */
658         leal    -36(%ebp), %esp
659         popal
660         popfl
661         leave
662         ret
664         SIZE(call_into_lisp_tramp)
665 #endif
667         .align  align_16byte,0x90
668         .globl  GNAME(post_signal_tramp)
669         TYPE(GNAME(post_signal_tramp))
670 GNAME(post_signal_tramp):
671         /* this is notionally the second half of a function whose first half
672          * doesn't exist.  This is where call_into_lisp returns when called
673          * using return_to_lisp_function */
674         addl $12,%esp   /* clear call_into_lisp args from stack */
675         popal           /* restore registers */
676         popfl
677 #ifdef LISP_FEATURE_DARWIN
678         /* skip two padding words */
679         addl $8,%esp
680 #endif
681         leave
682         ret
683         SIZE(GNAME(post_signal_tramp))
686 /* When LISP_FEATURE_C_STACK_IS_CONTROL_STACK, we cannot safely scrub
687  * the control stack from C, largely due to not knowing where the
688  * active stack frame ends.  On such platforms, we reimplement the
689  * core scrubbing logic in assembly, in this case here:
690  */
691         .text
692         .align  align_16byte,0x90
693         .globl GNAME(arch_scrub_control_stack)
694         TYPE(GNAME(arch_scrub_control_stack))
695 GNAME(arch_scrub_control_stack):
696         /* We are passed three parameters:
697          * A (struct thread *) at [ESP+4],
698          * the address of the guard page at [ESP+8], and
699          * the address of the hard guard page at [ESP+12].
700          * We may trash EAX, ECX, and EDX with impunity.
701          * [ESP] is our return address, [ESP-4] is the first
702          * stack slot to scrub. */
704         /* We start by setting up our scrub pointer in EAX, our
705          * guard page upper bound in ECX, and our hard guard
706          * page upper bound in EDX. */
707         lea     -4(%esp), %eax
708         mov     GNAME(os_vm_page_size),%edx
709         mov     %edx, %ecx
710         add     8(%esp), %ecx
711         add     12(%esp), %edx
713         /* We need to do a memory operation relative to the
714          * thread pointer, so put it in %ecx and our guard
715          * page upper bound in 4(%esp). */
716         xchg    4(%esp), %ecx
718         /* Now we begin our main scrub loop. */
719 ascs_outer_loop:
721         /* If we're about to scrub the hard guard page, exit. */
722         cmp     %edx, %eax
723         jae     ascs_check_guard_page
724         cmp     12(%esp), %eax
725         ja      ascs_finished
727 ascs_check_guard_page:
728         /* If we're about to scrub the guard page, and the guard
729          * page is protected, exit. */
730         cmp     4(%esp), %eax
731         jae     ascs_clear_loop
732         cmp     8(%esp), %eax
733         jbe     ascs_clear_loop
734         /* test state_word.control_stack_guard_page_protected */
735         cmpb    $0, THREAD_STATE_WORD_OFFSET(%ecx)
736         jne     ascs_finished
738         /* Clear memory backwards to the start of the (4KiB) page */
739 ascs_clear_loop:
740         movl    $0, (%eax)
741         test    $0xfff, %eax
742         lea     -4(%eax), %eax
743         jnz     ascs_clear_loop
745         /* If we're about to hit the hard guard page, exit. */
746         cmp     %edx, %eax
747         jae     ascs_finished
749         /* If the next (previous?) 4KiB page contains a non-zero
750          * word, continue scrubbing. */
751 ascs_check_loop:
752         testl   $-1, (%eax)
753         jnz     ascs_outer_loop
754         test    $0xfff, %eax
755         lea     -4(%eax), %eax
756         jnz     ascs_check_loop
758 ascs_finished:
759         ret
760         SIZE(GNAME(arch_scrub_control_stack))