1/* ----------------------------------------------------------------------- 2 sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com> 3 Copyright (c) 2008 Red Hat, Inc. 4 5 PowerPC64 Assembly glue. 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#define LIBFFI_ASM 28#include <fficonfig.h> 29#include <ffi.h> 30 31 .file "linux64_closure.S" 32 33#ifdef POWERPC64 34 FFI_HIDDEN (ffi_closure_LINUX64) 35 .globl ffi_closure_LINUX64 36 .text 37 .cfi_startproc 38# if _CALL_ELF == 2 39ffi_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 48ffi_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 64 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 78 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 900: 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) 100 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) 107 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) 119 120 # load up the pointer to the parm save area 121 addi %r7, %r1, PARMSAVE 122# endif 123 std %r0, 16(%r1) 124 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) 131 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) 147 148 # load up the pointer to the saved fpr registers 149 addi %r8, %r1, -104 150 151 # load up the pointer to the result storage 152 addi %r6, %r1, -STACKFRAME+RETVAL 153 154 stdu %r1, -STACKFRAME(%r1) 155 .cfi_def_cfa_offset STACKFRAME 156 .cfi_offset 65, 16 157 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 173 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 177 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 189 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 194 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 388 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 401 402 403 FFI_HIDDEN (ffi_go_closure_linux64) 404 .globl ffi_go_closure_linux64 405 .text 406 .cfi_startproc 407# if _CALL_ELF == 2 408ffi_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 417ffi_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 433 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 4450: 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) 455 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) 470 471 # load up the pointer to the parm save area 472 addi %r7, %r1, PARMSAVE 473# endif 474 std %r0, 16(%r1) 475 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 483 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 497 498#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 499 .section .note.GNU-stack,"",@progbits 500#endif 501