将内联汇编代码转换为c++
Convert inline assembly code to C++
我正在做一个cpp项目。项目需要迁移到64位。它包含一些不能在x64上编译的内联汇编代码。这个函数包含汇编代码:
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;
}
我使用堆栈,数组来迁移这个"asm push val",但没有工作。虽然,它没有抛出任何编译错误,但逻辑没有工作。
所以,我想问,我可以在c++中使用什么来代替"__asm push val"。
这个问题一般是无法解决的;这是因为注释
// call the function & handle the return value. use __stdcall calling convention
表示依赖32位调用约定。
在32位x86中,stdcall
意味着所有参数都以相反的顺序在堆栈上传递(即首先推送最后一个参数)。也就是说,如果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位模式下,不是为真。因此代码不能被"移植";没有对应的port to。
至少部分基于寄存器的调用约定-如Win64在x64(64位x86)上的行为不同。对于这些,它取决于被调用函数接受的参数类型(在Windows中,您可以在通用寄存器中传递四个整型参数,在XMM
寄存器中传递一些浮点型参数)。因此,您需要了解更多关于您调用的函数的签名(原型),而不仅仅是"它需要N
参数",以便能够从上面的"anycall"类型包装器中正确封送参数。在64位模式下,对于您希望通过包装器调用的每个函数,您不仅需要知道总共有多少个参数,还需要知道有多少个在通用regs中,有多少在XMM
regs中,以及有多少在堆栈中。
"通过指针调用函数并将返回值复制到已知位置"部分是可移植的,可以用普通的C/c++表示。但是得到参数的部分,如上文所述,不能以任何直接的方式在32位stdcall
和任何64位x86调用约定之间移植 (Win64/x64和UN*X x86_64
约定都不允许预测函数所有参数的位置和总堆栈内存使用情况,只给出参数的数量和类型,而不是它们的顺序)。
具体需要做什么更多地取决于上述class ExternalFunctionCall
的调用者/用户,而不是您所展示的内联汇编的小样本。特别有必要知道成员m_argsBegin
和m_argsEnd
是如何初始化的,以及在哪里初始化的。
有几件事你需要解决。(我在另一个问题上查找了你的代码)。正如我所理解的,这段代码是一个包装器,调用位于指定地址的相当抽象的函数,该函数期望堆栈中有一定数量的数据,并且可以根据ArgType返回不同的东西。
如果你想用普通的C语言包装它,你必须定义几个函数原型(基于返回值),然后在你的开关上使用它们,但是你必须解决另一个问题,这是更棘手的。
在C中移植这些东西的问题是,你不知道你必须在堆栈中推入的参数的数量(数据大小),所以你将在定义原型时遇到麻烦。
让我们说func(char c)肯定会在堆栈中推入1字节(但也不总是正确的,因为数据对齐)。在你的情况下,你必须考虑一个解决方案,它将有一组参数与你需要在堆栈上的数据大小相等。乍一看,这不是你可以马上做到的。
乌利希期刊指南。你可以用func(char [] param);但它也有问题,在回答上面解释。
我知道这是一个有点老的问题,但我只是偶然发现:xbyak.
也许你在找什么?
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 复制列表初始化的隐式转换的等级是多少
- 正在将指针转换为范围
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 是否可以从int转换为enum类类型
- 了解 GLM- openGL 中的相机转换
- 将无符号char*转换为std::istream*C++