/Modules/_ctypes/libffi_msvc/win32.c

http://unladen-swallow.googlecode.com/ · C · 267 lines · 144 code · 40 blank · 83 comment · 0 complexity · 3edb1646d7a0551a10e31f9b60f4fa4d MD5 · raw file

  1. /* -----------------------------------------------------------------------
  2. win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc.
  3. Copyright (c) 2001 John Beniton
  4. Copyright (c) 2002 Ranjit Mathew
  5. X86 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:
  13. The above copyright notice and this permission notice shall be included
  14. in all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
  16. OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  18. IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  19. OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  20. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  21. OTHER DEALINGS IN THE SOFTWARE.
  22. ----------------------------------------------------------------------- */
  23. /* theller: almost verbatim translation from gas syntax to MSVC inline
  24. assembler code. */
  25. /* theller: ffi_call_SYSV and ffi_call_STDCALL now return an integer - the
  26. difference of the stack pointer before and after the function call. If
  27. everything is ok, zero is returned. If stdcall functions are passed the
  28. wrong number of arguments, the difference will be nonzero. */
  29. #include <ffi.h>
  30. #include <ffi_common.h>
  31. __declspec(naked) int
  32. ffi_call_SYSV(void (* prepfunc)(char *, extended_cif *), /* 8 */
  33. extended_cif *ecif, /* 12 */
  34. unsigned bytes, /* 16 */
  35. unsigned flags, /* 20 */
  36. unsigned *rvalue, /* 24 */
  37. void (*fn)()) /* 28 */
  38. {
  39. _asm {
  40. push ebp
  41. mov ebp, esp
  42. push esi // NEW: this register must be preserved across function calls
  43. // XXX SAVE ESP NOW!
  44. mov esi, esp // save stack pointer before the call
  45. // Make room for all of the new args.
  46. mov ecx, [ebp+16]
  47. sub esp, ecx // sub esp, bytes
  48. mov eax, esp
  49. // Place all of the ffi_prep_args in position
  50. push [ebp + 12] // ecif
  51. push eax
  52. call [ebp + 8] // prepfunc
  53. // Return stack to previous state and call the function
  54. add esp, 8
  55. // FIXME: Align the stack to a 128-bit boundary to avoid
  56. // potential performance hits.
  57. call [ebp + 28]
  58. // Remove the space we pushed for the args
  59. mov ecx, [ebp + 16]
  60. add esp, ecx
  61. // XXX ASSERT THAT ESP IS THE SAME NOW THAN BEFORE!
  62. sub esi, esp
  63. // Load %ecx with the return type code
  64. mov ecx, [ebp + 20]
  65. // If the return value pointer is NULL, assume no return value.
  66. /*
  67. Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction,
  68. otherwise only one BYTE will be compared (instead of a DWORD)!
  69. */
  70. cmp DWORD PTR [ebp + 24], 0
  71. jne sc_retint
  72. // Even if there is no space for the return value, we are
  73. // obliged to handle floating-point values.
  74. cmp ecx, FFI_TYPE_FLOAT
  75. jne sc_noretval
  76. // fstp %st(0)
  77. fstp st(0)
  78. jmp sc_epilogue
  79. sc_retint:
  80. cmp ecx, FFI_TYPE_INT
  81. jne sc_retfloat
  82. // # Load %ecx with the pointer to storage for the return value
  83. mov ecx, [ebp + 24]
  84. mov [ecx + 0], eax
  85. jmp sc_epilogue
  86. sc_retfloat:
  87. cmp ecx, FFI_TYPE_FLOAT
  88. jne sc_retdouble
  89. // Load %ecx with the pointer to storage for the return value
  90. mov ecx, [ebp+24]
  91. // fstps (%ecx)
  92. fstp DWORD PTR [ecx]
  93. jmp sc_epilogue
  94. sc_retdouble:
  95. cmp ecx, FFI_TYPE_DOUBLE
  96. jne sc_retlongdouble
  97. // movl 24(%ebp),%ecx
  98. mov ecx, [ebp+24]
  99. fstp QWORD PTR [ecx]
  100. jmp sc_epilogue
  101. jmp sc_retlongdouble // avoid warning about unused label
  102. sc_retlongdouble:
  103. cmp ecx, FFI_TYPE_LONGDOUBLE
  104. jne sc_retint64
  105. // Load %ecx with the pointer to storage for the return value
  106. mov ecx, [ebp+24]
  107. // fstpt (%ecx)
  108. fstp QWORD PTR [ecx] /* XXX ??? */
  109. jmp sc_epilogue
  110. sc_retint64:
  111. cmp ecx, FFI_TYPE_SINT64
  112. jne sc_retstruct
  113. // Load %ecx with the pointer to storage for the return value
  114. mov ecx, [ebp+24]
  115. mov [ecx+0], eax
  116. mov [ecx+4], edx
  117. sc_retstruct:
  118. // Nothing to do!
  119. sc_noretval:
  120. sc_epilogue:
  121. mov eax, esi
  122. pop esi // NEW restore: must be preserved across function calls
  123. mov esp, ebp
  124. pop ebp
  125. ret
  126. }
  127. }
  128. __declspec(naked) int
  129. ffi_call_STDCALL(void (* prepfunc)(char *, extended_cif *), /* 8 */
  130. extended_cif *ecif, /* 12 */
  131. unsigned bytes, /* 16 */
  132. unsigned flags, /* 20 */
  133. unsigned *rvalue, /* 24 */
  134. void (*fn)()) /* 28 */
  135. {
  136. _asm {
  137. push ebp
  138. mov ebp, esp
  139. push esi // NEW: this register must be preserved across function calls
  140. // XXX SAVE ESP NOW!
  141. mov esi, esp
  142. // Make room for all of the new args.
  143. mov ecx, [ebp+16]
  144. sub esp, ecx
  145. mov eax, esp
  146. // Place all of the ffi_prep_args in position
  147. push [ebp + 12] // ecif
  148. push eax
  149. call [ebp + 8] // prepfunc
  150. // Return stack to previous state and call the function
  151. add esp, 8
  152. // FIXME: Align the stack to a 128-bit boundary to avoid
  153. // potential performance hits.
  154. call [ebp + 28]
  155. // stdcall functions pop arguments off the stack themselves
  156. // XXX IS ESP NOW THE SAME AS BEFORE?
  157. sub esi, esp
  158. // Load %ecx with the return type code
  159. mov ecx, [ebp + 20]
  160. // If the return value pointer is NULL, assume no return value.
  161. /*
  162. Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction,
  163. otherwise only one BYTE will be compared (instead of a DWORD)!
  164. */
  165. cmp DWORD PTR [ebp + 24], 0
  166. jne sc_retint
  167. // Even if there is no space for the return value, we are
  168. // obliged to handle floating-point values.
  169. cmp ecx, FFI_TYPE_FLOAT
  170. jne sc_noretval
  171. // fstp %st(0)
  172. fstp st(0)
  173. jmp sc_epilogue
  174. sc_retint:
  175. cmp ecx, FFI_TYPE_INT
  176. jne sc_retfloat
  177. // # Load %ecx with the pointer to storage for the return value
  178. mov ecx, [ebp + 24]
  179. mov [ecx + 0], eax
  180. jmp sc_epilogue
  181. sc_retfloat:
  182. cmp ecx, FFI_TYPE_FLOAT
  183. jne sc_retdouble
  184. // Load %ecx with the pointer to storage for the return value
  185. mov ecx, [ebp+24]
  186. // fstps (%ecx)
  187. fstp DWORD PTR [ecx]
  188. jmp sc_epilogue
  189. sc_retdouble:
  190. cmp ecx, FFI_TYPE_DOUBLE
  191. jne sc_retlongdouble
  192. // movl 24(%ebp),%ecx
  193. mov ecx, [ebp+24]
  194. fstp QWORD PTR [ecx]
  195. jmp sc_epilogue
  196. jmp sc_retlongdouble // avoid warning about unused label
  197. sc_retlongdouble:
  198. cmp ecx, FFI_TYPE_LONGDOUBLE
  199. jne sc_retint64
  200. // Load %ecx with the pointer to storage for the return value
  201. mov ecx, [ebp+24]
  202. // fstpt (%ecx)
  203. fstp QWORD PTR [ecx] /* XXX ??? */
  204. jmp sc_epilogue
  205. sc_retint64:
  206. cmp ecx, FFI_TYPE_SINT64
  207. jne sc_retstruct
  208. // Load %ecx with the pointer to storage for the return value
  209. mov ecx, [ebp+24]
  210. mov [ecx+0], eax
  211. mov [ecx+4], edx
  212. sc_retstruct:
  213. // Nothing to do!
  214. sc_noretval:
  215. sc_epilogue:
  216. mov eax, esi
  217. pop esi // NEW restore: must be preserved across function calls
  218. mov esp, ebp
  219. pop ebp
  220. ret
  221. }
  222. }