as_callfunc_x86.cpp 40 KB

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