78f245bda0762dee0f1074eaaad9e33ef918645b
[libffi.git] / src / x86 / sysv.S
1 /* -----------------------------------------------------------------------
2    sysv.S - Copyright (c) 2013  The Written Word, Inc.
3           - Copyright (c) 1996,1998,2001-2003,2005,2008,2010  Red Hat, Inc.
4    
5    X86 Foreign Function Interface 
6
7    Permission is hereby granted, free of charge, to any person obtaining
8    a copy of this software and associated documentation files (the
9    ``Software''), to deal in the Software without restriction, including
10    without limitation the rights to use, copy, modify, merge, publish,
11    distribute, sublicense, and/or sell copies of the Software, and to
12    permit persons to whom the Software is furnished to do so, subject to
13    the following conditions:
14
15    The above copyright notice and this permission notice shall be included
16    in all copies or substantial portions of the Software.
17
18    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25    DEALINGS IN THE SOFTWARE.
26    ----------------------------------------------------------------------- */
27
28 #ifndef __x86_64__
29
30 #define LIBFFI_ASM      
31 #include <fficonfig.h>
32 #include <ffi.h>
33 #include "internal.h"
34
35 #define C2(X, Y)  X ## Y
36 #define C1(X, Y)  C2(X, Y)
37 #ifdef __USER_LABEL_PREFIX__
38 # define C(X)     C1(__USER_LABEL_PREFIX__, X)
39 #else
40 # define C(X)     X
41 #endif
42
43 #ifdef X86_DARWIN
44 # define L(X)     C1(L, X)
45 #else
46 # define L(X)     C1(.L, X)
47 #endif
48
49 #ifdef __ELF__
50 # define ENDF(X)  .type X,@function; .size X, . - X
51 #else
52 # define ENDF(X)
53 #endif
54
55 /* Handle win32 fastcall name mangling.  */
56 #ifdef X86_WIN32
57 # define ffi_call_i386          @ffi_call_i386@8
58 # define ffi_closure_inner      @ffi_closure_inner@8
59 #else
60 # define ffi_call_i386          C(ffi_call_i386)
61 # define ffi_closure_inner      C(ffi_closure_inner)
62 #endif
63
64 /* This macro allows the safe creation of jump tables without an
65    actual table.  The entry points into the table are all 8 bytes.
66    The use of ORG asserts that we're at the correct location.  */
67 /* ??? The clang assembler doesn't handle .org with symbolic expressions.  */
68 #if defined(__clang__) || defined(__APPLE__) || (defined (__sun__) && defined(__svr4__))
69 # define E(BASE, X)     .balign 8
70 #else
71 # define E(BASE, X)     .balign 8; .org BASE + X * 8
72 #endif
73
74         .text
75         .balign 16
76         .globl  ffi_call_i386
77         FFI_HIDDEN(ffi_call_i386)
78
79 /* This is declared as
80
81    void ffi_call_i386(struct call_frame *frame, char *argp)
82         __attribute__((fastcall));
83
84    Thus the arguments are present in
85
86         ecx: frame
87         edx: argp
88 */
89
90 ffi_call_i386:
91 L(UW0):
92         # cfi_startproc
93 #if !HAVE_FASTCALL
94         movl    4(%esp), %ecx
95         movl    8(%esp), %edx
96 #endif
97         movl    (%esp), %eax            /* move the return address */
98         movl    %ebp, (%ecx)            /* store %ebp into local frame */
99         movl    %eax, 4(%ecx)           /* store retaddr into local frame */
100
101         /* New stack frame based off ebp.  This is a itty bit of unwind
102            trickery in that the CFA *has* changed.  There is no easy way
103            to describe it correctly on entry to the function.  Fortunately,
104            it doesn't matter too much since at all points we can correctly
105            unwind back to ffi_call.  Note that the location to which we
106            moved the return address is (the new) CFA-4, so from the
107            perspective of the unwind info, it hasn't moved.  */
108         movl    %ecx, %ebp
109 L(UW1):
110         # cfi_def_cfa(%ebp, 8)
111         # cfi_rel_offset(%ebp, 0)
112
113         movl    %edx, %esp              /* set outgoing argument stack */
114         movl    20+R_EAX*4(%ebp), %eax  /* set register arguments */
115         movl    20+R_EDX*4(%ebp), %edx
116         movl    20+R_ECX*4(%ebp), %ecx
117
118         call    *8(%ebp)
119
120         movl    12(%ebp), %ecx          /* load return type code */
121         movl    %ebx, 8(%ebp)           /* preserve %ebx */
122 L(UW2):
123         # cfi_rel_offset(%ebx, 8)
124
125         andl    $X86_RET_TYPE_MASK, %ecx
126 #ifdef __PIC__
127         call    C(__x86.get_pc_thunk.bx)
128 L(pc1):
129         leal    L(store_table)-L(pc1)(%ebx, %ecx, 8), %ebx
130 #else
131         leal    L(store_table)(,%ecx, 8), %ebx
132 #endif
133         movl    16(%ebp), %ecx          /* load result address */
134         jmp     *%ebx
135
136         .balign 8
137 L(store_table):
138 E(L(store_table), X86_RET_FLOAT)
139         fstps   (%ecx)
140         jmp     L(e1)
141 E(L(store_table), X86_RET_DOUBLE)
142         fstpl   (%ecx)
143         jmp     L(e1)
144 E(L(store_table), X86_RET_LDOUBLE)
145         fstpt   (%ecx)
146         jmp     L(e1)
147 E(L(store_table), X86_RET_SINT8)
148         movsbl  %al, %eax
149         mov     %eax, (%ecx)
150         jmp     L(e1)
151 E(L(store_table), X86_RET_SINT16)
152         movswl  %ax, %eax
153         mov     %eax, (%ecx)
154         jmp     L(e1)
155 E(L(store_table), X86_RET_UINT8)
156         movzbl  %al, %eax
157         mov     %eax, (%ecx)
158         jmp     L(e1)
159 E(L(store_table), X86_RET_UINT16)
160         movzwl  %ax, %eax
161         mov     %eax, (%ecx)
162         jmp     L(e1)
163 E(L(store_table), X86_RET_INT64)
164         movl    %edx, 4(%ecx)
165         /* fallthru */
166 E(L(store_table), X86_RET_INT32)
167         movl    %eax, (%ecx)
168         /* fallthru */
169 E(L(store_table), X86_RET_VOID)
170 L(e1):
171         movl    8(%ebp), %ebx
172         movl    %ebp, %esp
173         popl    %ebp
174 L(UW3):
175         # cfi_remember_state
176         # cfi_def_cfa(%esp, 4)
177         # cfi_restore(%ebx)
178         # cfi_restore(%ebp)
179         ret
180 L(UW4):
181         # cfi_restore_state
182
183 E(L(store_table), X86_RET_STRUCTPOP)
184         jmp     L(e1)
185 E(L(store_table), X86_RET_STRUCTARG)
186         jmp     L(e1)
187 E(L(store_table), X86_RET_STRUCT_1B)
188         movb    %al, (%ecx)
189         jmp     L(e1)
190 E(L(store_table), X86_RET_STRUCT_2B)
191         movw    %ax, (%ecx)
192         jmp     L(e1)
193
194         /* Fill out the table so that bad values are predictable.  */
195 E(L(store_table), X86_RET_UNUSED14)
196         ud2
197 E(L(store_table), X86_RET_UNUSED15)
198         ud2
199
200 L(UW5):
201         # cfi_endproc
202 ENDF(ffi_call_i386)
203
204 /* The inner helper is declared as
205
206    void ffi_closure_inner(struct closure_frame *frame, char *argp)
207         __attribute_((fastcall))
208
209    Thus the arguments are placed in
210
211         ecx:    frame
212         edx:    argp
213 */
214
215 /* Macros to help setting up the closure_data structure.  */
216
217 #if HAVE_FASTCALL
218 # define closure_FS     (40 + 4)
219 # define closure_CF     0
220 #else
221 # define closure_FS     (8 + 40 + 12)
222 # define closure_CF     8
223 #endif
224
225 #define FFI_CLOSURE_SAVE_REGS           \
226         movl    %eax, closure_CF+16+R_EAX*4(%esp);      \
227         movl    %edx, closure_CF+16+R_EDX*4(%esp);      \
228         movl    %ecx, closure_CF+16+R_ECX*4(%esp)
229
230 #define FFI_CLOSURE_COPY_TRAMP_DATA                                     \
231         movl    FFI_TRAMPOLINE_SIZE(%eax), %edx;        /* copy cif */  \
232         movl    FFI_TRAMPOLINE_SIZE+4(%eax), %ecx;      /* copy fun */  \
233         movl    FFI_TRAMPOLINE_SIZE+8(%eax), %eax;      /* copy user_data */ \
234         movl    %edx, closure_CF+28(%esp);                              \
235         movl    %ecx, closure_CF+32(%esp);                              \
236         movl    %eax, closure_CF+36(%esp)
237
238 #if HAVE_FASTCALL
239 # define FFI_CLOSURE_PREP_CALL                                          \
240         movl    %esp, %ecx;                     /* load closure_data */ \
241         leal    closure_FS+4(%esp), %edx;       /* load incoming stack */
242 #else
243 # define FFI_CLOSURE_PREP_CALL                                          \
244         leal    closure_CF(%esp), %ecx;         /* load closure_data */ \
245         leal    closure_FS+4(%esp), %edx;       /* load incoming stack */ \
246         movl    %ecx, (%esp);                                           \
247         movl    %edx, 4(%esp)
248 #endif
249
250 #define FFI_CLOSURE_CALL_INNER(UWN) \
251         call    ffi_closure_inner
252
253 #define FFI_CLOSURE_MASK_AND_JUMP(N, UW)                                \
254         andl    $X86_RET_TYPE_MASK, %eax;                               \
255         leal    L(C1(load_table,N))(, %eax, 8), %edx;                   \
256         movl    closure_CF(%esp), %eax;         /* optimiztic load */   \
257         jmp     *%edx
258
259 #ifdef __PIC__
260 # if defined X86_DARWIN || defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
261 #  undef FFI_CLOSURE_MASK_AND_JUMP
262 #  define FFI_CLOSURE_MASK_AND_JUMP(N, UW)                              \
263         andl    $X86_RET_TYPE_MASK, %eax;                               \
264         call    C(__x86.get_pc_thunk.dx);                               \
265 L(C1(pc,N)):                                                            \
266         leal    L(C1(load_table,N))-L(C1(pc,N))(%edx, %eax, 8), %edx;   \
267         movl    closure_CF(%esp), %eax;         /* optimiztic load */   \
268         jmp     *%edx
269 # else
270 #  define FFI_CLOSURE_CALL_INNER_SAVE_EBX
271 #  undef FFI_CLOSURE_CALL_INNER
272 #  define FFI_CLOSURE_CALL_INNER(UWN)                                   \
273         movl    %ebx, 40(%esp);                 /* save ebx */          \
274 L(C1(UW,UWN)):                                                          \
275         # cfi_rel_offset(%ebx, 40);                                     \
276         call    C(__x86.get_pc_thunk.bx);       /* load got register */ \
277         addl    $C(_GLOBAL_OFFSET_TABLE_), %ebx;                        \
278         call    ffi_closure_inner@PLT
279 #  undef FFI_CLOSURE_MASK_AND_JUMP
280 #  define FFI_CLOSURE_MASK_AND_JUMP(N, UWN)                             \
281         andl    $X86_RET_TYPE_MASK, %eax;                               \
282         leal    L(C1(load_table,N))@GOTOFF(%ebx, %eax, 8), %edx;        \
283         movl    40(%esp), %ebx;                 /* restore ebx */       \
284 L(C1(UW,UWN)):                                                          \
285         # cfi_restore(%ebx);                                            \
286         movl    closure_CF(%esp), %eax;         /* optimiztic load */   \
287         jmp     *%edx
288 # endif /* DARWIN || HIDDEN */
289 #endif /* __PIC__ */
290
291         .balign 16
292         .globl  C(ffi_go_closure_EAX)
293         FFI_HIDDEN(C(ffi_go_closure_EAX))
294 C(ffi_go_closure_EAX):
295 L(UW6):
296         # cfi_startproc
297         subl    $closure_FS, %esp
298 L(UW7):
299         # cfi_def_cfa_offset(closure_FS + 4)
300         FFI_CLOSURE_SAVE_REGS
301         movl    4(%eax), %edx                   /* copy cif */
302         movl    8(%eax), %ecx                   /* copy fun */
303         movl    %edx, closure_CF+28(%esp)
304         movl    %ecx, closure_CF+32(%esp)
305         movl    %eax, closure_CF+36(%esp)       /* closure is user_data */
306         jmp     L(do_closure_i386)
307 L(UW8):
308         # cfi_endproc
309 ENDF(C(ffi_go_closure_EAX))
310
311         .balign 16
312         .globl  C(ffi_go_closure_ECX)
313         FFI_HIDDEN(C(ffi_go_closure_ECX))
314 C(ffi_go_closure_ECX):
315 L(UW9):
316         # cfi_startproc
317         subl    $closure_FS, %esp
318 L(UW10):
319         # cfi_def_cfa_offset(closure_FS + 4)
320         FFI_CLOSURE_SAVE_REGS
321         movl    4(%ecx), %edx                   /* copy cif */
322         movl    8(%ecx), %eax                   /* copy fun */
323         movl    %edx, closure_CF+28(%esp)
324         movl    %eax, closure_CF+32(%esp)
325         movl    %ecx, closure_CF+36(%esp)       /* closure is user_data */
326         jmp     L(do_closure_i386)
327 L(UW11):
328         # cfi_endproc
329 ENDF(C(ffi_go_closure_ECX))
330
331 /* The closure entry points are reached from the ffi_closure trampoline.
332    On entry, %eax contains the address of the ffi_closure.  */
333
334         .balign 16
335         .globl  C(ffi_closure_i386)
336         FFI_HIDDEN(C(ffi_closure_i386))
337
338 C(ffi_closure_i386):
339 L(UW12):
340         # cfi_startproc
341         subl    $closure_FS, %esp
342 L(UW13):
343         # cfi_def_cfa_offset(closure_FS + 4)
344
345         FFI_CLOSURE_SAVE_REGS
346         FFI_CLOSURE_COPY_TRAMP_DATA
347
348         /* Entry point from preceeding Go closures.  */
349 L(do_closure_i386):
350
351         FFI_CLOSURE_PREP_CALL
352         FFI_CLOSURE_CALL_INNER(14)
353         FFI_CLOSURE_MASK_AND_JUMP(2, 15)
354
355         .balign 8
356 L(load_table2):
357 E(L(load_table2), X86_RET_FLOAT)
358         flds    closure_CF(%esp)
359         jmp     L(e2)
360 E(L(load_table2), X86_RET_DOUBLE)
361         fldl    closure_CF(%esp)
362         jmp     L(e2)
363 E(L(load_table2), X86_RET_LDOUBLE)
364         fldt    closure_CF(%esp)
365         jmp     L(e2)
366 E(L(load_table2), X86_RET_SINT8)
367         movsbl  %al, %eax
368         jmp     L(e2)
369 E(L(load_table2), X86_RET_SINT16)
370         movswl  %ax, %eax
371         jmp     L(e2)
372 E(L(load_table2), X86_RET_UINT8)
373         movzbl  %al, %eax
374         jmp     L(e2)
375 E(L(load_table2), X86_RET_UINT16)
376         movzwl  %ax, %eax
377         jmp     L(e2)
378 E(L(load_table2), X86_RET_INT64)
379         movl    closure_CF+4(%esp), %edx
380         jmp     L(e2)
381 E(L(load_table2), X86_RET_INT32)
382         nop
383         /* fallthru */
384 E(L(load_table2), X86_RET_VOID)
385 L(e2):
386         addl    $closure_FS, %esp
387 L(UW16):
388         # cfi_adjust_cfa_offset(-closure_FS)
389         ret
390 L(UW17):
391         # cfi_adjust_cfa_offset(closure_FS)
392 E(L(load_table2), X86_RET_STRUCTPOP)
393         addl    $closure_FS, %esp
394 L(UW18):
395         # cfi_adjust_cfa_offset(-closure_FS)
396         ret     $4
397 L(UW19):
398         # cfi_adjust_cfa_offset(closure_FS)
399 E(L(load_table2), X86_RET_STRUCTARG)
400         jmp     L(e2)
401 E(L(load_table2), X86_RET_STRUCT_1B)
402         movzbl  %al, %eax
403         jmp     L(e2)
404 E(L(load_table2), X86_RET_STRUCT_2B)
405         movzwl  %ax, %eax
406         jmp     L(e2)
407
408         /* Fill out the table so that bad values are predictable.  */
409 E(L(load_table2), X86_RET_UNUSED14)
410         ud2
411 E(L(load_table2), X86_RET_UNUSED15)
412         ud2
413
414 L(UW20):
415         # cfi_endproc
416 ENDF(C(ffi_closure_i386))
417
418         .balign 16
419         .globl  C(ffi_go_closure_STDCALL)
420         FFI_HIDDEN(C(ffi_go_closure_STDCALL))
421 C(ffi_go_closure_STDCALL):
422 L(UW21):
423         # cfi_startproc
424         subl    $closure_FS, %esp
425 L(UW22):
426         # cfi_def_cfa_offset(closure_FS + 4)
427         FFI_CLOSURE_SAVE_REGS
428         movl    4(%ecx), %edx                   /* copy cif */
429         movl    8(%ecx), %eax                   /* copy fun */
430         movl    %edx, closure_CF+28(%esp)
431         movl    %eax, closure_CF+32(%esp)
432         movl    %ecx, closure_CF+36(%esp)       /* closure is user_data */
433         jmp     L(do_closure_STDCALL)
434 L(UW23):
435         # cfi_endproc
436 ENDF(C(ffi_go_closure_STDCALL))
437
438 /* For REGISTER, we have no available parameter registers, and so we
439    enter here having pushed the closure onto the stack.  */
440
441         .balign 16
442         .globl  C(ffi_closure_REGISTER)
443         FFI_HIDDEN(C(ffi_closure_REGISTER))
444 C(ffi_closure_REGISTER):
445 L(UW24):
446         # cfi_startproc
447         # cfi_def_cfa(%esp, 8)
448         # cfi_offset(%eip, -8)
449         subl    $closure_FS-4, %esp
450 L(UW25):
451         # cfi_def_cfa_offset(closure_FS + 4)
452         FFI_CLOSURE_SAVE_REGS
453         movl    closure_FS-4(%esp), %ecx        /* load retaddr */
454         movl    closure_FS(%esp), %eax          /* load closure */
455         movl    %ecx, closure_FS(%esp)          /* move retaddr */
456         jmp     L(do_closure_REGISTER)
457 L(UW26):
458         # cfi_endproc
459 ENDF(C(ffi_closure_REGISTER))
460
461 /* For STDCALL (and others), we need to pop N bytes of arguments off
462    the stack following the closure.  The amount needing to be popped
463    is returned to us from ffi_closure_inner.  */
464
465         .balign 16
466         .globl  C(ffi_closure_STDCALL)
467         FFI_HIDDEN(C(ffi_closure_STDCALL))
468 C(ffi_closure_STDCALL):
469 L(UW27):
470         # cfi_startproc
471         subl    $closure_FS, %esp
472 L(UW28):
473         # cfi_def_cfa_offset(closure_FS + 4)
474
475         FFI_CLOSURE_SAVE_REGS
476
477         /* Entry point from ffi_closure_REGISTER.  */
478 L(do_closure_REGISTER):
479
480         FFI_CLOSURE_COPY_TRAMP_DATA
481
482         /* Entry point from preceeding Go closure.  */
483 L(do_closure_STDCALL):
484
485         FFI_CLOSURE_PREP_CALL
486         FFI_CLOSURE_CALL_INNER(29)
487
488         movl    %eax, %ecx
489         shrl    $X86_RET_POP_SHIFT, %ecx        /* isolate pop count */
490         leal    closure_FS(%esp, %ecx), %ecx    /* compute popped esp */
491         movl    closure_FS(%esp), %edx          /* move return address */
492         movl    %edx, (%ecx)
493
494         /* From this point on, the value of %esp upon return is %ecx+4,
495            and we've copied the return address to %ecx to make return easy.
496            There's no point in representing this in the unwind info, as
497            there is always a window between the mov and the ret which
498            will be wrong from one point of view or another.  */
499
500         FFI_CLOSURE_MASK_AND_JUMP(3, 30)
501
502         .balign 8
503 L(load_table3):
504 E(L(load_table3), X86_RET_FLOAT)
505         flds    closure_CF(%esp)
506         movl    %ecx, %esp
507         ret
508 E(L(load_table3), X86_RET_DOUBLE)
509         fldl    closure_CF(%esp)
510         movl    %ecx, %esp
511         ret
512 E(L(load_table3), X86_RET_LDOUBLE)
513         fldt    closure_CF(%esp)
514         movl    %ecx, %esp
515         ret
516 E(L(load_table3), X86_RET_SINT8)
517         movsbl  %al, %eax
518         movl    %ecx, %esp
519         ret
520 E(L(load_table3), X86_RET_SINT16)
521         movswl  %ax, %eax
522         movl    %ecx, %esp
523         ret
524 E(L(load_table3), X86_RET_UINT8)
525         movzbl  %al, %eax
526         movl    %ecx, %esp
527         ret
528 E(L(load_table3), X86_RET_UINT16)
529         movzwl  %ax, %eax
530         movl    %ecx, %esp
531         ret
532 E(L(load_table3), X86_RET_INT64)
533         movl    closure_CF+4(%esp), %edx
534         movl    %ecx, %esp
535         ret
536 E(L(load_table3), X86_RET_INT32)
537         movl    %ecx, %esp
538         ret
539 E(L(load_table3), X86_RET_VOID)
540         movl    %ecx, %esp
541         ret
542 E(L(load_table3), X86_RET_STRUCTPOP)
543         movl    %ecx, %esp
544         ret
545 E(L(load_table3), X86_RET_STRUCTARG)
546         movl    %ecx, %esp
547         ret
548 E(L(load_table3), X86_RET_STRUCT_1B)
549         movzbl  %al, %eax
550         movl    %ecx, %esp
551         ret
552 E(L(load_table3), X86_RET_STRUCT_2B)
553         movzwl  %ax, %eax
554         movl    %ecx, %esp
555         ret
556
557         /* Fill out the table so that bad values are predictable.  */
558 E(L(load_table3), X86_RET_UNUSED14)
559         ud2
560 E(L(load_table3), X86_RET_UNUSED15)
561         ud2
562
563 L(UW31):
564         # cfi_endproc
565 ENDF(C(ffi_closure_STDCALL))
566
567 #if !FFI_NO_RAW_API
568
569 #define raw_closure_S_FS        (16+16+12)
570
571         .balign 16
572         .globl  C(ffi_closure_raw_SYSV)
573         FFI_HIDDEN(C(ffi_closure_raw_SYSV))
574 C(ffi_closure_raw_SYSV):
575 L(UW32):
576         # cfi_startproc
577         subl    $raw_closure_S_FS, %esp
578 L(UW33):
579         # cfi_def_cfa_offset(raw_closure_S_FS + 4)
580         movl    %ebx, raw_closure_S_FS-4(%esp)
581 L(UW34):
582         # cfi_rel_offset(%ebx, raw_closure_S_FS-4)
583
584         movl    FFI_TRAMPOLINE_SIZE+8(%eax), %edx       /* load cl->user_data */
585         movl    %edx, 12(%esp)
586         leal    raw_closure_S_FS+4(%esp), %edx          /* load raw_args */
587         movl    %edx, 8(%esp)
588         leal    16(%esp), %edx                          /* load &res */
589         movl    %edx, 4(%esp)
590         movl    FFI_TRAMPOLINE_SIZE(%eax), %ebx         /* load cl->cif */
591         movl    %ebx, (%esp)
592         call    *FFI_TRAMPOLINE_SIZE+4(%eax)            /* call cl->fun */
593
594         movl    20(%ebx), %eax                          /* load cif->flags */
595         andl    $X86_RET_TYPE_MASK, %eax
596 #ifdef __PIC__
597         call    C(__x86.get_pc_thunk.bx)
598 L(pc4):
599         leal    L(load_table4)-L(pc4)(%ebx, %eax, 8), %ecx
600 #else
601         leal    L(load_table4)(,%eax, 8), %ecx
602 #endif
603         movl    raw_closure_S_FS-4(%esp), %ebx
604 L(UW35):
605         # cfi_restore(%ebx)
606         movl    16(%esp), %eax                          /* Optimistic load */
607         jmp     *%ecx
608
609         .balign 8
610 L(load_table4):
611 E(L(load_table4), X86_RET_FLOAT)
612         flds    16(%esp)
613         jmp     L(e4)
614 E(L(load_table4), X86_RET_DOUBLE)
615         fldl    16(%esp)
616         jmp     L(e4)
617 E(L(load_table4), X86_RET_LDOUBLE)
618         fldt    16(%esp)
619         jmp     L(e4)
620 E(L(load_table4), X86_RET_SINT8)
621         movsbl  %al, %eax
622         jmp     L(e4)
623 E(L(load_table4), X86_RET_SINT16)
624         movswl  %ax, %eax
625         jmp     L(e4)
626 E(L(load_table4), X86_RET_UINT8)
627         movzbl  %al, %eax
628         jmp     L(e4)
629 E(L(load_table4), X86_RET_UINT16)
630         movzwl  %ax, %eax
631         jmp     L(e4)
632 E(L(load_table4), X86_RET_INT64)
633         movl    16+4(%esp), %edx
634         jmp     L(e4)
635 E(L(load_table4), X86_RET_INT32)
636         nop
637         /* fallthru */
638 E(L(load_table4), X86_RET_VOID)
639 L(e4):
640         addl    $raw_closure_S_FS, %esp
641 L(UW36):
642         # cfi_adjust_cfa_offset(-raw_closure_S_FS)
643         ret
644 L(UW37):
645         # cfi_adjust_cfa_offset(raw_closure_S_FS)
646 E(L(load_table4), X86_RET_STRUCTPOP)
647         addl    $raw_closure_S_FS, %esp
648 L(UW38):
649         # cfi_adjust_cfa_offset(-raw_closure_S_FS)
650         ret     $4
651 L(UW39):
652         # cfi_adjust_cfa_offset(raw_closure_S_FS)
653 E(L(load_table4), X86_RET_STRUCTARG)
654         jmp     L(e4)
655 E(L(load_table4), X86_RET_STRUCT_1B)
656         movzbl  %al, %eax
657         jmp     L(e4)
658 E(L(load_table4), X86_RET_STRUCT_2B)
659         movzwl  %ax, %eax
660         jmp     L(e4)
661
662         /* Fill out the table so that bad values are predictable.  */
663 E(L(load_table4), X86_RET_UNUSED14)
664         ud2
665 E(L(load_table4), X86_RET_UNUSED15)
666         ud2
667
668 L(UW40):
669         # cfi_endproc
670 ENDF(C(ffi_closure_raw_SYSV))
671
672 #define raw_closure_T_FS        (16+16+8)
673
674         .balign 16
675         .globl  C(ffi_closure_raw_THISCALL)
676         FFI_HIDDEN(C(ffi_closure_raw_THISCALL))
677 C(ffi_closure_raw_THISCALL):
678 L(UW41):
679         # cfi_startproc
680         /* Rearrange the stack such that %ecx is the first argument.
681            This means moving the return address.  */
682         popl    %edx
683 L(UW42):
684         # cfi_def_cfa_offset(0)
685         # cfi_register(%eip, %edx)
686         pushl   %ecx
687 L(UW43):
688         # cfi_adjust_cfa_offset(4)
689         pushl   %edx
690 L(UW44):
691         # cfi_adjust_cfa_offset(4)
692         # cfi_rel_offset(%eip, 0)
693         subl    $raw_closure_T_FS, %esp
694 L(UW45):
695         # cfi_adjust_cfa_offset(raw_closure_T_FS)
696         movl    %ebx, raw_closure_T_FS-4(%esp)
697 L(UW46):
698         # cfi_rel_offset(%ebx, raw_closure_T_FS-4)
699
700         movl    FFI_TRAMPOLINE_SIZE+8(%eax), %edx       /* load cl->user_data */
701         movl    %edx, 12(%esp)
702         leal    raw_closure_T_FS+4(%esp), %edx          /* load raw_args */
703         movl    %edx, 8(%esp)
704         leal    16(%esp), %edx                          /* load &res */
705         movl    %edx, 4(%esp)
706         movl    FFI_TRAMPOLINE_SIZE(%eax), %ebx         /* load cl->cif */
707         movl    %ebx, (%esp)
708         call    *FFI_TRAMPOLINE_SIZE+4(%eax)            /* call cl->fun */
709
710         movl    20(%ebx), %eax                          /* load cif->flags */
711         andl    $X86_RET_TYPE_MASK, %eax
712 #ifdef __PIC__
713         call    C(__x86.get_pc_thunk.bx)
714 L(pc5):
715         leal    L(load_table5)-L(pc5)(%ebx, %eax, 8), %ecx
716 #else
717         leal    L(load_table5)(,%eax, 8), %ecx
718 #endif
719         movl    raw_closure_T_FS-4(%esp), %ebx
720 L(UW47):
721         # cfi_restore(%ebx)
722         movl    16(%esp), %eax                          /* Optimistic load */
723         jmp     *%ecx
724
725         .balign 8
726 L(load_table5):
727 E(L(load_table5), X86_RET_FLOAT)
728         flds    16(%esp)
729         jmp     L(e5)
730 E(L(load_table5), X86_RET_DOUBLE)
731         fldl    16(%esp)
732         jmp     L(e5)
733 E(L(load_table5), X86_RET_LDOUBLE)
734         fldt    16(%esp)
735         jmp     L(e5)
736 E(L(load_table5), X86_RET_SINT8)
737         movsbl  %al, %eax
738         jmp     L(e5)
739 E(L(load_table5), X86_RET_SINT16)
740         movswl  %ax, %eax
741         jmp     L(e5)
742 E(L(load_table5), X86_RET_UINT8)
743         movzbl  %al, %eax
744         jmp     L(e5)
745 E(L(load_table5), X86_RET_UINT16)
746         movzwl  %ax, %eax
747         jmp     L(e5)
748 E(L(load_table5), X86_RET_INT64)
749         movl    16+4(%esp), %edx
750         jmp     L(e5)
751 E(L(load_table5), X86_RET_INT32)
752         nop
753         /* fallthru */
754 E(L(load_table5), X86_RET_VOID)
755 L(e5):
756         addl    $raw_closure_T_FS, %esp
757 L(UW48):
758         # cfi_adjust_cfa_offset(-raw_closure_T_FS)
759         /* Remove the extra %ecx argument we pushed.  */
760         ret     $4
761 L(UW49):
762         # cfi_adjust_cfa_offset(raw_closure_T_FS)
763 E(L(load_table5), X86_RET_STRUCTPOP)
764         addl    $raw_closure_T_FS, %esp
765 L(UW50):
766         # cfi_adjust_cfa_offset(-raw_closure_T_FS)
767         ret     $8
768 L(UW51):
769         # cfi_adjust_cfa_offset(raw_closure_T_FS)
770 E(L(load_table5), X86_RET_STRUCTARG)
771         jmp     L(e5)
772 E(L(load_table5), X86_RET_STRUCT_1B)
773         movzbl  %al, %eax
774         jmp     L(e5)
775 E(L(load_table5), X86_RET_STRUCT_2B)
776         movzwl  %ax, %eax
777         jmp     L(e5)
778
779         /* Fill out the table so that bad values are predictable.  */
780 E(L(load_table5), X86_RET_UNUSED14)
781         ud2
782 E(L(load_table5), X86_RET_UNUSED15)
783         ud2
784
785 L(UW52):
786         # cfi_endproc
787 ENDF(C(ffi_closure_raw_THISCALL))
788
789 #endif /* !FFI_NO_RAW_API */
790
791 #ifdef X86_DARWIN
792 # define COMDAT(X)                                                      \
793         .section __TEXT,__textcoal_nt,coalesced,pure_instructions;      \
794         .weak_definition X;                                             \
795         .private_extern X
796 #elif defined __ELF__ && !(defined(__sun__) && defined(__svr4__))
797 # define COMDAT(X)                                                      \
798         .section .text.X,"axG",@progbits,X,comdat;                      \
799         .globl  X;                                                      \
800         FFI_HIDDEN(X)
801 #else
802 # define COMDAT(X)
803 #endif
804
805 #if defined(__PIC__)
806         COMDAT(C(__x86.get_pc_thunk.bx))
807 C(__x86.get_pc_thunk.bx):
808         movl    (%esp), %ebx
809         ret
810 ENDF(C(__x86.get_pc_thunk.bx))
811 # if defined X86_DARWIN || defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
812         COMDAT(C(__x86.get_pc_thunk.dx))
813 C(__x86.get_pc_thunk.dx):
814         movl    (%esp), %edx
815         ret
816 ENDF(C(__x86.get_pc_thunk.dx))
817 #endif /* DARWIN || HIDDEN */
818 #endif /* __PIC__ */
819
820 /* Sadly, OSX cctools-as doesn't understand .cfi directives at all.  */
821
822 #ifdef __APPLE__
823 .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
824 EHFrame0:
825 #elif defined(X86_WIN32)
826 .section .eh_frame,"r"
827 #elif defined(HAVE_AS_X86_64_UNWIND_SECTION_TYPE)
828 .section .eh_frame,EH_FRAME_FLAGS,@unwind
829 #else
830 .section .eh_frame,EH_FRAME_FLAGS,@progbits
831 #endif
832
833 #ifdef HAVE_AS_X86_PCREL
834 # define PCREL(X)       X - .
835 #else
836 # define PCREL(X)       X@rel
837 #endif
838
839 /* Simplify advancing between labels.  Assume DW_CFA_advance_loc1 fits.  */
840 #define ADV(N, P)       .byte 2, L(N)-L(P)
841
842         .balign 4
843 L(CIE):
844         .set    L(set0),L(ECIE)-L(SCIE)
845         .long   L(set0)                 /* CIE Length */
846 L(SCIE):
847         .long   0                       /* CIE Identifier Tag */
848         .byte   1                       /* CIE Version */
849         .ascii  "zR\0"                  /* CIE Augmentation */
850         .byte   1                       /* CIE Code Alignment Factor */
851         .byte   0x7c                    /* CIE Data Alignment Factor */
852         .byte   0x8                     /* CIE RA Column */
853         .byte   1                       /* Augmentation size */
854         .byte   0x1b                    /* FDE Encoding (pcrel sdata4) */
855         .byte   0xc, 4, 4               /* DW_CFA_def_cfa, %esp offset 4 */
856         .byte   0x80+8, 1               /* DW_CFA_offset, %eip offset 1*-4 */
857         .balign 4
858 L(ECIE):
859
860         .set    L(set1),L(EFDE1)-L(SFDE1)
861         .long   L(set1)                 /* FDE Length */
862 L(SFDE1):
863         .long   L(SFDE1)-L(CIE)         /* FDE CIE offset */
864         .long   PCREL(L(UW0))           /* Initial location */
865         .long   L(UW5)-L(UW0)           /* Address range */
866         .byte   0                       /* Augmentation size */
867         ADV(UW1, UW0)
868         .byte   0xc, 5, 8               /* DW_CFA_def_cfa, %ebp 8 */
869         .byte   0x80+5, 2               /* DW_CFA_offset, %ebp 2*-4 */
870         ADV(UW2, UW1)
871         .byte   0x80+3, 0               /* DW_CFA_offset, %ebx 0*-4 */
872         ADV(UW3, UW2)
873         .byte   0xa                     /* DW_CFA_remember_state */
874         .byte   0xc, 4, 4               /* DW_CFA_def_cfa, %esp 4 */
875         .byte   0xc0+3                  /* DW_CFA_restore, %ebx */
876         .byte   0xc0+5                  /* DW_CFA_restore, %ebp */
877         ADV(UW4, UW3)
878         .byte   0xb                     /* DW_CFA_restore_state */
879         .balign 4
880 L(EFDE1):
881
882         .set    L(set2),L(EFDE2)-L(SFDE2)
883         .long   L(set2)                 /* FDE Length */
884 L(SFDE2):
885         .long   L(SFDE2)-L(CIE)         /* FDE CIE offset */
886         .long   PCREL(L(UW6))           /* Initial location */
887         .long   L(UW8)-L(UW6)           /* Address range */
888         .byte   0                       /* Augmentation size */
889         ADV(UW7, UW6)
890         .byte   0xe, closure_FS+4       /* DW_CFA_def_cfa_offset */
891         .balign 4
892 L(EFDE2):
893
894         .set    L(set3),L(EFDE3)-L(SFDE3)
895         .long   L(set3)                 /* FDE Length */
896 L(SFDE3):
897         .long   L(SFDE3)-L(CIE)         /* FDE CIE offset */
898         .long   PCREL(L(UW9))           /* Initial location */
899         .long   L(UW11)-L(UW9)          /* Address range */
900         .byte   0                       /* Augmentation size */
901         ADV(UW10, UW9)
902         .byte   0xe, closure_FS+4       /* DW_CFA_def_cfa_offset */
903         .balign 4
904 L(EFDE3):
905
906         .set    L(set4),L(EFDE4)-L(SFDE4)
907         .long   L(set4)                 /* FDE Length */
908 L(SFDE4):
909         .long   L(SFDE4)-L(CIE)         /* FDE CIE offset */
910         .long   PCREL(L(UW12))          /* Initial location */
911         .long   L(UW20)-L(UW12)         /* Address range */
912         .byte   0                       /* Augmentation size */
913         ADV(UW13, UW12)
914         .byte   0xe, closure_FS+4       /* DW_CFA_def_cfa_offset */
915 #ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX
916         ADV(UW14, UW13)
917         .byte   0x80+3, (40-(closure_FS+4))/-4  /* DW_CFA_offset %ebx */
918         ADV(UW15, UW14)
919         .byte   0xc0+3                  /* DW_CFA_restore %ebx */
920         ADV(UW16, UW15)
921 #else
922         ADV(UW16, UW13)
923 #endif
924         .byte   0xe, 4                  /* DW_CFA_def_cfa_offset */
925         ADV(UW17, UW16)
926         .byte   0xe, closure_FS+4       /* DW_CFA_def_cfa_offset */
927         ADV(UW18, UW17)
928         .byte   0xe, 4                  /* DW_CFA_def_cfa_offset */
929         ADV(UW19, UW18)
930         .byte   0xe, closure_FS+4       /* DW_CFA_def_cfa_offset */
931         .balign 4
932 L(EFDE4):
933
934         .set    L(set5),L(EFDE5)-L(SFDE5)
935         .long   L(set5)                 /* FDE Length */
936 L(SFDE5):
937         .long   L(SFDE5)-L(CIE)         /* FDE CIE offset */
938         .long   PCREL(L(UW21))          /* Initial location */
939         .long   L(UW23)-L(UW21)         /* Address range */
940         .byte   0                       /* Augmentation size */
941         ADV(UW22, UW21)
942         .byte   0xe, closure_FS+4       /* DW_CFA_def_cfa_offset */
943         .balign 4
944 L(EFDE5):
945
946         .set    L(set6),L(EFDE6)-L(SFDE6)
947         .long   L(set6)                 /* FDE Length */
948 L(SFDE6):
949         .long   L(SFDE6)-L(CIE)         /* FDE CIE offset */
950         .long   PCREL(L(UW24))          /* Initial location */
951         .long   L(UW26)-L(UW24)         /* Address range */
952         .byte   0                       /* Augmentation size */
953         .byte   0xe, 8                  /* DW_CFA_def_cfa_offset */
954         .byte   0x80+8, 2               /* DW_CFA_offset %eip, 2*-4 */
955         ADV(UW25, UW24)
956         .byte   0xe, closure_FS+4       /* DW_CFA_def_cfa_offset */
957         .balign 4
958 L(EFDE6):
959
960         .set    L(set7),L(EFDE7)-L(SFDE7)
961         .long   L(set7)                 /* FDE Length */
962 L(SFDE7):
963         .long   L(SFDE7)-L(CIE)         /* FDE CIE offset */
964         .long   PCREL(L(UW27))          /* Initial location */
965         .long   L(UW31)-L(UW27)         /* Address range */
966         .byte   0                       /* Augmentation size */
967         ADV(UW28, UW27)
968         .byte   0xe, closure_FS+4       /* DW_CFA_def_cfa_offset */
969 #ifdef FFI_CLOSURE_CALL_INNER_SAVE_EBX
970         ADV(UW29, UW28)
971         .byte   0x80+3, (40-(closure_FS+4))/-4  /* DW_CFA_offset %ebx */
972         ADV(UW30, UW29)
973         .byte   0xc0+3                  /* DW_CFA_restore %ebx */
974 #endif
975         .balign 4
976 L(EFDE7):
977
978 #if !FFI_NO_RAW_API
979         .set    L(set8),L(EFDE8)-L(SFDE8)
980         .long   L(set8)                 /* FDE Length */
981 L(SFDE8):
982         .long   L(SFDE8)-L(CIE)         /* FDE CIE offset */
983         .long   PCREL(L(UW32))          /* Initial location */
984         .long   L(UW40)-L(UW32)         /* Address range */
985         .byte   0                       /* Augmentation size */
986         ADV(UW33, UW32)
987         .byte   0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */
988         ADV(UW34, UW33)
989         .byte   0x80+3, 2               /* DW_CFA_offset %ebx 2*-4 */
990         ADV(UW35, UW34)
991         .byte   0xc0+3                  /* DW_CFA_restore %ebx */
992         ADV(UW36, UW35)
993         .byte   0xe, 4                  /* DW_CFA_def_cfa_offset */
994         ADV(UW37, UW36)
995         .byte   0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */
996         ADV(UW38, UW37)
997         .byte   0xe, 4                  /* DW_CFA_def_cfa_offset */
998         ADV(UW39, UW38)
999         .byte   0xe, raw_closure_S_FS+4 /* DW_CFA_def_cfa_offset */
1000         .balign 4
1001 L(EFDE8):
1002
1003         .set    L(set9),L(EFDE9)-L(SFDE9)
1004         .long   L(set9)                 /* FDE Length */
1005 L(SFDE9):
1006         .long   L(SFDE9)-L(CIE)         /* FDE CIE offset */
1007         .long   PCREL(L(UW41))          /* Initial location */
1008         .long   L(UW52)-L(UW41)         /* Address range */
1009         .byte   0                       /* Augmentation size */
1010         ADV(UW42, UW41)
1011         .byte   0xe, 0                  /* DW_CFA_def_cfa_offset */
1012         .byte   0x9, 8, 2               /* DW_CFA_register %eip, %edx */
1013         ADV(UW43, UW42)
1014         .byte   0xe, 4                  /* DW_CFA_def_cfa_offset */
1015         ADV(UW44, UW43)
1016         .byte   0xe, 8                  /* DW_CFA_def_cfa_offset */
1017         .byte   0x80+8, 2               /* DW_CFA_offset %eip 2*-4 */
1018         ADV(UW45, UW44)
1019         .byte   0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */
1020         ADV(UW46, UW45)
1021         .byte   0x80+3, 3               /* DW_CFA_offset %ebx 3*-4 */
1022         ADV(UW47, UW46)
1023         .byte   0xc0+3                  /* DW_CFA_restore %ebx */
1024         ADV(UW48, UW47)
1025         .byte   0xe, 8                  /* DW_CFA_def_cfa_offset */
1026         ADV(UW49, UW48)
1027         .byte   0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */
1028         ADV(UW50, UW49)
1029         .byte   0xe, 8                  /* DW_CFA_def_cfa_offset */
1030         ADV(UW51, UW50)
1031         .byte   0xe, raw_closure_T_FS+8 /* DW_CFA_def_cfa_offset */
1032         .balign 4
1033 L(EFDE9):
1034 #endif /* !FFI_NO_RAW_API */
1035
1036 #endif /* ifndef __x86_64__ */
1037
1038 #if defined __ELF__ && defined __linux__
1039         .section        .note.GNU-stack,"",@progbits
1040 #endif