Visual studio doesn't use EBP when referring to stack variable - c++

I have the following C++ code
int myFuncSum( int a, int b)
{
int c;
c = a + b;
return c;
}
int main(int argc, char *argv[])
{
int result;
result = myFuncSum(100, 200);
return 0;
}
When I step through this in the disassembly window of Visual Studio 2008 on my Win7 Pro machine, I see the following for the call to myFuncSum():
int myFuncSum( int a, int b)
{
001C1000 push ebp
001C1001 mov ebp,esp
001C1003 push ecx
int c;
c = a + b;
001C1004 mov eax,dword ptr [a] <--------------------
001C1007 add eax,dword ptr [b] <--------------------
001C100A mov dword ptr [c],eax <--------------------
return c;
001C100D mov eax,dword ptr [c] <--------------------
}
As I have indicated, the four lines that refer to the variables a, b and c refer to them as such, not as offsets relative to EBP.
Can anyone please suggest what I need to do to Visual Studio to get it to refer to them via EBP? I have already disabled C++ optimisations in the project settings; without doing so I don't even get my function called.

The disassembler is just trying to be helpful, not spamming you too much about irrelevant details. Not entirely accidental, this syntax abbreviation is also permitted in inline assembly with the __asm keyword.
You can switch back-and-forth, right-click the disassembly window and untick Show Symbol Names. Now you'll see the real machine code:
c = a + b;
003613DE mov eax,dword ptr [ebp+8]
003613E1 add eax,dword ptr [ebp+0Ch]
003613E4 mov dword ptr [ebp-8],eax
return c;
003613E7 mov eax,dword ptr [ebp-8]

Related

c++ stack memory scope with curly braces

