   const reference compiler output
void my_func (int a, const int& b)...int a = 1;0052943E  mov    dword ptr [a],1 my_func (a , 2);00529445  mov    dword ptr [ebp-0D4h],2 0052944F  lea    eax,[ebp-0D4h] 00529455  push   eax  00529456  mov    ecx,dword ptr [a] 00529459  push   ecx  0052945A  call   my_func (5165EEh) 0052945F  add    esp,8 This is a bit of code generated by VC++ 2005 Debug. I understand how the assembly is working. At 00529445, I understand why it's moving 2 into 'a' stack location off the base pointer, and then pushing the address on the stack for the function call. But what I'd like to know is how it chose that address? This is code from the start of a function, so ebp-0D4h appears to be way out somewhere on the stack?   
  Isn't it putting the "2" value directly into wherever the original variable lives in memory - which is available via the stack given you're in a child subroutine?(Been a long time since I did any x86, sadly)   ;  0xD4 is space for the stack frame.   ;  What's the rest of my_func look like?  Also is my_func by any chance in an anonymous namespace?   ;This page seems to indicate1) ebp is usually directly related to esp2) ebp minus X is space for variablesSo, since you're obviously looking at a debug build, the compiler generates exactly the code you typed, which means it must create a temporary variable to hold "2" so there can be a const reference to it.  It creates this variable, and passes the address of it as a parameter to my_func (since references are just pointers with slightly different semantics).[edit] Oh.. and it chose -0d4h because it (the compiler) knows about all the other variables and such things and keeps track of where they all are, what's on the stack, etc - something that can be tedious to do by hand and is quite natural to program a compiler to do.   ;Quote:Original post by popsoftheyearSo, since you're obviously looking at a debug build, the compiler generates exactly the code you typed, which means it must create a temporary variable to hold "2" so there can be a const reference to it.  It creates this variable, and passes the address of it as a parameter to my_funcIf my_func isn't inlined, it will always need to create a variable, then pass pointer to it. It could potentially be removed by link time optimization.Quote: (since references are just pointers with slightly different semantics).I don't think any compiler treats the differently at assembly level.   ;Quote:Original post by AntheusQuote:Original post by popsoftheyearSo, since you're obviously looking at a debug build, the compiler generates exactly the code you typed, which means it must create a temporary variable to hold "2" so there can be a const reference to it.  It creates this variable, and passes the address of it as a parameter to my_funcIf my_func isn't inlined, it will always need to create a variable, then pass pointer to it. It could potentially be removed by link time optimization.True indeed - I guess it's not so obvious.  On the other hand, the OP did say this was from a debug build (even if I only just now noticed that).Quote:Quote: (since references are just pointers with slightly different semantics).I don't think any compiler treats the differently at assembly level.Me neither, but I meant in C++ langauge (some people realize this, some people don't.  Looks like OP does, but just to make sure...)   ;  Thanks for the replies!So, maybe my example wasn't so clear. My apologies. I deliberately chose debug mode to avoid things being optimized away. I give here the full original code (Update: In the next post I give the same sample but without the run-time and buffer overflow checks turned on):void my_func (int a, const int& b){// Nothing here}void procedure1 (){00529420  push   ebp00529421  mov    ebp,esp00529423  sub    esp,0D8h00529429  push   ebx0052942A  push   esi0052942B  push   edi0052942C  lea    edi,[ebp-0D8h]00529432  mov    ecx,36h00529437  mov    eax,0CCCCCCCCh0052943C  rep stos    dword ptr es:[edi]int a = 1;0052943E  mov    dword ptr [a],1my_func (a , 2);00529445  mov    dword ptr [ebp-0D4h],20052944F  lea    eax,[ebp-0D4h]00529455  push   eax00529456  mov    ecx,dword ptr [a]00529459  push   ecx0052945A  call   my_func (5165EEh)0052945F  add    esp,800582DA2  pop    edi00582DA3  pop    esi00582DA4  pop    ebx00582DA5  add    esp,0D8h00582DAB  cmp    ebp,esp00582DAD  call   @ILT+37260(__RTC_CheckEsp) (513191h)00582DB2  mov    esp,ebp00582DB4  pop    ebp00582DB5  retThe reason I'm asking this is because I'm doing the whole "my own compiler/VM" thing. I'm at the point where I need the compiler to handle function calls where the result of the expression for a parameter cannot be just left on the stack. I have an idea of how to do it, but figured looking at how VC++ 2005 did it would be a good start.As has been pointed out, and as can be seen in the assembly, the '2' is part of an immediate mode mov instruction. The '2' is part of the instruction steam (which we can't take the address of), so it mov's it into a memory location so we can eventually push the address of that memory on the stack for the function call. This works fine and I think I can understand why the '2' is not just pushed onto the stack, and it's address given:Take a function and call:void my_func2 (int a, const int& b, int c); // Functionmy_func2 (1, 2, 3); // CallGiven a __cdecl calling convention, we can see that 3 would be pushed on first, then the '2', then '2's address, and finally '1'. But the function call expects functions in a fixed order on the stack, some offset from ebp, and we've got an erroneous '2' stuck in the middle.So, I can understand choosing another address to stuff '2' into. What I don't understand is how it came up with that address. My own plan of handling this was to pre-process all parameters that needed temporary addresses, and push them onto the stack first, and do the final parameter pushing afterwards (because those parameters would now have addresses available, as a result of the pre-process step).popsoftheyear, are you suggesting this memory has been allocated by the compiler before, it has noted it as being unused, and so it's using it? Am I understanding it correctly? Or is there more of a plan from the compiler for these cases.P.S. I chose references instead of pointers, because this simple case does not happen with pointers. For example:void my_func2 (int a, const int* const b, int c); // Functionmy_func2 (1, 2, 3); // Cannot convert to pointermy_func2 (1, &2, 3); // Cannot take address (no address to take)// Interestingly, the compiler can sit back and relax, while you make the temporary variable and take it's address manually:int x = 2;my_func2 (1, &x, 3);Update: See next post!   ;  So it took me so long to write the previous post, I pretty much figured out what was happening...Showing all the code was the key, illustrating the source of that address (See line 00529423 in the previous post). I recompiled without any runtime or buffer overflow checks, and it simplifies the output somewhat. I have commented on the assembly as best as I could. Feel free to point out any errors.:void my_func (int a, const int& b){00582D30  push   ebp  00582D31  mov    ebp,esp 00582D33  sub    esp,40h 00582D36  push   ebx  00582D37  push   esi  00582D38  push   edi  }00582D39  pop    edi  00582D3A  pop    esi  00582D3B  pop    ebx  00582D3C  mov    esp,ebp 00582D3E  pop    ebp  00582D3F  ret void procedure1 (){00582D60  push   ebp // Save old stack frame (base pointer)00582D61  mov    ebp,esp // New stack frame, starting from current stack pointer00582D63  sub    esp,48h // Allocating 72 bytes on the stack, for some reason00582D66  push   ebx  // Save register00582D67  push   esi  // Save register00582D68  push   edi  // Save registerint a = 1;00582D69  mov    dword ptr [ebp-4],1 // Use first 4 bytes of the 72 allocated, for 'a'my_func (a , 2);00582D70  mov    dword ptr [ebp-48h],2  // Use the last 4 bytes of the 72 allocated, for '2' // ('2' goes from [ebp-48h] to [ebp-48h+4], which is [ebp-44h], which is in the allocated range)00582D77  lea    eax,[ebp-48h] // Load effective address of '2' into eax register00582D7A  push   eax // Push parameter 2// (last parameter is first on the stack due to __cdecl calling convention)00582D7B  mov    ecx,dword ptr [ebp-4] // Move value of 'a' into ecx00582D7E  push   ecx // Push parameter 1 00582D7F  call   005165EE // Call the my_func function00582D84  add    esp,8 // Pop parameters just pushed}00582D87  pop    edi - Restore register  00582D88  pop    esi - Restore register  00582D89  pop    ebx - Restore register  00582D8A  mov    esp,ebp // Restore the stack pointer to the base pointer00582D8C  pop    ebp // Restore the calling stack frame00582D8D  ret // Return control to calling functionThere are some surprises here for me. I would have expected a single push for 'a'. Instead the compiler appears to allocate a bunch of space at the start (in this case 72 bytes), and uses that. Presumably a single sub op, and some movs are faster than push ops? A similar surprise with the single add to esp instead of two pops, given that it's a debug build.   ;  If you compile in release (even with optimizations off) I believe the 0x40 bytes of stack space won't be allocated.   