0.9.8.7:
[sbcl.git] / src / runtime / x86-assem.S
1 /*
2  * very-low-level utilities for runtime support
3  */
4
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  */
15 \f
16 #define LANGUAGE_ASSEMBLY
17 #include "sbcl.h"
18 #include "validate.h"
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"
24         
25 /* Minimize conditionalization for different OS naming schemes. 
26  *
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)
31  *
32  * (Except Win32, which is unlikely ever to be ELF, sorry. -- AB 2005-12-08)
33  */
34 #if defined __linux__  || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __sun
35 #define GNAME(var) var
36 #else
37 #define GNAME(var) _##var
38 #endif
39
40 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
41  * want alignment in bytes. 
42  *
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)
48  */
49 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun) || defined(LISP_FEATURE_WIN32)
50 #define align_4byte     4
51 #define align_8byte     8
52 #define align_16byte    16
53 #else
54 #define align_4byte     2
55 #define align_8byte     3
56 #define align_16byte    4       
57 #endif                  
58
59 /*
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 #ifndef LISP_FEATURE_WIN32
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
72
73         .text
74         .global GNAME(foreign_function_call_active)
75         .global GNAME(all_threads)
76 \f
77 /*
78  * A call to call_into_c preserves esi, edi, and ebp.   
79  * (The C function will preserve ebx, esi, edi, and ebp across its
80  * function call, but we trash ebx ourselves by using it to save the
81  * return Lisp address.)
82  *
83  * Return values are in eax and maybe edx for quads, or st(0) for
84  * floats.
85  *
86  * This should work for Lisp calls C calls Lisp calls C..
87  */
88         .text
89         .align  align_16byte,0x90
90         .global GNAME(call_into_c)
91         TYPE(GNAME(call_into_c))
92 GNAME(call_into_c):
93         movl    $1,GNAME(foreign_function_call_active)
94
95 /* Save the return Lisp address in ebx. */
96         popl    %ebx
97
98 /* Setup the NPX for C */
99         fstp    %st(0)
100         fstp    %st(0)
101         fstp    %st(0)
102         fstp    %st(0)
103         fstp    %st(0)
104         fstp    %st(0)
105         fstp    %st(0)
106         fstp    %st(0)
107
108 #ifdef LISP_FEATURE_WIN32
109         cld
110 #endif
111
112         call    *%eax           # normal callout using Lisp stack
113
114         movl    %eax,%ecx       # remember integer return value
115
116 /* Check for a return FP value. */
117         fxam
118         fnstsw  %eax
119         andl    $0x4500,%eax
120         cmpl    $0x4100,%eax
121         jne     Lfp_rtn_value
122
123 /* The return value is in eax, or eax,edx? */
124 /* Set up the NPX stack for Lisp. */
125         fldz                    # Ensure no regs are empty.
126         fldz
127         fldz
128         fldz
129         fldz
130         fldz
131         fldz
132         fldz
133
134 /* Restore the return value. */
135         movl    %ecx,%eax       # maybe return value
136
137         movl    $0,GNAME(foreign_function_call_active)
138 /* Return. */
139         jmp     *%ebx
140
141 Lfp_rtn_value:
142 /* The return result is in st(0). */
143 /* Set up the NPX stack for Lisp, placing the result in st(0). */
144         fldz                    # Ensure no regs are empty.
145         fldz
146         fldz
147         fldz
148         fldz
149         fldz
150         fldz
151         fxch    %st(7)          # Move the result back to st(0).
152
153 /* We don't need to restore eax, because the result is in st(0). */
154
155         movl    $0,GNAME(foreign_function_call_active)
156 /* Return. */   
157         jmp     *%ebx
158
159         SIZE(GNAME(call_into_c))
160
161 \f
162         .text   
163         .global GNAME(call_into_lisp_first_time)
164         TYPE(GNAME(call_into_lisp_first_time))
165                 
166 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
167  * the stack changes.  We don't worry too much about saving registers 
168  * here, because we never expect to return from the initial call to lisp 
169  * anyway */
170         
171         .align  align_16byte,0x90
172 GNAME(call_into_lisp_first_time):
173         pushl   %ebp            # Save old frame pointer.
174         movl    %esp,%ebp       # Establish new frame.
175 #ifndef LISP_FEATURE_WIN32
176         movl    %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
177         movl    GNAME(all_threads),%eax
178         movl    THREAD_CONTROL_STACK_START_OFFSET(%eax) ,%esp
179         /* don't think too hard about what happens if we get interrupted
180         * here */
181         addl    $THREAD_CONTROL_STACK_SIZE-4,%esp
182 #else
183 /* Win32 -really- doesn't like you switching stacks out from under it. */
184         movl    GNAME(all_threads),%eax
185 #endif
186         jmp     Lstack
187 \f
188         .text   
189         .global GNAME(call_into_lisp)
190         TYPE(GNAME(call_into_lisp))
191                 
192 /* The C conventions require that ebx, esi, edi, and ebp be preserved
193  * across function calls. */
194         
195         .align  align_16byte,0x90
196 GNAME(call_into_lisp):
197         pushl   %ebp            # Save old frame pointer.
198         movl    %esp,%ebp       # Establish new frame.
199 Lstack:
200 /* Save the NPX state */
201         fwait                   # Catch any pending NPX exceptions.
202         subl    $108,%esp       # Make room for the NPX state.
203         fnsave  (%esp)          # save and reset NPX
204
205         movl    (%esp),%eax     # Load NPX control word.
206         andl    $0xfffff2ff,%eax        # Set rounding mode to nearest.
207         orl     $0x00000200,%eax        # Set precision to 64 bits.  (53-bit mantissa)
208         pushl   %eax
209         fldcw   (%esp)          # Recover modes.
210         popl    %eax
211
212         fldz                    # Ensure no FP regs are empty.
213         fldz
214         fldz
215         fldz
216         fldz
217         fldz
218         fldz
219         fldz
220         
221 /* Save C regs: ebx esi edi. */
222         pushl   %ebx
223         pushl   %esi
224         pushl   %edi
225         
226 /* Clear descriptor regs. */
227         xorl    %eax,%eax       # lexenv
228         xorl    %ebx,%ebx       # available
229         xorl    %ecx,%ecx       # arg count
230         xorl    %edx,%edx       # first arg
231         xorl    %edi,%edi       # second arg
232         xorl    %esi,%esi       # third arg
233
234 /* no longer in function call */
235         movl    %eax, GNAME(foreign_function_call_active)
236
237         movl    %esp,%ebx       # remember current stack
238         pushl   %ebx            # Save entry stack on (maybe) new stack.
239
240         /* Establish Lisp args. */
241         movl     8(%ebp),%eax   # lexenv?
242         movl    12(%ebp),%ebx   # address of arg vec
243         movl    16(%ebp),%ecx   # num args
244         shll    $2,%ecx         # Make num args into fixnum.
245         cmpl    $0,%ecx
246         je      Ldone
247         movl    (%ebx),%edx     # arg0
248         cmpl    $4,%ecx
249         je      Ldone
250         movl    4(%ebx),%edi    # arg1
251         cmpl    $8,%ecx
252         je      Ldone
253         movl    8(%ebx),%esi    # arg2
254 Ldone:  
255         /* Registers eax, ecx, edx, edi, and esi are now live. */
256
257         /* Alloc new frame. */
258         mov     %esp,%ebx       # The current sp marks start of new frame.
259         push    %ebp            # fp in save location S0
260         sub     $8,%esp         # Ensure 3 slots are allocated, one above.
261         mov     %ebx,%ebp       # Switch to new frame.
262
263         call    *CLOSURE_FUN_OFFSET(%eax)
264         
265         /* If the function returned multiple values, it will return to
266            this point.  Lose them */
267         mov     %ebx, %esp
268         /* A singled value function returns here */
269
270 /* Restore the stack, in case there was a stack change. */
271         popl    %esp            # c-sp
272
273 /* Restore C regs: ebx esi edi. */
274         popl    %edi
275         popl    %esi
276         popl    %ebx
277
278 /* Restore the NPX state. */
279         frstor  (%esp)
280         addl    $108, %esp
281         
282         popl    %ebp            # c-sp
283         movl    %edx,%eax       # c-val
284         ret
285         SIZE(GNAME(call_into_lisp))
286 \f
287 /* support for saving and restoring the NPX state from C */
288         .text
289         .global GNAME(fpu_save)
290         TYPE(GNAME(fpu_save))
291         .align  2,0x90
292 GNAME(fpu_save):
293         movl    4(%esp),%eax
294         fnsave  (%eax)          # Save the NPX state. (resets NPX)
295         ret
296         SIZE(GNAME(fpu_save))
297
298         .global GNAME(fpu_restore)
299         TYPE(GNAME(fpu_restore))
300         .align  2,0x90
301 GNAME(fpu_restore):
302         movl    4(%esp),%eax
303         frstor  (%eax)          # Restore the NPX state.
304         ret
305         SIZE(GNAME(fpu_restore))
306 \f
307 /*
308  * the undefined-function trampoline
309  */
310         .text
311         .align  align_4byte,0x90
312         .global GNAME(undefined_tramp)
313         TYPE(GNAME(undefined_tramp))
314         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
315 GNAME(undefined_tramp):
316         int3
317         .byte   trap_Error
318         .byte   2
319         .byte   UNDEFINED_FUN_ERROR
320         .byte   sc_DescriptorReg # eax in the Descriptor-reg SC
321         ret
322         SIZE(GNAME(undefined_tramp))
323
324 /*
325  * the closure trampoline
326  */
327         .text
328         .align  align_4byte,0x90
329         .global GNAME(closure_tramp)
330         TYPE(GNAME(closure_tramp))
331         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
332 GNAME(closure_tramp):
333         movl    FDEFN_FUN_OFFSET(%eax),%eax
334         /* FIXME: The '*' after "jmp" in the next line is from PVE's
335          * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
336          * reasonable, and it certainly seems as though if CMU CL needs it,
337          * SBCL needs it too, but I haven't actually verified that it's
338          * right. It would be good to find a way to force the flow of
339          * control through here to test it. */
340         jmp     *CLOSURE_FUN_OFFSET(%eax)
341         SIZE(GNAME(closure_tramp))
342
343 /*
344  * fun-end breakpoint magic
345  */
346         .text
347         .global GNAME(fun_end_breakpoint_guts)
348         .align  align_4byte
349 GNAME(fun_end_breakpoint_guts):
350         /* Multiple Value return */
351         jmp     multiple_value_return
352         /* Single value return: The eventual return will now use the
353            multiple values return convention but with a return values
354            count of one. */
355         movl    %esp,%ebx       # Setup ebx - the ofp.
356         subl    $4,%esp         # Allocate one stack slot for the return value
357         movl    $4,%ecx         # Setup ecx for one return value.
358         movl    $NIL,%edi       # default second value
359         movl    $NIL,%esi       # default third value
360                 
361 multiple_value_return:
362         
363         .global GNAME(fun_end_breakpoint_trap)
364 GNAME(fun_end_breakpoint_trap):
365         int3
366         .byte   trap_FunEndBreakpoint
367         hlt                     # We should never return here.
368
369         .global GNAME(fun_end_breakpoint_end)
370 GNAME(fun_end_breakpoint_end):
371
372 \f
373         .global GNAME(do_pending_interrupt)
374         TYPE(GNAME(do_pending_interrupt))
375         .align  align_4byte,0x90
376 GNAME(do_pending_interrupt):
377         int3
378         .byte   trap_PendingInterrupt
379         ret
380         SIZE(GNAME(do_pending_interrupt))
381 \f
382
383 /*
384  * Allocate bytes and return the start of the allocated space
385  * in the specified destination register.
386  *
387  * In the general case the size will be in the destination register.
388  *
389  * All registers must be preserved except the destination.
390  * The C conventions will preserve ebx, esi, edi, and ebp.
391  * So only eax, ecx, and edx need special care here.
392  */
393         
394         .globl  GNAME(alloc_to_eax)
395         TYPE(GNAME(alloc_to_eax))
396         .align  align_4byte,0x90
397 GNAME(alloc_to_eax):
398         pushl   %ecx    # Save ecx and edx as C could destroy them.
399         pushl   %edx
400         pushl   %eax    # Push the size.
401         call    GNAME(alloc)
402         addl    $4,%esp # Pop the size arg.
403         popl    %edx    # Restore ecx and edx.
404         popl    %ecx
405         ret
406         SIZE(GNAME(alloc_to_eax))
407
408         .globl  GNAME(alloc_8_to_eax)
409         TYPE(GNAME(alloc_8_to_eax))
410         .align  align_4byte,0x90
411 GNAME(alloc_8_to_eax):
412         pushl   %ecx    # Save ecx and edx as C could destroy them.
413         pushl   %edx
414         pushl   $8      # Push the size.
415         call    GNAME(alloc)
416         addl    $4,%esp # Pop the size arg.
417         popl    %edx    # Restore ecx and edx.
418         popl    %ecx
419         ret
420         SIZE(GNAME(alloc_8_to_eax))
421
422         .globl  GNAME(alloc_8_to_eax)
423         TYPE(GNAME(alloc_8_to_eax))
424         .align  align_4byte,0x90
425
426         .globl  GNAME(alloc_16_to_eax)
427         TYPE(GNAME(alloc_16_to_eax))
428         .align  align_4byte,0x90
429 GNAME(alloc_16_to_eax):
430         pushl   %ecx    # Save ecx and edx as C could destroy them.
431         pushl   %edx
432         pushl   $16     # Push the size.
433         call    GNAME(alloc)
434         addl    $4,%esp # Pop the size arg.
435         popl    %edx    # Restore ecx and edx.
436         popl    %ecx
437         ret
438         SIZE(GNAME(alloc_16_to_eax))
439
440         .globl  GNAME(alloc_to_ecx)
441         TYPE(GNAME(alloc_to_ecx))
442         .align  align_4byte,0x90
443 GNAME(alloc_to_ecx):
444         pushl   %eax    # Save eax and edx as C could destroy them.
445         pushl   %edx
446         pushl   %ecx    # Push the size.
447         call    GNAME(alloc)
448         addl    $4,%esp # Pop the size arg.
449         movl    %eax,%ecx       # Set up the destination.
450         popl    %edx    # Restore eax and edx.
451         popl    %eax
452         ret
453         SIZE(GNAME(alloc_to_ecx))
454
455         .globl  GNAME(alloc_8_to_ecx)
456         TYPE(GNAME(alloc_8_to_ecx))
457         .align  align_4byte,0x90
458 GNAME(alloc_8_to_ecx):
459         pushl   %eax    # Save eax and edx as C could destroy them.
460         pushl   %edx
461         pushl   $8      # Push the size.
462         call    GNAME(alloc)
463         addl    $4,%esp # Pop the size arg.
464         movl    %eax,%ecx       # Set up the destination.
465         popl    %edx    # Restore eax and edx.
466         popl    %eax
467         ret
468         SIZE(GNAME(alloc_8_to_ecx))
469
470         .globl  GNAME(alloc_16_to_ecx)
471         TYPE(GNAME(alloc_16_to_ecx))
472         .align  align_4byte,0x90
473 GNAME(alloc_16_to_ecx):
474         pushl   %eax    # Save eax and edx as C could destroy them.
475         pushl   %edx
476         pushl   $16     # Push the size.
477         call    GNAME(alloc)
478         addl    $4,%esp # Pop the size arg.
479         movl    %eax,%ecx       # Set up the destination.
480         popl    %edx    # Restore eax and edx.
481         popl    %eax
482         ret
483         SIZE(GNAME(alloc_16_to_ecx))
484
485
486         .globl  GNAME(alloc_to_edx)
487         TYPE(GNAME(alloc_to_edx))
488         .align  align_4byte,0x90
489 GNAME(alloc_to_edx):
490         pushl   %eax    # Save eax and ecx as C could destroy them.
491         pushl   %ecx
492         pushl   %edx    # Push the size.
493         call    GNAME(alloc)
494         addl    $4,%esp # Pop the size arg.
495         movl    %eax,%edx       # Set up the destination.
496         popl    %ecx    # Restore eax and ecx.
497         popl    %eax
498         ret
499         SIZE(GNAME(alloc_to_edx))
500
501         .globl  GNAME(alloc_8_to_edx)
502         TYPE(GNAME(alloc_8_to_edx))
503         .align  align_4byte,0x90
504 GNAME(alloc_8_to_edx):
505         pushl   %eax    # Save eax and ecx as C could destroy them.
506         pushl   %ecx
507         pushl   $8      # Push the size.
508         call    GNAME(alloc)
509         addl    $4,%esp # Pop the size arg.
510         movl    %eax,%edx       # Set up the destination.
511         popl    %ecx    # Restore eax and ecx.
512         popl    %eax
513         ret
514         SIZE(GNAME(alloc_8_to_edx))
515
516         .globl  GNAME(alloc_16_to_edx)
517         TYPE(GNAME(alloc_16_to_edx))
518         .align  align_4byte,0x90
519 GNAME(alloc_16_to_edx):
520         pushl   %eax    # Save eax and ecx as C could destroy them.
521         pushl   %ecx
522         pushl   $16     # Push the size.
523         call    GNAME(alloc)
524         addl    $4,%esp # Pop the size arg.
525         movl    %eax,%edx       # Set up the destination.
526         popl    %ecx    # Restore eax and ecx.
527         popl    %eax
528         ret
529         SIZE(GNAME(alloc_16_to_edx))
530
531
532
533         .globl  GNAME(alloc_to_ebx)
534         TYPE(GNAME(alloc_to_ebx))
535         .align  align_4byte,0x90
536 GNAME(alloc_to_ebx):
537         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
538         pushl   %ecx
539         pushl   %edx
540         pushl   %ebx    # Push the size.
541         call    GNAME(alloc)
542         addl    $4,%esp # Pop the size arg.
543         movl    %eax,%ebx       # Set up the destination.
544         popl    %edx    # Restore eax, ecx and edx.
545         popl    %ecx
546         popl    %eax
547         ret
548         SIZE(GNAME(alloc_to_ebx))
549
550         .globl  GNAME(alloc_8_to_ebx)
551         TYPE(GNAME(alloc_8_to_ebx))
552         .align  align_4byte,0x90
553 GNAME(alloc_8_to_ebx):
554         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
555         pushl   %ecx
556         pushl   %edx
557         pushl   $8      # Push the size.
558         call    GNAME(alloc)
559         addl    $4,%esp # Pop the size arg.
560         movl    %eax,%ebx       # Set up the destination.
561         popl    %edx    # Restore eax, ecx and edx.
562         popl    %ecx
563         popl    %eax
564         ret
565         SIZE(GNAME(alloc_8_to_ebx))
566
567         .globl  GNAME(alloc_16_to_ebx)
568         TYPE(GNAME(alloc_16_to_ebx))
569         .align  align_4byte,0x90
570 GNAME(alloc_16_to_ebx):
571         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
572         pushl   %ecx
573         pushl   %edx
574         pushl   $16     # Push the size
575         call    GNAME(alloc)
576         addl    $4,%esp # pop the size arg.
577         movl    %eax,%ebx       # setup the destination.
578         popl    %edx    # Restore eax, ecx and edx.
579         popl    %ecx
580         popl    %eax
581         ret
582         SIZE(GNAME(alloc_16_to_ebx))
583
584
585
586         .globl  GNAME(alloc_to_esi)
587         TYPE(GNAME(alloc_to_esi))
588         .align  align_4byte,0x90
589 GNAME(alloc_to_esi):
590         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
591         pushl   %ecx
592         pushl   %edx
593         pushl   %esi    # Push the size
594         call    GNAME(alloc)
595         addl    $4,%esp # pop the size arg.
596         movl    %eax,%esi       # setup the destination.
597         popl    %edx    # Restore eax, ecx and edx.
598         popl    %ecx
599         popl    %eax
600         ret
601         SIZE(GNAME(alloc_to_esi))
602
603         .globl  GNAME(alloc_8_to_esi)
604         TYPE(GNAME(alloc_8_to_esi))
605         .align  align_4byte,0x90
606 GNAME(alloc_8_to_esi):
607         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
608         pushl   %ecx
609         pushl   %edx
610         pushl   $8      # Push the size
611         call    GNAME(alloc)
612         addl    $4,%esp # pop the size arg.
613         movl    %eax,%esi       # setup the destination.
614         popl    %edx    # Restore eax, ecx and edx.
615         popl    %ecx
616         popl    %eax
617         ret
618         SIZE(GNAME(alloc_8_to_esi))
619
620         .globl  GNAME(alloc_16_to_esi)
621         TYPE(GNAME(alloc_16_to_esi))
622         .align  align_4byte,0x90
623 GNAME(alloc_16_to_esi):
624         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
625         pushl   %ecx
626         pushl   %edx
627         pushl   $16     # Push the size
628         call    GNAME(alloc)
629         addl    $4,%esp # pop the size arg.
630         movl    %eax,%esi       # setup the destination.
631         popl    %edx    # Restore eax, ecx and edx.
632         popl    %ecx
633         popl    %eax
634         ret
635         SIZE(GNAME(alloc_16_to_esi))
636
637
638         .globl  GNAME(alloc_to_edi)
639         TYPE(GNAME(alloc_to_edi))
640         .align  align_4byte,0x90
641 GNAME(alloc_to_edi):
642         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
643         pushl   %ecx
644         pushl   %edx
645         pushl   %edi    # Push the size
646         call    GNAME(alloc)
647         addl    $4,%esp # pop the size arg.
648         movl    %eax,%edi       # setup the destination.
649         popl    %edx    # Restore eax, ecx and edx.
650         popl    %ecx
651         popl    %eax
652         ret
653         SIZE(GNAME(alloc_to_edi))
654
655         .globl  GNAME(alloc_8_to_edi)
656         TYPE(GNAME(alloc_8_to_edi))
657         .align  align_4byte,0x90
658 GNAME(alloc_8_to_edi):
659         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
660         pushl   %ecx
661         pushl   %edx
662         pushl   $8      # Push the size
663         call    GNAME(alloc)
664         addl    $4,%esp # pop the size arg.
665         movl    %eax,%edi       # setup the destination.
666         popl    %edx    # Restore eax, ecx and edx.
667         popl    %ecx
668         popl    %eax
669         ret
670         SIZE(GNAME(alloc_8_to_edi))
671
672         .globl  GNAME(alloc_16_to_edi)
673         TYPE(GNAME(alloc_16_to_edi))
674         .align  align_4byte,0x90
675 GNAME(alloc_16_to_edi):
676         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
677         pushl   %ecx
678         pushl   %edx
679         pushl   $16     # Push the size
680         call    GNAME(alloc)
681         addl    $4,%esp # pop the size arg.
682         movl    %eax,%edi       # setup the destination.
683         popl    %edx    # Restore eax, ecx and edx.
684         popl    %ecx
685         popl    %eax
686         ret
687         SIZE(GNAME(alloc_16_to_edi))
688
689         
690 /* Called from lisp when an inline allocation overflows.
691    Every register except the result needs to be preserved.
692    We depend on C to preserve ebx, esi, edi, and ebp.
693    But where necessary must save eax, ecx, edx. */
694
695 #ifdef LISP_FEATURE_SB_THREAD
696 #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET
697 #else
698 #define START_REGION GNAME(boxed_region)
699 #endif
700                 
701 /* This routine handles an overflow with eax=crfp+size. So the
702    size=eax-crfp. */
703         .align  align_4byte
704         .globl  GNAME(alloc_overflow_eax)
705         TYPE(GNAME(alloc_overflow_eax))
706 GNAME(alloc_overflow_eax):
707         pushl   %ecx            # Save ecx
708         pushl   %edx            # Save edx
709         /* Calculate the size for the allocation. */
710         subl    START_REGION,%eax
711         pushl   %eax            # Push the size
712         call    GNAME(alloc)
713         addl    $4,%esp # pop the size arg.
714         popl    %edx    # Restore edx.
715         popl    %ecx    # Restore ecx.
716         ret
717         SIZE(GNAME(alloc_overflow_eax))
718
719         .align  align_4byte
720         .globl  GNAME(alloc_overflow_ecx)
721         TYPE(GNAME(alloc_overflow_ecx))
722 GNAME(alloc_overflow_ecx):
723         pushl   %eax            # Save eax
724         pushl   %edx            # Save edx
725         /* Calculate the size for the allocation. */
726         subl    START_REGION,%ecx
727         pushl   %ecx            # Push the size
728         call    GNAME(alloc)
729         addl    $4,%esp # pop the size arg.
730         movl    %eax,%ecx       # setup the destination.
731         popl    %edx    # Restore edx.
732         popl    %eax    # Restore eax.
733         ret
734         SIZE(GNAME(alloc_overflow_ecx))
735
736         .align  align_4byte
737         .globl  GNAME(alloc_overflow_edx)
738         TYPE(GNAME(alloc_overflow_edx))
739 GNAME(alloc_overflow_edx):
740         pushl   %eax            # Save eax
741         pushl   %ecx            # Save ecx
742         /* Calculate the size for the allocation. */
743         subl    START_REGION,%edx
744         pushl   %edx            # Push the size
745         call    GNAME(alloc)
746         addl    $4,%esp # pop the size arg.
747         movl    %eax,%edx       # setup the destination.
748         popl    %ecx    # Restore ecx.
749         popl    %eax    # Restore eax.
750         ret
751         SIZE(GNAME(alloc_overflow_edx))
752
753 /* This routine handles an overflow with ebx=crfp+size. So the
754    size=ebx-crfp. */
755         .align  align_4byte
756         .globl  GNAME(alloc_overflow_ebx)
757         TYPE(GNAME(alloc_overflow_ebx))
758 GNAME(alloc_overflow_ebx):
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,%ebx
764         pushl   %ebx            # Push the size
765         call    GNAME(alloc)
766         addl    $4,%esp # pop the size arg.
767         movl    %eax,%ebx       # setup the destination.
768         popl    %edx    # Restore edx.
769         popl    %ecx    # Restore ecx.
770         popl    %eax    # Restore eax.
771         ret
772         SIZE(GNAME(alloc_overflow_ebx))
773
774 /* This routine handles an overflow with esi=crfp+size. So the
775    size=esi-crfp. */
776         .align  align_4byte
777         .globl  GNAME(alloc_overflow_esi)
778         TYPE(GNAME(alloc_overflow_esi))
779 GNAME(alloc_overflow_esi):
780         pushl   %eax            # Save eax
781         pushl   %ecx            # Save ecx
782         pushl   %edx            # Save edx
783         /* Calculate the size for the allocation. */
784         subl    START_REGION,%esi
785         pushl   %esi            # Push the size
786         call    GNAME(alloc)
787         addl    $4,%esp # pop the size arg.
788         movl    %eax,%esi       # setup the destination.
789         popl    %edx    # Restore edx.
790         popl    %ecx    # Restore ecx.
791         popl    %eax    # Restore eax.
792         ret
793         SIZE(GNAME(alloc_overflow_esi))
794
795         .align  align_4byte
796         .globl  GNAME(alloc_overflow_edi)
797         TYPE(GNAME(alloc_overflow_edi))
798 GNAME(alloc_overflow_edi):
799         pushl   %eax            # Save eax
800         pushl   %ecx            # Save ecx
801         pushl   %edx            # Save edx
802         /* Calculate the size for the allocation. */
803         subl    START_REGION,%edi
804         pushl   %edi            # Push the size
805         call    GNAME(alloc)
806         addl    $4,%esp # pop the size arg.
807         movl    %eax,%edi       # setup the destination.
808         popl    %edx    # Restore edx.
809         popl    %ecx    # Restore ecx.
810         popl    %eax    # Restore eax.
811         ret
812         SIZE(GNAME(alloc_overflow_edi))
813
814         .align  align_4byte,0x90
815         .globl  GNAME(post_signal_tramp)
816         TYPE(GNAME(post_signal_tramp))
817 GNAME(post_signal_tramp):
818         /* this is notionally the second half of a function whose first half
819          * doesn't exist.  This is where call_into_lisp returns when called 
820          * using return_to_lisp_function */
821         addl $12,%esp   /* clear call_into_lisp args from stack */
822         popal           /* restore registers */
823         popfl
824         leave
825         ret
826         SIZE(GNAME(post_signal_tramp))
827
828 #ifdef LISP_FEATURE_WIN32
829         /*
830          * This is part of the funky magic for exception handling on win32.
831          * see sigtrap_emulator() in win32-os.c for details.
832          */
833         .global GNAME(sigtrap_trampoline)
834 GNAME(sigtrap_trampoline):
835         pushl   %eax
836         pushl   %ebp
837         movl    %esp, %ebp
838         call    GNAME(sigtrap_wrapper)
839         pop     %eax
840         pop     %eax
841         int3
842         .byte   trap_ContextRestore
843         hlt                     # We should never return here.
844
845         /*
846          * This is part of the funky magic for exception handling on win32.
847          * see handle_exception() in win32-os.c for details.
848          */
849         .global GNAME(exception_trampoline)
850 GNAME(exception_trampoline):
851         pushl   %eax
852         pushl   %ebp
853         movl    %esp, %ebp
854         call    GNAME(handle_win32_exception_wrapper)
855         pop     %eax
856         pop     %eax
857         int3
858         .byte   trap_ContextRestore
859         hlt                     # We should never return here.
860 #endif
861         
862         .end