1

I'm new to asm x86 and I've been looking for a while why, on x86 / visual C++ 2010 , a function call like this :

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

given :

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

vector2f something_on_vector2f(vector2f vec)
{
    return vec;
}

generates an assembly code with such a big stack allocation (224 bytes) and 3 'push' instead of the 2 expected (push 'x' + push '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)  
...

What are the extra push and extra stack allocation for ?

I'm using libjit and only 2 push are generated => that creates a bug when calling the function from JIT code as the native code does not expect the arguments in the stack at the same EBP offset.

Juicebox
  • 442
  • 4
  • 11
  • 1
    Don't pass structures around by value! – Carl Norum Jul 29 '13 at 21:52
  • It is a test to check that my script using Libjit can handle all possible cases :) In C++ I never pass struct by value but by const ref – Juicebox Jul 29 '13 at 22:06
  • 4
    If a function returns a structure that is too big to fit in the EAX register, [a hidden parameter is passed which specifies where the return value should be stored](http://stackoverflow.com/questions/6731140/how-does-c-return-a-structure). You are seeing that hidden parameter. – Raymond Chen Jul 29 '13 at 23:26

2 Answers2

2

The basic problem is that you are looking at the code that's generated in the Debug build. Which has very little to do with the code your customer is going to run.

The big chunk of extra stack alloc is generated by the /Zi option. Which supports Edit + Continue, you can edit the function and add extra local variables without having to rebuild your program. That's very nice, but it does require the compiler to allow you the option. You can't add extra variables if there isn't any space for them.

The other code is auto-generated, if you don't follow the Rule Of Three then the compiler will auto-generate the copy constructor and assignment operator. You are seeing it being used. RVO (Return Value Optimization) is a standard C++ optimizer feature. But you'll only get it when the optimizer is turned on. It is not in the Debug build.

Feature, not a bug. The code looks sucky because you asked the compiler to make it suck. So you can debug it. If you want to see what it really looks like then debug the Release build code. It's not going to be as pretty. Erm, debuggable.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Very interesting. I didn't know about the RVO technique... I indeed was looking at the debug build and it explains well the stack "over allocation", but you said RVO technique shoudn't be present in debug build... and it does : it's the same build i show you... I suppose it is an optimization which doesn't affect debugging and it is probably not a bad thing keeping it even in debug build... – Juicebox Jul 30 '13 at 09:14
0

I will guess for 256 byte alignment for possible SSE or SSE2 use (nah that's 16 byte) or for cache efficiency or perhaps for CUDA use which require 256 byte alignment. Still, I agree that it is pretty silly. Look at your compiler defaults for structure alignment to be sure.

Michael Dorgan
  • 12,453
  • 3
  • 31
  • 61
  • I suspected alignment too, but 16 byte ... not 256 ^^ I will check what you suggest it's a good idea :) – Juicebox Jul 29 '13 at 22:07