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 )
39 #define SIZEOF_FRAME2 ( 8 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG )
48 SUBU $sp, SIZEOF_FRAME # Frame size
50 REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
52 REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
57 move t9, callback # callback function pointer
58 REG_S flags, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # flags
60 # Allocate at least 4 words in the argstack
62 bge bytes, 4 * FFI_SIZEOF_ARG, bigger
63 LI v0, 4 * FFI_SIZEOF_ARG
67 ADDU t0, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned
68 and v0, t0, -2 * FFI_SIZEOF_ARG # to an 8 byte boundry
71 SUBU $sp, $sp, v0 # move the stack pointer to reflect the
74 ADDU a0, $sp, 4 * FFI_SIZEOF_ARG
75 ADDU a3, $fp, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG
79 REG_L t0, SIZEOF_FRAME + 3*FFI_SIZEOF_ARG($fp) # load the flags word
80 add t2, t0, 0 # and copy it into t2
82 and t0, ((1<<4)-1) # mask out the return type
83 SRL t2, 4 # shift our arg info
85 ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
87 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)
95 bne t0, FFI_ARGS_D, pass_f
96 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
97 REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double
98 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
102 bne t0, FFI_ARGS_F, pass_d_d
103 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
104 REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float
105 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
106 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
110 bne t0, FFI_ARGS_DD, pass_f_f
111 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
112 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles
116 bne t0, FFI_ARGS_FF, pass_d_f
117 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
118 l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats
119 REG_L a2, 2*FFI_SIZEOF_ARG($sp)
120 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
124 bne t0, FFI_ARGS_DF, pass_f_d
125 l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
126 l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
127 REG_L a3, 3*FFI_SIZEOF_ARG($sp)
131 # assume that the only other combination must be float then double
132 # bne t0, FFI_ARGS_F_D, call_it
133 l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
134 l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
137 # Load the function pointer
138 REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
140 # If the return value pointer is NULL, assume no return value.
141 REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
144 bne t2, FFI_TYPE_INT, retlonglong
146 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
151 # Really any 64-bit int, signed or not.
152 bne t2, FFI_TYPE_UINT64, retfloat
154 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
160 bne t2, FFI_TYPE_FLOAT, retdouble
162 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
167 bne t2, FFI_TYPE_DOUBLE, noretval
169 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
179 REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
180 REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address
181 ADDU $sp, SIZEOF_FRAME # Fix stack pointer
188 /* ffi_closure_O32. Expects address of the passed-in ffi_closure
189 in t0. Stores any arguments passed in registers onto the
190 stack, then calls ffi_closure_mips_inner_O32, which
191 then decodes them. */
195 .globl ffi_closure_O32
200 .frame $fp, SIZEOF_FRAME2, $31
204 SUBU $sp, SIZEOF_FRAME2
205 .cprestore SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG
207 REG_S $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
209 REG_S ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) # Save return address
214 # Store all possible argument registers. If there are more than
215 # four arguments, then they should be stored above where we put $7.
216 REG_S $4, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG($fp)
217 REG_S $5, SIZEOF_FRAME2 + 1*FFI_SIZEOF_ARG($fp)
218 REG_S $6, SIZEOF_FRAME2 + 2*FFI_SIZEOF_ARG($fp)
219 REG_S $7, SIZEOF_FRAME2 + 3*FFI_SIZEOF_ARG($fp)
221 # Store all possible float/double registers.
222 s.d $f12, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG($fp)
223 s.d $f14, SIZEOF_FRAME2 - 8*FFI_SIZEOF_ARG($fp)
225 # Call ffi_closure_mips_inner_O32 to do the work.
226 la $25, ffi_closure_mips_inner_O32
227 move $4, $8 # Pointer to the ffi_closure
228 addu $5, $fp, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG
229 addu $6, $fp, SIZEOF_FRAME2 + 0*FFI_SIZEOF_ARG
230 addu $7, $fp, SIZEOF_FRAME2 - 10*FFI_SIZEOF_ARG
233 # Load the return value into the appropriate register.
236 beq $8, $9, closure_done
238 li $9, FFI_TYPE_FLOAT
239 l.s $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
240 beq $8, $9, closure_done
242 li $9, FFI_TYPE_DOUBLE
243 l.d $f0, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
244 beq $8, $9, closure_done
246 li $9, FFI_TYPE_SINT64
247 REG_L $3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp)
250 li $9, FFI_TYPE_UINT64
251 REG_L $3, SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($fp)
255 REG_L $2, SIZEOF_FRAME2 - 4*FFI_SIZEOF_ARG($fp)
260 REG_L $fp, SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
261 REG_L ra, SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) # Restore return address
262 ADDU $sp, SIZEOF_FRAME2
267 /* DWARF-2 unwind info. */
269 .section .eh_frame,"a",@progbits
271 .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry
273 .4byte 0x0 # CIE Identifier Tag
274 .byte 0x1 # CIE Version
275 .ascii "zR\0" # CIE Augmentation
276 .uleb128 0x1 # CIE Code Alignment Factor
277 .sleb128 4 # CIE Data Alignment Factor
278 .byte 0x1f # CIE RA Column
279 .uleb128 0x1 # Augmentation size
280 .byte 0x1b # FDE Encoding (pcrel sdata4)
281 .byte 0xc # DW_CFA_def_cfa
287 .4byte $LEFDE0-$LASFDE0 # FDE Length
289 .4byte $LASFDE0-$Lframe0 # FDE CIE offset
290 .4byte $LFB0-. # FDE initial location
291 .4byte $LFE0-$LFB0 # FDE address range
292 .uleb128 0x0 # Augmentation size
293 .byte 0x4 # DW_CFA_advance_loc4
295 .byte 0xe # DW_CFA_def_cfa_offset
297 .byte 0x4 # DW_CFA_advance_loc4
299 .byte 0x11 # DW_CFA_offset_extended_sf
301 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
302 .byte 0x11 # DW_CFA_offset_extended_sf
304 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
305 .byte 0x4 # DW_CFA_advance_loc4
307 .byte 0xc # DW_CFA_def_cfa
313 .4byte $LEFDE1-$LASFDE1 # FDE Length
315 .4byte $LASFDE1-$Lframe0 # FDE CIE offset
316 .4byte $LFB1-. # FDE initial location
317 .4byte $LFE1-$LFB1 # FDE address range
318 .uleb128 0x0 # Augmentation size
319 .byte 0x4 # DW_CFA_advance_loc4
321 .byte 0xe # DW_CFA_def_cfa_offset
323 .byte 0x4 # DW_CFA_advance_loc4
325 .byte 0x11 # DW_CFA_offset_extended_sf
327 .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
328 .byte 0x11 # DW_CFA_offset_extended_sf
330 .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
331 .byte 0x4 # DW_CFA_advance_loc4
333 .byte 0xc # DW_CFA_def_cfa