/Modules/_ctypes/libffi/src/mips/o32.S

http://unladen-swallow.googlecode.com/ · Assembly · 381 lines · 282 code · 46 blank · 53 comment · 3 complexity · ded4d88fee780e3a2962fc40e355f52e MD5 · raw file

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