powerpc: fix bootstrap.
[official-gcc.git] / libffi / src / powerpc / linux64_closure.S
blob5663bb4022361a4d10749e4efb5623c1ca2cf107
1 /* -----------------------------------------------------------------------
2    sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com>
3             Copyright (c) 2008 Red Hat, Inc.
5    PowerPC64 Assembly glue.
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:
15    The above copyright notice and this permission notice shall be included
16    in all copies or substantial portions of the Software.
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 #define LIBFFI_ASM
28 #include <fficonfig.h>
29 #include <ffi.h>
31         .file   "linux64_closure.S"
33 #ifdef POWERPC64
34         FFI_HIDDEN (ffi_closure_LINUX64)
35         .globl  ffi_closure_LINUX64
36         .text
37         .cfi_startproc
38 # if _CALL_ELF == 2
39 ffi_closure_LINUX64:
40 #  ifndef __PCREL__
41         addis   %r2, %r12, .TOC.-ffi_closure_LINUX64@ha
42         addi    %r2, %r2, .TOC.-ffi_closure_LINUX64@l
43 #  endif
44         .localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64
45 # else
46         .section        ".opd","aw"
47         .align  3
48 ffi_closure_LINUX64:
49 #  ifdef _CALL_LINUX
50         .quad   .L.ffi_closure_LINUX64,.TOC.@tocbase,0
51         .type   ffi_closure_LINUX64,@function
52         .text
53 .L.ffi_closure_LINUX64:
54 #  else
55         FFI_HIDDEN (.ffi_closure_LINUX64)
56         .globl  .ffi_closure_LINUX64
57         .quad   .ffi_closure_LINUX64,.TOC.@tocbase,0
58         .size   ffi_closure_LINUX64,24
59         .type   .ffi_closure_LINUX64,@function
60         .text
61 .ffi_closure_LINUX64:
62 #  endif
63 # endif
65 # if _CALL_ELF == 2
66 #  32 byte special reg save area + 64 byte parm save area
67 #  + 64 byte retval area + 13*8 fpr save area + round to 16
68 #  define STACKFRAME 272
69 #  define PARMSAVE 32
70 #  define RETVAL PARMSAVE+64
71 # else
72 #  48 bytes special reg save area + 64 bytes parm save area
73 #  + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
74 #  define STACKFRAME 240
75 #  define PARMSAVE 48
76 #  define RETVAL PARMSAVE+64
77 # endif
79 # if _CALL_ELF == 2
80         ld      %r12, FFI_TRAMPOLINE_SIZE(%r11)         # closure->cif
81         mflr    %r0
82         lwz     %r12, 28(%r12)                          # cif->flags
83         mtcrf   0x40, %r12
84         addi    %r12, %r1, PARMSAVE
85         bt      7, 0f
86         # Our caller has not allocated a parameter save area.
87         # We need to allocate one here and use it to pass gprs to
88         # ffi_closure_helper_LINUX64.
89         addi    %r12, %r1, -STACKFRAME+PARMSAVE
91         # Save general regs into parm save area
92         std     %r3, 0(%r12)
93         std     %r4, 8(%r12)
94         std     %r5, 16(%r12)
95         std     %r6, 24(%r12)
96         std     %r7, 32(%r12)
97         std     %r8, 40(%r12)
98         std     %r9, 48(%r12)
99         std     %r10, 56(%r12)
101         # load up the pointer to the parm save area
102         mr      %r7, %r12
103 # else
104         # copy r2 to r11 and load TOC into r2
105         mr      %r11, %r2
106         ld      %r2, 16(%r2)
108         mflr    %r0
109         # Save general regs into parm save area
110         # This is the parameter save area set up by our caller.
111         std     %r3, PARMSAVE+0(%r1)
112         std     %r4, PARMSAVE+8(%r1)
113         std     %r5, PARMSAVE+16(%r1)
114         std     %r6, PARMSAVE+24(%r1)
115         std     %r7, PARMSAVE+32(%r1)
116         std     %r8, PARMSAVE+40(%r1)
117         std     %r9, PARMSAVE+48(%r1)
118         std     %r10, PARMSAVE+56(%r1)
120         # load up the pointer to the parm save area
121         addi    %r7, %r1, PARMSAVE
122 # endif
123         std     %r0, 16(%r1)
125         # closure->cif
126         ld      %r3, FFI_TRAMPOLINE_SIZE(%r11)
127         # closure->fun
128         ld      %r4, FFI_TRAMPOLINE_SIZE+8(%r11)
129         # closure->user_data
130         ld      %r5, FFI_TRAMPOLINE_SIZE+16(%r11)
132 .Ldoclosure:
133         # next save fpr 1 to fpr 13
134         stfd    %f1, -104+(0*8)(%r1)
135         stfd    %f2, -104+(1*8)(%r1)
136         stfd    %f3, -104+(2*8)(%r1)
137         stfd    %f4, -104+(3*8)(%r1)
138         stfd    %f5, -104+(4*8)(%r1)
139         stfd    %f6, -104+(5*8)(%r1)
140         stfd    %f7, -104+(6*8)(%r1)
141         stfd    %f8, -104+(7*8)(%r1)
142         stfd    %f9, -104+(8*8)(%r1)
143         stfd    %f10, -104+(9*8)(%r1)
144         stfd    %f11, -104+(10*8)(%r1)
145         stfd    %f12, -104+(11*8)(%r1)
146         stfd    %f13, -104+(12*8)(%r1)
148         # load up the pointer to the saved fpr registers
149         addi    %r8, %r1, -104
151         # load up the pointer to the result storage
152         addi    %r6, %r1, -STACKFRAME+RETVAL
154         stdu    %r1, -STACKFRAME(%r1)
155         .cfi_def_cfa_offset STACKFRAME
156         .cfi_offset 65, 16
158         # make the call
159 # if defined _CALL_LINUX || _CALL_ELF == 2
160 #  ifdef __PCREL__
161         bl ffi_closure_helper_LINUX64@notoc
162 .Lret:
163 #  else
164         bl ffi_closure_helper_LINUX64
165 .Lret:
166         nop
167 #  endif
168 # else
169         bl .ffi_closure_helper_LINUX64
170 .Lret:
171         nop
172 # endif
174         # now r3 contains the return type
175         # so use it to look up in a table
176         # so we know how to deal with each type
178         # look up the proper starting point in table
179         # by using return type as offset
180         ld %r0, STACKFRAME+16(%r1)
181         cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT
182         bge .Lsmall
183         mflr %r4                # move address of .Lret to r4
184         sldi %r3, %r3, 4        # now multiply return type by 16
185         addi %r4, %r4, .Lret_type0 - .Lret
186         add %r3, %r3, %r4       # add contents of table to table address
187         mtctr %r3
188         bctr                    # jump to it
190 # Each of the ret_typeX code fragments has to be exactly 16 bytes long
191 # (4 instructions). For cache effectiveness we align to a 16 byte boundary
192 # first.
193         .align 4
195 .Lret_type0:
196 # case FFI_TYPE_VOID
197         mtlr %r0
198         addi %r1, %r1, STACKFRAME
199         .cfi_def_cfa_offset 0
200         blr
201         .cfi_def_cfa_offset STACKFRAME
202         nop
203 # case FFI_TYPE_INT
204 # ifdef __LITTLE_ENDIAN__
205         lwa %r3, RETVAL+0(%r1)
206 # else
207         lwa %r3, RETVAL+4(%r1)
208 # endif
209         mtlr %r0
210         addi %r1, %r1, STACKFRAME
211         .cfi_def_cfa_offset 0
212         blr
213         .cfi_def_cfa_offset STACKFRAME
214 # case FFI_TYPE_FLOAT
215         lfs %f1, RETVAL+0(%r1)
216         mtlr %r0
217         addi %r1, %r1, STACKFRAME
218         .cfi_def_cfa_offset 0
219         blr
220         .cfi_def_cfa_offset STACKFRAME
221 # case FFI_TYPE_DOUBLE
222         lfd %f1, RETVAL+0(%r1)
223         mtlr %r0
224         addi %r1, %r1, STACKFRAME
225         .cfi_def_cfa_offset 0
226         blr
227         .cfi_def_cfa_offset STACKFRAME
228 # case FFI_TYPE_LONGDOUBLE
229         lfd %f1, RETVAL+0(%r1)
230         mtlr %r0
231         lfd %f2, RETVAL+8(%r1)
232         b .Lfinish
233 # case FFI_TYPE_UINT8
234 # ifdef __LITTLE_ENDIAN__
235         lbz %r3, RETVAL+0(%r1)
236 # else
237         lbz %r3, RETVAL+7(%r1)
238 # endif
239         mtlr %r0
240         addi %r1, %r1, STACKFRAME
241         .cfi_def_cfa_offset 0
242         blr
243         .cfi_def_cfa_offset STACKFRAME
244 # case FFI_TYPE_SINT8
245 # ifdef __LITTLE_ENDIAN__
246         lbz %r3, RETVAL+0(%r1)
247 # else
248         lbz %r3, RETVAL+7(%r1)
249 # endif
250         extsb %r3,%r3
251         mtlr %r0
252         b .Lfinish
253 # case FFI_TYPE_UINT16
254 # ifdef __LITTLE_ENDIAN__
255         lhz %r3, RETVAL+0(%r1)
256 # else
257         lhz %r3, RETVAL+6(%r1)
258 # endif
259         mtlr %r0
260 .Lfinish:
261         addi %r1, %r1, STACKFRAME
262         .cfi_def_cfa_offset 0
263         blr
264         .cfi_def_cfa_offset STACKFRAME
265 # case FFI_TYPE_SINT16
266 # ifdef __LITTLE_ENDIAN__
267         lha %r3, RETVAL+0(%r1)
268 # else
269         lha %r3, RETVAL+6(%r1)
270 # endif
271         mtlr %r0
272         addi %r1, %r1, STACKFRAME
273         .cfi_def_cfa_offset 0
274         blr
275         .cfi_def_cfa_offset STACKFRAME
276 # case FFI_TYPE_UINT32
277 # ifdef __LITTLE_ENDIAN__
278         lwz %r3, RETVAL+0(%r1)
279 # else
280         lwz %r3, RETVAL+4(%r1)
281 # endif
282         mtlr %r0
283         addi %r1, %r1, STACKFRAME
284         .cfi_def_cfa_offset 0
285         blr
286         .cfi_def_cfa_offset STACKFRAME
287 # case FFI_TYPE_SINT32
288 # ifdef __LITTLE_ENDIAN__
289         lwa %r3, RETVAL+0(%r1)
290 # else
291         lwa %r3, RETVAL+4(%r1)
292 # endif
293         mtlr %r0
294         addi %r1, %r1, STACKFRAME
295         .cfi_def_cfa_offset 0
296         blr
297         .cfi_def_cfa_offset STACKFRAME
298 # case FFI_TYPE_UINT64
299         ld %r3, RETVAL+0(%r1)
300         mtlr %r0
301         addi %r1, %r1, STACKFRAME
302         .cfi_def_cfa_offset 0
303         blr
304         .cfi_def_cfa_offset STACKFRAME
305 # case FFI_TYPE_SINT64
306         ld %r3, RETVAL+0(%r1)
307         mtlr %r0
308         addi %r1, %r1, STACKFRAME
309         .cfi_def_cfa_offset 0
310         blr
311         .cfi_def_cfa_offset STACKFRAME
312 # case FFI_TYPE_STRUCT
313         mtlr %r0
314         addi %r1, %r1, STACKFRAME
315         .cfi_def_cfa_offset 0
316         blr
317         .cfi_def_cfa_offset STACKFRAME
318         nop
319 # case FFI_TYPE_POINTER
320         ld %r3, RETVAL+0(%r1)
321         mtlr %r0
322         addi %r1, %r1, STACKFRAME
323         .cfi_def_cfa_offset 0
324         blr
325         .cfi_def_cfa_offset STACKFRAME
326 # case FFI_V2_TYPE_FLOAT_HOMOG
327         lfs %f1, RETVAL+0(%r1)
328         lfs %f2, RETVAL+4(%r1)
329         lfs %f3, RETVAL+8(%r1)
330         b .Lmorefloat
331 # case FFI_V2_TYPE_DOUBLE_HOMOG
332         lfd %f1, RETVAL+0(%r1)
333         lfd %f2, RETVAL+8(%r1)
334         lfd %f3, RETVAL+16(%r1)
335         lfd %f4, RETVAL+24(%r1)
336         mtlr %r0
337         lfd %f5, RETVAL+32(%r1)
338         lfd %f6, RETVAL+40(%r1)
339         lfd %f7, RETVAL+48(%r1)
340         lfd %f8, RETVAL+56(%r1)
341         addi %r1, %r1, STACKFRAME
342         .cfi_def_cfa_offset 0
343         blr
344         .cfi_def_cfa_offset STACKFRAME
345 .Lmorefloat:
346         lfs %f4, RETVAL+12(%r1)
347         mtlr %r0
348         lfs %f5, RETVAL+16(%r1)
349         lfs %f6, RETVAL+20(%r1)
350         lfs %f7, RETVAL+24(%r1)
351         lfs %f8, RETVAL+28(%r1)
352         addi %r1, %r1, STACKFRAME
353         .cfi_def_cfa_offset 0
354         blr
355         .cfi_def_cfa_offset STACKFRAME
356 .Lsmall:
357 # ifdef __LITTLE_ENDIAN__
358         ld %r3,RETVAL+0(%r1)
359         mtlr %r0
360         ld %r4,RETVAL+8(%r1)
361         addi %r1, %r1, STACKFRAME
362         .cfi_def_cfa_offset 0
363         blr
364 # else
365         # A struct smaller than a dword is returned in the low bits of r3
366         # ie. right justified.  Larger structs are passed left justified
367         # in r3 and r4.  The return value area on the stack will have
368         # the structs as they are usually stored in memory.
369         cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes?
370         neg %r5, %r3
371         ld %r3,RETVAL+0(%r1)
372         blt .Lsmalldown
373         mtlr %r0
374         ld %r4,RETVAL+8(%r1)
375         addi %r1, %r1, STACKFRAME
376         .cfi_def_cfa_offset 0
377         blr
378         .cfi_def_cfa_offset STACKFRAME
379 .Lsmalldown:
380         addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7
381         mtlr %r0
382         sldi %r5, %r5, 3
383         addi %r1, %r1, STACKFRAME
384         .cfi_def_cfa_offset 0
385         srd %r3, %r3, %r5
386         blr
387 # endif
389         .cfi_endproc
390 # if _CALL_ELF == 2
391         .size   ffi_closure_LINUX64,.-ffi_closure_LINUX64
392 # else
393 #  ifdef _CALL_LINUX
394         .size   ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64
395 #  else
396         .long   0
397         .byte   0,12,0,1,128,0,0,0
398         .size   .ffi_closure_LINUX64,.-.ffi_closure_LINUX64
399 #  endif
400 # endif
403         FFI_HIDDEN (ffi_go_closure_linux64)
404         .globl  ffi_go_closure_linux64
405         .text
406         .cfi_startproc
407 # if _CALL_ELF == 2
408 ffi_go_closure_linux64:
409 #  ifndef __PCREL__
410         addis   %r2, %r12, .TOC.-ffi_go_closure_linux64@ha
411         addi    %r2, %r2, .TOC.-ffi_go_closure_linux64@l
412 #  endif
413         .localentry ffi_go_closure_linux64, . - ffi_go_closure_linux64
414 # else
415         .section        ".opd","aw"
416         .align  3
417 ffi_go_closure_linux64:
418 #  ifdef _CALL_LINUX
419         .quad   .L.ffi_go_closure_linux64,.TOC.@tocbase,0
420         .type   ffi_go_closure_linux64,@function
421         .text
422 .L.ffi_go_closure_linux64:
423 #  else
424         FFI_HIDDEN (.ffi_go_closure_linux64)
425         .globl  .ffi_go_closure_linux64
426         .quad   .ffi_go_closure_linux64,.TOC.@tocbase,0
427         .size   ffi_go_closure_linux64,24
428         .type   .ffi_go_closure_linux64,@function
429         .text
430 .ffi_go_closure_linux64:
431 #  endif
432 # endif
434 # if _CALL_ELF == 2
435         ld      %r12, 8(%r11)                           # closure->cif
436         mflr    %r0
437         lwz     %r12, 28(%r12)                          # cif->flags
438         mtcrf   0x40, %r12
439         addi    %r12, %r1, PARMSAVE
440         bt      7, 0f
441         # Our caller has not allocated a parameter save area.
442         # We need to allocate one here and use it to pass gprs to
443         # ffi_closure_helper_LINUX64.
444         addi    %r12, %r1, -STACKFRAME+PARMSAVE
446         # Save general regs into parm save area
447         std     %r3, 0(%r12)
448         std     %r4, 8(%r12)
449         std     %r5, 16(%r12)
450         std     %r6, 24(%r12)
451         std     %r7, 32(%r12)
452         std     %r8, 40(%r12)
453         std     %r9, 48(%r12)
454         std     %r10, 56(%r12)
456         # load up the pointer to the parm save area
457         mr      %r7, %r12
458 # else
459         mflr    %r0
460         # Save general regs into parm save area
461         # This is the parameter save area set up by our caller.
462         std     %r3, PARMSAVE+0(%r1)
463         std     %r4, PARMSAVE+8(%r1)
464         std     %r5, PARMSAVE+16(%r1)
465         std     %r6, PARMSAVE+24(%r1)
466         std     %r7, PARMSAVE+32(%r1)
467         std     %r8, PARMSAVE+40(%r1)
468         std     %r9, PARMSAVE+48(%r1)
469         std     %r10, PARMSAVE+56(%r1)
471         # load up the pointer to the parm save area
472         addi    %r7, %r1, PARMSAVE
473 # endif
474         std     %r0, 16(%r1)
476         # closure->cif
477         ld      %r3, 8(%r11)
478         # closure->fun
479         ld      %r4, 16(%r11)
480         # user_data
481         mr      %r5, %r11
482         b       .Ldoclosure
484         .cfi_endproc
485 # if _CALL_ELF == 2
486         .size   ffi_go_closure_linux64,.-ffi_go_closure_linux64
487 # else
488 #  ifdef _CALL_LINUX
489         .size   ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64
490 #  else
491         .long   0
492         .byte   0,12,0,1,128,0,0,0
493         .size   .ffi_go_closure_linux64,.-.ffi_go_closure_linux64
494 #  endif
495 # endif
496 #endif
498 #if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
499         .section        .note.GNU-stack,"",@progbits
500 #endif