1 /* ----------------------------------------------------------------------- 2 sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub (at) 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 # if _CALL_ELF == 2 37 .text 38 ffi_closure_LINUX64: 39 addis %r2, %r12, .TOC.-ffi_closure_LINUX64@ha 40 addi %r2, %r2, .TOC.-ffi_closure_LINUX64@l 41 .localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64 42 # else 43 .section ".opd","aw" 44 .align 3 45 ffi_closure_LINUX64: 46 # ifdef _CALL_LINUX 47 .quad .L.ffi_closure_LINUX64,.TOC.@tocbase,0 48 .type ffi_closure_LINUX64,@function 49 .text 50 .L.ffi_closure_LINUX64: 51 # else 52 FFI_HIDDEN (.ffi_closure_LINUX64) 53 .globl .ffi_closure_LINUX64 54 .quad .ffi_closure_LINUX64,.TOC.@tocbase,0 55 .size ffi_closure_LINUX64,24 56 .type .ffi_closure_LINUX64,@function 57 .text 58 .ffi_closure_LINUX64: 59 # endif 60 # endif 61 62 # if _CALL_ELF == 2 63 # 32 byte special reg save area + 64 byte parm save area 64 # + 64 byte retval area + 13*8 fpr save area + round to 16 65 # define STACKFRAME 272 66 # define PARMSAVE 32 67 # define RETVAL PARMSAVE+64 68 # else 69 # 48 bytes special reg save area + 64 bytes parm save area 70 # + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 71 # define STACKFRAME 240 72 # define PARMSAVE 48 73 # define RETVAL PARMSAVE+64 74 # endif 75 76 .LFB1: 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, .Lparmsave 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 88 .Lparmsave: 89 std %r0, 16(%r1) 90 # Save general regs into parm save area 91 std %r3, 0(%r12) 92 std %r4, 8(%r12) 93 std %r5, 16(%r12) 94 std %r6, 24(%r12) 95 std %r7, 32(%r12) 96 std %r8, 40(%r12) 97 std %r9, 48(%r12) 98 std %r10, 56(%r12) 99 100 # load up the pointer to the parm save area 101 mr %r5, %r12 102 # else 103 # copy r2 to r11 and load TOC into r2 104 mr %r11, %r2 105 ld %r2, 16(%r11) 106 107 mflr %r0 108 # Save general regs into parm save area 109 # This is the parameter save area set up by our caller. 110 std %r3, PARMSAVE+0(%r1) 111 std %r4, PARMSAVE+8(%r1) 112 std %r5, PARMSAVE+16(%r1) 113 std %r6, PARMSAVE+24(%r1) 114 std %r7, PARMSAVE+32(%r1) 115 std %r8, PARMSAVE+40(%r1) 116 std %r9, PARMSAVE+48(%r1) 117 std %r10, PARMSAVE+56(%r1) 118 119 std %r0, 16(%r1) 120 121 # load up the pointer to the parm save area 122 addi %r5, %r1, PARMSAVE 123 # endif 124 125 # next save fpr 1 to fpr 13 126 stfd %f1, -104+(0*8)(%r1) 127 stfd %f2, -104+(1*8)(%r1) 128 stfd %f3, -104+(2*8)(%r1) 129 stfd %f4, -104+(3*8)(%r1) 130 stfd %f5, -104+(4*8)(%r1) 131 stfd %f6, -104+(5*8)(%r1) 132 stfd %f7, -104+(6*8)(%r1) 133 stfd %f8, -104+(7*8)(%r1) 134 stfd %f9, -104+(8*8)(%r1) 135 stfd %f10, -104+(9*8)(%r1) 136 stfd %f11, -104+(10*8)(%r1) 137 stfd %f12, -104+(11*8)(%r1) 138 stfd %f13, -104+(12*8)(%r1) 139 140 # load up the pointer to the saved fpr registers */ 141 addi %r6, %r1, -104 142 143 # load up the pointer to the result storage 144 addi %r4, %r1, -STACKFRAME+RETVAL 145 146 stdu %r1, -STACKFRAME(%r1) 147 .LCFI0: 148 149 # get the context pointer from the trampoline 150 mr %r3, %r11 151 152 # make the call 153 # if defined _CALL_LINUX || _CALL_ELF == 2 154 bl ffi_closure_helper_LINUX64 155 # else 156 bl .ffi_closure_helper_LINUX64 157 # endif 158 .Lret: 159 160 # now r3 contains the return type 161 # so use it to look up in a table 162 # so we know how to deal with each type 163 164 # look up the proper starting point in table 165 # by using return type as offset 166 ld %r0, STACKFRAME+16(%r1) 167 cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT 168 bge .Lsmall 169 mflr %r4 # move address of .Lret to r4 170 sldi %r3, %r3, 4 # now multiply return type by 16 171 addi %r4, %r4, .Lret_type0 - .Lret 172 add %r3, %r3, %r4 # add contents of table to table address 173 mtctr %r3 174 bctr # jump to it 175 176 # Each of the ret_typeX code fragments has to be exactly 16 bytes long 177 # (4 instructions). For cache effectiveness we align to a 16 byte boundary 178 # first. 179 .align 4 180 181 .Lret_type0: 182 # case FFI_TYPE_VOID 183 mtlr %r0 184 addi %r1, %r1, STACKFRAME 185 blr 186 nop 187 # case FFI_TYPE_INT 188 # ifdef __LITTLE_ENDIAN__ 189 lwa %r3, RETVAL+0(%r1) 190 # else 191 lwa %r3, RETVAL+4(%r1) 192 # endif 193 mtlr %r0 194 addi %r1, %r1, STACKFRAME 195 blr 196 # case FFI_TYPE_FLOAT 197 lfs %f1, RETVAL+0(%r1) 198 mtlr %r0 199 addi %r1, %r1, STACKFRAME 200 blr 201 # case FFI_TYPE_DOUBLE 202 lfd %f1, RETVAL+0(%r1) 203 mtlr %r0 204 addi %r1, %r1, STACKFRAME 205 blr 206 # case FFI_TYPE_LONGDOUBLE 207 lfd %f1, RETVAL+0(%r1) 208 mtlr %r0 209 lfd %f2, RETVAL+8(%r1) 210 b .Lfinish 211 # case FFI_TYPE_UINT8 212 # ifdef __LITTLE_ENDIAN__ 213 lbz %r3, RETVAL+0(%r1) 214 # else 215 lbz %r3, RETVAL+7(%r1) 216 # endif 217 mtlr %r0 218 addi %r1, %r1, STACKFRAME 219 blr 220 # case FFI_TYPE_SINT8 221 # ifdef __LITTLE_ENDIAN__ 222 lbz %r3, RETVAL+0(%r1) 223 # else 224 lbz %r3, RETVAL+7(%r1) 225 # endif 226 extsb %r3,%r3 227 mtlr %r0 228 b .Lfinish 229 # case FFI_TYPE_UINT16 230 # ifdef __LITTLE_ENDIAN__ 231 lhz %r3, RETVAL+0(%r1) 232 # else 233 lhz %r3, RETVAL+6(%r1) 234 # endif 235 mtlr %r0 236 .Lfinish: 237 addi %r1, %r1, STACKFRAME 238 blr 239 # case FFI_TYPE_SINT16 240 # ifdef __LITTLE_ENDIAN__ 241 lha %r3, RETVAL+0(%r1) 242 # else 243 lha %r3, RETVAL+6(%r1) 244 # endif 245 mtlr %r0 246 addi %r1, %r1, STACKFRAME 247 blr 248 # case FFI_TYPE_UINT32 249 # ifdef __LITTLE_ENDIAN__ 250 lwz %r3, RETVAL+0(%r1) 251 # else 252 lwz %r3, RETVAL+4(%r1) 253 # endif 254 mtlr %r0 255 addi %r1, %r1, STACKFRAME 256 blr 257 # case FFI_TYPE_SINT32 258 # ifdef __LITTLE_ENDIAN__ 259 lwa %r3, RETVAL+0(%r1) 260 # else 261 lwa %r3, RETVAL+4(%r1) 262 # endif 263 mtlr %r0 264 addi %r1, %r1, STACKFRAME 265 blr 266 # case FFI_TYPE_UINT64 267 ld %r3, RETVAL+0(%r1) 268 mtlr %r0 269 addi %r1, %r1, STACKFRAME 270 blr 271 # case FFI_TYPE_SINT64 272 ld %r3, RETVAL+0(%r1) 273 mtlr %r0 274 addi %r1, %r1, STACKFRAME 275 blr 276 # case FFI_TYPE_STRUCT 277 mtlr %r0 278 addi %r1, %r1, STACKFRAME 279 blr 280 nop 281 # case FFI_TYPE_POINTER 282 ld %r3, RETVAL+0(%r1) 283 mtlr %r0 284 addi %r1, %r1, STACKFRAME 285 blr 286 # case FFI_V2_TYPE_FLOAT_HOMOG 287 lfs %f1, RETVAL+0(%r1) 288 lfs %f2, RETVAL+4(%r1) 289 lfs %f3, RETVAL+8(%r1) 290 b .Lmorefloat 291 # case FFI_V2_TYPE_DOUBLE_HOMOG 292 lfd %f1, RETVAL+0(%r1) 293 lfd %f2, RETVAL+8(%r1) 294 lfd %f3, RETVAL+16(%r1) 295 lfd %f4, RETVAL+24(%r1) 296 mtlr %r0 297 lfd %f5, RETVAL+32(%r1) 298 lfd %f6, RETVAL+40(%r1) 299 lfd %f7, RETVAL+48(%r1) 300 lfd %f8, RETVAL+56(%r1) 301 addi %r1, %r1, STACKFRAME 302 blr 303 .Lmorefloat: 304 lfs %f4, RETVAL+12(%r1) 305 mtlr %r0 306 lfs %f5, RETVAL+16(%r1) 307 lfs %f6, RETVAL+20(%r1) 308 lfs %f7, RETVAL+24(%r1) 309 lfs %f8, RETVAL+28(%r1) 310 addi %r1, %r1, STACKFRAME 311 blr 312 .Lsmall: 313 # ifdef __LITTLE_ENDIAN__ 314 ld %r3,RETVAL+0(%r1) 315 mtlr %r0 316 ld %r4,RETVAL+8(%r1) 317 addi %r1, %r1, STACKFRAME 318 blr 319 # else 320 # A struct smaller than a dword is returned in the low bits of r3 321 # ie. right justified. Larger structs are passed left justified 322 # in r3 and r4. The return value area on the stack will have 323 # the structs as they are usually stored in memory. 324 cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes? 325 neg %r5, %r3 326 ld %r3,RETVAL+0(%r1) 327 blt .Lsmalldown 328 mtlr %r0 329 ld %r4,RETVAL+8(%r1) 330 addi %r1, %r1, STACKFRAME 331 blr 332 .Lsmalldown: 333 addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7 334 mtlr %r0 335 sldi %r5, %r5, 3 336 addi %r1, %r1, STACKFRAME 337 srd %r3, %r3, %r5 338 blr 339 # endif 340 341 .LFE1: 342 .long 0 343 .byte 0,12,0,1,128,0,0,0 344 # if _CALL_ELF == 2 345 .size ffi_closure_LINUX64,.-ffi_closure_LINUX64 346 # else 347 # ifdef _CALL_LINUX 348 .size ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64 349 # else 350 .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 351 # endif 352 # endif 353 354 .section .eh_frame,EH_FRAME_FLAGS,@progbits 355 .Lframe1: 356 .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry 357 .LSCIE1: 358 .4byte 0x0 # CIE Identifier Tag 359 .byte 0x1 # CIE Version 360 .ascii "zR\0" # CIE Augmentation 361 .uleb128 0x1 # CIE Code Alignment Factor 362 .sleb128 -8 # CIE Data Alignment Factor 363 .byte 0x41 # CIE RA Column 364 .uleb128 0x1 # Augmentation size 365 .byte 0x14 # FDE Encoding (pcrel udata8) 366 .byte 0xc # DW_CFA_def_cfa 367 .uleb128 0x1 368 .uleb128 0x0 369 .align 3 370 .LECIE1: 371 .LSFDE1: 372 .4byte .LEFDE1-.LASFDE1 # FDE Length 373 .LASFDE1: 374 .4byte .LASFDE1-.Lframe1 # FDE CIE offset 375 .8byte .LFB1-. # FDE initial location 376 .8byte .LFE1-.LFB1 # FDE address range 377 .uleb128 0x0 # Augmentation size 378 .byte 0x2 # DW_CFA_advance_loc1 379 .byte .LCFI0-.LFB1 380 .byte 0xe # DW_CFA_def_cfa_offset 381 .uleb128 STACKFRAME 382 .byte 0x11 # DW_CFA_offset_extended_sf 383 .uleb128 0x41 384 .sleb128 -2 385 .align 3 386 .LEFDE1: 387 388 # if defined __ELF__ && defined __linux__ 389 .section .note.GNU-stack,"",@progbits 390 # endif 391 #endif 392