I'm looking for a double check on my understanding. I ran across code of this form:
#define BUFLEN_256 256
int main()
{
const char* charPtr = "";
if (true /* some real test here */)
{
char buf[BUFLEN_256] = { 0 };
snprintf(buf, BUFLEN_256, "Some string goes here..");
charPtr = buf;
}
std::cout << charPtr << std::endl; // Is accessing charPtr technically dangerous here?
}
My immediate thought was bug, the stack memory assigned to buf[] is no longer guaranteed to belong to the array once you exit the if(){}. But the code builds and runs without problem, and in double checking myself I got confused. I'm not good at assembly, but if I'm reading it correctly it does not appear that the stack pointer is reset after leaving the curly braces. Can someone double check me on that and chime in as to whether this code is technically valid? Here is the code with the assembly (built with Visual Studio 2019). My thought is this code is not OK, but I've been wrong on odd issues before.
#define BUFLEN_256 256
int main()
{
00DA25C0 push ebp
00DA25C1 mov ebp,esp
00DA25C3 sub esp,1D8h
00DA25C9 push ebx
00DA25CA push esi
00DA25CB push edi
00DA25CC lea edi,[ebp-1D8h]
00DA25D2 mov ecx,76h
00DA25D7 mov eax,0CCCCCCCCh
00DA25DC rep stos dword ptr es:[edi]
00DA25DE mov eax,dword ptr [__security_cookie (0DAC004h)]
00DA25E3 xor eax,ebp
00DA25E5 mov dword ptr [ebp-4],eax
00DA25E8 mov ecx,offset _1FACD15F_scratch#cpp (0DAF029h)
00DA25ED call #__CheckForDebuggerJustMyCode#4 (0DA138Eh)
const char* charPtr = "";
00DA25F2 mov dword ptr [charPtr],offset string "" (0DA9B30h)
if (true /* some real test here */)
00DA25F9 mov eax,1
00DA25FE test eax,eax
00DA2600 je main+7Ah (0DA263Ah)
{
char buf[BUFLEN_256] = { 0 };
00DA2602 push 100h
00DA2607 push 0
00DA2609 lea eax,[ebp-114h]
00DA260F push eax
00DA2610 call _memset (0DA1186h)
00DA2615 add esp,0Ch
snprintf(buf, BUFLEN_256, "Some string goes here..");
00DA2618 push offset string "Some string goes here.." (0DA9BB8h)
00DA261D push 100h
00DA2622 lea eax,[ebp-114h]
00DA2628 push eax
00DA2629 call _snprintf (0DA1267h)
00DA262E add esp,0Ch
charPtr = buf;
00DA2631 lea eax,[ebp-114h]
00DA2637 mov dword ptr [charPtr],eax
}
std::cout << charPtr << std::endl;
00DA263A mov esi,esp
00DA263C push offset std::endl<char,std::char_traits<char> > (0DA103Ch)
00DA2641 mov eax,dword ptr [charPtr]
00DA2644 push eax
00DA2645 mov ecx,dword ptr [__imp_std::cout (0DAD0D4h)]
00DA264B push ecx
00DA264C call std::operator<<<std::char_traits<char> > (0DA11AEh)
00DA2651 add esp,8
00DA2654 mov ecx,eax
00DA2656 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0DAD0A0h)]
00DA265C cmp esi,esp
00DA265E call __RTC_CheckEsp (0DA129Eh)
}
00DA2663 xor eax,eax
00DA2665 push edx
00DA2666 mov ecx,ebp
00DA2668 push eax
00DA2669 lea edx,ds:[0DA2694h]
00DA266F call #_RTC_CheckStackVars#8 (0DA1235h)
00DA2674 pop eax
00DA2675 pop edx
00DA2676 pop edi
00DA2677 pop esi
00DA2678 pop ebx
00DA2679 mov ecx,dword ptr [ebp-4]
00DA267C xor ecx,ebp
00DA267E call #__security_check_cookie#4 (0DA1181h)
00DA2683 add esp,1D8h
00DA2689 cmp ebp,esp
00DA268B call __RTC_CheckEsp (0DA129Eh)
00DA2690 mov esp,ebp
00DA2692 pop ebp
00DA2693 ret
00DA2694 add dword ptr [eax],eax
00DA2696 add byte ptr [eax],al
00DA2698 pushfd
00DA2699 fiadd dword ptr es:[eax]
00DA269C in al,dx
00DA269D ?? ??????
00DA269E ?? ??????
}
My immediate thought was bug, the stack memory assigned to buf[] is no longer guaranteed to belong to the array once you exit the if(){}.
That is correct.
But the code builds and runs without problem
Undefined Behavior. In the cout << charPtr statement, charPtr is a dangling pointer to invalid memory. Whether or not the memory has been physically freed is irrelevent. The memory has gone out of scope.
I'm not good at assembly, but if I'm reading it correctly it does not appear that the stack pointer is reset after leaving the curly braces.
That is correct.
The memory for the array is being pre-allocated at the top of the stack frame when the function is entered (as part of the sub esp, 1D8h instruction), and then gets released during cleanup of the stack frame when the function exits (as part of the add esp, 1D8h instruction).
As you can see, when the if is entered, the very first thing it does is to call _memset() to zero out an array which already exists at [ebp-114h].
But that is an implementation detail, don't rely on that.
Can someone double check me on that and chime in as to whether this code is technically valid?
It is not.
What you're seeing is 'undefined' behavior. Stack memory is typically allocated all in one go at the start. So when a variable goes out-of-scope on the stack, that memory becomes available for re-use. Since you're not overwriting the stack with anything after the if statement, the data previously stored there is still intact. If you were to allocate additional memory/data to the stack after the if statement, you'd see a much different result.
See this post here:
What happens when a variable goes out of scope?
Edit:
To elaborate and demonstrate this, consider the following modification of your code (Compiled on VS2019 v142 x64):
#include <iostream>
#define BUFLEN_256 256
int main()
{
char* charPtr;
char other_buf[BUFLEN_256] = { 0 };
char* charPtr2 = other_buf;
if (true /* some real test here */)
{
char buf[BUFLEN_256] = { 0 };
snprintf(buf, BUFLEN_256, "Some string goes here..");
charPtr = buf;
}
std::cout << charPtr << std::endl;
for (int n = 0; n < 3000; ++n)
{
*charPtr2 = 'a';
charPtr2++;
}
std::cout << charPtr << std::endl;
}
Output
Some string goes here..
Some string goes haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaca
Of course, keeping in mind that every compiler handles optimizations differently, and this may or may not happen in every case. That is why the behavior is 'undefined'. This example is more-so demonstrating overrunning the stack intentionally (buffer-overrun), but it illustrates the same effect. I'd produce a more direct example of legitimate cases where this could happen, but ironically undefined behavior is difficult to intentionally reproduce.
Yes, accessing charPtr in this way is undefined behaviour - and hence dangerous - because buf goes out of scope at the closing brace.
In practise, the code may work (or appear to work) because the memory used for buf is not re-used immediately but you should not, of course, rely on that. Whoever wrote this code made a mistake.

