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