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, 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 CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 ----------------------------------------------------------------------- */
27 #include <fficonfig.h>
30 /* Only build this code if we are compiling for o32 */
32 #if defined(FFI_MIPS_O32)
38 #define SIZEOF_FRAME (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG)
39 #define A3_OFF (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG)
40 #define FP_OFF (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG)
41 #define RA_OFF (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG)
51 SUBU $sp, SIZEOF_FRAME # Frame size
53 REG_S $fp, FP_OFF($sp) # Save frame pointer
55 REG_S ra, RA_OFF($sp) # Save return address
60 move t9, callback # callback function pointer
61 REG_S flags, A3_OFF($fp) # flags
63 # Allocate at least 4 words in the argstack
64 LI v0, 4 * FFI_SIZEOF_ARG
65 blt bytes, v0, sixteen
67 ADDU v0, bytes, 7 # make sure it is aligned
68 and v0, -8 # to an 8 byte boundry
71 SUBU $sp, v0 # move the stack pointer to reflect the
74 ADDU a0, $sp, 4 * FFI_SIZEOF_ARG
78 REG_L t0, A3_OFF($fp) # load the flags word
79 SRL t2, t0, 4 # shift our arg info
80 and t0, ((1<<4)-1) # mask out the return type
82 ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
84 bnez t0, pass_d # make it quick for int
85 REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
86 REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
87 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
88 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
92 bne t0, FFI_ARGS_D, pass_f
93 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
94 REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double
95 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
99 bne t0, FFI_ARGS_F, pass_d_d
100 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
101 REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float
102 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
103 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
107 bne t0, FFI_ARGS_DD, pass_f_f
108 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
109 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles
113 bne t0, FFI_ARGS_FF, pass_d_f
114 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
115 l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats
116 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
117 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
121 bne t0, FFI_ARGS_DF, pass_f_d
122 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
123 l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
124 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
128 # assume that the only other combination must be float then double
129 # bne t0, FFI_ARGS_F_D, call_it
130 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
131 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
134 # Load the function pointer
135 REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
137 # If the return value pointer is NULL, assume no return value.
138 REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
141 bne t2, FFI_TYPE_INT, retlonglong
143 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
148 # Really any 64-bit int, signed or not.
149 bne t2, FFI_TYPE_UINT64, retfloat
151 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
157 bne t2, FFI_TYPE_FLOAT, retdouble
159 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
164 bne t2, FFI_TYPE_DOUBLE, noretval
166 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
176 REG_L $fp, FP_OFF($sp) # Restore frame pointer
177 REG_L ra, RA_OFF($sp) # Restore return address
178 ADDU $sp, SIZEOF_FRAME # Fix stack pointer
185 /* ffi_closure_O32. Expects address of the passed-in ffi_closure
186 in t4 ($12). Stores any arguments passed in registers onto the
187 stack, then calls ffi_closure_mips_inner_O32, which
195 0 - a0 save, original sp
200 -5 - return value high (v1)
201 -6 - return value low (v0)
202 -7 - f14 (le high, be low)
203 -8 - f14 (le low, be high)
204 -9 - f12 (le high, be low)
205 -10 - f12 (le low, be high)
206 -11 - Called function a3 save
207 -12 - Called function a2 save
208 -13 - Called function a1 save
209 -14 - Called function a0 save, our sp and fp point here
212 #define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG)
213 #define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
214 #define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
215 #define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
216 #define A0_OFF2 (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG)
217 #define RA_OFF2 (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG)
218 #define FP_OFF2 (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG)
219 #define S0_OFF2 (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG)
220 #define GP_OFF2 (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG)
221 #define V1_OFF2 (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG)
222 #define V0_OFF2 (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG)
223 #define FA_1_1_OFF2 (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG)
224 #define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
225 #define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
226 #define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
230 .globl ffi_closure_O32
235 .frame $fp, SIZEOF_FRAME2, ra
239 SUBU $sp, SIZEOF_FRAME2
242 REG_S $16, S0_OFF2($sp) # Save s0
243 REG_S $fp, FP_OFF2($sp) # Save frame pointer
244 REG_S ra, RA_OFF2($sp) # Save return address
249 # Store all possible argument registers. If there are more than
250 # four arguments, then they are stored above where we put a3.
251 REG_S a0, A0_OFF2($fp)
252 REG_S a1, A1_OFF2($fp)
253 REG_S a2, A2_OFF2($fp)
254 REG_S a3, A3_OFF2($fp)
256 # Load ABI enum to s0
257 REG_L $16, 20($12) # cif pointer follows tramp.
258 REG_L $16, 0($16) # abi is first member.
261 bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
263 # Store all possible float/double registers.
264 s.d $f12, FA_0_0_OFF2($fp)
265 s.d $f14, FA_1_0_OFF2($fp)
267 # Call ffi_closure_mips_inner_O32 to do the work.
268 la t9, ffi_closure_mips_inner_O32
269 move a0, $12 # Pointer to the ffi_closure
270 addu a1, $fp, V0_OFF2
271 addu a2, $fp, A0_OFF2
272 addu a3, $fp, FA_0_0_OFF2
275 # Load the return value into the appropriate register.
278 beq $8, $9, closure_done
281 bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT
283 li $9, FFI_TYPE_FLOAT
284 l.s $f0, V0_OFF2($fp)
285 beq $8, $9, closure_done
287 li $9, FFI_TYPE_DOUBLE
288 l.d $f0, V0_OFF2($fp)
289 beq $8, $9, closure_done
291 REG_L $3, V1_OFF2($fp)
292 REG_L $2, V0_OFF2($fp)
297 REG_L $16, S0_OFF2($sp) # Restore s0
298 REG_L $fp, FP_OFF2($sp) # Restore frame pointer
299 REG_L ra, RA_OFF2($sp) # Restore return address
300 ADDU $sp, SIZEOF_FRAME2
305 /* DWARF-2 unwind info. */
307 .section .eh_frame,"a",@progbits
309 .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry
311 .4byte 0x0 # CIE Identifier Tag
312 .byte 0x1 # CIE Version
313 .ascii "zR\0" # CIE Augmentation
314 .uleb128 0x1 # CIE Code Alignment Factor
315 .sleb128 4 # CIE Data Alignment Factor
316 .byte 0x1f # CIE RA Column
317 .uleb128 0x1 # Augmentation size
318 .byte 0x00 # FDE Encoding (absptr)
319 .byte 0xc # DW_CFA_def_cfa
325 .4byte $LEFDE0-$LASFDE0 # FDE Length
327 .4byte $LASFDE0-$Lframe0 # FDE CIE offset
328 .4byte $LFB0 # FDE initial location
329 .4byte $LFE0-$LFB0 # FDE address range
330 .uleb128 0x0 # Augmentation size
331 .byte 0x4 # DW_CFA_advance_loc4
333 .byte 0xe # DW_CFA_def_cfa_offset
335 .byte 0x4 # DW_CFA_advance_loc4
337 .byte 0x11 # DW_CFA_offset_extended_sf
339 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
340 .byte 0x11 # DW_CFA_offset_extended_sf
342 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
343 .byte 0x4 # DW_CFA_advance_loc4
345 .byte 0xc # DW_CFA_def_cfa
351 .4byte $LEFDE1-$LASFDE1 # FDE Length
353 .4byte $LASFDE1-$Lframe0 # FDE CIE offset
354 .4byte $LFB1 # FDE initial location
355 .4byte $LFE1-$LFB1 # FDE address range
356 .uleb128 0x0 # Augmentation size
357 .byte 0x4 # DW_CFA_advance_loc4
359 .byte 0xe # DW_CFA_def_cfa_offset
361 .byte 0x4 # DW_CFA_advance_loc4
363 .byte 0x11 # DW_CFA_offset_extended_sf
365 .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
366 .byte 0x11 # DW_CFA_offset_extended_sf
368 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
369 .byte 0x11 # DW_CFA_offset_extended_sf
371 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
372 .byte 0x4 # DW_CFA_advance_loc4
374 .byte 0xc # DW_CFA_def_cfa