Will template function typedef specifier be properly inlined when creating each instance of template function?

Have made function that operates on several streams of data in same time, creates output result which is put to destination stream. It has been put huge amount of time to optimize performance of this function (openmp, intrinsics, and etc...). And it performs beautifully.
There is alot math involved here, needless to say very long function.
Now I want to implement in same function with math replacement code for each instance of this without writing each version of this function. Where I want to differentiate between different instances of this function using only #defines or inlined function (code has to be inlined in each version).
Went for templates, but templates allow only type specifiers, and realized that #defines can't be used here. Remaining solution would be inlined math functions, so simplified idea is to create header like this:
'alm_quasimodo.h':
#pragma once
typedef struct ALM_DATA
{
int l, t, r, b;
int scan;
BYTE* data;
} ALM_DATA;
typedef BYTE (*MATH_FX)(BYTE&, BYTE&);
// etc
inline BYTE math_a1(BYTE& A, BYTE& B){ return ((BYTE)((B > A) ? B:A)); }
inline BYTE math_a2(BYTE& A, BYTE& B){ return ((BYTE)(255 - ((long)((long)(255 - A) * (255 - B)) >> 8))); }
inline BYTE math_a3(BYTE& A, BYTE& B){ return ((BYTE)((B < 128)?(2*(((long)A>>1)+64))*((float)B/255):(255-(2*(255-(((long)A>>1)+64))*(float)(255-B)/255)))); }
// etc
template <typename MATH>
inline int const template_math_av (MATH math, ALM_DATA& a, ALM_DATA& b)
{
// ultra simplified version of very complex code
for (int y = a.t; y <= a.b; y++)
{
int yoffset = y * a.scan;
for (int x = a.l; x <= a.r; x++)
{
int xoffset = yoffset + x;
a.data[xoffset] = math(a.data[xoffset], b.data[xoffset]);
}
}
return 0;
}
ALM_API int math_caller(int condition, ALM_DATA& a, ALM_DATA& b);
and math_caller is defined in 'alm_quasimodo.cpp' as follows:
#include "stdafx.h"
#include "alm_quazimodo.h"
ALM_API int math_caller(int condition, ALM_DATA& a, ALM_DATA& b)
{
switch(condition)
{
case 1: return template_math_av<MATH_FX>(math_a1, a, b);
break;
case 2: return template_math_av<MATH_FX>(math_a2, a, b);
break;
case 3: return template_math_av<MATH_FX>(math_a3, a, b);
break;
// etc
}
return -1;
}
Main concern here is optimization, mainly in-lining of MATH function code, and not to break existing optimizations of original code. Without writing each instance of function for specific math operation, of course ;)
So does this template inlines properly all math functions?
And any suggestions how to optimize this function template?
If nothing, thanks for reading this lengthy question.
It all depends on your compiler, optimization level, and how and where are math_a1 to math_a3 functions defined.
Usually, the compiler can optimize this if the functions in question are inline function in the same compilation unit as the rest of the code.
If this doesn't happen for you, you may want to consider functors instead of functions.
Here are some simple examples I experimented with. You can do the same for your function, and check the behavior of different compilers.
For my example, GCC 7.3 and clang 6.0 are pretty good in optimizing-out function calls (provided they see the definition of the function of course). However, somewhat surprisingly, ICC 18.0.0 is only able to optimize-out functors and closures. Even inline functions give it some trouble.
Just to have some code here in case the link stops working in the future.
For the following code:
template <typename T, int size, typename Closure>
T accumulate(T (&array)[size], T init, Closure closure) {
for (int i = 0; i < size; ++i) {
init = closure(init, array[i]);
}
return init;
}
int sum(int x, int y) { return x + y; }
inline int sub_inline(int x, int y) { return x - y; }
struct mul_functor {
int operator ()(int x, int y) const { return x * y; }
};
extern int extern_operation(int x, int y);
int accumulate_function(int (&array)[5]) {
return accumulate(array, 0, sum);
}
int accumulate_inline(int (&array)[5]) {
return accumulate(array, 0, sub_inline);
}
int accumulate_functor(int (&array)[5]) {
return accumulate(array, 1, mul_functor());
}
int accumulate_closure(int (&array)[5]) {
return accumulate(array, 0, [](int x, int y) { return x | y; });
}
int accumulate_exetern(int (&array)[5]) {
return accumulate(array, 0, extern_operation);
}
GCC 7.3 (x86) produces the following assembly:
sum(int, int):
lea eax, [rdi+rsi]
ret
accumulate_function(int (&) [5]):
mov eax, DWORD PTR [rdi+4]
add eax, DWORD PTR [rdi]
add eax, DWORD PTR [rdi+8]
add eax, DWORD PTR [rdi+12]
add eax, DWORD PTR [rdi+16]
ret
accumulate_inline(int (&) [5]):
mov eax, DWORD PTR [rdi]
neg eax
sub eax, DWORD PTR [rdi+4]
sub eax, DWORD PTR [rdi+8]
sub eax, DWORD PTR [rdi+12]
sub eax, DWORD PTR [rdi+16]
ret
accumulate_functor(int (&) [5]):
mov eax, DWORD PTR [rdi]
imul eax, DWORD PTR [rdi+4]
imul eax, DWORD PTR [rdi+8]
imul eax, DWORD PTR [rdi+12]
imul eax, DWORD PTR [rdi+16]
ret
accumulate_closure(int (&) [5]):
mov eax, DWORD PTR [rdi+4]
or eax, DWORD PTR [rdi+8]
or eax, DWORD PTR [rdi+12]
or eax, DWORD PTR [rdi]
or eax, DWORD PTR [rdi+16]
ret
accumulate_exetern(int (&) [5]):
push rbp
push rbx
lea rbp, [rdi+20]
mov rbx, rdi
xor eax, eax
sub rsp, 8
.L8:
mov esi, DWORD PTR [rbx]
mov edi, eax
add rbx, 4
call extern_operation(int, int)
cmp rbx, rbp
jne .L8
add rsp, 8
pop rbx
pop rbp
ret

