1 /* -----------------------------------------------------------------------
2 n32.S - Copyright (c) 1996, 1998, 2005, 2007, 2009, 2010 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 n32 */
33 #if defined(FFI_MIPS_N32)
41 #define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG )
52 .frame $fp, SIZEOF_FRAME, ra
53 .mask 0xc0000000,-FFI_SIZEOF_ARG
57 SUBU $sp, SIZEOF_FRAME # Frame size
59 REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
60 REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
64 move t9, callback # callback function pointer
65 REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
66 REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags
67 REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
68 REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn
70 # Allocate at least 4 words in the argstack
72 bge bytes, 4 * FFI_SIZEOF_ARG, bigger
73 LI v0, 4 * FFI_SIZEOF_ARG
77 ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned
78 and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry.
81 SUBU $sp, $sp, v0 # move the stack pointer to reflect the
84 move a0, $sp # 4 * FFI_SIZEOF_ARG
85 ADDU a3, $fp, 3 * FFI_SIZEOF_ARG
90 # Copy the stack pointer to t9
93 # Fix the stack if there are more than 8 64bit slots worth
96 # Load the number of bytes
97 REG_L t6, 2*FFI_SIZEOF_ARG($fp)
99 # Is it bigger than 8 * FFI_SIZEOF_ARG?
100 daddiu t8, t6, -(8 * FFI_SIZEOF_ARG)
107 REG_L t6, 3*FFI_SIZEOF_ARG($fp) # load the flags word into t6.
109 and t4, t6, ((1<<FFI_FLAG_BITS)-1)
111 REG_L a0, 0*FFI_SIZEOF_ARG(t9)
114 bne t4, FFI_TYPE_FLOAT, arg1_doublep
115 l.s $f12, 0*FFI_SIZEOF_ARG(t9)
118 l.d $f12, 0*FFI_SIZEOF_ARG(t9)
121 SRL t4, t6, 1*FFI_FLAG_BITS
122 and t4, ((1<<FFI_FLAG_BITS)-1)
124 REG_L a1, 1*FFI_SIZEOF_ARG(t9)
127 bne t4, FFI_TYPE_FLOAT, arg2_doublep
128 l.s $f13, 1*FFI_SIZEOF_ARG(t9)
131 l.d $f13, 1*FFI_SIZEOF_ARG(t9)
134 SRL t4, t6, 2*FFI_FLAG_BITS
135 and t4, ((1<<FFI_FLAG_BITS)-1)
137 REG_L a2, 2*FFI_SIZEOF_ARG(t9)
140 bne t4, FFI_TYPE_FLOAT, arg3_doublep
141 l.s $f14, 2*FFI_SIZEOF_ARG(t9)
144 l.d $f14, 2*FFI_SIZEOF_ARG(t9)
147 SRL t4, t6, 3*FFI_FLAG_BITS
148 and t4, ((1<<FFI_FLAG_BITS)-1)
150 REG_L a3, 3*FFI_SIZEOF_ARG(t9)
153 bne t4, FFI_TYPE_FLOAT, arg4_doublep
154 l.s $f15, 3*FFI_SIZEOF_ARG(t9)
157 l.d $f15, 3*FFI_SIZEOF_ARG(t9)
160 SRL t4, t6, 4*FFI_FLAG_BITS
161 and t4, ((1<<FFI_FLAG_BITS)-1)
163 REG_L a4, 4*FFI_SIZEOF_ARG(t9)
166 bne t4, FFI_TYPE_FLOAT, arg5_doublep
167 l.s $f16, 4*FFI_SIZEOF_ARG(t9)
170 l.d $f16, 4*FFI_SIZEOF_ARG(t9)
173 SRL t4, t6, 5*FFI_FLAG_BITS
174 and t4, ((1<<FFI_FLAG_BITS)-1)
176 REG_L a5, 5*FFI_SIZEOF_ARG(t9)
179 bne t4, FFI_TYPE_FLOAT, arg6_doublep
180 l.s $f17, 5*FFI_SIZEOF_ARG(t9)
183 l.d $f17, 5*FFI_SIZEOF_ARG(t9)
186 SRL t4, t6, 6*FFI_FLAG_BITS
187 and t4, ((1<<FFI_FLAG_BITS)-1)
189 REG_L a6, 6*FFI_SIZEOF_ARG(t9)
192 bne t4, FFI_TYPE_FLOAT, arg7_doublep
193 l.s $f18, 6*FFI_SIZEOF_ARG(t9)
196 l.d $f18, 6*FFI_SIZEOF_ARG(t9)
199 SRL t4, t6, 7*FFI_FLAG_BITS
200 and t4, ((1<<FFI_FLAG_BITS)-1)
202 REG_L a7, 7*FFI_SIZEOF_ARG(t9)
205 bne t4, FFI_TYPE_FLOAT, arg8_doublep
206 l.s $f19, 7*FFI_SIZEOF_ARG(t9)
209 l.d $f19, 7*FFI_SIZEOF_ARG(t9)
213 # Load the function pointer
214 REG_L t9, 5*FFI_SIZEOF_ARG($fp)
216 # If the return value pointer is NULL, assume no return value.
217 REG_L t5, 4*FFI_SIZEOF_ARG($fp)
220 # Shift the return type flag over
221 SRL t6, 8*FFI_FLAG_BITS
223 beq t6, FFI_TYPE_SINT32, retint
224 bne t6, FFI_TYPE_INT, retfloat
227 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
232 bne t6, FFI_TYPE_FLOAT, retdouble
234 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
239 bne t6, FFI_TYPE_DOUBLE, retstruct_d
241 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
246 bne t6, FFI_TYPE_STRUCT_D, retstruct_f
248 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
253 bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d
255 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
260 bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
262 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
268 bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
270 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
276 bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
278 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
284 bne t6, FFI_TYPE_STRUCT_FD, retstruct_d_soft
286 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
292 bne t6, FFI_TYPE_STRUCT_D_SOFT, retstruct_f_soft
294 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
299 bne t6, FFI_TYPE_STRUCT_F_SOFT, retstruct_d_d_soft
301 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
306 bne t6, FFI_TYPE_STRUCT_DD_SOFT, retstruct_f_f_soft
308 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
314 bne t6, FFI_TYPE_STRUCT_FF_SOFT, retstruct_d_f_soft
316 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
322 bne t6, FFI_TYPE_STRUCT_DF_SOFT, retstruct_f_d_soft
324 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
330 bne t6, FFI_TYPE_STRUCT_FD_SOFT, retstruct_small
332 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
338 bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
340 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
345 bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct
347 REG_L t4, 4*FFI_SIZEOF_ARG($fp)
359 REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
360 REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address
361 ADDU $sp, SIZEOF_FRAME # Fix stack pointer
367 /* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
368 ($12). Stores any arguments passed in registers onto the stack,
369 then calls ffi_closure_mips_inner_N32, which then decodes
374 20 - Start of parameters, original sp
375 19 - Called function a7 save
376 18 - Called function a6 save
377 17 - Called function a5 save
378 16 - Called function a4 save
379 15 - Called function a3 save
380 14 - Called function a2 save
381 13 - Called function a1 save
382 12 - Called function a0 save
383 11 - Called function f19
384 10 - Called function f18
385 9 - Called function f17
386 8 - Called function f16
387 7 - Called function f15
388 6 - Called function f14
389 5 - Called function f13
390 4 - Called function f12
391 3 - return value high (v1 or $f2)
392 2 - return value low (v0 or $f0)
394 0 - gp save our sp points here
397 #define SIZEOF_FRAME2 (20 * FFI_SIZEOF_ARG)
399 #define A7_OFF2 (19 * FFI_SIZEOF_ARG)
400 #define A6_OFF2 (18 * FFI_SIZEOF_ARG)
401 #define A5_OFF2 (17 * FFI_SIZEOF_ARG)
402 #define A4_OFF2 (16 * FFI_SIZEOF_ARG)
403 #define A3_OFF2 (15 * FFI_SIZEOF_ARG)
404 #define A2_OFF2 (14 * FFI_SIZEOF_ARG)
405 #define A1_OFF2 (13 * FFI_SIZEOF_ARG)
406 #define A0_OFF2 (12 * FFI_SIZEOF_ARG)
408 #define F19_OFF2 (11 * FFI_SIZEOF_ARG)
409 #define F18_OFF2 (10 * FFI_SIZEOF_ARG)
410 #define F17_OFF2 (9 * FFI_SIZEOF_ARG)
411 #define F16_OFF2 (8 * FFI_SIZEOF_ARG)
412 #define F15_OFF2 (7 * FFI_SIZEOF_ARG)
413 #define F14_OFF2 (6 * FFI_SIZEOF_ARG)
414 #define F13_OFF2 (5 * FFI_SIZEOF_ARG)
415 #define F12_OFF2 (4 * FFI_SIZEOF_ARG)
417 #define V1_OFF2 (3 * FFI_SIZEOF_ARG)
418 #define V0_OFF2 (2 * FFI_SIZEOF_ARG)
420 #define RA_OFF2 (1 * FFI_SIZEOF_ARG)
421 #define GP_OFF2 (0 * FFI_SIZEOF_ARG)
424 .globl ffi_closure_N32
428 .frame $sp, SIZEOF_FRAME2, ra
429 .mask 0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
431 SUBU $sp, SIZEOF_FRAME2
433 .cpsetup t9, GP_OFF2, ffi_closure_N32
434 REG_S ra, RA_OFF2($sp) # Save return address
436 # Store all possible argument registers. If there are more than
437 # fit in registers, then they were stored on the stack.
438 REG_S a0, A0_OFF2($sp)
439 REG_S a1, A1_OFF2($sp)
440 REG_S a2, A2_OFF2($sp)
441 REG_S a3, A3_OFF2($sp)
442 REG_S a4, A4_OFF2($sp)
443 REG_S a5, A5_OFF2($sp)
444 REG_S a6, A6_OFF2($sp)
445 REG_S a7, A7_OFF2($sp)
447 # Store all possible float/double registers.
448 s.d $f12, F12_OFF2($sp)
449 s.d $f13, F13_OFF2($sp)
450 s.d $f14, F14_OFF2($sp)
451 s.d $f15, F15_OFF2($sp)
452 s.d $f16, F16_OFF2($sp)
453 s.d $f17, F17_OFF2($sp)
454 s.d $f18, F18_OFF2($sp)
455 s.d $f19, F19_OFF2($sp)
457 # Call ffi_closure_mips_inner_N32 to do the real work.
458 LA t9, ffi_closure_mips_inner_N32
459 move a0, $12 # Pointer to the ffi_closure
460 ADDU a1, $sp, V0_OFF2
461 ADDU a2, $sp, A0_OFF2
462 ADDU a3, $sp, F12_OFF2
465 # Return flags are in v0
466 bne v0, FFI_TYPE_SINT32, cls_retint
471 bne v0, FFI_TYPE_INT, cls_retfloat
472 REG_L v0, V0_OFF2($sp)
476 bne v0, FFI_TYPE_FLOAT, cls_retdouble
477 l.s $f0, V0_OFF2($sp)
481 bne v0, FFI_TYPE_DOUBLE, cls_retstruct_d
482 l.d $f0, V0_OFF2($sp)
486 bne v0, FFI_TYPE_STRUCT_D, cls_retstruct_f
487 l.d $f0, V0_OFF2($sp)
491 bne v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d
492 l.s $f0, V0_OFF2($sp)
496 bne v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f
497 l.d $f0, V0_OFF2($sp)
498 l.d $f2, V1_OFF2($sp)
502 bne v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f
503 l.s $f0, V0_OFF2($sp)
504 l.s $f2, V1_OFF2($sp)
508 bne v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d
509 l.d $f0, V0_OFF2($sp)
510 l.s $f2, V1_OFF2($sp)
514 bne v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
515 l.s $f0, V0_OFF2($sp)
516 l.d $f2, V1_OFF2($sp)
519 cls_retstruct_small2:
520 REG_L v0, V0_OFF2($sp)
521 REG_L v1, V1_OFF2($sp)
525 REG_L ra, RA_OFF2($sp) # Restore return address
527 ADDU $sp, SIZEOF_FRAME2
533 .section .eh_frame,"aw",@progbits
535 .4byte .LECIE1-.LSCIE1 # length
538 .byte 0x1 # Version 1
539 .ascii "\000" # Augmentation
540 .uleb128 0x1 # Code alignment 1
541 .sleb128 -4 # Data alignment -4
542 .byte 0x1f # Return Address $31
543 .byte 0xc # DW_CFA_def_cfa
544 .uleb128 0x1d # in $sp
545 .uleb128 0x0 # offset 0
546 .align EH_FRAME_ALIGN
550 .4byte .LEFDE1-.LASFDE1 # length.
552 .4byte .LASFDE1-.Lframe1 # CIE_pointer.
553 FDE_ADDR_BYTES .LFB3 # initial_location.
554 FDE_ADDR_BYTES .LFE3-.LFB3 # address_range.
555 .byte 0x4 # DW_CFA_advance_loc4
556 .4byte .LCFI0-.LFB3 # to .LCFI0
557 .byte 0xe # DW_CFA_def_cfa_offset
558 .uleb128 SIZEOF_FRAME # adjust stack.by SIZEOF_FRAME
559 .byte 0x4 # DW_CFA_advance_loc4
560 .4byte .LCFI1-.LCFI0 # to .LCFI1
561 .byte 0x9e # DW_CFA_offset of $fp
562 .uleb128 2*FFI_SIZEOF_ARG/4 #
563 .byte 0x9f # DW_CFA_offset of ra
564 .uleb128 1*FFI_SIZEOF_ARG/4 #
565 .byte 0x4 # DW_CFA_advance_loc4
566 .4byte .LCFI3-.LCFI1 # to .LCFI3
567 .byte 0xd # DW_CFA_def_cfa_register
568 .uleb128 0x1e # in $fp
569 .align EH_FRAME_ALIGN
572 .4byte .LEFDE3-.LASFDE3 # length
574 .4byte .LASFDE3-.Lframe1 # CIE_pointer.
575 FDE_ADDR_BYTES .LFB2 # initial_location.
576 FDE_ADDR_BYTES .LFE2-.LFB2 # address_range.
577 .byte 0x4 # DW_CFA_advance_loc4
578 .4byte .LCFI5-.LFB2 # to .LCFI5
579 .byte 0xe # DW_CFA_def_cfa_offset
580 .uleb128 SIZEOF_FRAME2 # adjust stack.by SIZEOF_FRAME
581 .byte 0x4 # DW_CFA_advance_loc4
582 .4byte .LCFI6-.LCFI5 # to .LCFI6
583 .byte 0x9c # DW_CFA_offset of $gp ($28)
584 .uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
585 .byte 0x9f # DW_CFA_offset of ra ($31)
586 .uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
587 .align EH_FRAME_ALIGN
589 #endif /* __GNUC__ */