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# 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 67# define PARMSAVE 32 68# define RETVAL PARMSAVE+64 69# else 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 73# define PARMSAVE 48 74# define RETVAL PARMSAVE+64 75# endif 76 77# if _CALL_ELF == 2 78 ld %r12, FFI_TRAMPOLINE_SIZE(%r11) # closure->cif 79 mflr %r0 80 lwz %r12, 28(%r12) # cif->flags 81 mtcrf 0x40, %r12 82 addi %r12, %r1, PARMSAVE 83 bt 7, 0f 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 880: 89 # Save general regs into parm save area 90 std %r3, 0(%r12) 91 std %r4, 8(%r12) 92 std %r5, 16(%r12) 93 std %r6, 24(%r12) 94 std %r7, 32(%r12) 95 std %r8, 40(%r12) 96 std %r9, 48(%r12) 97 std %r10, 56(%r12) 98 99 # load up the pointer to the parm save area 100 mr %r7, %r12 101# else 102 # copy r2 to r11 and load TOC into r2 103 mr %r11, %r2 104 ld %r2, 16(%r2) 105 106 mflr %r0 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) 117 118 # load up the pointer to the parm save area 119 addi %r7, %r1, PARMSAVE 120# endif 121 std %r0, 16(%r1) 122 123 # closure->cif 124 ld %r3, FFI_TRAMPOLINE_SIZE(%r11) 125 # closure->fun 126 ld %r4, FFI_TRAMPOLINE_SIZE+8(%r11) 127 # closure->user_data 128 ld %r5, FFI_TRAMPOLINE_SIZE+16(%r11) 129 130.Ldoclosure: 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) 145 146 # load up the pointer to the saved fpr registers */ 147 addi %r8, %r1, -104 148 149 # load up the pointer to the result storage 150 addi %r6, %r1, -STACKFRAME+RETVAL 151 152 stdu %r1, -STACKFRAME(%r1) 153 .cfi_def_cfa_offset STACKFRAME 154 .cfi_offset 65, 16 155 156 # make the call 157# if defined _CALL_LINUX || _CALL_ELF == 2 158 bl ffi_closure_helper_LINUX64 159# else 160 bl .ffi_closure_helper_LINUX64 161# endif 162.Lret: 163 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 167 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 172 bge .Lsmall 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 177 mtctr %r3 178 bctr # jump to it 179 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 182# first. 183 .align 4 184 185.Lret_type0: 186# case FFI_TYPE_VOID 187 mtlr %r0 188 addi %r1, %r1, STACKFRAME 189 .cfi_def_cfa_offset 0 190 blr 191 .cfi_def_cfa_offset STACKFRAME 192 nop 193# case FFI_TYPE_INT 194# ifdef __LITTLE_ENDIAN__ 195 lwa %r3, RETVAL+0(%r1) 196# else 197 lwa %r3, RETVAL+4(%r1) 198# endif 199 mtlr %r0 200 addi %r1, %r1, STACKFRAME 201 .cfi_def_cfa_offset 0 202 blr 203 .cfi_def_cfa_offset STACKFRAME 204# case FFI_TYPE_FLOAT 205 lfs %f1, RETVAL+0(%r1) 206 mtlr %r0 207 addi %r1, %r1, STACKFRAME 208 .cfi_def_cfa_offset 0 209 blr 210 .cfi_def_cfa_offset STACKFRAME 211# case FFI_TYPE_DOUBLE 212 lfd %f1, RETVAL+0(%r1) 213 mtlr %r0 214 addi %r1, %r1, STACKFRAME 215 .cfi_def_cfa_offset 0 216 blr 217 .cfi_def_cfa_offset STACKFRAME 218# case FFI_TYPE_LONGDOUBLE 219 lfd %f1, RETVAL+0(%r1) 220 mtlr %r0 221 lfd %f2, RETVAL+8(%r1) 222 b .Lfinish 223# case FFI_TYPE_UINT8 224# ifdef __LITTLE_ENDIAN__ 225 lbz %r3, RETVAL+0(%r1) 226# else 227 lbz %r3, RETVAL+7(%r1) 228# endif 229 mtlr %r0 230 addi %r1, %r1, STACKFRAME 231 .cfi_def_cfa_offset 0 232 blr 233 .cfi_def_cfa_offset STACKFRAME 234# case FFI_TYPE_SINT8 235# ifdef __LITTLE_ENDIAN__ 236 lbz %r3, RETVAL+0(%r1) 237# else 238 lbz %r3, RETVAL+7(%r1) 239# endif 240 extsb %r3,%r3 241 mtlr %r0 242 b .Lfinish 243# case FFI_TYPE_UINT16 244# ifdef __LITTLE_ENDIAN__ 245 lhz %r3, RETVAL+0(%r1) 246# else 247 lhz %r3, RETVAL+6(%r1) 248# endif 249 mtlr %r0 250.Lfinish: 251 addi %r1, %r1, STACKFRAME 252 .cfi_def_cfa_offset 0 253 blr 254 .cfi_def_cfa_offset STACKFRAME 255# case FFI_TYPE_SINT16 256# ifdef __LITTLE_ENDIAN__ 257 lha %r3, RETVAL+0(%r1) 258# else 259 lha %r3, RETVAL+6(%r1) 260# endif 261 mtlr %r0 262 addi %r1, %r1, STACKFRAME 263 .cfi_def_cfa_offset 0 264 blr 265 .cfi_def_cfa_offset STACKFRAME 266# case FFI_TYPE_UINT32 267# ifdef __LITTLE_ENDIAN__ 268 lwz %r3, RETVAL+0(%r1) 269# else 270 lwz %r3, RETVAL+4(%r1) 271# endif 272 mtlr %r0 273 addi %r1, %r1, STACKFRAME 274 .cfi_def_cfa_offset 0 275 blr 276 .cfi_def_cfa_offset STACKFRAME 277# case FFI_TYPE_SINT32 278# ifdef __LITTLE_ENDIAN__ 279 lwa %r3, RETVAL+0(%r1) 280# else 281 lwa %r3, RETVAL+4(%r1) 282# endif 283 mtlr %r0 284 addi %r1, %r1, STACKFRAME 285 .cfi_def_cfa_offset 0 286 blr 287 .cfi_def_cfa_offset STACKFRAME 288# case FFI_TYPE_UINT64 289 ld %r3, RETVAL+0(%r1) 290 mtlr %r0 291 addi %r1, %r1, STACKFRAME 292 .cfi_def_cfa_offset 0 293 blr 294 .cfi_def_cfa_offset STACKFRAME 295# case FFI_TYPE_SINT64 296 ld %r3, RETVAL+0(%r1) 297 mtlr %r0 298 addi %r1, %r1, STACKFRAME 299 .cfi_def_cfa_offset 0 300 blr 301 .cfi_def_cfa_offset STACKFRAME 302# case FFI_TYPE_STRUCT 303 mtlr %r0 304 addi %r1, %r1, STACKFRAME 305 .cfi_def_cfa_offset 0 306 blr 307 .cfi_def_cfa_offset STACKFRAME 308 nop 309# case FFI_TYPE_POINTER 310 ld %r3, RETVAL+0(%r1) 311 mtlr %r0 312 addi %r1, %r1, STACKFRAME 313 .cfi_def_cfa_offset 0 314 blr 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) 320 b .Lmorefloat 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) 326 mtlr %r0 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 333 blr 334 .cfi_def_cfa_offset STACKFRAME 335.Lmorefloat: 336 lfs %f4, RETVAL+12(%r1) 337 mtlr %r0 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 344 blr 345 .cfi_def_cfa_offset STACKFRAME 346.Lsmall: 347# ifdef __LITTLE_ENDIAN__ 348 ld %r3,RETVAL+0(%r1) 349 mtlr %r0 350 ld %r4,RETVAL+8(%r1) 351 addi %r1, %r1, STACKFRAME 352 .cfi_def_cfa_offset 0 353 blr 354# else 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? 360 neg %r5, %r3 361 ld %r3,RETVAL+0(%r1) 362 blt .Lsmalldown 363 mtlr %r0 364 ld %r4,RETVAL+8(%r1) 365 addi %r1, %r1, STACKFRAME 366 .cfi_def_cfa_offset 0 367 blr 368 .cfi_def_cfa_offset STACKFRAME 369.Lsmalldown: 370 addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7 371 mtlr %r0 372 sldi %r5, %r5, 3 373 addi %r1, %r1, STACKFRAME 374 .cfi_def_cfa_offset 0 375 srd %r3, %r3, %r5 376 blr 377# endif 378 379 .cfi_endproc 380# if _CALL_ELF == 2 381 .size ffi_closure_LINUX64,.-ffi_closure_LINUX64 382# else 383# ifdef _CALL_LINUX 384 .size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64 385# else 386 .long 0 387 .byte 0,12,0,1,128,0,0,0 388 .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 389# endif 390# endif 391 392 393 FFI_HIDDEN (ffi_go_closure_linux64) 394 .globl ffi_go_closure_linux64 395 .text 396 .cfi_startproc 397# if _CALL_ELF == 2 398ffi_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 402# else 403 .section ".opd","aw" 404 .align 3 405ffi_go_closure_linux64: 406# ifdef _CALL_LINUX 407 .quad .L.ffi_go_closure_linux64,.TOC.@tocbase,0 408 .type ffi_go_closure_linux64,@function 409 .text 410.L.ffi_go_closure_linux64: 411# else 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 417 .text 418.ffi_go_closure_linux64: 419# endif 420# endif 421 422# if _CALL_ELF == 2 423 ld %r12, 8(%r11) # closure->cif 424 mflr %r0 425 lwz %r12, 28(%r12) # cif->flags 426 mtcrf 0x40, %r12 427 addi %r12, %r1, PARMSAVE 428 bt 7, 0f 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 4330: 434 # Save general regs into parm save area 435 std %r3, 0(%r12) 436 std %r4, 8(%r12) 437 std %r5, 16(%r12) 438 std %r6, 24(%r12) 439 std %r7, 32(%r12) 440 std %r8, 40(%r12) 441 std %r9, 48(%r12) 442 std %r10, 56(%r12) 443 444 # load up the pointer to the parm save area 445 mr %r7, %r12 446# else 447 mflr %r0 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) 458 459 # load up the pointer to the parm save area 460 addi %r7, %r1, PARMSAVE 461# endif 462 std %r0, 16(%r1) 463 464 # closure->cif 465 ld %r3, 8(%r11) 466 # closure->fun 467 ld %r4, 16(%r11) 468 # user_data 469 mr %r5, %r11 470 b .Ldoclosure 471 472 .cfi_endproc 473# if _CALL_ELF == 2 474 .size ffi_go_closure_linux64,.-ffi_go_closure_linux64 475# else 476# ifdef _CALL_LINUX 477 .size ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64 478# else 479 .long 0 480 .byte 0,12,0,1,128,0,0,0 481 .size .ffi_go_closure_linux64,.-.ffi_go_closure_linux64 482# endif 483# endif 484#endif 485 486#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2 487 .section .note.GNU-stack,"",@progbits 488#endif 489