as_callfunc_x86.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2013 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. //
  24. // as_callfunc_x86.cpp
  25. //
  26. // These functions handle the actual calling of system functions
  27. //
  28. #include "as_config.h"
  29. #ifndef AS_MAX_PORTABILITY
  30. #ifdef AS_X86
  31. #include "as_callfunc.h"
  32. #include "as_scriptengine.h"
  33. #include "as_texts.h"
  34. #include "as_tokendef.h"
  35. #include "as_context.h"
  36. BEGIN_AS_NAMESPACE
  37. //
  38. // With some compile level optimizations the functions don't clear the FPU
  39. // stack themselves. So we have to do it as part of calling the native functions,
  40. // as the compiler will not be able to predict when it is supposed to do it by
  41. // itself due to the dynamic nature of scripts
  42. //
  43. // - fninit clears the FPU stack and the FPU control word
  44. // - emms only clears the FPU stack, while preserving the FPU control word
  45. //
  46. // By default I use fninit as it seems to be what works for most people,
  47. // but some may find it necessary to define this as emms instead.
  48. //
  49. // TODO: Figure out when one or the other must be used, and a way to
  50. // configure this automatically in as_config.h
  51. //
  52. #ifndef CLEAR_FPU_STACK
  53. #define CLEAR_FPU_STACK fninit
  54. #endif
  55. // These macros are just to allow me to use the above macro in the GNUC style inline assembly
  56. #define _S(x) _TOSTRING(x)
  57. #define _TOSTRING(x) #x
  58. // Prototypes
  59. asQWORD CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func);
  60. asQWORD CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
  61. asQWORD CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
  62. asQWORD CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
  63. asQWORD CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
  64. asQWORD CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
  65. asQWORD CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func);
  66. asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
  67. asQWORD CallThisCallFunctionRetByRef(const void *, const asDWORD *, int, asFUNCTION_t, void *retPtr);
  68. asDWORD GetReturnedFloat();
  69. asQWORD GetReturnedDouble();
  70. asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/)
  71. {
  72. asCScriptEngine *engine = context->m_engine;
  73. asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
  74. asQWORD retQW = 0;
  75. // Prepare the parameters
  76. int paramSize = sysFunc->paramSize;
  77. asDWORD paramBuffer[64];
  78. if( sysFunc->takesObjByVal )
  79. {
  80. paramSize = 0;
  81. int spos = 0;
  82. int dpos = 1;
  83. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  84. {
  85. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
  86. {
  87. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  88. if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
  89. {
  90. paramBuffer[dpos++] = args[spos++];
  91. paramSize++;
  92. }
  93. else
  94. #endif
  95. {
  96. // Copy the object's memory to the buffer
  97. // TODO: bug: Must call the object's copy constructor instead of doing a memcpy,
  98. // as the object may hold a pointer to itself. It's not enough to
  99. // change only this memcpy as the assembler routine also makes a copy
  100. // of paramBuffer to the final stack location. To avoid the second
  101. // copy the C++ routine should point paramBuffer to the final stack
  102. // position and copy the values directly to that location. The assembler
  103. // routines then don't need to copy anything, and will just be
  104. // responsible for setting up the registers and the stack frame appropriately.
  105. memcpy(&paramBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
  106. // Delete the original memory
  107. engine->CallFree(*(char**)(args+spos));
  108. spos++;
  109. dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
  110. paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
  111. }
  112. }
  113. else
  114. {
  115. // Copy the value directly
  116. paramBuffer[dpos++] = args[spos++];
  117. if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
  118. paramBuffer[dpos++] = args[spos++];
  119. paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
  120. }
  121. }
  122. // Keep a free location at the beginning
  123. args = &paramBuffer[1];
  124. }
  125. // Make the actual call
  126. asFUNCTION_t func = sysFunc->func;
  127. int callConv = sysFunc->callConv;
  128. if( sysFunc->hostReturnInMemory )
  129. callConv++;
  130. switch( callConv )
  131. {
  132. case ICC_CDECL:
  133. retQW = CallCDeclFunction(args, paramSize<<2, func);
  134. break;
  135. case ICC_CDECL_RETURNINMEM:
  136. retQW = CallCDeclFunctionRetByRef(args, paramSize<<2, func, retPointer);
  137. break;
  138. case ICC_STDCALL:
  139. retQW = CallSTDCallFunction(args, paramSize<<2, func);
  140. break;
  141. case ICC_STDCALL_RETURNINMEM:
  142. // Push the return pointer on the stack
  143. paramSize++;
  144. args--;
  145. *(asPWORD*)args = (size_t)retPointer;
  146. retQW = CallSTDCallFunction(args, paramSize<<2, func);
  147. break;
  148. case ICC_THISCALL:
  149. retQW = CallThisCallFunction(obj, args, paramSize<<2, func);
  150. break;
  151. case ICC_THISCALL_RETURNINMEM:
  152. retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, func, retPointer);
  153. break;
  154. case ICC_VIRTUAL_THISCALL:
  155. {
  156. // Get virtual function table from the object pointer
  157. asFUNCTION_t *vftable = *(asFUNCTION_t**)obj;
  158. retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2]);
  159. }
  160. break;
  161. case ICC_VIRTUAL_THISCALL_RETURNINMEM:
  162. {
  163. // Get virtual function table from the object pointer
  164. asFUNCTION_t *vftable = *(asFUNCTION_t**)obj;
  165. retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], retPointer);
  166. }
  167. break;
  168. case ICC_CDECL_OBJLAST:
  169. retQW = CallCDeclFunctionObjLast(obj, args, paramSize<<2, func);
  170. break;
  171. case ICC_CDECL_OBJLAST_RETURNINMEM:
  172. // Call the system object method as a cdecl with the obj ref as the last parameter
  173. retQW = CallCDeclFunctionRetByRefObjLast(obj, args, paramSize<<2, func, retPointer);
  174. break;
  175. case ICC_CDECL_OBJFIRST:
  176. // Call the system object method as a cdecl with the obj ref as the first parameter
  177. retQW = CallCDeclFunctionObjFirst(obj, args, paramSize<<2, func);
  178. break;
  179. case ICC_CDECL_OBJFIRST_RETURNINMEM:
  180. // Call the system object method as a cdecl with the obj ref as the first parameter
  181. retQW = CallCDeclFunctionRetByRefObjFirst(obj, args, paramSize<<2, func, retPointer);
  182. break;
  183. default:
  184. context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
  185. }
  186. // If the return is a float value we need to get the value from the FP register
  187. if( sysFunc->hostReturnFloat )
  188. {
  189. if( sysFunc->hostReturnSize == 1 )
  190. *(asDWORD*)&retQW = GetReturnedFloat();
  191. else
  192. retQW = GetReturnedDouble();
  193. }
  194. return retQW;
  195. }
  196. // On GCC we need to prevent the compiler from inlining these assembler routines when
  197. // optimizing for speed (-O3), as the loop labels get duplicated which cause compile errors.
  198. #ifdef __GNUC__
  199. #define NOINLINE __attribute ((__noinline__))
  200. #else
  201. #define NOINLINE
  202. #endif
  203. asQWORD NOINLINE CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
  204. {
  205. volatile asQWORD retQW = 0;
  206. #if defined ASM_INTEL
  207. // Copy the data to the real stack. If we fail to do
  208. // this we may run into trouble in case of exceptions.
  209. __asm
  210. {
  211. // We must save registers that are used
  212. push ecx
  213. // Clear the FPU stack, in case the called function doesn't do it by itself
  214. CLEAR_FPU_STACK
  215. // Copy arguments from script
  216. // stack to application stack
  217. mov ecx, paramSize
  218. mov eax, args
  219. add eax, ecx
  220. cmp ecx, 0
  221. je endcopy
  222. copyloop:
  223. sub eax, 4
  224. push dword ptr [eax]
  225. sub ecx, 4
  226. jne copyloop
  227. endcopy:
  228. // Call function
  229. call [func]
  230. // Pop arguments from stack
  231. add esp, paramSize
  232. // Copy return value from EAX:EDX
  233. lea ecx, retQW
  234. mov [ecx], eax
  235. mov 4[ecx], edx
  236. // Restore registers
  237. pop ecx
  238. }
  239. #elif defined ASM_AT_N_T
  240. // It is not possible to rely on ESP or BSP to refer to variables or arguments on the stack
  241. // depending on compiler settings BSP may not even be used, and the ESP is not always on the
  242. // same offset from the local variables. Because the code adjusts the ESP register it is not
  243. // possible to inform the arguments through symbolic names below.
  244. // It's not also not possible to rely on the memory layout of the function arguments, because
  245. // on some compiler versions and settings the arguments may be copied to local variables with a
  246. // different ordering before they are accessed by the rest of the code.
  247. // I'm copying the arguments into this array where I know the exact memory layout. The address
  248. // of this array will then be passed to the inline asm in the EDX register.
  249. volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  250. asm __volatile__(
  251. _S(CLEAR_FPU_STACK) "\n"
  252. "pushl %%ebx \n"
  253. "movl %%edx, %%ebx \n"
  254. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  255. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  256. // to calculate how much we will put on the stack during this call.
  257. "movl 4(%%ebx), %%eax \n" // paramSize
  258. "addl $4, %%eax \n" // counting esp that we will push on the stack
  259. "movl %%esp, %%ecx \n"
  260. "subl %%eax, %%ecx \n"
  261. "andl $15, %%ecx \n"
  262. "movl %%esp, %%eax \n"
  263. "subl %%ecx, %%esp \n"
  264. "pushl %%eax \n" // Store the original stack pointer
  265. // Copy all arguments to the stack and call the function
  266. "movl 4(%%ebx), %%ecx \n" // paramSize
  267. "movl 0(%%ebx), %%eax \n" // args
  268. "addl %%ecx, %%eax \n" // push arguments on the stack
  269. "cmp $0, %%ecx \n"
  270. "je endcopy \n"
  271. "copyloop: \n"
  272. "subl $4, %%eax \n"
  273. "pushl (%%eax) \n"
  274. "subl $4, %%ecx \n"
  275. "jne copyloop \n"
  276. "endcopy: \n"
  277. "call *8(%%ebx) \n"
  278. "addl 4(%%ebx), %%esp \n" // pop arguments
  279. // Pop the alignment bytes
  280. "popl %%esp \n"
  281. "popl %%ebx \n"
  282. // Copy EAX:EDX to retQW. As the stack pointer has been
  283. // restored it is now safe to access the local variable
  284. "leal %1, %%ecx \n"
  285. "movl %%eax, 0(%%ecx) \n"
  286. "movl %%edx, 4(%%ecx) \n"
  287. : // output
  288. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  289. : "%eax", "%ecx" // clobber
  290. );
  291. #endif
  292. return retQW;
  293. }
  294. asQWORD NOINLINE CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
  295. {
  296. volatile asQWORD retQW = 0;
  297. #if defined ASM_INTEL
  298. // Copy the data to the real stack. If we fail to do
  299. // this we may run into trouble in case of exceptions.
  300. __asm
  301. {
  302. // We must save registers that are used
  303. push ecx
  304. // Clear the FPU stack, in case the called function doesn't do it by itself
  305. CLEAR_FPU_STACK
  306. // Push the object pointer as the last argument to the function
  307. push obj
  308. // Copy arguments from script
  309. // stack to application stack
  310. mov ecx, paramSize
  311. mov eax, args
  312. add eax, ecx
  313. cmp ecx, 0
  314. je endcopy
  315. copyloop:
  316. sub eax, 4
  317. push dword ptr [eax]
  318. sub ecx, 4
  319. jne copyloop
  320. endcopy:
  321. // Call function
  322. call [func]
  323. // Pop arguments from stack
  324. add esp, paramSize
  325. add esp, 4
  326. // Copy return value from EAX:EDX
  327. lea ecx, retQW
  328. mov [ecx], eax
  329. mov 4[ecx], edx
  330. // Restore registers
  331. pop ecx
  332. }
  333. #elif defined ASM_AT_N_T
  334. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  335. asm __volatile__ (
  336. _S(CLEAR_FPU_STACK) "\n"
  337. "pushl %%ebx \n"
  338. "movl %%edx, %%ebx \n"
  339. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  340. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  341. // to calculate how much we will put on the stack during this call.
  342. "movl 8(%%ebx), %%eax \n" // paramSize
  343. "addl $8, %%eax \n" // counting esp that we will push on the stack
  344. "movl %%esp, %%ecx \n"
  345. "subl %%eax, %%ecx \n"
  346. "andl $15, %%ecx \n"
  347. "movl %%esp, %%eax \n"
  348. "subl %%ecx, %%esp \n"
  349. "pushl %%eax \n" // Store the original stack pointer
  350. "pushl 0(%%ebx) \n" // obj
  351. "movl 8(%%ebx), %%ecx \n" // paramSize
  352. "movl 4(%%ebx), %%eax \n" // args
  353. "addl %%ecx, %%eax \n" // push arguments on the stack
  354. "cmp $0, %%ecx \n"
  355. "je endcopy8 \n"
  356. "copyloop8: \n"
  357. "subl $4, %%eax \n"
  358. "pushl (%%eax) \n"
  359. "subl $4, %%ecx \n"
  360. "jne copyloop8 \n"
  361. "endcopy8: \n"
  362. "call *12(%%ebx) \n"
  363. "addl 8(%%ebx), %%esp \n" // pop arguments
  364. "addl $4, %%esp \n" // pop obj
  365. // Pop the alignment bytes
  366. "popl %%esp \n"
  367. "popl %%ebx \n"
  368. // Copy EAX:EDX to retQW. As the stack pointer has been
  369. // restored it is now safe to access the local variable
  370. "leal %1, %%ecx \n"
  371. "movl %%eax, 0(%%ecx) \n"
  372. "movl %%edx, 4(%%ecx) \n"
  373. : // output
  374. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  375. : "%eax", "%ecx" // clobber
  376. );
  377. #endif
  378. return retQW;
  379. }
  380. asQWORD NOINLINE CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
  381. {
  382. volatile asQWORD retQW = 0;
  383. #if defined ASM_INTEL
  384. // Copy the data to the real stack. If we fail to do
  385. // this we may run into trouble in case of exceptions.
  386. __asm
  387. {
  388. // We must save registers that are used
  389. push ecx
  390. // Clear the FPU stack, in case the called function doesn't do it by itself
  391. CLEAR_FPU_STACK
  392. // Copy arguments from script
  393. // stack to application stack
  394. mov ecx, paramSize
  395. mov eax, args
  396. add eax, ecx
  397. cmp ecx, 0
  398. je endcopy
  399. copyloop:
  400. sub eax, 4
  401. push dword ptr [eax]
  402. sub ecx, 4
  403. jne copyloop
  404. endcopy:
  405. // push object as first parameter
  406. push obj
  407. // Call function
  408. call [func]
  409. // Pop arguments from stack
  410. add esp, paramSize
  411. add esp, 4
  412. // Copy return value from EAX:EDX
  413. lea ecx, retQW
  414. mov [ecx], eax
  415. mov 4[ecx], edx
  416. // Restore registers
  417. pop ecx
  418. }
  419. #elif defined ASM_AT_N_T
  420. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  421. asm __volatile__ (
  422. _S(CLEAR_FPU_STACK) "\n"
  423. "pushl %%ebx \n"
  424. "movl %%edx, %%ebx \n"
  425. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  426. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  427. // to calculate how much we will put on the stack during this call.
  428. "movl 8(%%ebx), %%eax \n" // paramSize
  429. "addl $8, %%eax \n" // counting esp that we will push on the stack
  430. "movl %%esp, %%ecx \n"
  431. "subl %%eax, %%ecx \n"
  432. "andl $15, %%ecx \n"
  433. "movl %%esp, %%eax \n"
  434. "subl %%ecx, %%esp \n"
  435. "pushl %%eax \n" // Store the original stack pointer
  436. "movl 8(%%ebx), %%ecx \n" // paramSize
  437. "movl 4(%%ebx), %%eax \n" // args
  438. "addl %%ecx, %%eax \n" // push arguments on the stack
  439. "cmp $0, %%ecx \n"
  440. "je endcopy6 \n"
  441. "copyloop6: \n"
  442. "subl $4, %%eax \n"
  443. "pushl (%%eax) \n"
  444. "subl $4, %%ecx \n"
  445. "jne copyloop6 \n"
  446. "endcopy6: \n"
  447. "pushl 0(%%ebx) \n" // push obj
  448. "call *12(%%ebx) \n"
  449. "addl 8(%%ebx), %%esp \n" // pop arguments
  450. "addl $4, %%esp \n" // pop obj
  451. // Pop the alignment bytes
  452. "popl %%esp \n"
  453. "popl %%ebx \n"
  454. // Copy EAX:EDX to retQW. As the stack pointer has been
  455. // restored it is now safe to access the local variable
  456. "leal %1, %%ecx \n"
  457. "movl %%eax, 0(%%ecx) \n"
  458. "movl %%edx, 4(%%ecx) \n"
  459. : // output
  460. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  461. : "%eax", "%ecx" // clobber
  462. );
  463. #endif
  464. return retQW;
  465. }
  466. asQWORD NOINLINE CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
  467. {
  468. volatile asQWORD retQW = 0;
  469. #if defined ASM_INTEL
  470. // Copy the data to the real stack. If we fail to do
  471. // this we may run into trouble in case of exceptions.
  472. __asm
  473. {
  474. // We must save registers that are used
  475. push ecx
  476. // Clear the FPU stack, in case the called function doesn't do it by itself
  477. CLEAR_FPU_STACK
  478. // Copy arguments from script
  479. // stack to application stack
  480. mov ecx, paramSize
  481. mov eax, args
  482. add eax, ecx
  483. cmp ecx, 0
  484. je endcopy
  485. copyloop:
  486. sub eax, 4
  487. push dword ptr [eax]
  488. sub ecx, 4
  489. jne copyloop
  490. endcopy:
  491. // Push the object pointer
  492. push obj
  493. // Push the return pointer
  494. push retPtr;
  495. // Call function
  496. call [func]
  497. // Pop arguments from stack
  498. add esp, paramSize
  499. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  500. // Pop the return pointer
  501. add esp, 8
  502. #else
  503. add esp, 4
  504. #endif
  505. // Copy return value from EAX:EDX
  506. lea ecx, retQW
  507. mov [ecx], eax
  508. mov 4[ecx], edx
  509. // Restore registers
  510. pop ecx
  511. }
  512. #elif defined ASM_AT_N_T
  513. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
  514. asm __volatile__ (
  515. _S(CLEAR_FPU_STACK) "\n"
  516. "pushl %%ebx \n"
  517. "movl %%edx, %%ebx \n"
  518. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  519. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  520. // to calculate how much we will put on the stack during this call.
  521. "movl 8(%%ebx), %%eax \n" // paramSize
  522. "addl $12, %%eax \n" // counting esp that we will push on the stack
  523. "movl %%esp, %%ecx \n"
  524. "subl %%eax, %%ecx \n"
  525. "andl $15, %%ecx \n"
  526. "movl %%esp, %%eax \n"
  527. "subl %%ecx, %%esp \n"
  528. "pushl %%eax \n" // Store the original stack pointer
  529. "movl 8(%%ebx), %%ecx \n" // paramSize
  530. "movl 4(%%ebx), %%eax \n" // args
  531. "addl %%ecx, %%eax \n" // push arguments on the stack
  532. "cmp $0, %%ecx \n"
  533. "je endcopy5 \n"
  534. "copyloop5: \n"
  535. "subl $4, %%eax \n"
  536. "pushl (%%eax) \n"
  537. "subl $4, %%ecx \n"
  538. "jne copyloop5 \n"
  539. "endcopy5: \n"
  540. "pushl 0(%%ebx) \n" // push object first
  541. "pushl 16(%%ebx) \n" // retPtr
  542. "call *12(%%ebx) \n" // func
  543. "addl 8(%%ebx), %%esp \n" // pop arguments
  544. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  545. "addl $8, %%esp \n" // Pop the return pointer and object pointer
  546. #else
  547. "addl $4, %%esp \n" // Pop the object pointer
  548. #endif
  549. // Pop the alignment bytes
  550. "popl %%esp \n"
  551. "popl %%ebx \n"
  552. // Copy EAX:EDX to retQW. As the stack pointer has been
  553. // restored it is now safe to access the local variable
  554. "leal %1, %%ecx \n"
  555. "movl %%eax, 0(%%ecx) \n"
  556. "movl %%edx, 4(%%ecx) \n"
  557. : // output
  558. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  559. : "%eax", "%ecx" // clobber
  560. );
  561. #endif
  562. return retQW;
  563. }
  564. asQWORD NOINLINE CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
  565. {
  566. volatile asQWORD retQW = 0;
  567. #if defined ASM_INTEL
  568. // Copy the data to the real stack. If we fail to do
  569. // this we may run into trouble in case of exceptions.
  570. __asm
  571. {
  572. // We must save registers that are used
  573. push ecx
  574. // Clear the FPU stack, in case the called function doesn't do it by itself
  575. CLEAR_FPU_STACK
  576. // Copy arguments from script
  577. // stack to application stack
  578. mov ecx, paramSize
  579. mov eax, args
  580. add eax, ecx
  581. cmp ecx, 0
  582. je endcopy
  583. copyloop:
  584. sub eax, 4
  585. push dword ptr [eax]
  586. sub ecx, 4
  587. jne copyloop
  588. endcopy:
  589. // Push the return pointer
  590. push retPtr;
  591. // Call function
  592. call [func]
  593. // Pop arguments from stack
  594. add esp, paramSize
  595. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  596. // Pop the return pointer
  597. add esp, 4
  598. #endif
  599. // Copy return value from EAX:EDX
  600. lea ecx, retQW
  601. mov [ecx], eax
  602. mov 4[ecx], edx
  603. // Restore registers
  604. pop ecx
  605. // return value in EAX or EAX:EDX
  606. }
  607. #elif defined ASM_AT_N_T
  608. volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
  609. asm __volatile__ (
  610. _S(CLEAR_FPU_STACK) "\n"
  611. "pushl %%ebx \n"
  612. "movl %%edx, %%ebx \n"
  613. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  614. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  615. // to calculate how much we will put on the stack during this call.
  616. "movl 4(%%ebx), %%eax \n" // paramSize
  617. "addl $8, %%eax \n" // counting esp that we will push on the stack
  618. "movl %%esp, %%ecx \n"
  619. "subl %%eax, %%ecx \n"
  620. "andl $15, %%ecx \n"
  621. "movl %%esp, %%eax \n"
  622. "subl %%ecx, %%esp \n"
  623. "pushl %%eax \n" // Store the original stack pointer
  624. "movl 4(%%ebx), %%ecx \n" // paramSize
  625. "movl 0(%%ebx), %%eax \n" // args
  626. "addl %%ecx, %%eax \n" // push arguments on the stack
  627. "cmp $0, %%ecx \n"
  628. "je endcopy7 \n"
  629. "copyloop7: \n"
  630. "subl $4, %%eax \n"
  631. "pushl (%%eax) \n"
  632. "subl $4, %%ecx \n"
  633. "jne copyloop7 \n"
  634. "endcopy7: \n"
  635. "pushl 12(%%ebx) \n" // retPtr
  636. "call *8(%%ebx) \n" // func
  637. "addl 4(%%ebx), %%esp \n" // pop arguments
  638. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  639. "addl $4, %%esp \n" // Pop the return pointer
  640. #endif
  641. // Pop the alignment bytes
  642. "popl %%esp \n"
  643. "popl %%ebx \n"
  644. // Copy EAX:EDX to retQW. As the stack pointer has been
  645. // restored it is now safe to access the local variable
  646. "leal %1, %%ecx \n"
  647. "movl %%eax, 0(%%ecx) \n"
  648. "movl %%edx, 4(%%ecx) \n"
  649. : // output
  650. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  651. : "%eax", "%ecx" // clobber
  652. );
  653. #endif
  654. return retQW;
  655. }
  656. asQWORD NOINLINE CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
  657. {
  658. volatile asQWORD retQW = 0;
  659. #if defined ASM_INTEL
  660. // Copy the data to the real stack. If we fail to do
  661. // this we may run into trouble in case of exceptions.
  662. __asm
  663. {
  664. // We must save registers that are used
  665. push ecx
  666. // Clear the FPU stack, in case the called function doesn't do it by itself
  667. CLEAR_FPU_STACK
  668. push obj
  669. // Copy arguments from script
  670. // stack to application stack
  671. mov ecx, paramSize
  672. mov eax, args
  673. add eax, ecx
  674. cmp ecx, 0
  675. je endcopy
  676. copyloop:
  677. sub eax, 4
  678. push dword ptr [eax]
  679. sub ecx, 4
  680. jne copyloop
  681. endcopy:
  682. // Push the return pointer
  683. push retPtr;
  684. // Call function
  685. call [func]
  686. // Pop arguments from stack
  687. add esp, paramSize
  688. add esp, 4
  689. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  690. // Pop the return pointer
  691. add esp, 4
  692. #endif
  693. // Copy return value from EAX:EDX
  694. lea ecx, retQW
  695. mov [ecx], eax
  696. mov 4[ecx], edx
  697. // Restore registers
  698. pop ecx
  699. }
  700. #elif defined ASM_AT_N_T
  701. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
  702. asm __volatile__ (
  703. _S(CLEAR_FPU_STACK) "\n"
  704. "pushl %%ebx \n"
  705. "movl %%edx, %%ebx \n"
  706. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  707. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  708. // to calculate how much we will put on the stack during this call.
  709. "movl 8(%%ebx), %%eax \n" // paramSize
  710. "addl $12, %%eax \n" // counting esp that we will push on the stack
  711. "movl %%esp, %%ecx \n"
  712. "subl %%eax, %%ecx \n"
  713. "andl $15, %%ecx \n"
  714. "movl %%esp, %%eax \n"
  715. "subl %%ecx, %%esp \n"
  716. "pushl %%eax \n" // Store the original stack pointer
  717. "pushl 0(%%ebx) \n" // obj
  718. "movl 8(%%ebx), %%ecx \n" // paramSize
  719. "movl 4(%%ebx), %%eax \n" // args
  720. "addl %%ecx, %%eax \n" // push arguments on the stack
  721. "cmp $0, %%ecx \n"
  722. "je endcopy4 \n"
  723. "copyloop4: \n"
  724. "subl $4, %%eax \n"
  725. "pushl (%%eax) \n"
  726. "subl $4, %%ecx \n"
  727. "jne copyloop4 \n"
  728. "endcopy4: \n"
  729. "pushl 16(%%ebx) \n" // retPtr
  730. "call *12(%%ebx) \n" // func
  731. "addl 8(%%ebx), %%esp \n" // pop arguments
  732. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  733. "addl $8, %%esp \n" // Pop the return pointer and object pointer
  734. #else
  735. "addl $4, %%esp \n" // Pop the object pointer
  736. #endif
  737. // Pop the alignment bytes
  738. "popl %%esp \n"
  739. "popl %%ebx \n"
  740. // Copy EAX:EDX to retQW. As the stack pointer has been
  741. // restored it is now safe to access the local variable
  742. "leal %1, %%ecx \n"
  743. "movl %%eax, 0(%%ecx) \n"
  744. "movl %%edx, 4(%%ecx) \n"
  745. : // output
  746. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  747. : "%eax", "%ecx" // clobber
  748. );
  749. #endif
  750. return retQW;
  751. }
  752. asQWORD NOINLINE CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
  753. {
  754. volatile asQWORD retQW = 0;
  755. #if defined ASM_INTEL
  756. // Copy the data to the real stack. If we fail to do
  757. // this we may run into trouble in case of exceptions.
  758. __asm
  759. {
  760. // We must save registers that are used
  761. push ecx
  762. // Clear the FPU stack, in case the called function doesn't do it by itself
  763. CLEAR_FPU_STACK
  764. // Copy arguments from script
  765. // stack to application stack
  766. mov ecx, paramSize
  767. mov eax, args
  768. add eax, ecx
  769. cmp ecx, 0
  770. je endcopy
  771. copyloop:
  772. sub eax, 4
  773. push dword ptr [eax]
  774. sub ecx, 4
  775. jne copyloop
  776. endcopy:
  777. // Call function
  778. call [func]
  779. // The callee already removed parameters from the stack
  780. // Copy return value from EAX:EDX
  781. lea ecx, retQW
  782. mov [ecx], eax
  783. mov 4[ecx], edx
  784. // Restore registers
  785. pop ecx
  786. }
  787. #elif defined ASM_AT_N_T
  788. volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  789. asm __volatile__ (
  790. _S(CLEAR_FPU_STACK) "\n"
  791. "pushl %%ebx \n"
  792. "movl %%edx, %%ebx \n"
  793. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  794. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  795. // to calculate how much we will put on the stack during this call.
  796. "movl 4(%%ebx), %%eax \n" // paramSize
  797. "addl $4, %%eax \n" // counting esp that we will push on the stack
  798. "movl %%esp, %%ecx \n"
  799. "subl %%eax, %%ecx \n"
  800. "andl $15, %%ecx \n"
  801. "movl %%esp, %%eax \n"
  802. "subl %%ecx, %%esp \n"
  803. "pushl %%eax \n" // Store the original stack pointer
  804. "movl 4(%%ebx), %%ecx \n" // paramSize
  805. "movl 0(%%ebx), %%eax \n" // args
  806. "addl %%ecx, %%eax \n" // push arguments on the stack
  807. "cmp $0, %%ecx \n"
  808. "je endcopy2 \n"
  809. "copyloop2: \n"
  810. "subl $4, %%eax \n"
  811. "pushl (%%eax) \n"
  812. "subl $4, %%ecx \n"
  813. "jne copyloop2 \n"
  814. "endcopy2: \n"
  815. "call *8(%%ebx) \n" // callee pops the arguments
  816. // Pop the alignment bytes
  817. "popl %%esp \n"
  818. "popl %%ebx \n"
  819. // Copy EAX:EDX to retQW. As the stack pointer has been
  820. // restored it is now safe to access the local variable
  821. "leal %1, %%ecx \n"
  822. "movl %%eax, 0(%%ecx) \n"
  823. "movl %%edx, 4(%%ecx) \n"
  824. : // output
  825. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  826. : "%eax", "%ecx" // clobber
  827. );
  828. #endif
  829. return retQW;
  830. }
  831. asQWORD NOINLINE CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
  832. {
  833. volatile asQWORD retQW = 0;
  834. #if defined ASM_INTEL
  835. // Copy the data to the real stack. If we fail to do
  836. // this we may run into trouble in case of exceptions.
  837. __asm
  838. {
  839. // We must save registers that are used
  840. push ecx
  841. // Clear the FPU stack, in case the called function doesn't do it by itself
  842. CLEAR_FPU_STACK
  843. // Copy arguments from script
  844. // stack to application stack
  845. mov ecx, paramSize
  846. mov eax, args
  847. add eax, ecx
  848. cmp ecx, 0
  849. je endcopy
  850. copyloop:
  851. sub eax, 4
  852. push dword ptr [eax]
  853. sub ecx, 4
  854. jne copyloop
  855. endcopy:
  856. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  857. // Push the object pointer on the stack
  858. push obj
  859. #else
  860. // Move object pointer to ECX
  861. mov ecx, obj
  862. #endif
  863. // Call function
  864. call [func]
  865. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  866. // Pop arguments
  867. add esp, paramSize
  868. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  869. // Pop object pointer
  870. add esp, 4
  871. #endif
  872. #endif
  873. // Copy return value from EAX:EDX
  874. lea ecx, retQW
  875. mov [ecx], eax
  876. mov 4[ecx], edx
  877. // Restore registers
  878. pop ecx
  879. }
  880. #elif defined ASM_AT_N_T
  881. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  882. asm __volatile__ (
  883. _S(CLEAR_FPU_STACK) "\n"
  884. "pushl %%ebx \n"
  885. "movl %%edx, %%ebx \n"
  886. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  887. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  888. // to calculate how much we will put on the stack during this call.
  889. "movl 8(%%ebx), %%eax \n" // paramSize
  890. "addl $8, %%eax \n" // counting esp that we will push on the stack
  891. "movl %%esp, %%ecx \n"
  892. "subl %%eax, %%ecx \n"
  893. "andl $15, %%ecx \n"
  894. "movl %%esp, %%eax \n"
  895. "subl %%ecx, %%esp \n"
  896. "pushl %%eax \n" // Store the original stack pointer
  897. "movl 8(%%ebx), %%ecx \n" // paramSize
  898. "movl 4(%%ebx), %%eax \n" // args
  899. "addl %%ecx, %%eax \n" // push all arguments on the stack
  900. "cmp $0, %%ecx \n"
  901. "je endcopy1 \n"
  902. "copyloop1: \n"
  903. "subl $4, %%eax \n"
  904. "pushl (%%eax) \n"
  905. "subl $4, %%ecx \n"
  906. "jne copyloop1 \n"
  907. "endcopy1: \n"
  908. "movl 0(%%ebx), %%ecx \n" // move obj into ECX
  909. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  910. "pushl %%ecx \n" // push obj on the stack
  911. #endif
  912. "call *12(%%ebx) \n"
  913. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  914. "addl 8(%%ebx), %%esp \n" // pop arguments
  915. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  916. "addl $4, %%esp \n" // pop obj
  917. #endif
  918. #endif
  919. // Pop the alignment bytes
  920. "popl %%esp \n"
  921. "popl %%ebx \n"
  922. // Copy EAX:EDX to retQW. As the stack pointer has been
  923. // restored it is now safe to access the local variable
  924. "leal %1, %%ecx \n"
  925. "movl %%eax, 0(%%ecx) \n"
  926. "movl %%edx, 4(%%ecx) \n"
  927. : // output
  928. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  929. : "%eax", "%ecx" // clobber
  930. );
  931. #endif
  932. return retQW;
  933. }
  934. asQWORD NOINLINE CallThisCallFunctionRetByRef(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
  935. {
  936. volatile asQWORD retQW = 0;
  937. #if defined ASM_INTEL
  938. // Copy the data to the real stack. If we fail to do
  939. // this we may run into trouble in case of exceptions.
  940. __asm
  941. {
  942. // We must save registers that are used
  943. push ecx
  944. // Clear the FPU stack, in case the called function doesn't do it by itself
  945. CLEAR_FPU_STACK
  946. // Copy arguments from script
  947. // stack to application stack
  948. mov ecx, paramSize
  949. mov eax, args
  950. add eax, ecx
  951. cmp ecx, 0
  952. je endcopy
  953. copyloop:
  954. sub eax, 4
  955. push dword ptr [eax]
  956. sub ecx, 4
  957. jne copyloop
  958. endcopy:
  959. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  960. // Push the object pointer on the stack
  961. push obj
  962. #else
  963. // Move object pointer to ECX
  964. mov ecx, obj
  965. #endif
  966. // Push the return pointer
  967. push retPtr
  968. // Call function
  969. call [func]
  970. #ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER
  971. // Pop the return pointer
  972. add esp, 4
  973. #endif
  974. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  975. // Pop arguments
  976. add esp, paramSize
  977. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  978. // Pop object pointer
  979. add esp, 4
  980. #endif
  981. #endif
  982. // Copy return value from EAX:EDX
  983. lea ecx, retQW
  984. mov [ecx], eax
  985. mov 4[ecx], edx
  986. // Restore registers
  987. pop ecx
  988. }
  989. #elif defined ASM_AT_N_T
  990. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
  991. asm __volatile__ (
  992. _S(CLEAR_FPU_STACK) "\n"
  993. "pushl %%ebx \n"
  994. "movl %%edx, %%ebx \n"
  995. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  996. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  997. // to calculate how much we will put on the stack during this call.
  998. "movl 8(%%ebx), %%eax \n" // paramSize
  999. "addl $12, %%eax \n" // counting esp that we will push on the stack
  1000. "movl %%esp, %%ecx \n"
  1001. "subl %%eax, %%ecx \n"
  1002. "andl $15, %%ecx \n"
  1003. "movl %%esp, %%eax \n"
  1004. "subl %%ecx, %%esp \n"
  1005. "pushl %%eax \n" // Store the original stack pointer
  1006. "movl 8(%%ebx), %%ecx \n" // paramSize
  1007. "movl 4(%%ebx), %%eax \n" // args
  1008. "addl %%ecx, %%eax \n" // push all arguments to the stack
  1009. "cmp $0, %%ecx \n"
  1010. "je endcopy3 \n"
  1011. "copyloop3: \n"
  1012. "subl $4, %%eax \n"
  1013. "pushl (%%eax) \n"
  1014. "subl $4, %%ecx \n"
  1015. "jne copyloop3 \n"
  1016. "endcopy3: \n"
  1017. #if defined(__MINGW32__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4)
  1018. // MinGW made some strange choices with 4.7, and the thiscall calling convention
  1019. // when returning an object in memory is completely different from when not returning
  1020. // in memory
  1021. "pushl 0(%%ebx) \n" // push obj on the stack
  1022. "movl 16(%%ebx), %%ecx \n" // move the return pointer into ECX
  1023. "call *12(%%ebx) \n" // call the function
  1024. #else
  1025. "movl 0(%%ebx), %%ecx \n" // move obj into ECX
  1026. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1027. "pushl %%ecx \n" // push obj on the stack
  1028. #endif
  1029. "pushl 16(%%ebx) \n" // push retPtr on the stack
  1030. "call *12(%%ebx) \n"
  1031. #ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER
  1032. "addl $4, %%esp \n" // pop return pointer
  1033. #endif
  1034. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  1035. "addl 8(%%ebx), %%esp \n" // pop arguments
  1036. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1037. "addl $4, %%esp \n" // pop the object pointer
  1038. #endif
  1039. #endif
  1040. #endif // MINGW
  1041. // Pop the alignment bytes
  1042. "popl %%esp \n"
  1043. "popl %%ebx \n"
  1044. // Copy EAX:EDX to retQW. As the stack pointer has been
  1045. // restored it is now safe to access the local variable
  1046. "leal %1, %%ecx \n"
  1047. "movl %%eax, 0(%%ecx) \n"
  1048. "movl %%edx, 4(%%ecx) \n"
  1049. : // output
  1050. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  1051. : "%eax", "%ecx" // clobber
  1052. );
  1053. #endif
  1054. return retQW;
  1055. }
  1056. asDWORD GetReturnedFloat()
  1057. {
  1058. asDWORD f;
  1059. #if defined ASM_INTEL
  1060. // Get the float value from ST0
  1061. __asm fstp dword ptr [f]
  1062. #elif defined ASM_AT_N_T
  1063. asm("fstps %0 \n" : "=m" (f));
  1064. #endif
  1065. return f;
  1066. }
  1067. asQWORD GetReturnedDouble()
  1068. {
  1069. asQWORD d;
  1070. #if defined ASM_INTEL
  1071. // Get the double value from ST0
  1072. __asm fstp qword ptr [d]
  1073. #elif defined ASM_AT_N_T
  1074. asm("fstpl %0 \n" : "=m" (d));
  1075. #endif
  1076. return d;
  1077. }
  1078. END_AS_NAMESPACE
  1079. #endif // AS_X86
  1080. #endif // AS_MAX_PORTABILITY