as_callfunc_x86.cpp 40 KB

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