The compiler decided to call the function `POW`, instead of evaluating it at compile time. Why?

I got the snippet below from this comment by #CaffeineAddict.
#include <iostream>
template<typename base_t, typename expo_t>
constexpr base_t POW(base_t base, expo_t expo)
{
return (expo != 0) ? base * POW(base, expo - 1) : 1;
}
int main(int argc, char** argv)
{
std::cout << POW((unsigned __int64)2, 63) << std::endl;
return 0;
}
with the following disassembly obtained from VS2015:
int main(int argc, char** argv)
{
009418A0 push ebp
009418A1 mov ebp,esp
009418A3 sub esp,0C0h
009418A9 push ebx
009418AA push esi
009418AB push edi
009418AC lea edi,[ebp-0C0h]
009418B2 mov ecx,30h
009418B7 mov eax,0CCCCCCCCh
009418BC rep stos dword ptr es:[edi]
std::cout << POW((unsigned __int64)2, 63) << std::endl;
009418BE mov esi,esp
009418C0 push offset std::endl<char,std::char_traits<char> > (0941064h)
009418C5 push 3Fh
009418C7 push 0
009418C9 push 2
009418CB call POW<unsigned __int64,int> (09410FAh) <<========
009418D0 add esp,0Ch
009418D3 mov edi,esp
009418D5 push edx
009418D6 push eax
009418D7 mov ecx,dword ptr [_imp_?cout#std##3V?$basic_ostream#DU?$char_traits#D#std###1#A (094A098h)]
009418DD call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (094A0ACh)]
009418E3 cmp edi,esp
009418E5 call __RTC_CheckEsp (0941127h)
009418EA mov ecx,eax
009418EC call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (094A0B0h)]
009418F2 cmp esi,esp
009418F4 call __RTC_CheckEsp (0941127h)
return 0;
009418F9 xor eax,eax
}
which shows (see the characters "<<======" introduced by me in the disassembly) that the compiler didn't evaluate the function POW at compile time. From his comment, #CaffeineAddict seemed to expect this behavior from the compiler. But I still can't understand why was this expected at all?
Two reasons.
First, a constexpr function isn't guaranteed to be called at compile time. To force the compiler to call it at compile time, you must store it in a constexpr variable first, i.e.
constexpr auto pow = POW((unsigned __int64)2, 63);
std::cout << pow << std::endl;
Secondly, you must build the project in Release configuration. In VS, you'll find you can break-point through constexpr functions if you have built the project using Debug configuration.

