2009-06-04 Andrew Haley <aph@redhat.com>
[official-gcc.git] / libffi / src / x86 / unix64.S
blob3e31abc60a0e2d513456d4fa6db39b33497394c9
1 /* -----------------------------------------------------------------------
2    unix64.S - Copyright (c) 2002, 2008  Bo Thorsen <bo@suse.de>
4    x86-64 Foreign Function Interface 
6    Permission is hereby granted, free of charge, to any person obtaining
7    a copy of this software and associated documentation files (the
8    ``Software''), to deal in the Software without restriction, including
9    without limitation the rights to use, copy, modify, merge, publish,
10    distribute, sublicense, and/or sell copies of the Software, and to
11    permit persons to whom the Software is furnished to do so, subject to
12    the following conditions:
14    The above copyright notice and this permission notice shall be included
15    in all copies or substantial portions of the Software.
17    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24    DEALINGS IN THE SOFTWARE.
25    ----------------------------------------------------------------------- */
27 #ifdef __x86_64__
28 #define LIBFFI_ASM      
29 #include <fficonfig.h>
30 #include <ffi.h>
32 .text
34 /* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
35                     void *raddr, void (*fnaddr)());
37    Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
38    for this function.  This has been allocated by ffi_call.  We also
39    deallocate some of the stack that has been alloca'd.  */
41         .align  2
42         .globl  ffi_call_unix64
43         .type   ffi_call_unix64,@function
45 ffi_call_unix64:
46 .LUW0:
47         movq    (%rsp), %r10            /* Load return address.  */
48         leaq    (%rdi, %rsi), %rax      /* Find local stack base.  */
49         movq    %rdx, (%rax)            /* Save flags.  */
50         movq    %rcx, 8(%rax)           /* Save raddr.  */
51         movq    %rbp, 16(%rax)          /* Save old frame pointer.  */
52         movq    %r10, 24(%rax)          /* Relocate return address.  */
53         movq    %rax, %rbp              /* Finalize local stack frame.  */
54 .LUW1:
55         movq    %rdi, %r10              /* Save a copy of the register area. */
56         movq    %r8, %r11               /* Save a copy of the target fn.  */
57         movl    %r9d, %eax              /* Set number of SSE registers.  */
59         /* Load up all argument registers.  */
60         movq    (%r10), %rdi
61         movq    8(%r10), %rsi
62         movq    16(%r10), %rdx
63         movq    24(%r10), %rcx
64         movq    32(%r10), %r8
65         movq    40(%r10), %r9
66         testl   %eax, %eax
67         jnz     .Lload_sse
68 .Lret_from_load_sse:
70         /* Deallocate the reg arg area.  */
71         leaq    176(%r10), %rsp
73         /* Call the user function.  */
74         call    *%r11
76         /* Deallocate stack arg area; local stack frame in redzone.  */
77         leaq    24(%rbp), %rsp
79         movq    0(%rbp), %rcx           /* Reload flags.  */
80         movq    8(%rbp), %rdi           /* Reload raddr.  */
81         movq    16(%rbp), %rbp          /* Reload old frame pointer.  */
82 .LUW2:
84         /* The first byte of the flags contains the FFI_TYPE.  */
85         movzbl  %cl, %r10d
86         leaq    .Lstore_table(%rip), %r11
87         movslq  (%r11, %r10, 4), %r10
88         addq    %r11, %r10
89         jmp     *%r10
91 .Lstore_table:
92         .long   .Lst_void-.Lstore_table         /* FFI_TYPE_VOID */
93         .long   .Lst_sint32-.Lstore_table       /* FFI_TYPE_INT */
94         .long   .Lst_float-.Lstore_table        /* FFI_TYPE_FLOAT */
95         .long   .Lst_double-.Lstore_table       /* FFI_TYPE_DOUBLE */
96         .long   .Lst_ldouble-.Lstore_table      /* FFI_TYPE_LONGDOUBLE */
97         .long   .Lst_uint8-.Lstore_table        /* FFI_TYPE_UINT8 */
98         .long   .Lst_sint8-.Lstore_table        /* FFI_TYPE_SINT8 */
99         .long   .Lst_uint16-.Lstore_table       /* FFI_TYPE_UINT16 */
100         .long   .Lst_sint16-.Lstore_table       /* FFI_TYPE_SINT16 */
101         .long   .Lst_uint32-.Lstore_table       /* FFI_TYPE_UINT32 */
102         .long   .Lst_sint32-.Lstore_table       /* FFI_TYPE_SINT32 */
103         .long   .Lst_int64-.Lstore_table        /* FFI_TYPE_UINT64 */
104         .long   .Lst_int64-.Lstore_table        /* FFI_TYPE_SINT64 */
105         .long   .Lst_struct-.Lstore_table       /* FFI_TYPE_STRUCT */
106         .long   .Lst_int64-.Lstore_table        /* FFI_TYPE_POINTER */
108         .align 2
109 .Lst_void:
110         ret
111         .align 2
113 .Lst_uint8:
114         movzbq  %al, %rax
115         movq    %rax, (%rdi)
116         ret
117         .align 2
118 .Lst_sint8:
119         movsbq  %al, %rax
120         movq    %rax, (%rdi)
121         ret
122         .align 2
123 .Lst_uint16:
124         movzwq  %ax, %rax
125         movq    %rax, (%rdi)
126         .align 2
127 .Lst_sint16:
128         movswq  %ax, %rax
129         movq    %rax, (%rdi)
130         ret
131         .align 2
132 .Lst_uint32:
133         movl    %eax, %eax
134         movq    %rax, (%rdi)
135         .align 2
136 .Lst_sint32:
137         cltq
138         movq    %rax, (%rdi)
139         ret
140         .align 2
141 .Lst_int64:
142         movq    %rax, (%rdi)
143         ret
145         .align 2
146 .Lst_float:
147         movss   %xmm0, (%rdi)
148         ret
149         .align 2
150 .Lst_double:
151         movsd   %xmm0, (%rdi)
152         ret
153 .Lst_ldouble:
154         fstpt   (%rdi)
155         ret
157         .align 2
158 .Lst_struct:
159         leaq    -20(%rsp), %rsi         /* Scratch area in redzone.  */
161         /* We have to locate the values now, and since we don't want to
162            write too much data into the user's return value, we spill the
163            value to a 16 byte scratch area first.  Bits 8, 9, and 10
164            control where the values are located.  Only one of the three
165            bits will be set; see ffi_prep_cif_machdep for the pattern.  */
166         movd    %xmm0, %r10
167         movd    %xmm1, %r11
168         testl   $0x100, %ecx
169         cmovnz  %rax, %rdx
170         cmovnz  %r10, %rax
171         testl   $0x200, %ecx
172         cmovnz  %r10, %rdx
173         testl   $0x400, %ecx
174         cmovnz  %r10, %rax
175         cmovnz  %r11, %rdx
176         movq    %rax, (%rsi)
177         movq    %rdx, 8(%rsi)
179         /* Bits 12-31 contain the true size of the structure.  Copy from
180            the scratch area to the true destination.  */
181         shrl    $12, %ecx
182         rep movsb
183         ret
185         /* Many times we can avoid loading any SSE registers at all.
186            It's not worth an indirect jump to load the exact set of
187            SSE registers needed; zero or all is a good compromise.  */
188         .align 2
189 .LUW3:
190 .Lload_sse:
191         movdqa  48(%r10), %xmm0
192         movdqa  64(%r10), %xmm1
193         movdqa  80(%r10), %xmm2
194         movdqa  96(%r10), %xmm3
195         movdqa  112(%r10), %xmm4
196         movdqa  128(%r10), %xmm5
197         movdqa  144(%r10), %xmm6
198         movdqa  160(%r10), %xmm7
199         jmp     .Lret_from_load_sse
201 .LUW4:
202         .size    ffi_call_unix64,.-ffi_call_unix64
204         .align  2
205         .globl ffi_closure_unix64
206         .type   ffi_closure_unix64,@function
208 ffi_closure_unix64:
209 .LUW5:
210         /* The carry flag is set by the trampoline iff SSE registers
211            are used.  Don't clobber it before the branch instruction.  */
212         leaq    -200(%rsp), %rsp
213 .LUW6:
214         movq    %rdi, (%rsp)
215         movq    %rsi, 8(%rsp)
216         movq    %rdx, 16(%rsp)
217         movq    %rcx, 24(%rsp)
218         movq    %r8, 32(%rsp)
219         movq    %r9, 40(%rsp)
220         jc      .Lsave_sse
221 .Lret_from_save_sse:
223         movq    %r10, %rdi
224         leaq    176(%rsp), %rsi
225         movq    %rsp, %rdx
226         leaq    208(%rsp), %rcx
227         call    ffi_closure_unix64_inner@PLT
229         /* Deallocate stack frame early; return value is now in redzone.  */
230         addq    $200, %rsp
231 .LUW7:
233         /* The first byte of the return value contains the FFI_TYPE.  */
234         movzbl  %al, %r10d
235         leaq    .Lload_table(%rip), %r11
236         movslq  (%r11, %r10, 4), %r10
237         addq    %r11, %r10
238         jmp     *%r10
240 .Lload_table:
241         .long   .Lld_void-.Lload_table          /* FFI_TYPE_VOID */
242         .long   .Lld_int32-.Lload_table         /* FFI_TYPE_INT */
243         .long   .Lld_float-.Lload_table         /* FFI_TYPE_FLOAT */
244         .long   .Lld_double-.Lload_table        /* FFI_TYPE_DOUBLE */
245         .long   .Lld_ldouble-.Lload_table       /* FFI_TYPE_LONGDOUBLE */
246         .long   .Lld_int8-.Lload_table          /* FFI_TYPE_UINT8 */
247         .long   .Lld_int8-.Lload_table          /* FFI_TYPE_SINT8 */
248         .long   .Lld_int16-.Lload_table         /* FFI_TYPE_UINT16 */
249         .long   .Lld_int16-.Lload_table         /* FFI_TYPE_SINT16 */
250         .long   .Lld_int32-.Lload_table         /* FFI_TYPE_UINT32 */
251         .long   .Lld_int32-.Lload_table         /* FFI_TYPE_SINT32 */
252         .long   .Lld_int64-.Lload_table         /* FFI_TYPE_UINT64 */
253         .long   .Lld_int64-.Lload_table         /* FFI_TYPE_SINT64 */
254         .long   .Lld_struct-.Lload_table        /* FFI_TYPE_STRUCT */
255         .long   .Lld_int64-.Lload_table         /* FFI_TYPE_POINTER */
257         .align 2
258 .Lld_void:
259         ret
261         .align 2
262 .Lld_int8:
263         movzbl  -24(%rsp), %eax
264         ret
265         .align 2
266 .Lld_int16:
267         movzwl  -24(%rsp), %eax
268         ret
269         .align 2
270 .Lld_int32:
271         movl    -24(%rsp), %eax
272         ret
273         .align 2
274 .Lld_int64:
275         movq    -24(%rsp), %rax
276         ret
278         .align 2
279 .Lld_float:
280         movss   -24(%rsp), %xmm0
281         ret
282         .align 2
283 .Lld_double:
284         movsd   -24(%rsp), %xmm0
285         ret
286         .align 2
287 .Lld_ldouble:
288         fldt    -24(%rsp)
289         ret
291         .align 2
292 .Lld_struct:
293         /* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
294            %rax/%xmm0, %xmm0/%xmm1.  We collapse two by always loading
295            both rdx and xmm1 with the second word.  For the remaining,
296            bit 8 set means xmm0 gets the second word, and bit 9 means
297            that rax gets the second word.  */
298         movq    -24(%rsp), %rcx
299         movq    -16(%rsp), %rdx
300         movq    -16(%rsp), %xmm1
301         testl   $0x100, %eax
302         cmovnz  %rdx, %rcx
303         movd    %rcx, %xmm0
304         testl   $0x200, %eax
305         movq    -24(%rsp), %rax
306         cmovnz  %rdx, %rax
307         ret
309         /* See the comment above .Lload_sse; the same logic applies here.  */
310         .align 2
311 .LUW8:
312 .Lsave_sse:
313         movdqa  %xmm0, 48(%rsp)
314         movdqa  %xmm1, 64(%rsp)
315         movdqa  %xmm2, 80(%rsp)
316         movdqa  %xmm3, 96(%rsp)
317         movdqa  %xmm4, 112(%rsp)
318         movdqa  %xmm5, 128(%rsp)
319         movdqa  %xmm6, 144(%rsp)
320         movdqa  %xmm7, 160(%rsp)
321         jmp     .Lret_from_save_sse
323 .LUW9:
324         .size   ffi_closure_unix64,.-ffi_closure_unix64
326         .section        .eh_frame,"a",@progbits
327 .Lframe1:
328         .long   .LECIE1-.LSCIE1         /* CIE Length */
329 .LSCIE1:
330         .long   0                       /* CIE Identifier Tag */
331         .byte   1                       /* CIE Version */
332         .ascii "zR\0"                   /* CIE Augmentation */
333         .uleb128 1                      /* CIE Code Alignment Factor */
334         .sleb128 -8                     /* CIE Data Alignment Factor */
335         .byte   0x10                    /* CIE RA Column */
336         .uleb128 1                      /* Augmentation size */
337         .byte   0x1b                    /* FDE Encoding (pcrel sdata4) */
338         .byte   0xc                     /* DW_CFA_def_cfa, %rsp offset 8 */
339         .uleb128 7
340         .uleb128 8
341         .byte   0x80+16                 /* DW_CFA_offset, %rip offset 1*-8 */
342         .uleb128 1
343         .align 8
344 .LECIE1:
345 .LSFDE1:
346         .long   .LEFDE1-.LASFDE1        /* FDE Length */
347 .LASFDE1:
348         .long   .LASFDE1-.Lframe1       /* FDE CIE offset */
349 #if HAVE_AS_X86_PCREL
350         .long   .LUW0-.                 /* FDE initial location */
351 #else
352         .long   .LUW0@rel
353 #endif
354         .long   .LUW4-.LUW0             /* FDE address range */
355         .uleb128 0x0                    /* Augmentation size */
357         .byte   0x4                     /* DW_CFA_advance_loc4 */
358         .long   .LUW1-.LUW0
360         /* New stack frame based off rbp.  This is a itty bit of unwind
361            trickery in that the CFA *has* changed.  There is no easy way
362            to describe it correctly on entry to the function.  Fortunately,
363            it doesn't matter too much since at all points we can correctly
364            unwind back to ffi_call.  Note that the location to which we
365            moved the return address is (the new) CFA-8, so from the
366            perspective of the unwind info, it hasn't moved.  */
367         .byte   0xc                     /* DW_CFA_def_cfa, %rbp offset 32 */
368         .uleb128 6
369         .uleb128 32
370         .byte   0x80+6                  /* DW_CFA_offset, %rbp offset 2*-8 */
371         .uleb128 2
372         .byte   0xa                     /* DW_CFA_remember_state */
374         .byte   0x4                     /* DW_CFA_advance_loc4 */
375         .long   .LUW2-.LUW1
376         .byte   0xc                     /* DW_CFA_def_cfa, %rsp offset 8 */
377         .uleb128 7
378         .uleb128 8
379         .byte   0xc0+6                  /* DW_CFA_restore, %rbp */
381         .byte   0x4                     /* DW_CFA_advance_loc4 */
382         .long   .LUW3-.LUW2
383         .byte   0xb                     /* DW_CFA_restore_state */
385         .align 8
386 .LEFDE1:
387 .LSFDE3:
388         .long   .LEFDE3-.LASFDE3        /* FDE Length */
389 .LASFDE3:
390         .long   .LASFDE3-.Lframe1       /* FDE CIE offset */
391 #if HAVE_AS_X86_PCREL
392         .long   .LUW5-.                 /* FDE initial location */
393 #else
394         .long   .LUW5@rel
395 #endif
396         .long   .LUW9-.LUW5             /* FDE address range */
397         .uleb128 0x0                    /* Augmentation size */
399         .byte   0x4                     /* DW_CFA_advance_loc4 */
400         .long   .LUW6-.LUW5
401         .byte   0xe                     /* DW_CFA_def_cfa_offset */
402         .uleb128 208
403         .byte   0xa                     /* DW_CFA_remember_state */
405         .byte   0x4                     /* DW_CFA_advance_loc4 */
406         .long   .LUW7-.LUW6
407         .byte   0xe                     /* DW_CFA_def_cfa_offset */
408         .uleb128 8
410         .byte   0x4                     /* DW_CFA_advance_loc4 */
411         .long   .LUW8-.LUW7
412         .byte   0xb                     /* DW_CFA_restore_state */
414         .align 8
415 .LEFDE3:
417 #endif /* __x86_64__ */
419 #if defined __ELF__ && defined __linux__
420         .section        .note.GNU-stack,"",@progbits
421 #endif