1/* ----------------------------------------------------------------------- 2 n32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc. 3 4 MIPS Foreign Function Interface 5 6 Permission is hereby granted, free of charge, to any person obtaining 7 a copy of this software and associated documentation files (the 8 ``Software''), to deal in the Software without restriction, including 9 without limitation the rights to use, copy, modify, merge, publish, 10 distribute, sublicense, and/or sell copies of the Software, and to 11 permit persons to whom the Software is furnished to do so, subject to 12 the following conditions: 13 14 The above copyright notice and this permission notice shall be included 15 in all copies or substantial portions of the Software. 16 17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 21 ANY CLAIM, DAMAGES OR 22 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 OTHER DEALINGS IN THE SOFTWARE. 25 ----------------------------------------------------------------------- */ 26 27#define LIBFFI_ASM 28#include <fficonfig.h> 29#include <ffi.h> 30 31/* Only build this code if we are compiling for n32 */ 32 33#if defined(FFI_MIPS_N32) 34 35#define callback a0 36#define bytes a2 37#define flags a3 38#define raddr a4 39#define fn a5 40 41#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG ) 42 43 .abicalls 44 .text 45 .align 2 46 .globl ffi_call_N32 47 .ent ffi_call_N32 48ffi_call_N32: 49.LFB3: 50 .frame $fp, SIZEOF_FRAME, ra 51 .mask 0xc0000000,-FFI_SIZEOF_ARG 52 .fmask 0x00000000,0 53 54 # Prologue 55 SUBU $sp, SIZEOF_FRAME # Frame size 56.LCFI0: 57 REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer 58 REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address 59.LCFI1: 60 move $fp, $sp 61.LCFI3: 62 move t9, callback # callback function pointer 63 REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes 64 REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags 65 REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr 66 REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn 67 68 # Allocate at least 4 words in the argstack 69 move v0, bytes 70 bge bytes, 4 * FFI_SIZEOF_ARG, bigger 71 LI v0, 4 * FFI_SIZEOF_ARG 72 b sixteen 73 74 bigger: 75 ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned 76 and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry. 77 78sixteen: 79 SUBU $sp, $sp, v0 # move the stack pointer to reflect the 80 # arg space 81 82 move a0, $sp # 4 * FFI_SIZEOF_ARG 83 ADDU a3, $fp, 3 * FFI_SIZEOF_ARG 84 85 # Call ffi_prep_args 86 jal t9 87 88 # Copy the stack pointer to t9 89 move t9, $sp 90 91 # Fix the stack if there are more than 8 64bit slots worth 92 # of arguments. 93 94 # Load the number of bytes 95 REG_L t6, 2*FFI_SIZEOF_ARG($fp) 96 97 # Is it bigger than 8 * FFI_SIZEOF_ARG? 98 daddiu t8, t6, -(8 * FFI_SIZEOF_ARG) 99 bltz t8, loadregs 100 101 ADDU t9, t9, t8 102 103loadregs: 104 105 REG_L t6, 3*FFI_SIZEOF_ARG($fp) # load the flags word into t6. 106 107 and t4, t6, ((1<<FFI_FLAG_BITS)-1) 108 bnez t4, arg1_floatp 109 REG_L a0, 0*FFI_SIZEOF_ARG(t9) 110 b arg1_next 111arg1_floatp: 112 bne t4, FFI_TYPE_FLOAT, arg1_doublep 113 l.s $f12, 0*FFI_SIZEOF_ARG(t9) 114 b arg1_next 115arg1_doublep: 116 l.d $f12, 0*FFI_SIZEOF_ARG(t9) 117arg1_next: 118 119 SRL t4, t6, 1*FFI_FLAG_BITS 120 and t4, ((1<<FFI_FLAG_BITS)-1) 121 bnez t4, arg2_floatp 122 REG_L a1, 1*FFI_SIZEOF_ARG(t9) 123 b arg2_next 124arg2_floatp: 125 bne t4, FFI_TYPE_FLOAT, arg2_doublep 126 l.s $f13, 1*FFI_SIZEOF_ARG(t9) 127 b arg2_next 128arg2_doublep: 129 l.d $f13, 1*FFI_SIZEOF_ARG(t9) 130arg2_next: 131 132 SRL t4, t6, 2*FFI_FLAG_BITS 133 and t4, ((1<<FFI_FLAG_BITS)-1) 134 bnez t4, arg3_floatp 135 REG_L a2, 2*FFI_SIZEOF_ARG(t9) 136 b arg3_next 137arg3_floatp: 138 bne t4, FFI_TYPE_FLOAT, arg3_doublep 139 l.s $f14, 2*FFI_SIZEOF_ARG(t9) 140 b arg3_next 141arg3_doublep: 142 l.d $f14, 2*FFI_SIZEOF_ARG(t9) 143arg3_next: 144 145 SRL t4, t6, 3*FFI_FLAG_BITS 146 and t4, ((1<<FFI_FLAG_BITS)-1) 147 bnez t4, arg4_floatp 148 REG_L a3, 3*FFI_SIZEOF_ARG(t9) 149 b arg4_next 150arg4_floatp: 151 bne t4, FFI_TYPE_FLOAT, arg4_doublep 152 l.s $f15, 3*FFI_SIZEOF_ARG(t9) 153 b arg4_next 154arg4_doublep: 155 l.d $f15, 3*FFI_SIZEOF_ARG(t9) 156arg4_next: 157 158 SRL t4, t6, 4*FFI_FLAG_BITS 159 and t4, ((1<<FFI_FLAG_BITS)-1) 160 bnez t4, arg5_floatp 161 REG_L a4, 4*FFI_SIZEOF_ARG(t9) 162 b arg5_next 163arg5_floatp: 164 bne t4, FFI_TYPE_FLOAT, arg5_doublep 165 l.s $f16, 4*FFI_SIZEOF_ARG(t9) 166 b arg5_next 167arg5_doublep: 168 l.d $f16, 4*FFI_SIZEOF_ARG(t9) 169arg5_next: 170 171 SRL t4, t6, 5*FFI_FLAG_BITS 172 and t4, ((1<<FFI_FLAG_BITS)-1) 173 bnez t4, arg6_floatp 174 REG_L a5, 5*FFI_SIZEOF_ARG(t9) 175 b arg6_next 176arg6_floatp: 177 bne t4, FFI_TYPE_FLOAT, arg6_doublep 178 l.s $f17, 5*FFI_SIZEOF_ARG(t9) 179 b arg6_next 180arg6_doublep: 181 l.d $f17, 5*FFI_SIZEOF_ARG(t9) 182arg6_next: 183 184 SRL t4, t6, 6*FFI_FLAG_BITS 185 and t4, ((1<<FFI_FLAG_BITS)-1) 186 bnez t4, arg7_floatp 187 REG_L a6, 6*FFI_SIZEOF_ARG(t9) 188 b arg7_next 189arg7_floatp: 190 bne t4, FFI_TYPE_FLOAT, arg7_doublep 191 l.s $f18, 6*FFI_SIZEOF_ARG(t9) 192 b arg7_next 193arg7_doublep: 194 l.d $f18, 6*FFI_SIZEOF_ARG(t9) 195arg7_next: 196 197 SRL t4, t6, 7*FFI_FLAG_BITS 198 and t4, ((1<<FFI_FLAG_BITS)-1) 199 bnez t4, arg8_floatp 200 REG_L a7, 7*FFI_SIZEOF_ARG(t9) 201 b arg8_next 202arg8_floatp: 203 bne t4, FFI_TYPE_FLOAT, arg8_doublep 204 l.s $f19, 7*FFI_SIZEOF_ARG(t9) 205 b arg8_next 206arg8_doublep: 207 l.d $f19, 7*FFI_SIZEOF_ARG(t9) 208arg8_next: 209 210callit: 211 # Load the function pointer 212 REG_L t9, 5*FFI_SIZEOF_ARG($fp) 213 214 # If the return value pointer is NULL, assume no return value. 215 REG_L t5, 4*FFI_SIZEOF_ARG($fp) 216 beqz t5, noretval 217 218 # Shift the return type flag over 219 SRL t6, 8*FFI_FLAG_BITS 220 221 bne t6, FFI_TYPE_INT, retfloat 222 jal t9 223 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 224 REG_S v0, 0(t4) 225 b epilogue 226 227retfloat: 228 bne t6, FFI_TYPE_FLOAT, retdouble 229 jal t9 230 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 231 s.s $f0, 0(t4) 232 b epilogue 233 234retdouble: 235 bne t6, FFI_TYPE_DOUBLE, retstruct_d 236 jal t9 237 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 238 s.d $f0, 0(t4) 239 b epilogue 240 241retstruct_d: 242 bne t6, FFI_TYPE_STRUCT_D, retstruct_f 243 jal t9 244 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 245 s.d $f0, 0(t4) 246 b epilogue 247 248retstruct_f: 249 bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d 250 jal t9 251 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 252 s.s $f0, 0(t4) 253 b epilogue 254 255retstruct_d_d: 256 bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f 257 jal t9 258 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 259 s.d $f0, 0(t4) 260 s.d $f2, 8(t4) 261 b epilogue 262 263retstruct_f_f: 264 bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f 265 jal t9 266 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 267 s.s $f0, 0(t4) 268 s.s $f2, 4(t4) 269 b epilogue 270 271retstruct_d_f: 272 bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d 273 jal t9 274 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 275 s.d $f0, 0(t4) 276 s.s $f2, 8(t4) 277 b epilogue 278 279retstruct_f_d: 280 bne t6, FFI_TYPE_STRUCT_FD, retstruct_small 281 jal t9 282 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 283 s.s $f0, 0(t4) 284 s.d $f2, 8(t4) 285 b epilogue 286 287retstruct_small: 288 bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2 289 jal t9 290 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 291 REG_S v0, 0(t4) 292 b epilogue 293 294retstruct_small2: 295 bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct 296 jal t9 297 REG_L t4, 4*FFI_SIZEOF_ARG($fp) 298 REG_S v0, 0(t4) 299 REG_S v1, 8(t4) 300 b epilogue 301 302retstruct: 303noretval: 304 jal t9 305 306 # Epilogue 307epilogue: 308 move $sp, $fp 309 REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer 310 REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address 311 ADDU $sp, SIZEOF_FRAME # Fix stack pointer 312 j ra 313 314.LFE3: 315 .end ffi_call_N32 316 317/* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0 318 ($12). Stores any arguments passed in registers onto the stack, 319 then calls ffi_closure_mips_inner_N32, which then decodes 320 them. 321 322 Stack layout: 323 324 20 - Start of parameters, original sp 325 19 - Called function a7 save 326 18 - Called function a6 save 327 17 - Called function a5 save 328 16 - Called function a4 save 329 15 - Called function a3 save 330 14 - Called function a2 save 331 13 - Called function a1 save 332 12 - Called function a0 save 333 11 - Called function f19 334 10 - Called function f18 335 9 - Called function f17 336 8 - Called function f16 337 7 - Called function f15 338 6 - Called function f14 339 5 - Called function f13 340 4 - Called function f12 341 3 - return value high (v1 or $f2) 342 2 - return value low (v0 or $f0) 343 1 - ra save 344 0 - gp save our sp points here 345 */ 346 347#define SIZEOF_FRAME2 (20 * FFI_SIZEOF_ARG) 348 349#define A7_OFF2 (19 * FFI_SIZEOF_ARG) 350#define A6_OFF2 (18 * FFI_SIZEOF_ARG) 351#define A5_OFF2 (17 * FFI_SIZEOF_ARG) 352#define A4_OFF2 (16 * FFI_SIZEOF_ARG) 353#define A3_OFF2 (15 * FFI_SIZEOF_ARG) 354#define A2_OFF2 (14 * FFI_SIZEOF_ARG) 355#define A1_OFF2 (13 * FFI_SIZEOF_ARG) 356#define A0_OFF2 (12 * FFI_SIZEOF_ARG) 357 358#define F19_OFF2 (11 * FFI_SIZEOF_ARG) 359#define F18_OFF2 (10 * FFI_SIZEOF_ARG) 360#define F17_OFF2 (9 * FFI_SIZEOF_ARG) 361#define F16_OFF2 (8 * FFI_SIZEOF_ARG) 362#define F15_OFF2 (7 * FFI_SIZEOF_ARG) 363#define F14_OFF2 (6 * FFI_SIZEOF_ARG) 364#define F13_OFF2 (5 * FFI_SIZEOF_ARG) 365#define F12_OFF2 (4 * FFI_SIZEOF_ARG) 366 367#define V1_OFF2 (3 * FFI_SIZEOF_ARG) 368#define V0_OFF2 (2 * FFI_SIZEOF_ARG) 369 370#define RA_OFF2 (1 * FFI_SIZEOF_ARG) 371#define GP_OFF2 (0 * FFI_SIZEOF_ARG) 372 373 .align 2 374 .globl ffi_closure_N32 375 .ent ffi_closure_N32 376ffi_closure_N32: 377.LFB2: 378 .frame $sp, SIZEOF_FRAME2, ra 379 .mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2) 380 .fmask 0x00000000,0 381 SUBU $sp, SIZEOF_FRAME2 382.LCFI5: 383 .cpsetup t9, GP_OFF2, ffi_closure_N32 384 REG_S ra, RA_OFF2($sp) # Save return address 385.LCFI6: 386 # Store all possible argument registers. If there are more than 387 # fit in registers, then they were stored on the stack. 388 REG_S a0, A0_OFF2($sp) 389 REG_S a1, A1_OFF2($sp) 390 REG_S a2, A2_OFF2($sp) 391 REG_S a3, A3_OFF2($sp) 392 REG_S a4, A4_OFF2($sp) 393 REG_S a5, A5_OFF2($sp) 394 REG_S a6, A6_OFF2($sp) 395 REG_S a7, A7_OFF2($sp) 396 397 # Store all possible float/double registers. 398 s.d $f12, F12_OFF2($sp) 399 s.d $f13, F13_OFF2($sp) 400 s.d $f14, F14_OFF2($sp) 401 s.d $f15, F15_OFF2($sp) 402 s.d $f16, F16_OFF2($sp) 403 s.d $f17, F17_OFF2($sp) 404 s.d $f18, F18_OFF2($sp) 405 s.d $f19, F19_OFF2($sp) 406 407 # Call ffi_closure_mips_inner_N32 to do the real work. 408 LA t9, ffi_closure_mips_inner_N32 409 move a0, $12 # Pointer to the ffi_closure 410 ADDU a1, $sp, V0_OFF2 411 ADDU a2, $sp, A0_OFF2 412 ADDU a3, $sp, F12_OFF2 413 jalr t9 414 415 # Return flags are in v0 416 bne v0, FFI_TYPE_INT, cls_retfloat 417 REG_L v0, V0_OFF2($sp) 418 b cls_epilogue 419 420cls_retfloat: 421 bne v0, FFI_TYPE_FLOAT, cls_retdouble 422 l.s $f0, V0_OFF2($sp) 423 b cls_epilogue 424 425cls_retdouble: 426 bne v0, FFI_TYPE_DOUBLE, cls_retstruct_d 427 l.d $f0, V0_OFF2($sp) 428 b cls_epilogue 429 430cls_retstruct_d: 431 bne v0, FFI_TYPE_STRUCT_D, cls_retstruct_f 432 l.d $f0, V0_OFF2($sp) 433 b cls_epilogue 434 435cls_retstruct_f: 436 bne v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d 437 l.s $f0, V0_OFF2($sp) 438 b cls_epilogue 439 440cls_retstruct_d_d: 441 bne v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f 442 l.d $f0, V0_OFF2($sp) 443 l.d $f2, V1_OFF2($sp) 444 b cls_epilogue 445 446cls_retstruct_f_f: 447 bne v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f 448 l.s $f0, V0_OFF2($sp) 449 l.s $f2, V1_OFF2($sp) 450 b cls_epilogue 451 452cls_retstruct_d_f: 453 bne v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d 454 l.d $f0, V0_OFF2($sp) 455 l.s $f2, V1_OFF2($sp) 456 b cls_epilogue 457 458cls_retstruct_f_d: 459 bne v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2 460 l.s $f0, V0_OFF2($sp) 461 l.d $f2, V1_OFF2($sp) 462 b cls_epilogue 463 464cls_retstruct_small2: 465 REG_L v0, V0_OFF2($sp) 466 REG_L v1, V1_OFF2($sp) 467 468 # Epilogue 469cls_epilogue: 470 REG_L ra, RA_OFF2($sp) # Restore return address 471 .cpreturn 472 ADDU $sp, SIZEOF_FRAME2 473 j ra 474.LFE2: 475 .end ffi_closure_N32 476 477 .section .eh_frame,"aw",@progbits 478.Lframe1: 479 .4byte .LECIE1-.LSCIE1 # length 480.LSCIE1: 481 .4byte 0x0 # CIE 482 .byte 0x1 # Version 1 483 .ascii "\000" # Augmentation 484 .uleb128 0x1 # Code alignment 1 485 .sleb128 -4 # Data alignment -4 486 .byte 0x1f # Return Address $31 487 .byte 0xc # DW_CFA_def_cfa 488 .uleb128 0x1d # in $sp 489 .uleb128 0x0 # offset 0 490 .align EH_FRAME_ALIGN 491.LECIE1: 492 493.LSFDE1: 494 .4byte .LEFDE1-.LASFDE1 # length. 495.LASFDE1: 496 .4byte .LASFDE1-.Lframe1 # CIE_pointer. 497 FDE_ADDR_BYTES .LFB3 # initial_location. 498 FDE_ADDR_BYTES .LFE3-.LFB3 # address_range. 499 .byte 0x4 # DW_CFA_advance_loc4 500 .4byte .LCFI0-.LFB3 # to .LCFI0 501 .byte 0xe # DW_CFA_def_cfa_offset 502 .uleb128 SIZEOF_FRAME # adjust stack.by SIZEOF_FRAME 503 .byte 0x4 # DW_CFA_advance_loc4 504 .4byte .LCFI1-.LCFI0 # to .LCFI1 505 .byte 0x9e # DW_CFA_offset of $fp 506 .uleb128 2*FFI_SIZEOF_ARG/4 # 507 .byte 0x9f # DW_CFA_offset of ra 508 .uleb128 1*FFI_SIZEOF_ARG/4 # 509 .byte 0x4 # DW_CFA_advance_loc4 510 .4byte .LCFI3-.LCFI1 # to .LCFI3 511 .byte 0xd # DW_CFA_def_cfa_register 512 .uleb128 0x1e # in $fp 513 .align EH_FRAME_ALIGN 514.LEFDE1: 515.LSFDE3: 516 .4byte .LEFDE3-.LASFDE3 # length 517.LASFDE3: 518 .4byte .LASFDE3-.Lframe1 # CIE_pointer. 519 FDE_ADDR_BYTES .LFB2 # initial_location. 520 FDE_ADDR_BYTES .LFE2-.LFB2 # address_range. 521 .byte 0x4 # DW_CFA_advance_loc4 522 .4byte .LCFI5-.LFB2 # to .LCFI5 523 .byte 0xe # DW_CFA_def_cfa_offset 524 .uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME 525 .byte 0x4 # DW_CFA_advance_loc4 526 .4byte .LCFI6-.LCFI5 # to .LCFI6 527 .byte 0x9c # DW_CFA_offset of $gp ($28) 528 .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4 529 .byte 0x9f # DW_CFA_offset of ra ($31) 530 .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4 531 .align EH_FRAME_ALIGN 532.LEFDE3: 533 534#endif 535