函数调用时结构参数已损坏

时间:2012-06-12 16:27:10

标签: c++ visual-studio assembly x86 function-calls

在将结构作为参数传递时,我无法追踪奇怪行为的原因。

有问题的结构structFoo具有以下声明:

typedef struct _structFoo {
    int id;
    BSTR szDescription;
    VARIANT vData;
    BOOL bTransient;
} structFoo;

我有两个模块,A和B.模块A调用B :: foo(int id,uint filter,structFoo sF)。在A中,在调用之前,structFoo结构已正确形成并填充有效数据。但是,一旦对B :: foo()进行函数调用,structFoo参数就会包含垃圾数据。经过进一步检查,结果是复制的struct的地址被放入id字段,szDescription指向最近使用的字符串。函数调用后其他参数是正确的。

我不确定这种错位的原因,或者发生了什么,但在我看来,在函数调用完成之前,一切都在适当的位置。这是导致函数调用的反汇编:

0000000006003211  lea         rdi,[rsp+230h] 
0000000006003219  lea         rsi,[sAttPairId] 
0000000006003221  mov         ecx,30h 
0000000006003226  rep movs    byte ptr [rdi],byte ptr [rsi] 
0000000006003228  mov         rax,qword ptr [piConstruct] 
0000000006003230  mov         rax,qword ptr [rax] 
0000000006003233  lea         r9,[rsp+230h] 
000000000600323B  mov         r8d,800h 
0000000006003241  mov         edx,dword ptr [iHighNodeId] 
0000000006003248  mov         rcx,qword ptr [piConstruct] 
0000000006003250  call        qword ptr [rax+60h] 

这是函数调用后的反汇编:

0000000004B72470  mov         qword ptr [rsp+20h],r9 
0000000004B72475  mov         dword ptr [rsp+18h],r8d 
0000000004B7247A  mov         dword ptr [rsp+10h],edx 
0000000004B7247E  mov         qword ptr [rsp+8],rcx 
0000000004B72483  push        rsi  
0000000004B72484  push        rdi  
0000000004B72485  sub         rsp,0A8h 
0000000004B7248C  mov         rdi,rsp 
0000000004B7248F  mov         rcx,2Ah 
0000000004B72499  mov         eax,0CCCCCCCCh 
0000000004B7249E  rep stos    dword ptr [rdi] 
0000000004B724A0  mov         rcx,qword ptr [rsp+0C0h] 
0000000004B724A8  mov         qword ptr [rsp+90h],0FFFFFFFFFFFFFFFEh

sub rsp, 0A8h参数全部用数据设置后,但sF参数在其id字段中具有正确的structFoo信息的地址,而不是将此地址用作自己的指针。任何有关解决此问题的指导都非常感谢。

作为旁注,遗憾的是,更改B :: foo()以获取结构的地址而不是结构本身是一种选择。大量遗留代码依赖于我无权更改的此功能。

谢谢!

2 个答案:

答案 0 :(得分:0)

我想,模块AB是用不同的调用约定编译的。模块A通过引用/指针将结构传递给函数,而模块B期望按值接收堆栈上的结构。

B的头文件中可能有一个修饰符,如下所示:

__weird_call void B::foo( int id, uint filter, structFoo sF );

也许模块A的编译器不理解它,或者其他一些头文件定义它(#define __weird_call /* nothing */),或者沿着这些行的东西。

答案 1 :(得分:0)

我偶然发现了这个页面,同时寻找我遇到的类似问题的答案。 虽然我在互联网上找不到答案,但分享调试经验。

以下结构通过引用从一个函数传递给另一个函数,接收者会发现收到的数据是意外的:

typedef struct
{
    char time_st[30];
    char pipe_no;
    float loss;
    float power[4];
    int   mode;
    int   count;
}Parameters;

另一个发现是,如果我在与调用函数相同的文件中定义接收函数,问题就会消失。

经过调试,发现根本原因是意大利面使用" #pragma pack"在系统中的遗留.h文件中导致结构打包问题 - 由于在调用函数的.c文件中包含了几个遗留头文件,结构被打包,但是在接收函数的.c文件中(在项目活动期间写的是新的,结构被视为解压缩。

分辨率:添加足够的填充以使结构字对齐

typedef struct
{
    char time_st[30];
    char pad;
    char pipe_no;
    float loss;
    float power[4];
    int   mode;
    int   count;
}Parameters;