Home | History | Annotate | Download | only in mips
      1 /* -----------------------------------------------------------------------
      2    o32.S - Copyright (c) 1996, 1998, 2005  Red Hat, Inc.
      3 
      4    MIPS Foreign Function Interface
      5 
      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:
     13 
     14    The above copyright notice and this permission notice shall be included
     15    in all copies or substantial portions of the Software.
     16 
     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 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
     21 	ANY CLAIM, DAMAGES OR
     22    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     23    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     24    OTHER DEALINGS IN THE SOFTWARE.
     25    ----------------------------------------------------------------------- */
     26 
     27 #define LIBFFI_ASM
     28 #include <fficonfig.h>
     29 #include <ffi.h>
     30 
     31 /* Only build this code if we are compiling for o32 */
     32 
     33 #if defined(FFI_MIPS_O32)
     34 
     35 #define callback a0
     36 #define bytes	 a2
     37 #define flags	 a3
     38 
     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)
     43 
     44 	.abicalls
     45 	.text
     46 	.align	2
     47 	.globl	ffi_call_O32
     48 	.ent	ffi_call_O32
     49 ffi_call_O32:
     50 $LFB0:
     51 	# Prologue
     52 	SUBU	$sp, SIZEOF_FRAME	# Frame size
     53 $LCFI0:
     54 	REG_S	$fp, FP_OFF($sp)	# Save frame pointer
     55 $LCFI1:
     56 	REG_S	ra, RA_OFF($sp)		# Save return address
     57 $LCFI2:
     58 	move	$fp, $sp
     59 
     60 $LCFI3:
     61 	move	t9, callback		# callback function pointer
     62 	REG_S	flags, A3_OFF($fp)	# flags
     63 
     64 	# Allocate at least 4 words in the argstack
     65 	LI	v0, 4 * FFI_SIZEOF_ARG
     66 	blt	bytes, v0, sixteen
     67 
     68 	ADDU	v0, bytes, 7	# make sure it is aligned
     69 	and	v0, -8		# to an 8 byte boundry
     70 
     71 sixteen:
     72 	SUBU	$sp, v0		# move the stack pointer to reflect the
     73 				# arg space
     74 
     75 	ADDU	a0, $sp, 4 * FFI_SIZEOF_ARG
     76 
     77 	jalr	t9
     78 
     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
     82 
     83 	ADDU	$sp, 4 * FFI_SIZEOF_ARG		# adjust $sp to new args
     84 
     85 	bnez	t0, pass_d			# make it quick for int
     86 	REG_L	a0, 0*FFI_SIZEOF_ARG($sp)	# just go ahead and load the
     87 	REG_L	a1, 1*FFI_SIZEOF_ARG($sp)	# four regs.
     88 	REG_L	a2, 2*FFI_SIZEOF_ARG($sp)
     89 	REG_L	a3, 3*FFI_SIZEOF_ARG($sp)
     90 	b	call_it
     91 
     92 pass_d:
     93 	bne	t0, FFI_ARGS_D, pass_f
     94 	l.d	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
     95 	REG_L	a2,   2*FFI_SIZEOF_ARG($sp)	# passing a double
     96 	REG_L	a3,   3*FFI_SIZEOF_ARG($sp)
     97 	b	call_it
     98 
     99 pass_f:
    100 	bne	t0, FFI_ARGS_F, pass_d_d
    101 	l.s	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
    102 	REG_L	a1,   1*FFI_SIZEOF_ARG($sp)	# passing a float
    103 	REG_L	a2,   2*FFI_SIZEOF_ARG($sp)
    104 	REG_L	a3,   3*FFI_SIZEOF_ARG($sp)
    105 	b	call_it
    106 
    107 pass_d_d:
    108 	bne	t0, FFI_ARGS_DD, pass_f_f
    109 	l.d	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
    110 	l.d	$f14, 2*FFI_SIZEOF_ARG($sp)	# passing two doubles
    111 	b	call_it
    112 
    113 pass_f_f:
    114 	bne	t0, FFI_ARGS_FF, pass_d_f
    115 	l.s	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
    116 	l.s	$f14, 1*FFI_SIZEOF_ARG($sp)	# passing two floats
    117 	REG_L	a2,   2*FFI_SIZEOF_ARG($sp)
    118 	REG_L	a3,   3*FFI_SIZEOF_ARG($sp)
    119 	b	call_it
    120 
    121 pass_d_f:
    122 	bne	t0, FFI_ARGS_DF, pass_f_d
    123 	l.d	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
    124 	l.s	$f14, 2*FFI_SIZEOF_ARG($sp)	# passing double and float
    125 	REG_L	a3,   3*FFI_SIZEOF_ARG($sp)
    126 	b	call_it
    127 
    128 pass_f_d:
    129  # assume that the only other combination must be float then double
    130  #	bne	t0, FFI_ARGS_F_D, call_it
    131 	l.s	$f12, 0*FFI_SIZEOF_ARG($sp)	# load $fp regs from args
    132 	l.d	$f14, 2*FFI_SIZEOF_ARG($sp)	# passing double and float
    133 
    134 call_it:
    135 	# Load the function pointer
    136 	REG_L	t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
    137 
    138 	# If the return value pointer is NULL, assume no return value.
    139 	REG_L	t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
    140 	beqz	t1, noretval
    141 
    142 	bne     t2, FFI_TYPE_INT, retlonglong
    143 	jalr	t9
    144 	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
    145 	REG_S	v0, 0(t0)
    146 	b	epilogue
    147 
    148 retlonglong:
    149 	# Really any 64-bit int, signed or not.
    150 	bne	t2, FFI_TYPE_UINT64, retfloat
    151 	jalr	t9
    152 	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
    153 	REG_S	v1, 4(t0)
    154 	REG_S	v0, 0(t0)
    155 	b	epilogue
    156 
    157 retfloat:
    158 	bne     t2, FFI_TYPE_FLOAT, retdouble
    159 	jalr	t9
    160 	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
    161 	s.s	$f0, 0(t0)
    162 	b	epilogue
    163 
    164 retdouble:
    165 	bne	t2, FFI_TYPE_DOUBLE, noretval
    166 	jalr	t9
    167 	REG_L	t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
    168 	s.d	$f0, 0(t0)
    169 	b	epilogue
    170 
    171 noretval:
    172 	jalr	t9
    173 
    174 	# Epilogue
    175 epilogue:
    176 	move	$sp, $fp
    177 	REG_L	$fp, FP_OFF($sp)	# Restore frame pointer
    178 	REG_L	ra, RA_OFF($sp)		# Restore return address
    179 	ADDU	$sp, SIZEOF_FRAME	# Fix stack pointer
    180 	j	ra
    181 
    182 $LFE0:
    183 	.end	ffi_call_O32
    184 
    185 
    186 /* ffi_closure_O32. Expects address of the passed-in ffi_closure
    187 	in t4 ($12). Stores any arguments passed in registers onto the
    188 	stack, then calls ffi_closure_mips_inner_O32, which
    189 	then decodes them.
    190 
    191 	Stack layout:
    192 
    193 	 3 - a3 save
    194 	 2 - a2 save
    195 	 1 - a1 save
    196 	 0 - a0 save, original sp
    197 	-1 - ra save
    198 	-2 - fp save
    199 	-3 - $16 (s0) save
    200 	-4 - cprestore
    201 	-5 - return value high (v1)
    202 	-6 - return value low (v0)
    203 	-7 - f14 (le high, be low)
    204 	-8 - f14 (le low, be high)
    205 	-9 - f12 (le high, be low)
    206        -10 - f12 (le low, be high)
    207        -11 - Called function a3 save
    208        -12 - Called function a2 save
    209        -13 - Called function a1 save
    210        -14 - Called function a0 save, our sp and fp point here
    211 	 */
    212 
    213 #define SIZEOF_FRAME2	(14 * FFI_SIZEOF_ARG)
    214 #define A3_OFF2		(SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
    215 #define A2_OFF2		(SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
    216 #define A1_OFF2		(SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
    217 #define A0_OFF2		(SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG)
    218 #define RA_OFF2		(SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG)
    219 #define FP_OFF2		(SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG)
    220 #define S0_OFF2		(SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG)
    221 #define GP_OFF2		(SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG)
    222 #define V1_OFF2		(SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG)
    223 #define V0_OFF2		(SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG)
    224 #define FA_1_1_OFF2	(SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG)
    225 #define FA_1_0_OFF2	(SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
    226 #define FA_0_1_OFF2	(SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
    227 #define FA_0_0_OFF2	(SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
    228 
    229 	.text
    230 	.align	2
    231 	.globl	ffi_closure_O32
    232 	.ent	ffi_closure_O32
    233 ffi_closure_O32:
    234 $LFB1:
    235 	# Prologue
    236 	.frame	$fp, SIZEOF_FRAME2, ra
    237 	.set	noreorder
    238 	.cpload	t9
    239 	.set	reorder
    240 	SUBU	$sp, SIZEOF_FRAME2
    241 	.cprestore GP_OFF2
    242 $LCFI4:
    243 	REG_S	$16, S0_OFF2($sp)	 # Save s0
    244 	REG_S	$fp, FP_OFF2($sp)	 # Save frame pointer
    245 	REG_S	ra, RA_OFF2($sp)	 # Save return address
    246 $LCFI6:
    247 	move	$fp, $sp
    248 
    249 $LCFI7:
    250 	# Store all possible argument registers. If there are more than
    251 	# four arguments, then they are stored above where we put a3.
    252 	REG_S	a0, A0_OFF2($fp)
    253 	REG_S	a1, A1_OFF2($fp)
    254 	REG_S	a2, A2_OFF2($fp)
    255 	REG_S	a3, A3_OFF2($fp)
    256 
    257 	# Load ABI enum to s0
    258 	REG_L	$16, 20($12)	# cif pointer follows tramp.
    259 	REG_L	$16, 0($16)	# abi is first member.
    260 
    261 	li	$13, 1		# FFI_O32
    262 	bne	$16, $13, 1f	# Skip fp save if FFI_O32_SOFT_FLOAT
    263 
    264 	# Store all possible float/double registers.
    265 	s.d	$f12, FA_0_0_OFF2($fp)
    266 	s.d	$f14, FA_1_0_OFF2($fp)
    267 1:
    268 	# Call ffi_closure_mips_inner_O32 to do the work.
    269 	la	t9, ffi_closure_mips_inner_O32
    270 	move	a0, $12	 # Pointer to the ffi_closure
    271 	addu	a1, $fp, V0_OFF2
    272 	addu	a2, $fp, A0_OFF2
    273 	addu	a3, $fp, FA_0_0_OFF2
    274 	jalr	t9
    275 
    276 	# Load the return value into the appropriate register.
    277 	move	$8, $2
    278 	li	$9, FFI_TYPE_VOID
    279 	beq	$8, $9, closure_done
    280 
    281 	li	$13, 1		# FFI_O32
    282 	bne	$16, $13, 1f	# Skip fp restore if FFI_O32_SOFT_FLOAT
    283 
    284 	li	$9, FFI_TYPE_FLOAT
    285 	l.s	$f0, V0_OFF2($fp)
    286 	beq	$8, $9, closure_done
    287 
    288 	li	$9, FFI_TYPE_DOUBLE
    289 	l.d	$f0, V0_OFF2($fp)
    290 	beq	$8, $9, closure_done
    291 1:
    292 	REG_L	$3, V1_OFF2($fp)
    293 	REG_L	$2, V0_OFF2($fp)
    294 
    295 closure_done:
    296 	# Epilogue
    297 	move	$sp, $fp
    298 	REG_L	$16, S0_OFF2($sp)	 # Restore s0
    299 	REG_L	$fp, FP_OFF2($sp)	 # Restore frame pointer
    300 	REG_L	ra,  RA_OFF2($sp)	 # Restore return address
    301 	ADDU	$sp, SIZEOF_FRAME2
    302 	j	ra
    303 $LFE1:
    304 	.end	ffi_closure_O32
    305 
    306 /* DWARF-2 unwind info. */
    307 
    308 	.section	.eh_frame,"a",@progbits
    309 $Lframe0:
    310 	.4byte	$LECIE0-$LSCIE0	 # Length of Common Information Entry
    311 $LSCIE0:
    312 	.4byte	0x0	 # CIE Identifier Tag
    313 	.byte	0x1	 # CIE Version
    314 	.ascii "zR\0"	 # CIE Augmentation
    315 	.uleb128 0x1	 # CIE Code Alignment Factor
    316 	.sleb128 4	 # CIE Data Alignment Factor
    317 	.byte	0x1f	 # CIE RA Column
    318 	.uleb128 0x1	 # Augmentation size
    319 	.byte	0x00	 # FDE Encoding (absptr)
    320 	.byte	0xc	 # DW_CFA_def_cfa
    321 	.uleb128 0x1d
    322 	.uleb128 0x0
    323 	.align	2
    324 $LECIE0:
    325 $LSFDE0:
    326 	.4byte	$LEFDE0-$LASFDE0	 # FDE Length
    327 $LASFDE0:
    328 	.4byte	$LASFDE0-$Lframe0	 # FDE CIE offset
    329 	.4byte	$LFB0	 # FDE initial location
    330 	.4byte	$LFE0-$LFB0	 # FDE address range
    331 	.uleb128 0x0	 # Augmentation size
    332 	.byte	0x4	 # DW_CFA_advance_loc4
    333 	.4byte	$LCFI0-$LFB0
    334 	.byte	0xe	 # DW_CFA_def_cfa_offset
    335 	.uleb128 0x18
    336 	.byte	0x4	 # DW_CFA_advance_loc4
    337 	.4byte	$LCFI2-$LCFI0
    338 	.byte	0x11	 # DW_CFA_offset_extended_sf
    339 	.uleb128 0x1e	 # $fp
    340 	.sleb128 -2	 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
    341 	.byte	0x11	 # DW_CFA_offset_extended_sf
    342 	.uleb128 0x1f	 # $ra
    343 	.sleb128 -1	 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
    344 	.byte	0x4	 # DW_CFA_advance_loc4
    345 	.4byte	$LCFI3-$LCFI2
    346 	.byte	0xc	 # DW_CFA_def_cfa
    347 	.uleb128 0x1e
    348 	.uleb128 0x18
    349 	.align	2
    350 $LEFDE0:
    351 $LSFDE1:
    352 	.4byte	$LEFDE1-$LASFDE1	 # FDE Length
    353 $LASFDE1:
    354 	.4byte	$LASFDE1-$Lframe0	 # FDE CIE offset
    355 	.4byte	$LFB1	 # FDE initial location
    356 	.4byte	$LFE1-$LFB1	 # FDE address range
    357 	.uleb128 0x0	 # Augmentation size
    358 	.byte	0x4	 # DW_CFA_advance_loc4
    359 	.4byte	$LCFI4-$LFB1
    360 	.byte	0xe	 # DW_CFA_def_cfa_offset
    361 	.uleb128 0x38
    362 	.byte	0x4	 # DW_CFA_advance_loc4
    363 	.4byte	$LCFI6-$LCFI4
    364 	.byte	0x11	 # DW_CFA_offset_extended_sf
    365 	.uleb128 0x10	 # $16
    366 	.sleb128 -3	 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
    367 	.byte	0x11	 # DW_CFA_offset_extended_sf
    368 	.uleb128 0x1e	 # $fp
    369 	.sleb128 -2	 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
    370 	.byte	0x11	 # DW_CFA_offset_extended_sf
    371 	.uleb128 0x1f	 # $ra
    372 	.sleb128 -1	 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
    373 	.byte	0x4	 # DW_CFA_advance_loc4
    374 	.4byte	$LCFI7-$LCFI6
    375 	.byte	0xc	 # DW_CFA_def_cfa
    376 	.uleb128 0x1e
    377 	.uleb128 0x38
    378 	.align	2
    379 $LEFDE1:
    380 
    381 #endif
    382