将内联汇编代码转换为C ++ [英] Convert inline assembly code to C++

查看:174
本文介绍了将内联汇编代码转换为C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个cpp项目。该项目需要迁移到64位。它包含一些无法在x64上编译的Inline汇编代码。
这是包含汇编代码的函数:

I am working on a cpp project. The project need to be migrated to 64 bit. It contains some Inline assembly code which cannot compile on x64. This is the Function which contain the assembly code:

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 t工作。虽然,它不会抛出任何编译错误,但逻辑没有工作。

I used stack, array to migrate this "asm push val" but didn't work. Although, It don't throw any compilation error but logic didn't worked.

所以,我想问,我可以在C ++中使用,而不是__asm push val。

So, I want to ask, What can I use in C++ instead of "__asm push val". Any help will be appreciated.

推荐答案

问题一般不能解决;这是因为注释

The problem isn't solvable in general; that's because the comment,

// call the function & handle the return value.  use __stdcall calling convention

表示依靠 32位调用约定

indicates reliance on 32bit calling conventions.

在32位x86中, stdcall 表示所有参数以相反顺序传递到堆栈也就是说,如果 arg [0] addr 那么 arg [1] ,无论它的类型是 addr + sizeof(arg [0]))。这就是为什么你的示例中的以下代码:

In 32bit x86, stdcall means that all arguments are passed on the stack, in reverse order (i.e. the last arg is pushed first. That is, if arg[0] is at addr then arg[1], no matter it's type, is at addr + sizeof(arg[0])). That's the reason why the following code in your sample:

// 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])

actually can work - because it simply doesn't matter what exactly is there, what type the arguments are; all that's relevant is that each and every one of them is in a known memory location, and known-to-be-consecutive-in-memory. If you know that argument N is at addr, then you can know argument N+1 is at addr + sizeof(arg[N]).

评论说,已经正确布局了 - 不幸的是,这在64位模式下不是 true。因此,代码不能移植;没有等同于端口到。

That's what the comment says, "it's already layed out correctly" - unfortunately, this is not true in 64bit mode. The code therefore cannot be "ported"; there is no equivalent to port to.

调用至少部分基于寄存器的约定 - 就像Win64在x64(64位x86)上的行为不同。对于这些,它取决于被调用的函数采用什么类型的参数(在Windows中,在通用寄存器中传递四个整数类型的参数,在 XMM register)。因此,您需要更多地了解您调用的函数的签名(原型),而不仅仅是它需要 N 参数,以便能够以正确地从anycall类型封装器中像上面那样封装参数。在64位模式下,对于你希望通过你的包装器调用的每个函数,你不仅需要知道总共有多少个参数,而且还需要知道有多少个通用寄存器,有多少个在 XMM regs,以及堆栈中有多少。

Calling conventions that are at least partially register based - as is Win64 on x64 (64bit x86) behave differently. For those, it depends on what types of arguments the called functions take (you can, in Windows, pass four integer-type args in general-purpose registers plus some float-type args in XMM registers). You therefore need to know more about the signature (prototype) of the function you call than simply "it takes N arguments" in order to be able to correctly marshal args from an "anycall" type wrapper like the above. In 64bit mode, for every function you'd wish to call through your wrapper, you need to know not just how many args there are in total, but also how many are in general-purpose regs, how many in XMM regs, and how many on the stack.

通过指针调用func并将返回值复制到已知位置部分是可移植的,可以用简单的C / C ++表示。但是获得参数的部分,如上所述,<32> stdcall >和任何64位x86调用约定我知道(既不是Win64 / x64也不是UN * X x86_64 约定允许预测的位置和堆栈内存使用的所有参数一个函数只给出了args的数量和类型,但不是它们的排序)。

The "call a func through a pointer and copy the return value to a known location" part is portable and can be expressed in plain C/C++. But the part that gets the arguments for this, as per above, does not port in any straightforward way between 32bit stdcall and any 64bit x86 calling convention I know of (neither Win64/x64 nor the UN*X x86_64 conventions allow to predict both the locations and total stack memory usage of all arguments for a function given just the number and types of the args but not their ordering).

你需要做什么更多上面的类ExternalFunctionCall 的调用者/用户比你显示的内联汇编的小小样本。特别需要知道如何初始化成员 m_argsBegin m_argsEnd 。你能提供几个更多的细节如何类(所有成员变量/函数),以及其实际使用的例子吗?

What exactly you need to do depends much more on the callers/users of the above class ExternalFunctionCall than on the small little sample of inline assembly you've shown. It's particularly necessary to know how the members m_argsBegin and m_argsEnd are initialized and where. Can you provide a few more details on how the class looks like (all member variables/functions), as well as examples on its actual use ?

这篇关于将内联汇编代码转换为C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