1 /* -----------------------------------------------------------------------
2 o32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc.
4 MIPS Foreign Function Interface
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:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
28 #include <fficonfig.h>
31 /* Only build this code if we are compiling for o32 */
33 #if defined(FFI_MIPS_O32)
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)
52 SUBU $sp, SIZEOF_FRAME # Frame size
54 REG_S $fp, FP_OFF($sp) # Save frame pointer
56 REG_S ra, RA_OFF($sp) # Save return address
61 move t9, callback # callback function pointer
62 REG_S flags, A3_OFF($fp) # flags
64 # Allocate at least 4 words in the argstack
65 LI v0, 4 * FFI_SIZEOF_ARG
66 blt bytes, v0, sixteen
68 ADDU v0, bytes, 7 # make sure it is aligned
69 and v0, -8 # to an 8 byte boundry
72 SUBU $sp, v0 # move the stack pointer to reflect the
75 ADDU a0, $sp, 4 * FFI_SIZEOF_ARG
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
83 ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
85 #ifndef __mips_soft_float
86 bnez t0, pass_d # make it quick for int
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)
94 #ifndef __mips_soft_float
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)
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)
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
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)
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)
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
139 # Load the static chain pointer
140 REG_L t7, SIZEOF_FRAME + 6*FFI_SIZEOF_ARG($fp)
142 # Load the function pointer
143 REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
145 # If the return value pointer is NULL, assume no return value.
146 REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
149 bne t2, FFI_TYPE_INT, retlonglong
151 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
156 # Really any 64-bit int, signed or not.
157 bne t2, FFI_TYPE_UINT64, retfloat
159 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
165 bne t2, FFI_TYPE_FLOAT, retdouble
167 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
168 #ifndef __mips_soft_float
176 bne t2, FFI_TYPE_DOUBLE, noretval
178 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
179 #ifndef __mips_soft_float
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
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
212 0 - a0 save, original sp
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
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)
252 .globl ffi_go_closure_O32
253 .ent ffi_go_closure_O32
257 .frame $fp, SIZEOF_FRAME2, ra
261 SUBU $sp, SIZEOF_FRAME2
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
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)
278 # Load ABI enum to s0
279 REG_L $16, 4($15) # cif
280 REG_L $16, 0($16) # abi is first member.
283 bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
285 #ifndef __mips_soft_float
286 # Store all possible float/double registers.
287 s.d $f12, FA_0_0_OFF2($fp)
288 s.d $f14, FA_1_0_OFF2($fp)
291 # prepare arguments for ffi_closure_mips_inner_O32
292 REG_L a0, 4($15) # cif
293 REG_L a1, 8($15) # fun
294 move a2, $15 # user_data = go closure
295 addu a3, $fp, V0_OFF2 # rvalue
297 addu t9, $fp, A0_OFF2 # ar
298 REG_S t9, CALLED_A4_OFF2($fp)
300 addu t9, $fp, FA_0_0_OFF2 #fpr
301 REG_S t9, CALLED_A5_OFF2($fp)
306 .end ffi_go_closure_O32
309 .globl ffi_closure_O32
314 .frame $fp, SIZEOF_FRAME2, ra
318 SUBU $sp, SIZEOF_FRAME2
321 REG_S $16, S0_OFF2($sp) # Save s0
322 REG_S $fp, FP_OFF2($sp) # Save frame pointer
323 REG_S ra, RA_OFF2($sp) # Save return address
328 # Store all possible argument registers. If there are more than
329 # four arguments, then they are stored above where we put a3.
330 REG_S a0, A0_OFF2($fp)
331 REG_S a1, A1_OFF2($fp)
332 REG_S a2, A2_OFF2($fp)
333 REG_S a3, A3_OFF2($fp)
335 # Load ABI enum to s0
336 REG_L $16, 20($12) # cif pointer follows tramp.
337 REG_L $16, 0($16) # abi is first member.
340 bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
342 #ifndef __mips_soft_float
343 # Store all possible float/double registers.
344 s.d $f12, FA_0_0_OFF2($fp)
345 s.d $f14, FA_1_0_OFF2($fp)
348 # prepare arguments for ffi_closure_mips_inner_O32
349 REG_L a0, 20($12) # cif pointer follows tramp.
350 REG_L a1, 24($12) # fun
351 REG_L a2, 28($12) # user_data
352 addu a3, $fp, V0_OFF2 # rvalue
354 addu t9, $fp, A0_OFF2 # ar
355 REG_S t9, CALLED_A4_OFF2($fp)
357 addu t9, $fp, FA_0_0_OFF2 #fpr
358 REG_S t9, CALLED_A5_OFF2($fp)
361 la t9, ffi_closure_mips_inner_O32
362 # Call ffi_closure_mips_inner_O32 to do the work.
365 # Load the return value into the appropriate register.
368 beq $8, $9, closure_done
371 bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT
373 #ifndef __mips_soft_float
374 li $9, FFI_TYPE_FLOAT
375 l.s $f0, V0_OFF2($fp)
376 beq $8, $9, closure_done
378 li $9, FFI_TYPE_DOUBLE
379 l.d $f0, V0_OFF2($fp)
380 beq $8, $9, closure_done
383 REG_L $3, V1_OFF2($fp)
384 REG_L $2, V0_OFF2($fp)
389 REG_L $16, S0_OFF2($sp) # Restore s0
390 REG_L $fp, FP_OFF2($sp) # Restore frame pointer
391 REG_L ra, RA_OFF2($sp) # Restore return address
392 ADDU $sp, SIZEOF_FRAME2
397 /* DWARF-2 unwind info. */
399 .section .eh_frame,"a",@progbits
401 .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry
403 .4byte 0x0 # CIE Identifier Tag
404 .byte 0x1 # CIE Version
405 .ascii "zR\0" # CIE Augmentation
406 .uleb128 0x1 # CIE Code Alignment Factor
407 .sleb128 4 # CIE Data Alignment Factor
408 .byte 0x1f # CIE RA Column
409 .uleb128 0x1 # Augmentation size
410 .byte 0x00 # FDE Encoding (absptr)
411 .byte 0xc # DW_CFA_def_cfa
418 .4byte $LEFDE0-$LASFDE0 # FDE Length
420 .4byte $LASFDE0-$Lframe0 # FDE CIE offset
421 .4byte $LFB0 # FDE initial location
422 .4byte $LFE0-$LFB0 # FDE address range
423 .uleb128 0x0 # Augmentation size
424 .byte 0x4 # DW_CFA_advance_loc4
426 .byte 0xe # DW_CFA_def_cfa_offset
428 .byte 0x4 # DW_CFA_advance_loc4
429 .4byte $LCFI01-$LCFI00
430 .byte 0x11 # DW_CFA_offset_extended_sf
432 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
433 .byte 0x11 # DW_CFA_offset_extended_sf
435 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
436 .byte 0x4 # DW_CFA_advance_loc4
437 .4byte $LCFI02-$LCFI01
438 .byte 0xc # DW_CFA_def_cfa
445 .4byte $LEFDE1-$LASFDE1 # FDE Length
447 .4byte $LASFDE1-$Lframe0 # FDE CIE offset
448 .4byte $LFB1 # FDE initial location
449 .4byte $LFE1-$LFB1 # FDE address range
450 .uleb128 0x0 # Augmentation size
451 .byte 0x4 # DW_CFA_advance_loc4
453 .byte 0xe # DW_CFA_def_cfa_offset
454 .uleb128 SIZEOF_FRAME2
455 .byte 0x4 # DW_CFA_advance_loc4
456 .4byte $LCFI11-$LCFI10
457 .byte 0x11 # DW_CFA_offset_extended_sf
459 .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
460 .byte 0x11 # DW_CFA_offset_extended_sf
462 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
463 .byte 0x11 # DW_CFA_offset_extended_sf
465 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
466 .byte 0x4 # DW_CFA_advance_loc4
467 .4byte $LCFI12-$LCFI11
468 .byte 0xc # DW_CFA_def_cfa
470 .uleb128 SIZEOF_FRAME2
475 .4byte $LEFDE2-$LASFDE2 # FDE Length
477 .4byte $LASFDE2-$Lframe0 # FDE CIE offset
478 .4byte $LFB2 # FDE initial location
479 .4byte $LFE2-$LFB2 # FDE address range
480 .uleb128 0x0 # Augmentation size
481 .byte 0x4 # DW_CFA_advance_loc4
483 .byte 0xe # DW_CFA_def_cfa_offset
484 .uleb128 SIZEOF_FRAME2
485 .byte 0x4 # DW_CFA_advance_loc4
486 .4byte $LCFI21-$LCFI20
487 .byte 0x11 # DW_CFA_offset_extended_sf
489 .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
490 .byte 0x11 # DW_CFA_offset_extended_sf
492 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
493 .byte 0x11 # DW_CFA_offset_extended_sf
495 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
496 .byte 0x4 # DW_CFA_advance_loc4
497 .4byte $LCFI22-$LCFI21
498 .byte 0xc # DW_CFA_def_cfa
500 .uleb128 SIZEOF_FRAME2