1/* ----------------------------------------------------------------------- 2 o32.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, 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 o32 */ 32 33#if defined(FFI_MIPS_O32) 34 35#define callback a0 36#define bytes a2 37#define flags a3 38 39#define SIZEOF_FRAME (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG) 40#define A3_OFF (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG) 41#define FP_OFF (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG) 42#define RA_OFF (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG) 43 44 .abicalls 45 .text 46 .align 2 47 .globl ffi_call_O32 48 .ent ffi_call_O32 49ffi_call_O32: 50$LFB0: 51 # Prologue 52 SUBU $sp, SIZEOF_FRAME # Frame size 53$LCFI00: 54 REG_S $fp, FP_OFF($sp) # Save frame pointer 55$LCFI01: 56 REG_S ra, RA_OFF($sp) # Save return address 57$LCFI02: 58 move $fp, $sp 59 60$LCFI03: 61 move t9, callback # callback function pointer 62 REG_S flags, A3_OFF($fp) # flags 63 64 # Allocate at least 4 words in the argstack 65 LI v0, 4 * FFI_SIZEOF_ARG 66 blt bytes, v0, sixteen 67 68 ADDU v0, bytes, 7 # make sure it is aligned 69 and v0, -8 # to an 8 byte boundry 70 71sixteen: 72 SUBU $sp, v0 # move the stack pointer to reflect the 73 # arg space 74 75 ADDU a0, $sp, 4 * FFI_SIZEOF_ARG 76 77 jalr t9 78 79 REG_L t0, A3_OFF($fp) # load the flags word 80 SRL t2, t0, 4 # shift our arg info 81 and t0, ((1<<4)-1) # mask out the return type 82 83 ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args 84 85#ifndef __mips_soft_float 86 bnez t0, pass_d # make it quick for int 87#endif 88 REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the 89 REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs. 90 REG_L a2, 2*FFI_SIZEOF_ARG($sp) 91 REG_L a3, 3*FFI_SIZEOF_ARG($sp) 92 b call_it 93 94#ifndef __mips_soft_float 95pass_d: 96 bne t0, FFI_ARGS_D, pass_f 97 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args 98 REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double 99 REG_L a3, 3*FFI_SIZEOF_ARG($sp) 100 b call_it 101 102pass_f: 103 bne t0, FFI_ARGS_F, pass_d_d 104 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args 105 REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float 106 REG_L a2, 2*FFI_SIZEOF_ARG($sp) 107 REG_L a3, 3*FFI_SIZEOF_ARG($sp) 108 b call_it 109 110pass_d_d: 111 bne t0, FFI_ARGS_DD, pass_f_f 112 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args 113 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles 114 b call_it 115 116pass_f_f: 117 bne t0, FFI_ARGS_FF, pass_d_f 118 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args 119 l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats 120 REG_L a2, 2*FFI_SIZEOF_ARG($sp) 121 REG_L a3, 3*FFI_SIZEOF_ARG($sp) 122 b call_it 123 124pass_d_f: 125 bne t0, FFI_ARGS_DF, pass_f_d 126 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args 127 l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float 128 REG_L a3, 3*FFI_SIZEOF_ARG($sp) 129 b call_it 130 131pass_f_d: 132 # assume that the only other combination must be float then double 133 # bne t0, FFI_ARGS_F_D, call_it 134 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args 135 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float 136#endif 137 138call_it: 139 # Load the static chain pointer 140 REG_L t7, SIZEOF_FRAME + 6*FFI_SIZEOF_ARG($fp) 141 142 # Load the function pointer 143 REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp) 144 145 # If the return value pointer is NULL, assume no return value. 146 REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) 147 beqz t1, noretval 148 149 bne t2, FFI_TYPE_INT, retlonglong 150 jalr t9 151 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) 152 REG_S v0, 0(t0) 153 b epilogue 154 155retlonglong: 156 # Really any 64-bit int, signed or not. 157 bne t2, FFI_TYPE_UINT64, retfloat 158 jalr t9 159 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) 160 REG_S v1, 4(t0) 161 REG_S v0, 0(t0) 162 b epilogue 163 164retfloat: 165 bne t2, FFI_TYPE_FLOAT, retdouble 166 jalr t9 167 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) 168#ifndef __mips_soft_float 169 s.s $f0, 0(t0) 170#else 171 REG_S v0, 0(t0) 172#endif 173 b epilogue 174 175retdouble: 176 bne t2, FFI_TYPE_DOUBLE, noretval 177 jalr t9 178 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) 179#ifndef __mips_soft_float 180 s.d $f0, 0(t0) 181#else 182 REG_S v1, 4(t0) 183 REG_S v0, 0(t0) 184#endif 185 b epilogue 186 187noretval: 188 jalr t9 189 190 # Epilogue 191epilogue: 192 move $sp, $fp 193 REG_L $fp, FP_OFF($sp) # Restore frame pointer 194 REG_L ra, RA_OFF($sp) # Restore return address 195 ADDU $sp, SIZEOF_FRAME # Fix stack pointer 196 j ra 197 198$LFE0: 199 .end ffi_call_O32 200 201 202/* ffi_closure_O32. Expects address of the passed-in ffi_closure 203 in t4 ($12). Stores any arguments passed in registers onto the 204 stack, then calls ffi_closure_mips_inner_O32, which 205 then decodes them. 206 207 Stack layout: 208 209 3 - a3 save 210 2 - a2 save 211 1 - a1 save 212 0 - a0 save, original sp 213 -1 - ra save 214 -2 - fp save 215 -3 - $16 (s0) save 216 -4 - cprestore 217 -5 - return value high (v1) 218 -6 - return value low (v0) 219 -7 - f14 (le high, be low) 220 -8 - f14 (le low, be high) 221 -9 - f12 (le high, be low) 222 -10 - f12 (le low, be high) 223 -11 - Called function a5 save 224 -12 - Called function a4 save 225 -13 - Called function a3 save 226 -14 - Called function a2 save 227 -15 - Called function a1 save 228 -16 - Called function a0 save, our sp and fp point here 229 */ 230 231#define SIZEOF_FRAME2 (16 * FFI_SIZEOF_ARG) 232#define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG) 233#define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG) 234#define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG) 235#define A0_OFF2 (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG) 236#define RA_OFF2 (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG) 237#define FP_OFF2 (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG) 238#define S0_OFF2 (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG) 239#define GP_OFF2 (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG) 240#define V1_OFF2 (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG) 241#define V0_OFF2 (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG) 242#define FA_1_1_OFF2 (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG) 243#define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG) 244#define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG) 245#define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG) 246#define CALLED_A5_OFF2 (SIZEOF_FRAME2 - 11 * FFI_SIZEOF_ARG) 247#define CALLED_A4_OFF2 (SIZEOF_FRAME2 - 12 * FFI_SIZEOF_ARG) 248 249 .text 250 251 .align 2 252 .globl ffi_go_closure_O32 253 .ent ffi_go_closure_O32 254ffi_go_closure_O32: 255$LFB1: 256 # Prologue 257 .frame $fp, SIZEOF_FRAME2, ra 258 .set noreorder 259 .cpload t9 260 .set reorder 261 SUBU $sp, SIZEOF_FRAME2 262 .cprestore GP_OFF2 263$LCFI10: 264 265 REG_S $16, S0_OFF2($sp) # Save s0 266 REG_S $fp, FP_OFF2($sp) # Save frame pointer 267 REG_S ra, RA_OFF2($sp) # Save return address 268$LCFI11: 269 270 move $fp, $sp 271$LCFI12: 272 273 REG_S a0, A0_OFF2($fp) 274 REG_S a1, A1_OFF2($fp) 275 REG_S a2, A2_OFF2($fp) 276 REG_S a3, A3_OFF2($fp) 277 278 # Load ABI enum to s0 279 REG_L $16, 4($15) # cif 280 REG_L $16, 0($16) # abi is first member. 281 282 li $13, 1 # FFI_O32 283 bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT 284 285 # Store all possible float/double registers. 286 s.d $f12, FA_0_0_OFF2($fp) 287 s.d $f14, FA_1_0_OFF2($fp) 2881: 289 # prepare arguments for ffi_closure_mips_inner_O32 290 REG_L a0, 4($15) # cif 291 REG_L a1, 8($15) # fun 292 move a2, $15 # user_data = go closure 293 addu a3, $fp, V0_OFF2 # rvalue 294 295 addu t9, $fp, A0_OFF2 # ar 296 REG_S t9, CALLED_A4_OFF2($fp) 297 298 addu t9, $fp, FA_0_0_OFF2 #fpr 299 REG_S t9, CALLED_A5_OFF2($fp) 300 301 b $do_closure 302 303$LFE1: 304 .end ffi_go_closure_O32 305 306 .align 2 307 .globl ffi_closure_O32 308 .ent ffi_closure_O32 309ffi_closure_O32: 310$LFB2: 311 # Prologue 312 .frame $fp, SIZEOF_FRAME2, ra 313 .set noreorder 314 .cpload t9 315 .set reorder 316 SUBU $sp, SIZEOF_FRAME2 317 .cprestore GP_OFF2 318$LCFI20: 319 REG_S $16, S0_OFF2($sp) # Save s0 320 REG_S $fp, FP_OFF2($sp) # Save frame pointer 321 REG_S ra, RA_OFF2($sp) # Save return address 322$LCFI21: 323 move $fp, $sp 324 325$LCFI22: 326 # Store all possible argument registers. If there are more than 327 # four arguments, then they are stored above where we put a3. 328 REG_S a0, A0_OFF2($fp) 329 REG_S a1, A1_OFF2($fp) 330 REG_S a2, A2_OFF2($fp) 331 REG_S a3, A3_OFF2($fp) 332 333 # Load ABI enum to s0 334 REG_L $16, 20($12) # cif pointer follows tramp. 335 REG_L $16, 0($16) # abi is first member. 336 337 li $13, 1 # FFI_O32 338 bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT 339 340#ifndef __mips_soft_float 341 # Store all possible float/double registers. 342 s.d $f12, FA_0_0_OFF2($fp) 343 s.d $f14, FA_1_0_OFF2($fp) 344#endif 3451: 346 # prepare arguments for ffi_closure_mips_inner_O32 347 REG_L a0, 20($12) # cif pointer follows tramp. 348 REG_L a1, 24($12) # fun 349 REG_L a2, 28($12) # user_data 350 addu a3, $fp, V0_OFF2 # rvalue 351 352 addu t9, $fp, A0_OFF2 # ar 353 REG_S t9, CALLED_A4_OFF2($fp) 354 355 addu t9, $fp, FA_0_0_OFF2 #fpr 356 REG_S t9, CALLED_A5_OFF2($fp) 357 358$do_closure: 359 la t9, ffi_closure_mips_inner_O32 360 # Call ffi_closure_mips_inner_O32 to do the work. 361 jalr t9 362 363 # Load the return value into the appropriate register. 364 move $8, $2 365 li $9, FFI_TYPE_VOID 366 beq $8, $9, closure_done 367 368 li $13, 1 # FFI_O32 369 bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT 370 371#ifndef __mips_soft_float 372 li $9, FFI_TYPE_FLOAT 373 l.s $f0, V0_OFF2($fp) 374 beq $8, $9, closure_done 375 376 li $9, FFI_TYPE_DOUBLE 377 l.d $f0, V0_OFF2($fp) 378 beq $8, $9, closure_done 379#endif 3801: 381 REG_L $3, V1_OFF2($fp) 382 REG_L $2, V0_OFF2($fp) 383 384closure_done: 385 # Epilogue 386 move $sp, $fp 387 REG_L $16, S0_OFF2($sp) # Restore s0 388 REG_L $fp, FP_OFF2($sp) # Restore frame pointer 389 REG_L ra, RA_OFF2($sp) # Restore return address 390 ADDU $sp, SIZEOF_FRAME2 391 j ra 392$LFE2: 393 .end ffi_closure_O32 394 395/* DWARF-2 unwind info. */ 396 397 .section .eh_frame,"a",@progbits 398$Lframe0: 399 .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry 400$LSCIE0: 401 .4byte 0x0 # CIE Identifier Tag 402 .byte 0x1 # CIE Version 403 .ascii "zR\0" # CIE Augmentation 404 .uleb128 0x1 # CIE Code Alignment Factor 405 .sleb128 4 # CIE Data Alignment Factor 406 .byte 0x1f # CIE RA Column 407 .uleb128 0x1 # Augmentation size 408 .byte 0x00 # FDE Encoding (absptr) 409 .byte 0xc # DW_CFA_def_cfa 410 .uleb128 0x1d 411 .uleb128 0x0 412 .align 2 413$LECIE0: 414 415$LSFDE0: 416 .4byte $LEFDE0-$LASFDE0 # FDE Length 417$LASFDE0: 418 .4byte $LASFDE0-$Lframe0 # FDE CIE offset 419 .4byte $LFB0 # FDE initial location 420 .4byte $LFE0-$LFB0 # FDE address range 421 .uleb128 0x0 # Augmentation size 422 .byte 0x4 # DW_CFA_advance_loc4 423 .4byte $LCFI00-$LFB0 424 .byte 0xe # DW_CFA_def_cfa_offset 425 .uleb128 0x18 426 .byte 0x4 # DW_CFA_advance_loc4 427 .4byte $LCFI01-$LCFI00 428 .byte 0x11 # DW_CFA_offset_extended_sf 429 .uleb128 0x1e # $fp 430 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) 431 .byte 0x11 # DW_CFA_offset_extended_sf 432 .uleb128 0x1f # $ra 433 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) 434 .byte 0x4 # DW_CFA_advance_loc4 435 .4byte $LCFI02-$LCFI01 436 .byte 0xc # DW_CFA_def_cfa 437 .uleb128 0x1e 438 .uleb128 0x18 439 .align 2 440$LEFDE0: 441 442$LSFDE1: 443 .4byte $LEFDE1-$LASFDE1 # FDE Length 444$LASFDE1: 445 .4byte $LASFDE1-$Lframe0 # FDE CIE offset 446 .4byte $LFB1 # FDE initial location 447 .4byte $LFE1-$LFB1 # FDE address range 448 .uleb128 0x0 # Augmentation size 449 .byte 0x4 # DW_CFA_advance_loc4 450 .4byte $LCFI10-$LFB1 451 .byte 0xe # DW_CFA_def_cfa_offset 452 .uleb128 SIZEOF_FRAME2 453 .byte 0x4 # DW_CFA_advance_loc4 454 .4byte $LCFI11-$LCFI10 455 .byte 0x11 # DW_CFA_offset_extended_sf 456 .uleb128 0x10 # $16 457 .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp) 458 .byte 0x11 # DW_CFA_offset_extended_sf 459 .uleb128 0x1e # $fp 460 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) 461 .byte 0x11 # DW_CFA_offset_extended_sf 462 .uleb128 0x1f # $ra 463 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) 464 .byte 0x4 # DW_CFA_advance_loc4 465 .4byte $LCFI12-$LCFI11 466 .byte 0xc # DW_CFA_def_cfa 467 .uleb128 0x1e 468 .uleb128 SIZEOF_FRAME2 469 .align 2 470$LEFDE1: 471 472$LSFDE2: 473 .4byte $LEFDE2-$LASFDE2 # FDE Length 474$LASFDE2: 475 .4byte $LASFDE2-$Lframe0 # FDE CIE offset 476 .4byte $LFB2 # FDE initial location 477 .4byte $LFE2-$LFB2 # FDE address range 478 .uleb128 0x0 # Augmentation size 479 .byte 0x4 # DW_CFA_advance_loc4 480 .4byte $LCFI20-$LFB2 481 .byte 0xe # DW_CFA_def_cfa_offset 482 .uleb128 SIZEOF_FRAME2 483 .byte 0x4 # DW_CFA_advance_loc4 484 .4byte $LCFI21-$LCFI20 485 .byte 0x11 # DW_CFA_offset_extended_sf 486 .uleb128 0x10 # $16 487 .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp) 488 .byte 0x11 # DW_CFA_offset_extended_sf 489 .uleb128 0x1e # $fp 490 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) 491 .byte 0x11 # DW_CFA_offset_extended_sf 492 .uleb128 0x1f # $ra 493 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) 494 .byte 0x4 # DW_CFA_advance_loc4 495 .4byte $LCFI22-$LCFI21 496 .byte 0xc # DW_CFA_def_cfa 497 .uleb128 0x1e 498 .uleb128 SIZEOF_FRAME2 499 .align 2 500$LEFDE2: 501 502#endif 503