使用 struct 参数从程序集中调用 C++ 函数

Posted

技术标签:

【中文标题】使用 struct 参数从程序集中调用 C++ 函数【英文标题】:Calling C++ function from assembly, with struct argument 【发布时间】:2013-06-22 13:41:41 【问题描述】:

我遇到了一些意外行为,这可能意味着我不完全理解编译器在做什么。考虑以下人为设计的程序:

#include <stdio.h>

#pragma pack(push, 1)
struct A 
    unsigned short a;
    unsigned short b;

    explicit A() 
        printf("construct\n");
    
    ~A() 
        printf("destruct\n");
    
;
#pragma pack(pop)
static_assert(sizeof(A) == 4, "sizeof(A) != 4");

A  __stdcall f(int p1, A p2, int p3, int p4) 
    printf("%08X %08X %08X %08X\n", p1, p2, p3, p4);
    return p2;


int main() 
    __asm 
        push 4
        push 3
        push 2
        push 1
        call f

    
    return 0;

上面的程序会崩溃,但是如果我从struct A 中删除A()~A() 的定义,它不会。这个问题与编译器认为参数在堆栈上的位置有关,定义的构造函数认为它们比它们所在的位置多 4 个字节。如果我删除构造函数,我得到的输出是这样的:

00000001 00000002 00000003 00000004

这是我所期望的,但是我得到了定义的构造函数

00000002 00000003 00000004 00000000

这显然不是我所期望的。运行前者时,函数返回RETN 0x10,后者返回RETN 0x14,所以看起来它认为应该有另一个参数(为什么?)。我注意到,如果我将 f 更改为 void 函数,它会按预期工作。那么,有人可以向我解释发生了什么以及为什么吗?我关闭了所有优化。

【问题讨论】:

p2 的类型为 A。然而你正在传递一个int。我很惊讶它完全有效,因为这是完全未定义的。你确定这是正确的代码吗? @Adrian Aint 大小相同,并且它没有虚函数,所以我不明白为什么它不应该工作 当 A 是非 POD 时,您将出现意外行为。如果您真的想这样做,请反汇编编译器所做的事情以查看真正发生的事情。 @Adrian 是的,这似乎是问题所在。我只使用这些结构来解析游戏内存中的对象,所以这就是为什么它看起来有点奇怪,我猜。 【参考方案1】:

在汇编级别,只有简单的值才能通过将它们返回到寄存器中的方式从函数中返回,因此如果需要返回更复杂的对象,编译器会将其视为传递指向返回的指针对象:

void f(A *return_ptr,int p1,A p2,int p3,int p4);

但是可以进行某些优化。在您的示例中,您的类包含两个 16 位短路,这两个 16 位短路可以打包成一个 32 位整数并在寄存器中返回。但是,如果您定义了自定义析构函数,则该类不再被认为足够简单,无法进行此优化。

【讨论】:

非常感谢,我认为可能是这样的。你知道为什么这个问题只会在我定义自己的构造函数时出现吗? @user1520427:我在回答中添加了更多信息。

以上是关于使用 struct 参数从程序集中调用 C++ 函数的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 C# 从 C++ dll 调用 struct 中的函数

从程序集中访问类方法

通过 C API 从字符串创建和调用 python 函数

从 C++ 调用 python 函数时如何将 C++ 类作为参数传递?

调用使用 C# 返回结构数组的非托管 dll 函数

将 struct* 从 c# 传递到 c++ dll