1 /* -----------------------------------------------------------------------
2 o32.S - Copyright (c) 1996, 1998 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 )
47 SUBU $sp, SIZEOF_FRAME # Frame size
49 REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
51 REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
56 move t9, callback # callback function pointer
57 REG_S flags, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # flags
59 # Allocate at least 4 words in the argstack
61 bge bytes, 4 * FFI_SIZEOF_ARG, bigger
62 LI v0, 4 * FFI_SIZEOF_ARG
66 ADDU t0, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned
67 and v0, t0, -2 * FFI_SIZEOF_ARG # to an 8 byte boundry
70 SUBU $sp, $sp, v0 # move the stack pointer to reflect the
73 ADDU a0, $sp, 4 * FFI_SIZEOF_ARG
74 ADDU a3, $fp, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG
78 REG_L t0, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # load the flags word
79 add t2, t0, 0 # and copy it into t2
81 and t0, ((1<<4)-1) # mask out the return type
82 SRL t2, 4 # shift our arg info
84 ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
86 bnez t0, pass_d # make it quick for int
87 REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
88 REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
89 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
90 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
94 bne t0, FFI_ARGS_D, pass_f
95 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
96 REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double
97 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
101 bne t0, FFI_ARGS_F, pass_d_d
102 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
103 REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float
104 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
105 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
109 bne t0, FFI_ARGS_DD, pass_f_f
110 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
111 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles
115 bne t0, FFI_ARGS_FF, pass_d_f
116 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
117 l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats
118 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
119 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
123 bne t0, FFI_ARGS_DF, pass_f_d
124 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
125 l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
126 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
130 # assume that the only other combination must be float then double
131 # bne t0, FFI_ARGS_F_D, call_it
132 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
133 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
136 # Load the function pointer
137 REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
139 # If the return value pointer is NULL, assume no return value.
140 REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
143 bne t2, FFI_TYPE_INT, retlonglong
145 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
150 # Really any 64-bit int, signed or not.
151 bne t2, FFI_TYPE_UINT64, retfloat
153 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
159 bne t2, FFI_TYPE_FLOAT, retdouble
161 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
166 bne t2, FFI_TYPE_DOUBLE, noretval
168 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
178 REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
179 REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address
180 ADDU $sp, SIZEOF_FRAME # Fix stack pointer
187 /* ffi_closure_O32. Expects address of the passed-in ffi_closure
188 in t0. Stores any arguments passed in registers onto the
189 stack, then calls ffi_closure_mips_inner_O32, which
194 14 - Start of parameters, original sp
199 9 - return value high (v1)
200 8 - return value low (v0)
201 7 - f14 (le high, be low)
202 6 - f14 (le low, be high)
203 5 - f12 (le high, be low)
204 4 - f12 (le low, be high)
205 3 - Called function a3 save
206 2 - Called function a2 save
207 1 - Called function a1 save
208 0 - Called function a0 save our sp, fp point here
211 #define SIZEOF_FRAME2 ( 14 * FFI_SIZEOF_ARG )
215 .globl ffi_closure_O32
220 .frame $fp, SIZEOF_FRAME2, $31
224 SUBU $sp, SIZEOF_FRAME2
225 .cprestore SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG
227 REG_S $16, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp) # Save s0
228 REG_S $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
229 REG_S ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) # Save return address
234 # Store all possible argument registers. If there are more than
235 # four arguments, then they should be stored above where we put $7.
236 REG_S $4, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG($fp)
237 REG_S $5, SIZEOF_FRAME2 + 1*FFI_SIZEOF_ARG($fp)
238 REG_S $6, SIZEOF_FRAME2 + 2*FFI_SIZEOF_ARG($fp)
239 REG_S $7, SIZEOF_FRAME2 + 3*FFI_SIZEOF_ARG($fp)
241 # Load ABI enum to $16
242 REG_L $16, 20($8) # cif pointer follows tramp.
243 REG_L $16, 0($16) # abi is first member.
246 bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
248 # Store all possible float/double registers.
249 s.d $f12, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG($fp)
250 s.d $f14, SIZEOF_FRAME2 - 8*FFI_SIZEOF_ARG($fp)
252 # Call ffi_closure_mips_inner_O32 to do the work.
253 la $25, ffi_closure_mips_inner_O32
254 move $4, $8 # Pointer to the ffi_closure
255 addu $5, $fp, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG
256 addu $6, $fp, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG
257 addu $7, $fp, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG
260 # Load the return value into the appropriate register.
263 beq $8, $9, closure_done
266 bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT
268 li $9, FFI_TYPE_FLOAT
269 l.s $f0, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG($fp)
270 beq $8, $9, closure_done
272 li $9, FFI_TYPE_DOUBLE
273 l.d $f0, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG($fp)
274 beq $8, $9, closure_done
276 li $9, FFI_TYPE_SINT64
277 REG_L $3, SIZEOF_FRAME2 - 5*FFI_SIZEOF_ARG($fp)
279 li $9, FFI_TYPE_UINT64
283 REG_L $2, SIZEOF_FRAME2 - 6*FFI_SIZEOF_ARG($fp)
288 REG_L $16, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp) # Restore s0
289 REG_L $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
290 REG_L ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) # Restore return address
291 ADDU $sp, SIZEOF_FRAME2
296 /* DWARF-2 unwind info. */
298 .section .eh_frame,"a",@progbits
300 .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry
302 .4byte 0x0 # CIE Identifier Tag
303 .byte 0x1 # CIE Version
304 .ascii "zR\0" # CIE Augmentation
305 .uleb128 0x1 # CIE Code Alignment Factor
306 .sleb128 4 # CIE Data Alignment Factor
307 .byte 0x1f # CIE RA Column
308 .uleb128 0x1 # Augmentation size
309 .byte 0x1b # FDE Encoding (pcrel sdata4)
310 .byte 0xc # DW_CFA_def_cfa
316 .4byte $LEFDE0-$LASFDE0 # FDE Length
318 .4byte $LASFDE0-$Lframe0 # FDE CIE offset
319 .4byte $LFB0-. # FDE initial location
320 .4byte $LFE0-$LFB0 # FDE address range
321 .uleb128 0x0 # Augmentation size
322 .byte 0x4 # DW_CFA_advance_loc4
324 .byte 0xe # DW_CFA_def_cfa_offset
326 .byte 0x4 # DW_CFA_advance_loc4
328 .byte 0x11 # DW_CFA_offset_extended_sf
330 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
331 .byte 0x11 # DW_CFA_offset_extended_sf
333 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
334 .byte 0x4 # DW_CFA_advance_loc4
336 .byte 0xc # DW_CFA_def_cfa
342 .4byte $LEFDE1-$LASFDE1 # FDE Length
344 .4byte $LASFDE1-$Lframe0 # FDE CIE offset
345 .4byte $LFB1-. # FDE initial location
346 .4byte $LFE1-$LFB1 # FDE address range
347 .uleb128 0x0 # Augmentation size
348 .byte 0x4 # DW_CFA_advance_loc4
350 .byte 0xe # DW_CFA_def_cfa_offset
352 .byte 0x4 # DW_CFA_advance_loc4
354 .byte 0x11 # DW_CFA_offset_extended_sf
356 .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
357 .byte 0x11 # DW_CFA_offset_extended_sf
359 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
360 .byte 0x11 # DW_CFA_offset_extended_sf
362 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
363 .byte 0x4 # DW_CFA_advance_loc4
365 .byte 0xc # DW_CFA_def_cfa