Visual C++ - enable optimizations and browse the optimized code

How I can compile my project with optimizations turned on and see what optimizations changed in my code.
For example:
My original code:
printf("Test: %d",52);
for (int empty=0;i<100000;i++) {
//Nothing here
}
Now when I compile my code with optimzations ,I want to see: (I think it'll be like that)
printf("Test: 52");
The compiler doesn't optimize modify the source code (what you've shown in your question), but the binary, which consists of asm instructions.
How you turn optimization on and off depends on the compiler, so you'll have to refer to its documentation.
In MSVS, you can choose this option from the top toolbar - look for Debug (un-optimized) vs Release (optimized). You can see the binary code by stepping through the code with the debugger, right click -> show dissasembly.
Your code, for example, generates:
Without optimizations:
printf("Test: %d",52);
0097171E mov esi,esp
00971720 push 34h
00971722 push offset string "Test: %d" (9788C8h)
00971727 call dword ptr [__imp__printf (97C3E0h)]
0097172D add esp,8
00971730 cmp esi,esp
00971732 call #ILT+575(__RTC_CheckEsp) (971244h)
for (int i=0;i<100000;i++) {
00971737 mov dword ptr [i],0
0097173E jmp wmain+49h (971749h)
00971740 mov eax,dword ptr [i]
00971743 add eax,1
00971746 mov dword ptr [i],eax
00971749 cmp dword ptr [i],186A0h
00971750 jge wmain+54h (971754h)
//Nothing here
}
00971752 jmp wmain+40h (971740h)
With optimizations:
printf("Test: %d",52);
013A1000 push 34h
013A1002 push offset string "Test: %d" (13A20F4h)
013A1007 call dword ptr [__imp__printf (13A209Ch)]
013A100D add esp,8
for (int i=0;i<100000;i++) {
//Nothing here
}

Pointer to struct with offset

I have a pointer to struct, its 0xB7CD98. And the offset to some float value 0x540. How to get this value. All its in C++ and assembler. Another thing is that this its code from my dll injected to exe.
float buffer ;
_asm {
MOV EAX, [0xB7CD98]+0x540
MOV buffer, EAX
}
But it isn't work. Why?
Why are you using Assembly for that?
float* pBuffer = (float*)(0xB7CD98 + 0x540)
printf("%f", *pBuffer);
Disassembly of your code :
0FB310E7 mov eax,0B7D2D8h;
0FB310EC mov dword ptr [buffer],eax
//It just fill 'buffer' with 0xB7CD98+0x540
What you really want is this :
DWORD basePtr = *(DWORD*)0xB7CD98;
float someVal = *(float*)(basePtr + 0x540);
Or, if you wish to obtain a permanent pointer to this value :
typedef struct _XStruct
{
BYTE fill_0[0x540];
float Value;
}*PXStruct;
//...
PXStruct basePtr = (PXStruct)0xB7CD98;
//0F0745E7 mov dword ptr [basePtr],0B7CD98h
float buffer = basePtr->Value;
//0F0745EE mov eax,dword ptr [basePtr]
//0F0745F1 fld dword ptr [eax+540h]
//0F0745F7 fstp dword ptr [buffer]