3dfb53b20ff9262cd6ab156606e48fde7b69370d
[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 "validate.h"
18 #include "sbcl.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 #if defined __linux__  || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
33 #define GNAME(var) var
34 #else
35 #define GNAME(var) _##var
36 #endif
37
38 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
39  * want alignment in bytes. 
40  *
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)
46  */
47 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
48 #define align_4byte     4
49 #define align_8byte     8
50 #define align_16byte    16
51 #else
52 #define align_4byte     2
53 #define align_8byte     3
54 #define align_16byte    4       
55 #endif                  
56
57         .text
58         .global GNAME(foreign_function_call_active)
59         .global GNAME(all_threads)
60 \f
61 /*
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.)
66  *
67  * Return values are in eax and maybe edx for quads, or st(0) for
68  * floats.
69  *
70  * This should work for Lisp calls C calls Lisp calls C..
71  */
72         .text
73         .align  align_16byte,0x90
74         .global GNAME(call_into_c)
75         .type   GNAME(call_into_c),@function
76 GNAME(call_into_c):
77         movl    $1,GNAME(foreign_function_call_active)
78
79 /* Save the return Lisp address in ebx. */
80         popl    %ebx
81
82 /* Setup the NPX for C */
83         fstp    %st(0)
84         fstp    %st(0)
85         fstp    %st(0)
86         fstp    %st(0)
87         fstp    %st(0)
88         fstp    %st(0)
89         fstp    %st(0)
90         fstp    %st(0)
91
92         call    *%eax           # normal callout using Lisp stack
93
94         movl    %eax,%ecx       # remember integer return value
95
96 /* Check for a return FP value. */
97         fxam
98         fnstsw  %eax
99         andl    $0x4500,%eax
100         cmpl    $0x4100,%eax
101         jne     Lfp_rtn_value
102
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.
106         fldz
107         fldz
108         fldz
109         fldz
110         fldz
111         fldz
112         fldz
113
114 /* Restore the return value. */
115         movl    %ecx,%eax       # maybe return value
116
117         movl    $0,GNAME(foreign_function_call_active)
118 /* Return. */
119         jmp     *%ebx
120
121 Lfp_rtn_value:
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.
125         fldz
126         fldz
127         fldz
128         fldz
129         fldz
130         fldz
131         fxch    %st(7)          # Move the result back to st(0).
132
133 /* We don't need to restore eax, because the result is in st(0). */
134
135         movl    $0,GNAME(foreign_function_call_active)
136 /* Return. */   
137         jmp     *%ebx
138
139         .size   GNAME(call_into_c), . - GNAME(call_into_c)
140
141 \f
142         .text   
143         .global GNAME(call_into_lisp_first_time)
144         .type  GNAME(call_into_lisp_first_time),@function
145                 
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 
149  * anyway */
150         
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
159         * here */
160         addl    $THREAD_CONTROL_STACK_SIZE-4,%esp
161         jmp     Lstack
162 \f
163         .text   
164         .global GNAME(call_into_lisp)
165         .type  GNAME(call_into_lisp),@function
166                 
167 /* The C conventions require that ebx, esi, edi, and ebp be preserved
168  * across function calls. */
169         
170         .align  align_16byte,0x90
171 GNAME(call_into_lisp):
172         pushl   %ebp            # Save old frame pointer.
173         movl    %esp,%ebp       # Establish new frame.
174 Lstack:
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
179
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)
183         pushl   %eax
184         fldcw   (%esp)          # Recover modes.
185         popl    %eax
186
187         fldz                    # Ensure no FP regs are empty.
188         fldz
189         fldz
190         fldz
191         fldz
192         fldz
193         fldz
194         fldz
195         
196 /* Save C regs: ebx esi edi. */
197         pushl   %ebx
198         pushl   %esi
199         pushl   %edi
200         
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
208
209 /* no longer in function call */
210         movl    %eax, GNAME(foreign_function_call_active)
211
212         movl    %esp,%ebx       # remember current stack
213         pushl   %ebx            # Save entry stack on (maybe) new stack.
214
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.
220         cmpl    $0,%ecx
221         je      Ldone
222         movl    (%ebx),%edx     # arg0
223         cmpl    $4,%ecx
224         je      Ldone
225         movl    4(%ebx),%edi    # arg1
226         cmpl    $8,%ecx
227         je      Ldone
228         movl    8(%ebx),%esi    # arg2
229 Ldone:  
230         /* Registers eax, ecx, edx, edi, and esi are now live. */
231
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.
237
238         call    *CLOSURE_FUN_OFFSET(%eax)
239         
240         /* If the function returned multiple values, it will return to
241            this point.  Lose them */
242         mov     %ebx, %esp
243         /* A singled value function returns here */
244
245 /* Restore the stack, in case there was a stack change. */
246         popl    %esp            # c-sp
247
248 /* Restore C regs: ebx esi edi. */
249         popl    %edi
250         popl    %esi
251         popl    %ebx
252
253 /* Restore the NPX state. */
254         frstor  (%esp)
255         addl    $108, %esp
256         
257         popl    %ebp            # c-sp
258         movl    %edx,%eax       # c-val
259         ret
260         .size   GNAME(call_into_lisp), . - GNAME(call_into_lisp)
261 \f
262 /* support for saving and restoring the NPX state from C */
263         .text
264         .global GNAME(fpu_save)
265         .type   GNAME(fpu_save),@function
266         .align  2,0x90
267 GNAME(fpu_save):
268         movl    4(%esp),%eax
269         fnsave  (%eax)          # Save the NPX state. (resets NPX)
270         ret
271         .size   GNAME(fpu_save),.-GNAME(fpu_save)
272
273         .global GNAME(fpu_restore)
274         .type   GNAME(fpu_restore),@function
275         .align  2,0x90
276 GNAME(fpu_restore):
277         movl    4(%esp),%eax
278         frstor  (%eax)          # Restore the NPX state.
279         ret
280         .size   GNAME(fpu_restore),.-GNAME(fpu_restore)
281 \f
282 /*
283  * the undefined-function trampoline
284  */
285         .text
286         .align  align_4byte,0x90
287         .global GNAME(undefined_tramp)
288         .type   GNAME(undefined_tramp),@function
289 GNAME(undefined_tramp):
290         int3
291         .byte   trap_Error
292         .byte   2
293         .byte   UNDEFINED_FUN_ERROR
294         .byte   sc_DescriptorReg # eax in the Descriptor-reg SC
295         ret
296         .size   GNAME(undefined_tramp), .-GNAME(undefined_tramp)
297
298 /*
299  * the closure trampoline
300  */
301         .text
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)
315
316 /*
317  * fun-end breakpoint magic
318  */
319         .text
320         .global GNAME(fun_end_breakpoint_guts)
321         .align  align_4byte
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
327            count of one. */
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
333                 
334 multiple_value_return:
335         
336         .global GNAME(fun_end_breakpoint_trap)
337 GNAME(fun_end_breakpoint_trap):
338         int3
339         .byte   trap_FunEndBreakpoint
340         hlt                     # We should never return here.
341
342         .global GNAME(fun_end_breakpoint_end)
343 GNAME(fun_end_breakpoint_end):
344
345 \f
346         .global GNAME(do_pending_interrupt)
347         .type   GNAME(do_pending_interrupt),@function
348         .align  align_4byte,0x90
349 GNAME(do_pending_interrupt):
350         int3
351         .byte   trap_PendingInterrupt
352         ret
353         .size   GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt)
354 \f
355
356 /*
357  * Allocate bytes and return the start of the allocated space
358  * in the specified destination register.
359  *
360  * In the general case the size will be in the destination register.
361  *
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.
365  */
366         
367         .globl  GNAME(alloc_to_eax)
368         .type   GNAME(alloc_to_eax),@function
369         .align  align_4byte,0x90
370 GNAME(alloc_to_eax):
371         pushl   %ecx    # Save ecx and edx as C could destroy them.
372         pushl   %edx
373         pushl   %eax    # Push the size.
374         call    GNAME(alloc)
375         addl    $4,%esp # Pop the size arg.
376         popl    %edx    # Restore ecx and edx.
377         popl    %ecx
378         ret
379         .size   GNAME(alloc_to_eax),.-GNAME(alloc_to_eax)
380
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.
386         pushl   %edx
387         pushl   $8      # Push the size.
388         call    GNAME(alloc)
389         addl    $4,%esp # Pop the size arg.
390         popl    %edx    # Restore ecx and edx.
391         popl    %ecx
392         ret
393         .size   GNAME(alloc_8_to_eax),.-GNAME(alloc_8_to_eax)
394
395         .globl  GNAME(alloc_8_to_eax)
396         .type   GNAME(alloc_8_to_eax),@function
397         .align  align_4byte,0x90
398
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.
404         pushl   %edx
405         pushl   $16     # Push the size.
406         call    GNAME(alloc)
407         addl    $4,%esp # Pop the size arg.
408         popl    %edx    # Restore ecx and edx.
409         popl    %ecx
410         ret
411         .size   GNAME(alloc_16_to_eax),.-GNAME(alloc_16_to_eax)
412
413         .globl  GNAME(alloc_to_ecx)
414         .type   GNAME(alloc_to_ecx),@function
415         .align  align_4byte,0x90
416 GNAME(alloc_to_ecx):
417         pushl   %eax    # Save eax and edx as C could destroy them.
418         pushl   %edx
419         pushl   %ecx    # Push the size.
420         call    GNAME(alloc)
421         addl    $4,%esp # Pop the size arg.
422         movl    %eax,%ecx       # Set up the destination.
423         popl    %edx    # Restore eax and edx.
424         popl    %eax
425         ret
426         .size   GNAME(alloc_to_ecx),.-GNAME(alloc_to_ecx)
427
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.
433         pushl   %edx
434         pushl   $8      # Push the size.
435         call    GNAME(alloc)
436         addl    $4,%esp # Pop the size arg.
437         movl    %eax,%ecx       # Set up the destination.
438         popl    %edx    # Restore eax and edx.
439         popl    %eax
440         ret
441         .size   GNAME(alloc_8_to_ecx),.-GNAME(alloc_8_to_ecx)
442
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.
448         pushl   %edx
449         pushl   $16     # Push the size.
450         call    GNAME(alloc)
451         addl    $4,%esp # Pop the size arg.
452         movl    %eax,%ecx       # Set up the destination.
453         popl    %edx    # Restore eax and edx.
454         popl    %eax
455         ret
456         .size   GNAME(alloc_16_to_ecx),.-GNAME(alloc_16_to_ecx)
457
458
459         .globl  GNAME(alloc_to_edx)
460         .type   GNAME(alloc_to_edx),@function
461         .align  align_4byte,0x90
462 GNAME(alloc_to_edx):
463         pushl   %eax    # Save eax and ecx as C could destroy them.
464         pushl   %ecx
465         pushl   %edx    # Push the size.
466         call    GNAME(alloc)
467         addl    $4,%esp # Pop the size arg.
468         movl    %eax,%edx       # Set up the destination.
469         popl    %ecx    # Restore eax and ecx.
470         popl    %eax
471         ret
472         .size   GNAME(alloc_to_edx),.-GNAME(alloc_to_edx)
473
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.
479         pushl   %ecx
480         pushl   $8      # Push the size.
481         call    GNAME(alloc)
482         addl    $4,%esp # Pop the size arg.
483         movl    %eax,%edx       # Set up the destination.
484         popl    %ecx    # Restore eax and ecx.
485         popl    %eax
486         ret
487         .size   GNAME(alloc_8_to_edx),.-GNAME(alloc_8_to_edx)
488
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.
494         pushl   %ecx
495         pushl   $16     # Push the size.
496         call    GNAME(alloc)
497         addl    $4,%esp # Pop the size arg.
498         movl    %eax,%edx       # Set up the destination.
499         popl    %ecx    # Restore eax and ecx.
500         popl    %eax
501         ret
502         .size   GNAME(alloc_16_to_edx),.-GNAME(alloc_16_to_edx)
503
504
505
506         .globl  GNAME(alloc_to_ebx)
507         .type   GNAME(alloc_to_ebx),@function
508         .align  align_4byte,0x90
509 GNAME(alloc_to_ebx):
510         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
511         pushl   %ecx
512         pushl   %edx
513         pushl   %ebx    # Push the size.
514         call    GNAME(alloc)
515         addl    $4,%esp # Pop the size arg.
516         movl    %eax,%ebx       # Set up the destination.
517         popl    %edx    # Restore eax, ecx and edx.
518         popl    %ecx
519         popl    %eax
520         ret
521         .size   GNAME(alloc_to_ebx),.-GNAME(alloc_to_ebx)
522
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.
528         pushl   %ecx
529         pushl   %edx
530         pushl   $8      # Push the size.
531         call    GNAME(alloc)
532         addl    $4,%esp # Pop the size arg.
533         movl    %eax,%ebx       # Set up the destination.
534         popl    %edx    # Restore eax, ecx and edx.
535         popl    %ecx
536         popl    %eax
537         ret
538         .size   GNAME(alloc_8_to_ebx),.-GNAME(alloc_8_to_ebx)
539
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.
545         pushl   %ecx
546         pushl   %edx
547         pushl   $16     # Push the size
548         call    GNAME(alloc)
549         addl    $4,%esp # pop the size arg.
550         movl    %eax,%ebx       # setup the destination.
551         popl    %edx    # Restore eax, ecx and edx.
552         popl    %ecx
553         popl    %eax
554         ret
555         .size   GNAME(alloc_16_to_ebx),.-GNAME(alloc_16_to_ebx)
556
557
558
559         .globl  GNAME(alloc_to_esi)
560         .type   GNAME(alloc_to_esi),@function
561         .align  align_4byte,0x90
562 GNAME(alloc_to_esi):
563         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
564         pushl   %ecx
565         pushl   %edx
566         pushl   %esi    # Push the size
567         call    GNAME(alloc)
568         addl    $4,%esp # pop the size arg.
569         movl    %eax,%esi       # setup the destination.
570         popl    %edx    # Restore eax, ecx and edx.
571         popl    %ecx
572         popl    %eax
573         ret
574         .size   GNAME(alloc_to_esi),.-GNAME(alloc_to_esi)
575
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.
581         pushl   %ecx
582         pushl   %edx
583         pushl   $8      # Push the size
584         call    GNAME(alloc)
585         addl    $4,%esp # pop the size arg.
586         movl    %eax,%esi       # setup the destination.
587         popl    %edx    # Restore eax, ecx and edx.
588         popl    %ecx
589         popl    %eax
590         ret
591         .size   GNAME(alloc_8_to_esi),.-GNAME(alloc_8_to_esi)
592
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.
598         pushl   %ecx
599         pushl   %edx
600         pushl   $16     # Push the size
601         call    GNAME(alloc)
602         addl    $4,%esp # pop the size arg.
603         movl    %eax,%esi       # setup the destination.
604         popl    %edx    # Restore eax, ecx and edx.
605         popl    %ecx
606         popl    %eax
607         ret
608         .size   GNAME(alloc_16_to_esi),.-GNAME(alloc_16_to_esi)
609
610
611         .globl  GNAME(alloc_to_edi)
612         .type   GNAME(alloc_to_edi),@function
613         .align  align_4byte,0x90
614 GNAME(alloc_to_edi):
615         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
616         pushl   %ecx
617         pushl   %edx
618         pushl   %edi    # Push the size
619         call    GNAME(alloc)
620         addl    $4,%esp # pop the size arg.
621         movl    %eax,%edi       # setup the destination.
622         popl    %edx    # Restore eax, ecx and edx.
623         popl    %ecx
624         popl    %eax
625         ret
626         .size   GNAME(alloc_to_edi),.-GNAME(alloc_to_edi)
627
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.
633         pushl   %ecx
634         pushl   %edx
635         pushl   $8      # Push the size
636         call    GNAME(alloc)
637         addl    $4,%esp # pop the size arg.
638         movl    %eax,%edi       # setup the destination.
639         popl    %edx    # Restore eax, ecx and edx.
640         popl    %ecx
641         popl    %eax
642         ret
643         .size   GNAME(alloc_8_to_edi),.-GNAME(alloc_8_to_edi)
644
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.
650         pushl   %ecx
651         pushl   %edx
652         pushl   $16     # Push the size
653         call    GNAME(alloc)
654         addl    $4,%esp # pop the size arg.
655         movl    %eax,%edi       # setup the destination.
656         popl    %edx    # Restore eax, ecx and edx.
657         popl    %ecx
658         popl    %eax
659         ret
660         .size   GNAME(alloc_16_to_edi),.-GNAME(alloc_16_to_edi)
661
662         
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. */
667
668 #ifdef LISP_FEATURE_SB_THREAD
669 #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET
670 #define DISPLACEMENT $7
671 #else
672 #define START_REGION boxed_region
673 #define DISPLACEMENT $6
674 #endif
675                 
676 /* This routine handles an overflow with eax=crfp+size. So the
677    size=eax-crfp. */
678         .align  align_4byte
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
687         call    GNAME(alloc)
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.
692         ret
693         .size    GNAME(alloc_overflow_eax),.-GNAME(alloc_overflow_eax)
694
695         .align  align_4byte
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
704         call    GNAME(alloc)
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.
710         ret
711         .size    GNAME(alloc_overflow_ecx),.-GNAME(alloc_overflow_ecx)
712
713         .align  align_4byte
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
722         call    GNAME(alloc)
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.
728         ret
729         .size    GNAME(alloc_overflow_edx),.-GNAME(alloc_overflow_edx)
730
731 /* This routine handles an overflow with ebx=crfp+size. So the
732    size=ebx-crfp. */
733         .align  align_4byte
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
743         call    GNAME(alloc)
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.
750         ret
751         .size    GNAME(alloc_overflow_ebx),.-GNAME(alloc_overflow_ebx)
752
753 /* This routine handles an overflow with esi=crfp+size. So the
754    size=esi-crfp. */
755         .align  align_4byte
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
765         call    GNAME(alloc)
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.
772         ret
773         .size    GNAME(alloc_overflow_esi),.-GNAME(alloc_overflow_esi)
774
775         .align  align_4byte
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
785         call    GNAME(alloc)
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.
792         ret
793         .size    GNAME(alloc_overflow_edi),.-GNAME(alloc_overflow_edi)
794
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 */
804         leave
805         ret
806         .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp)
807
808         
809         .end