这是包含汇编代码的函数:
void ExternalFunctionCall::callFunction(ArgType resultType,void* resultBuffer) { #if defined(_NT_) || defined(__OS2__) // I386 // just copy the args buffer to the stack (it's already layed out correctly) int* begin = m_argsBegin; int* ptr = m_argsEnd; int arr[1000],i=0; while (ptr > begin) { int val = *(--ptr); __asm push val } void* functionAddress = m_functionAddress; // call the function & handle the return value. use __stdcall calling convention switch (resultType) { case voidType: __asm { call functionAddress } break; case pointerType: case int32Type: __asm { call functionAddress mov ebx,resultBuffer mov dword ptr [ebx],eax } break; case floatType: __asm { call functionAddress mov ebx,resultBuffer fstp dword ptr [ebx] } break; case doubleType: __asm { call functionAddress mov ebx,resultBuffer fstp qword ptr [ebx] } break; }
我使用stack,array来迁移这个“asm push val”但是没有用.虽然,它不会抛出任何编译错误,但逻辑没有奏效.
所以,我想问一下,我可以在C中使用什么而不是“__asm push val”.任何帮助将不胜感激.
解决方法
// call the function & handle the return value. use __stdcall calling convention
表示依赖于32位呼叫约定.
在32位x86中,stdcall意味着所有参数都以相反的顺序传递给堆栈(即最后一个arg被推送.也就是说,如果arg [0]在addr然后是arg [1],无论它是什么类型,都是在addr sizeof(arg [0])).这就是您的示例中以下代码的原因:
// just copy the args buffer to the stack (it's already layed out correctly) int* begin = m_argsBegin; int* ptr = m_argsEnd; int arr[1000],i=0; while (ptr > begin) { int val = *(--ptr); __asm push val }
实际上可以工作 – 因为它究竟是什么并不重要,参数是什么类型的;所有相关的是它们中的每一个都在已知的存储位置,并且已知在内存中是连续的.如果您知道参数N在addr处,那么您可以知道参数N 1在addr sizeof(arg [N]).
这就是评论所说的“它已经正确布局” – 不幸的是,在64位模式下并非如此.因此代码不能“移植”;没有相当于港口的.
调用至少部分基于寄存器的约定 – 就像x64(64位x86)上的Win64一样,表现不同.对于那些,它取决于被调用函数采用什么类型的参数(在Windows中,您可以在通用寄存器中传递四个整数类型的参数,在XMM寄存器中传递一些浮点类型的参数).因此,您需要了解更多关于您调用的函数的签名(原型),而不仅仅是“它需要N个参数”,以便能够正确地编组来自“anycall”类型包装器的args,如上所述.在64位模式下,对于您希望通过包装器调用的每个函数,您不仅需要知道总共有多少个args,还需要知道通用注册中有多少个,XMM注册中有多少个,以及如何很多在堆栈上.
“通过指针调用func并将返回值复制到已知位置”部分是可移植的,可以用普通的C/C++表示.但是,如上所述,获取此参数的部分并没有以任何直接的方式在32位stdcall和我所知道的任何64位x86调用约定之间移植(Win64 / x64和UN * X x86_64约定都不允许预测两者给定函数的所有参数的位置和总堆栈内存使用量,只给出了args的数量和类型,但没有给出它们的顺序).
您需要做什么更多地取决于上述类ExternalFunctionCall的调用者/用户,而不是您所显示的内联汇编的小样本.特别需要知道如何初始化成员m_argsBegin和m_argsEnd以及在哪里.您能否提供一些关于类的外观(所有成员变量/函数)的详细信息,以及实际使用的示例?