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 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 43# else 44 .section ".opd","aw" 45 .align 3 46ffi_closure_LINUX64: 47# ifdef _CALL_LINUX 48 .quad .L.ffi_closure_LINUX64,.TOC.@tocbase,0 49 .type ffi_closure_LINUX64,@function 50 .text 51.L.ffi_closure_LINUX64: 52# else 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 58 .text 59.ffi_closure_LINUX64: 60# endif 61# endif 62 63# if _CALL_ELF == 2 64# ifdef __VEC__ 65# 32 byte special reg save area + 64 byte parm save area 66# + 128 byte retval area + 13*8 fpr save area + 12*16 vec save area + round to 16 67# define STACKFRAME 528 68# else 69# 32 byte special reg save area + 64 byte parm save area 70# + 64 byte retval area + 13*8 fpr save area + round to 16 71# define STACKFRAME 272 72# endif 73# define PARMSAVE 32 74# define RETVAL PARMSAVE+64 75# else 76# 48 bytes special reg save area + 64 bytes parm save area 77# + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 78# define STACKFRAME 240 79# define PARMSAVE 48 80# define RETVAL PARMSAVE+64 81# endif 82 83# if _CALL_ELF == 2 84 ld %r12, FFI_TRAMPOLINE_SIZE(%r11) # closure->cif 85 mflr %r0 86 lwz %r12, 28(%r12) # cif->flags 87 mtcrf 0x40, %r12 88 addi %r12, %r1, PARMSAVE 89 bt 7, 0f 90 # Our caller has not allocated a parameter save area. 91 # We need to allocate one here and use it to pass gprs to 92 # ffi_closure_helper_LINUX64. 93 addi %r12, %r1, -STACKFRAME+PARMSAVE 940: 95 # Save general regs into parm save area 96 std %r3, 0(%r12) 97 std %r4, 8(%r12) 98 std %r5, 16(%r12) 99 std %r6, 24(%r12) 100 std %r7, 32(%r12) 101 std %r8, 40(%r12) 102 std %r9, 48(%r12) 103 std %r10, 56(%r12) 104 105 # load up the pointer to the parm save area 106 mr %r7, %r12 107# else 108 # copy r2 to r11 and load TOC into r2 109 mr %r11, %r2 110 ld %r2, 16(%r2) 111 112 mflr %r0 113 # Save general regs into parm save area 114 # This is the parameter save area set up by our caller. 115 std %r3, PARMSAVE+0(%r1) 116 std %r4, PARMSAVE+8(%r1) 117 std %r5, PARMSAVE+16(%r1) 118 std %r6, PARMSAVE+24(%r1) 119 std %r7, PARMSAVE+32(%r1) 120 std %r8, PARMSAVE+40(%r1) 121 std %r9, PARMSAVE+48(%r1) 122 std %r10, PARMSAVE+56(%r1) 123 124 # load up the pointer to the parm save area 125 addi %r7, %r1, PARMSAVE 126# endif 127 std %r0, 16(%r1) 128 129 # closure->cif 130 ld %r3, FFI_TRAMPOLINE_SIZE(%r11) 131 # closure->fun 132 ld %r4, FFI_TRAMPOLINE_SIZE+8(%r11) 133 # closure->user_data 134 ld %r5, FFI_TRAMPOLINE_SIZE+16(%r11) 135 136.Ldoclosure: 137 # next save fpr 1 to fpr 13 138 stfd %f1, -104+(0*8)(%r1) 139 stfd %f2, -104+(1*8)(%r1) 140 stfd %f3, -104+(2*8)(%r1) 141 stfd %f4, -104+(3*8)(%r1) 142 stfd %f5, -104+(4*8)(%r1) 143 stfd %f6, -104+(5*8)(%r1) 144 stfd %f7, -104+(6*8)(%r1) 145 stfd %f8, -104+(7*8)(%r1) 146 stfd %f9, -104+(8*8)(%r1) 147 stfd %f10, -104+(9*8)(%r1) 148 stfd %f11, -104+(10*8)(%r1) 149 stfd %f12, -104+(11*8)(%r1) 150 stfd %f13, -104+(12*8)(%r1) 151 152 # load up the pointer to the saved fpr registers 153 addi %r8, %r1, -104 154 155# ifdef __VEC__ 156 # load up the pointer to the saved vector registers 157 # 8 bytes padding for 16-byte alignment at -112(%r1) 158 addi %r9, %r8, -24 159 stvx %v13, 0, %r9 160 addi %r9, %r9, -16 161 stvx %v12, 0, %r9 162 addi %r9, %r9, -16 163 stvx %v11, 0, %r9 164 addi %r9, %r9, -16 165 stvx %v10, 0, %r9 166 addi %r9, %r9, -16 167 stvx %v9, 0, %r9 168 addi %r9, %r9, -16 169 stvx %v8, 0, %r9 170 addi %r9, %r9, -16 171 stvx %v7, 0, %r9 172 addi %r9, %r9, -16 173 stvx %v6, 0, %r9 174 addi %r9, %r9, -16 175 stvx %v5, 0, %r9 176 addi %r9, %r9, -16 177 stvx %v4, 0, %r9 178 addi %r9, %r9, -16 179 stvx %v3, 0, %r9 180 addi %r9, %r9, -16 181 stvx %v2, 0, %r9 182# endif 183 184 # load up the pointer to the result storage 185 addi %r6, %r1, -STACKFRAME+RETVAL 186 187 stdu %r1, -STACKFRAME(%r1) 188 .cfi_def_cfa_offset STACKFRAME 189 .cfi_offset 65, 16 190 191 # make the call 192# if defined _CALL_LINUX || _CALL_ELF == 2 193 bl ffi_closure_helper_LINUX64 194# else 195 bl .ffi_closure_helper_LINUX64 196# endif 197.Lret: 198 199 # now r3 contains the return type 200 # so use it to look up in a table 201 # so we know how to deal with each type 202 203 # look up the proper starting point in table 204 # by using return type as offset 205 ld %r0, STACKFRAME+16(%r1) 206 cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT 207 bge .Lsmall 208 mflr %r4 # move address of .Lret to r4 209 sldi %r3, %r3, 4 # now multiply return type by 16 210 addi %r4, %r4, .Lret_type0 - .Lret 211 add %r3, %r3, %r4 # add contents of table to table address 212 mtctr %r3 213 bctr # jump to it 214 215# Each of the ret_typeX code fragments has to be exactly 16 bytes long 216# (4 instructions). For cache effectiveness we align to a 16 byte boundary 217# first. 218 .align 4 219 220.Lret_type0: 221# case FFI_TYPE_VOID 222 mtlr %r0 223 addi %r1, %r1, STACKFRAME 224 .cfi_def_cfa_offset 0 225 blr 226 .cfi_def_cfa_offset STACKFRAME 227 nop 228# case FFI_TYPE_INT 229# ifdef __LITTLE_ENDIAN__ 230 lwa %r3, RETVAL+0(%r1) 231# else 232 lwa %r3, RETVAL+4(%r1) 233# endif 234 mtlr %r0 235 addi %r1, %r1, STACKFRAME 236 .cfi_def_cfa_offset 0 237 blr 238 .cfi_def_cfa_offset STACKFRAME 239# case FFI_TYPE_FLOAT 240 lfs %f1, RETVAL+0(%r1) 241 mtlr %r0 242 addi %r1, %r1, STACKFRAME 243 .cfi_def_cfa_offset 0 244 blr 245 .cfi_def_cfa_offset STACKFRAME 246# case FFI_TYPE_DOUBLE 247 lfd %f1, RETVAL+0(%r1) 248 mtlr %r0 249 addi %r1, %r1, STACKFRAME 250 .cfi_def_cfa_offset 0 251 blr 252 .cfi_def_cfa_offset STACKFRAME 253# case FFI_TYPE_LONGDOUBLE 254 lfd %f1, RETVAL+0(%r1) 255 mtlr %r0 256 lfd %f2, RETVAL+8(%r1) 257 b .Lfinish 258# case FFI_TYPE_UINT8 259# ifdef __LITTLE_ENDIAN__ 260 lbz %r3, RETVAL+0(%r1) 261# else 262 lbz %r3, RETVAL+7(%r1) 263# endif 264 mtlr %r0 265 addi %r1, %r1, STACKFRAME 266 .cfi_def_cfa_offset 0 267 blr 268 .cfi_def_cfa_offset STACKFRAME 269# case FFI_TYPE_SINT8 270# ifdef __LITTLE_ENDIAN__ 271 lbz %r3, RETVAL+0(%r1) 272# else 273 lbz %r3, RETVAL+7(%r1) 274# endif 275 extsb %r3,%r3 276 mtlr %r0 277 b .Lfinish 278# case FFI_TYPE_UINT16 279# ifdef __LITTLE_ENDIAN__ 280 lhz %r3, RETVAL+0(%r1) 281# else 282 lhz %r3, RETVAL+6(%r1) 283# endif 284 mtlr %r0 285.Lfinish: 286 addi %r1, %r1, STACKFRAME 287 .cfi_def_cfa_offset 0 288 blr 289 .cfi_def_cfa_offset STACKFRAME 290# case FFI_TYPE_SINT16 291# ifdef __LITTLE_ENDIAN__ 292 lha %r3, RETVAL+0(%r1) 293# else 294 lha %r3, RETVAL+6(%r1) 295# endif 296 mtlr %r0 297 addi %r1, %r1, STACKFRAME 298 .cfi_def_cfa_offset 0 299 blr 300 .cfi_def_cfa_offset STACKFRAME 301# case FFI_TYPE_UINT32 302# ifdef __LITTLE_ENDIAN__ 303 lwz %r3, RETVAL+0(%r1) 304# else 305 lwz %r3, RETVAL+4(%r1) 306# endif 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_SINT32 313# ifdef __LITTLE_ENDIAN__ 314 lwa %r3, RETVAL+0(%r1) 315# else 316 lwa %r3, RETVAL+4(%r1) 317# endif 318 mtlr %r0 319 addi %r1, %r1, STACKFRAME 320 .cfi_def_cfa_offset 0 321 blr 322 .cfi_def_cfa_offset STACKFRAME 323# case FFI_TYPE_UINT64 324 ld %r3, RETVAL+0(%r1) 325 mtlr %r0 326 addi %r1, %r1, STACKFRAME 327 .cfi_def_cfa_offset 0 328 blr 329 .cfi_def_cfa_offset STACKFRAME 330# case FFI_TYPE_SINT64 331 ld %r3, RETVAL+0(%r1) 332 mtlr %r0 333 addi %r1, %r1, STACKFRAME 334 .cfi_def_cfa_offset 0 335 blr 336 .cfi_def_cfa_offset STACKFRAME 337# case FFI_TYPE_STRUCT 338 mtlr %r0 339 addi %r1, %r1, STACKFRAME 340 .cfi_def_cfa_offset 0 341 blr 342 .cfi_def_cfa_offset STACKFRAME 343 nop 344# case FFI_TYPE_POINTER 345 ld %r3, RETVAL+0(%r1) 346 mtlr %r0 347 addi %r1, %r1, STACKFRAME 348 .cfi_def_cfa_offset 0 349 blr 350 .cfi_def_cfa_offset STACKFRAME 351# case FFI_V2_TYPE_VECTOR 352 addi %r3, %r1, RETVAL 353 lvx %v2, 0, %r3 354 mtlr %r0 355 b .Lfinish 356# case FFI_V2_TYPE_VECTOR_HOMOG 357 addi %r3, %r1, RETVAL 358 lvx %v2, 0, %r3 359 addi %r3, %r3, 16 360 b .Lmorevector 361# case FFI_V2_TYPE_FLOAT_HOMOG 362 lfs %f1, RETVAL+0(%r1) 363 lfs %f2, RETVAL+4(%r1) 364 lfs %f3, RETVAL+8(%r1) 365 b .Lmorefloat 366# case FFI_V2_TYPE_DOUBLE_HOMOG 367 lfd %f1, RETVAL+0(%r1) 368 lfd %f2, RETVAL+8(%r1) 369 lfd %f3, RETVAL+16(%r1) 370 lfd %f4, RETVAL+24(%r1) 371 mtlr %r0 372 lfd %f5, RETVAL+32(%r1) 373 lfd %f6, RETVAL+40(%r1) 374 lfd %f7, RETVAL+48(%r1) 375 lfd %f8, RETVAL+56(%r1) 376 addi %r1, %r1, STACKFRAME 377 .cfi_def_cfa_offset 0 378 blr 379 .cfi_def_cfa_offset STACKFRAME 380.Lmorevector: 381 lvx %v3, 0, %r3 382 addi %r3, %r3, 16 383 lvx %v4, 0, %r3 384 addi %r3, %r3, 16 385 lvx %v5, 0, %r3 386 mtlr %r0 387 addi %r3, %r3, 16 388 lvx %v6, 0, %r3 389 addi %r3, %r3, 16 390 lvx %v7, 0, %r3 391 addi %r3, %r3, 16 392 lvx %v8, 0, %r3 393 addi %r3, %r3, 16 394 lvx %v9, 0, %r3 395 addi %r1, %r1, STACKFRAME 396 .cfi_def_cfa_offset 0 397 blr 398 .cfi_def_cfa_offset STACKFRAME 399.Lmorefloat: 400 lfs %f4, RETVAL+12(%r1) 401 mtlr %r0 402 lfs %f5, RETVAL+16(%r1) 403 lfs %f6, RETVAL+20(%r1) 404 lfs %f7, RETVAL+24(%r1) 405 lfs %f8, RETVAL+28(%r1) 406 addi %r1, %r1, STACKFRAME 407 .cfi_def_cfa_offset 0 408 blr 409 .cfi_def_cfa_offset STACKFRAME 410.Lsmall: 411# ifdef __LITTLE_ENDIAN__ 412 ld %r3,RETVAL+0(%r1) 413 mtlr %r0 414 ld %r4,RETVAL+8(%r1) 415 addi %r1, %r1, STACKFRAME 416 .cfi_def_cfa_offset 0 417 blr 418# else 419 # A struct smaller than a dword is returned in the low bits of r3 420 # ie. right justified. Larger structs are passed left justified 421 # in r3 and r4. The return value area on the stack will have 422 # the structs as they are usually stored in memory. 423 cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes? 424 neg %r5, %r3 425 ld %r3,RETVAL+0(%r1) 426 blt .Lsmalldown 427 mtlr %r0 428 ld %r4,RETVAL+8(%r1) 429 addi %r1, %r1, STACKFRAME 430 .cfi_def_cfa_offset 0 431 blr 432 .cfi_def_cfa_offset STACKFRAME 433.Lsmalldown: 434 addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7 435 mtlr %r0 436 sldi %r5, %r5, 3 437 addi %r1, %r1, STACKFRAME 438 .cfi_def_cfa_offset 0 439 srd %r3, %r3, %r5 440 blr 441# endif 442 443 .cfi_endproc 444# if _CALL_ELF == 2 445 .size ffi_closure_LINUX64,.-ffi_closure_LINUX64 446# else 447# ifdef _CALL_LINUX 448 .size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64 449# else 450 .long 0 451 .byte 0,12,0,1,128,0,0,0 452 .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 453# endif 454# endif 455 456 457 FFI_HIDDEN (ffi_go_closure_linux64) 458 .globl ffi_go_closure_linux64 459 .text 460 .cfi_startproc 461# if _CALL_ELF == 2 462ffi_go_closure_linux64: 463 addis %r2, %r12, .TOC.-ffi_go_closure_linux64@ha 464 addi %r2, %r2, .TOC.-ffi_go_closure_linux64@l 465 .localentry ffi_go_closure_linux64, . - ffi_go_closure_linux64 466# else 467 .section ".opd","aw" 468 .align 3 469ffi_go_closure_linux64: 470# ifdef _CALL_LINUX 471 .quad .L.ffi_go_closure_linux64,.TOC.@tocbase,0 472 .type ffi_go_closure_linux64,@function 473 .text 474.L.ffi_go_closure_linux64: 475# else 476 FFI_HIDDEN (.ffi_go_closure_linux64) 477 .globl .ffi_go_closure_linux64 478 .quad .ffi_go_closure_linux64,.TOC.@tocbase,0 479 .size ffi_go_closure_linux64,24 480 .type .ffi_go_closure_linux64,@function 481 .text 482.ffi_go_closure_linux64: 483# endif 484# endif 485 486# if _CALL_ELF == 2 487 ld %r12, 8(%r11) # closure->cif 488 mflr %r0 489 lwz %r12, 28(%r12) # cif->flags 490 mtcrf 0x40, %r12 491 addi %r12, %r1, PARMSAVE 492 bt 7, 0f 493 # Our caller has not allocated a parameter save area. 494 # We need to allocate one here and use it to pass gprs to 495 # ffi_closure_helper_LINUX64. 496 addi %r12, %r1, -STACKFRAME+PARMSAVE 4970: 498 # Save general regs into parm save area 499 std %r3, 0(%r12) 500 std %r4, 8(%r12) 501 std %r5, 16(%r12) 502 std %r6, 24(%r12) 503 std %r7, 32(%r12) 504 std %r8, 40(%r12) 505 std %r9, 48(%r12) 506 std %r10, 56(%r12) 507 508 # load up the pointer to the parm save area 509 mr %r7, %r12 510# else 511 mflr %r0 512 # Save general regs into parm save area 513 # This is the parameter save area set up by our caller. 514 std %r3, PARMSAVE+0(%r1) 515 std %r4, PARMSAVE+8(%r1) 516 std %r5, PARMSAVE+16(%r1) 517 std %r6, PARMSAVE+24(%r1) 518 std %r7, PARMSAVE+32(%r1) 519 std %r8, PARMSAVE+40(%r1) 520 std %r9, PARMSAVE+48(%r1) 521 std %r10, PARMSAVE+56(%r1) 522 523 # load up the pointer to the parm save area 524 addi %r7, %r1, PARMSAVE 525# endif 526 std %r0, 16(%r1) 527 528 # closure->cif 529 ld %r3, 8(%r11) 530 # closure->fun 531 ld %r4, 16(%r11) 532 # user_data 533 mr %r5, %r11 534 b .Ldoclosure 535 536 .cfi_endproc 537# if _CALL_ELF == 2 538 .size ffi_go_closure_linux64,.-ffi_go_closure_linux64 539# else 540# ifdef _CALL_LINUX 541 .size ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64 542# else 543 .long 0 544 .byte 0,12,0,1,128,0,0,0 545 .size .ffi_go_closure_linux64,.-.ffi_go_closure_linux64 546# endif 547# endif 548#endif 549 550#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 551 .section .note.GNU-stack,"",@progbits 552#endif 553