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 ----------------------------------------------------------------------- */
28 #include <fficonfig.h>
31 .file "linux64_closure.S"
34 FFI_HIDDEN (ffi_closure_LINUX64)
35 .globl ffi_closure_LINUX64
40 addis %r2, %r12, .TOC.-ffi_closure_LINUX64@ha
41 addi %r2, %r2, .TOC.-ffi_closure_LINUX64@l
42 .localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64
48 .quad .L.ffi_closure_LINUX64,.TOC.@tocbase,0
49 .type ffi_closure_LINUX64,@function
51 .L.ffi_closure_LINUX64:
53 FFI_HIDDEN (.ffi_closure_LINUX64)
54 .globl .ffi_closure_LINUX64
55 .quad .ffi_closure_LINUX64,.TOC.@tocbase,0
56 .size ffi_closure_LINUX64,24
57 .type .ffi_closure_LINUX64,@function
64 # 32 byte special reg save area + 64 byte parm save area
65 # + 64 byte retval area + 13*8 fpr save area + round to 16
66 # define STACKFRAME 272
68 # define RETVAL PARMSAVE+64
70 # 48 bytes special reg save area + 64 bytes parm save area
71 # + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
72 # define STACKFRAME 240
74 # define RETVAL PARMSAVE+64
78 ld %r12, FFI_TRAMPOLINE_SIZE(%r11) # closure->cif
80 lwz %r12, 28(%r12) # cif->flags
82 addi %r12, %r1, PARMSAVE
84 # Our caller has not allocated a parameter save area.
85 # We need to allocate one here and use it to pass gprs to
86 # ffi_closure_helper_LINUX64.
87 addi %r12, %r1, -STACKFRAME+PARMSAVE
89 # Save general regs into parm save area
99 # load up the pointer to the parm save area
102 # copy r2 to r11 and load TOC into r2
107 # Save general regs into parm save area
108 # This is the parameter save area set up by our caller.
109 std %r3, PARMSAVE+0(%r1)
110 std %r4, PARMSAVE+8(%r1)
111 std %r5, PARMSAVE+16(%r1)
112 std %r6, PARMSAVE+24(%r1)
113 std %r7, PARMSAVE+32(%r1)
114 std %r8, PARMSAVE+40(%r1)
115 std %r9, PARMSAVE+48(%r1)
116 std %r10, PARMSAVE+56(%r1)
118 # load up the pointer to the parm save area
119 addi %r7, %r1, PARMSAVE
124 ld %r3, FFI_TRAMPOLINE_SIZE(%r11)
126 ld %r4, FFI_TRAMPOLINE_SIZE+8(%r11)
128 ld %r5, FFI_TRAMPOLINE_SIZE+16(%r11)
131 # next save fpr 1 to fpr 13
132 stfd %f1, -104+(0*8)(%r1)
133 stfd %f2, -104+(1*8)(%r1)
134 stfd %f3, -104+(2*8)(%r1)
135 stfd %f4, -104+(3*8)(%r1)
136 stfd %f5, -104+(4*8)(%r1)
137 stfd %f6, -104+(5*8)(%r1)
138 stfd %f7, -104+(6*8)(%r1)
139 stfd %f8, -104+(7*8)(%r1)
140 stfd %f9, -104+(8*8)(%r1)
141 stfd %f10, -104+(9*8)(%r1)
142 stfd %f11, -104+(10*8)(%r1)
143 stfd %f12, -104+(11*8)(%r1)
144 stfd %f13, -104+(12*8)(%r1)
146 # load up the pointer to the saved fpr registers */
149 # load up the pointer to the result storage
150 addi %r6, %r1, -STACKFRAME+RETVAL
152 stdu %r1, -STACKFRAME(%r1)
153 .cfi_def_cfa_offset STACKFRAME
157 # if defined _CALL_LINUX || _CALL_ELF == 2
158 bl ffi_closure_helper_LINUX64
160 bl .ffi_closure_helper_LINUX64
164 # now r3 contains the return type
165 # so use it to look up in a table
166 # so we know how to deal with each type
168 # look up the proper starting point in table
169 # by using return type as offset
170 ld %r0, STACKFRAME+16(%r1)
171 cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT
173 mflr %r4 # move address of .Lret to r4
174 sldi %r3, %r3, 4 # now multiply return type by 16
175 addi %r4, %r4, .Lret_type0 - .Lret
176 add %r3, %r3, %r4 # add contents of table to table address
180 # Each of the ret_typeX code fragments has to be exactly 16 bytes long
181 # (4 instructions). For cache effectiveness we align to a 16 byte boundary
188 addi %r1, %r1, STACKFRAME
189 .cfi_def_cfa_offset 0
191 .cfi_def_cfa_offset STACKFRAME
194 # ifdef __LITTLE_ENDIAN__
195 lwa %r3, RETVAL+0(%r1)
197 lwa %r3, RETVAL+4(%r1)
200 addi %r1, %r1, STACKFRAME
201 .cfi_def_cfa_offset 0
203 .cfi_def_cfa_offset STACKFRAME
204 # case FFI_TYPE_FLOAT
205 lfs %f1, RETVAL+0(%r1)
207 addi %r1, %r1, STACKFRAME
208 .cfi_def_cfa_offset 0
210 .cfi_def_cfa_offset STACKFRAME
211 # case FFI_TYPE_DOUBLE
212 lfd %f1, RETVAL+0(%r1)
214 addi %r1, %r1, STACKFRAME
215 .cfi_def_cfa_offset 0
217 .cfi_def_cfa_offset STACKFRAME
218 # case FFI_TYPE_LONGDOUBLE
219 lfd %f1, RETVAL+0(%r1)
221 lfd %f2, RETVAL+8(%r1)
223 # case FFI_TYPE_UINT8
224 # ifdef __LITTLE_ENDIAN__
225 lbz %r3, RETVAL+0(%r1)
227 lbz %r3, RETVAL+7(%r1)
230 addi %r1, %r1, STACKFRAME
231 .cfi_def_cfa_offset 0
233 .cfi_def_cfa_offset STACKFRAME
234 # case FFI_TYPE_SINT8
235 # ifdef __LITTLE_ENDIAN__
236 lbz %r3, RETVAL+0(%r1)
238 lbz %r3, RETVAL+7(%r1)
243 # case FFI_TYPE_UINT16
244 # ifdef __LITTLE_ENDIAN__
245 lhz %r3, RETVAL+0(%r1)
247 lhz %r3, RETVAL+6(%r1)
251 addi %r1, %r1, STACKFRAME
252 .cfi_def_cfa_offset 0
254 .cfi_def_cfa_offset STACKFRAME
255 # case FFI_TYPE_SINT16
256 # ifdef __LITTLE_ENDIAN__
257 lha %r3, RETVAL+0(%r1)
259 lha %r3, RETVAL+6(%r1)
262 addi %r1, %r1, STACKFRAME
263 .cfi_def_cfa_offset 0
265 .cfi_def_cfa_offset STACKFRAME
266 # case FFI_TYPE_UINT32
267 # ifdef __LITTLE_ENDIAN__
268 lwz %r3, RETVAL+0(%r1)
270 lwz %r3, RETVAL+4(%r1)
273 addi %r1, %r1, STACKFRAME
274 .cfi_def_cfa_offset 0
276 .cfi_def_cfa_offset STACKFRAME
277 # case FFI_TYPE_SINT32
278 # ifdef __LITTLE_ENDIAN__
279 lwa %r3, RETVAL+0(%r1)
281 lwa %r3, RETVAL+4(%r1)
284 addi %r1, %r1, STACKFRAME
285 .cfi_def_cfa_offset 0
287 .cfi_def_cfa_offset STACKFRAME
288 # case FFI_TYPE_UINT64
289 ld %r3, RETVAL+0(%r1)
291 addi %r1, %r1, STACKFRAME
292 .cfi_def_cfa_offset 0
294 .cfi_def_cfa_offset STACKFRAME
295 # case FFI_TYPE_SINT64
296 ld %r3, RETVAL+0(%r1)
298 addi %r1, %r1, STACKFRAME
299 .cfi_def_cfa_offset 0
301 .cfi_def_cfa_offset STACKFRAME
302 # case FFI_TYPE_STRUCT
304 addi %r1, %r1, STACKFRAME
305 .cfi_def_cfa_offset 0
307 .cfi_def_cfa_offset STACKFRAME
309 # case FFI_TYPE_POINTER
310 ld %r3, RETVAL+0(%r1)
312 addi %r1, %r1, STACKFRAME
313 .cfi_def_cfa_offset 0
315 .cfi_def_cfa_offset STACKFRAME
316 # case FFI_V2_TYPE_FLOAT_HOMOG
317 lfs %f1, RETVAL+0(%r1)
318 lfs %f2, RETVAL+4(%r1)
319 lfs %f3, RETVAL+8(%r1)
321 # case FFI_V2_TYPE_DOUBLE_HOMOG
322 lfd %f1, RETVAL+0(%r1)
323 lfd %f2, RETVAL+8(%r1)
324 lfd %f3, RETVAL+16(%r1)
325 lfd %f4, RETVAL+24(%r1)
327 lfd %f5, RETVAL+32(%r1)
328 lfd %f6, RETVAL+40(%r1)
329 lfd %f7, RETVAL+48(%r1)
330 lfd %f8, RETVAL+56(%r1)
331 addi %r1, %r1, STACKFRAME
332 .cfi_def_cfa_offset 0
334 .cfi_def_cfa_offset STACKFRAME
336 lfs %f4, RETVAL+12(%r1)
338 lfs %f5, RETVAL+16(%r1)
339 lfs %f6, RETVAL+20(%r1)
340 lfs %f7, RETVAL+24(%r1)
341 lfs %f8, RETVAL+28(%r1)
342 addi %r1, %r1, STACKFRAME
343 .cfi_def_cfa_offset 0
345 .cfi_def_cfa_offset STACKFRAME
347 # ifdef __LITTLE_ENDIAN__
351 addi %r1, %r1, STACKFRAME
352 .cfi_def_cfa_offset 0
355 # A struct smaller than a dword is returned in the low bits of r3
356 # ie. right justified. Larger structs are passed left justified
357 # in r3 and r4. The return value area on the stack will have
358 # the structs as they are usually stored in memory.
359 cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes?
365 addi %r1, %r1, STACKFRAME
366 .cfi_def_cfa_offset 0
368 .cfi_def_cfa_offset STACKFRAME
370 addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7
373 addi %r1, %r1, STACKFRAME
374 .cfi_def_cfa_offset 0
381 .size ffi_closure_LINUX64,.-ffi_closure_LINUX64
384 .size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64
387 .byte 0,12,0,1,128,0,0,0
388 .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64
393 FFI_HIDDEN (ffi_go_closure_linux64)
394 .globl ffi_go_closure_linux64
398 ffi_go_closure_linux64:
399 addis %r2, %r12, .TOC.-ffi_go_closure_linux64@ha
400 addi %r2, %r2, .TOC.-ffi_go_closure_linux64@l
401 .localentry ffi_go_closure_linux64, . - ffi_go_closure_linux64
405 ffi_go_closure_linux64:
407 .quad .L.ffi_go_closure_linux64,.TOC.@tocbase,0
408 .type ffi_go_closure_linux64,@function
410 .L.ffi_go_closure_linux64:
412 FFI_HIDDEN (.ffi_go_closure_linux64)
413 .globl .ffi_go_closure_linux64
414 .quad .ffi_go_closure_linux64,.TOC.@tocbase,0
415 .size ffi_go_closure_linux64,24
416 .type .ffi_go_closure_linux64,@function
418 .ffi_go_closure_linux64:
423 ld %r12, 8(%r11) # closure->cif
425 lwz %r12, 28(%r12) # cif->flags
427 addi %r12, %r1, PARMSAVE
429 # Our caller has not allocated a parameter save area.
430 # We need to allocate one here and use it to pass gprs to
431 # ffi_closure_helper_LINUX64.
432 addi %r12, %r1, -STACKFRAME+PARMSAVE
434 # Save general regs into parm save area
444 # load up the pointer to the parm save area
448 # Save general regs into parm save area
449 # This is the parameter save area set up by our caller.
450 std %r3, PARMSAVE+0(%r1)
451 std %r4, PARMSAVE+8(%r1)
452 std %r5, PARMSAVE+16(%r1)
453 std %r6, PARMSAVE+24(%r1)
454 std %r7, PARMSAVE+32(%r1)
455 std %r8, PARMSAVE+40(%r1)
456 std %r9, PARMSAVE+48(%r1)
457 std %r10, PARMSAVE+56(%r1)
459 # load up the pointer to the parm save area
460 addi %r7, %r1, PARMSAVE
474 .size ffi_go_closure_linux64,.-ffi_go_closure_linux64
477 .size ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64
480 .byte 0,12,0,1,128,0,0,0
481 .size .ffi_go_closure_linux64,.-.ffi_go_closure_linux64
486 #if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
487 .section .note.GNU-stack,"",@progbits