as_callfunc_x86.cpp 39 KB

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