意外的额外推送结构参数传递

时间:2013-07-29 21:48:58

标签: visual-c++ assembly x86

我是asm x86的新手,我一直在寻找一段时间为什么,在x86 / visual C ++ 2010上,这样的函数调用:

void test()
{
    vector2f vec;
    vec.x = 1.f;
    vec.y = 1.f;
    vec = something_on_vector2f(vec);
}

给出:

struct vector2f 
{
    vector2f() {}
    float x;
    float y;
}; 

vector2f something_on_vector2f(vector2f vec)
{
    return vec;
}

生成一个具有如此大堆栈分配(224字节)和3'推送'的汇编代码,而不是预期的2(推'x'+推'y')

...
00FBB780 55                   push        ebp  
00FBB781 8B EC                mov         ebp,esp  
00FBB783 81 EC E0 00 00 00    sub         esp,0E0h  (???)
...
002DB7B0 8B 45 F8             mov         eax,dword ptr [ebp-8]  (push 'x')
002DB7B3 50                   push        eax  
002DB7B4 8B 4D F4             mov         ecx,dword ptr [vec]    (push 'y')
002DB7B7 51                   push        ecx  
002DB7B8 8D 95 24 FF FF FF    lea         edx,[ebp-0DCh]         (push '???')
002DB7BE 52                   push        edx  
002DB7BF E8 4B E7 FF FF       call        normalize_vector2f (2D9F0Fh)  
...

什么是额外的推送和额外的堆栈分配?

我正在使用libjit,只生成2次推送=>从JIT代码调用函数时会产生错误,因为本机代码不希望堆栈中的参数处于相同的EBP偏移量。

2 个答案:

答案 0 :(得分:2)

基本问题是您正在查看在Debug构建中生成的代码。这与您的客户将要运行的代码几乎没有关系。

大量的额外堆栈分配由/ Zi选项生成。它支持编辑+继续,您可以编辑该功能并添加额外的局部变量,而无需重建您的程序。这非常好,但它确实需要编译器允许您选择。如果没有任何空间,则无法添加额外的变量。

其他代码是自动生成的,如果不遵循Rule Of Three,则编译器将自动生成复制构造函数和赋值运算符。你看到它被使用了。 RVO(返回值优化)是标准的C ++优化器功能。但是只有在打开优化器时才能获得它。它不在Debug构建中。

功能,而不是错误。代码看起来很糟糕,因为你要求编译器让它变得糟透了。所以你可以调试它。如果您想查看真正的外观,请调试Release构建代码。它不会那么漂亮。嗯,可调试。

答案 1 :(得分:0)

我猜测可能的SSE或SSE2使用的256字节对齐(nah即16字节)或者用于缓存效率,或者可能用于需要256字节对齐的CUDA使用。不过,我同意这很愚蠢。查看结构对齐的编译器默认值以确定。