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