Why is the stack frame pointer (EBP) incorrect in assembly release?
I noticed that the EBP pointer on top of the stack frame is not quite right when creating a simple plain MFC application object, and this only happens in a release build. Here is the code.
CMDIDemoApp::CMDIDemoApp()
{
// support Restart Manager
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;
#ifdef _MANAGED
// If the application is built using Common Language Runtime support (/clr):
// 1) This additional setting is needed for Restart Manager support to work properly.
// 2) In your project, you must add a reference to System.Windows.Forms in order to build.
System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException);
#endif
// breakpoint here, EBP is correct
// TODO: replace application ID string below with unique ID string; recommended
// format for string is CompanyName.ProductName.SubProduct.VersionInformation
SetAppID(_T("MDIDemo.AppID.NoVersion"));
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CMDIDemoApp object
CMDIDemoApp theApp; // breakpoint here, EBP is not what I would expect
// CMDIDemoApp initialization
BOOL CMDIDemoApp::InitInstance()
{
// InitCommonControlsEx() is required on Windows XP if an application
// manifest specifies use of ComCtl32.dll version 6 or later to enable
// visual styles. Otherwise, any window creation will fail.
INITCOMMONCONTROLSEX InitCtrls; // breakpoint here again EBP is good
InitCtrls.dwSize = sizeof(InitCtrls);
// Set this to include all the common control classes you want to use
// in your application.
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinApp::InitInstance();
// Initialize OLE libraries
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
EnableTaskbarInteraction(FALSE);
// AfxInitRichEdit2() is required to use RichEdit control
// AfxInitRichEdit2();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need
// Change the registry key under which our settings are stored
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(4); // Load standard INI file options (including MRU)
// Register the application document templates. Document templates
// serve as the connection between documents, frame windows and views
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_MDIDemoTYPE,
RUNTIME_CLASS(CMDIDemoDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMDIDemoView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
{
delete pMainFrame;
return FALSE;
}
m_pMainWnd = pMainFrame;
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line. Will return FALSE if
// app was launched with /RegServer, /Register, /Unregserver or /Unregister.
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The main window has been initialized, so show and update it
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
The stack in WinDbg is at a breakpoint at line CMDIDemoApp theApp;
0:000> k
# ChildEBP RetAddr
00 0049fbdc 638381cd MDIDemo!`dynamic initializer for 'theApp'' [e:\projects\vs2015 projects\mdidemo\mdidemo\mdidemo.cpp @ 55]
01 0049fbf8 001826c5 ucrtbase!_initterm+0x6d
02 0049fc3c 765d336a MDIDemo!__scrt_common_main_seh+0x7b [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 221]
03 0049fc48 76f59902 kernel32!BaseThreadInitThunk+0xe
04 0049fc88 76f598d5 ntdll!__RtlUserThreadStart+0x70
05 0049fca0 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> dc 0049fbdc
0049fbdc 00000e00 638381cd 00000000 00000000 .......c........
0049fbec 7efde000 00000005 1c53dd92 0049fc3c ...~......S.<.I.
0049fbfc 001826c5 00184604 00184618 04b2f942 .&...F...F..B...
0049fc0c 00000000 00000000 7efde000 0049fc00 ...........~..I.
0049fc1c 00000000 00000000 0049fc08 000000fd ..........I.....
0049fc2c 0049fc78 00182c2a 04e3677e 00000000 x.I.*,..~g......
0049fc3c 0049fc48 765d336a 7efde000 0049fc88 H.I.j3]v...~..I.
0049fc4c 76f59902 7efde000 6fe6f10a 00000000 ...v...~...o....
0:000> dc 0049fbf8
0049fbf8 0049fc3c 001826c5 00184604 00184618 <.I..&...F...F..
0049fc08 04b2f942 00000000 00000000 7efde000 B..............~
0049fc18 0049fc00 00000000 00000000 0049fc08 ..I...........I.
0049fc28 000000fd 0049fc78 00182c2a 04e3677e ....x.I.*,..~g..
0049fc38 00000000 0049fc48 765d336a 7efde000 ....H.I.j3]v...~
0049fc48 0049fc88 76f59902 7efde000 6fe6f10a ..I....v...~...o
0049fc58 00000000 00000000 7efde000 00000000 ...........~....
0049fc68 00000000 00000000 0049fc54 00000000 ........T.I.....
0:000> dc 0049fc3c
0049fc3c 0049fc48 765d336a 7efde000 0049fc88 H.I.j3]v...~..I.
0049fc4c 76f59902 7efde000 6fe6f10a 00000000 ...v...~...o....
0049fc5c 00000000 7efde000 00000000 00000000 .......~........
0049fc6c 00000000 0049fc54 00000000 ffffffff ....T.I.........
0049fc7c 76f958c5 195bcba2 00000000 0049fca0 .X.v..[.......I.
0049fc8c 76f598d5 001827b2 7efde000 00000000 ...v.'.....~....
0049fc9c 00000000 00000000 00000000 001827b2 .............'..
0049fcac 7efde000 00000000 00000000 00000000 ...~............
Note what it dc 0049fbdc
should have given 0049fbf8
, but it instead 00000e00
. Why does this happen and only in release? This is really correct in a debug build.
Also EFPs are correct when I set breakpoints in the constructor ( CMDIDemoApp::CMDIDemoApp()
) or any other function like CMDIDemoApp::InitInstance()
. So it is correct in any function, but not entirely correct when declaring a global object.
This is in contrast to my earlier question where EFP is simply wrong even in normal functions like constructor and InitIntance () in this project. The purpose of this question is to provide more information because in this case we know pretty well that the code is not broken, this is the default mfc application without any changes. This also qualifies as a separate issue.
Update
Assembly code in line CMDIDemoApp theApp
:
0:000> u
MDIDemo!`dynamic initializer for 'theApp'' [e:\projects\vs2015 projects\mdidemo\mdidemo\mdidemo.cpp @ 55]:
00ee1000 55 push ebp
00ee1001 8bec mov ebp,esp
00ee1003 68cc000000 push 0CCh
00ee1008 b9a892ee00 mov ecx,offset MDIDemo!theApp (00ee92a8)
00ee100d e86e0e0000 call MDIDemo!CMDIDemoApp::__autoclassinit2 (00ee1e80)
00ee1012 b9a892ee00 mov ecx,offset MDIDemo!theApp (00ee92a8)
00ee1017 e8a4050000 call MDIDemo!CMDIDemoApp::CMDIDemoApp (00ee15c0)
00ee101c 680040ee00 push offset MDIDemo!`dynamic atexit destructor for 'theApp'' (00ee4000)
The constructor node is as follows
MDIDemo!CMDIDemoApp::CMDIDemoApp:
00ee15c0 55 push ebp
00ee15c1 8bec mov ebp,esp
00ee15c3 6aff push 0FFFFFFFFh
00ee15c5 68a83eee00 push offset MDIDemo!__scrt_stub_for_acrt_initialize+0x4c (00ee3ea8)
00ee15ca 64a100000000 mov eax,dword ptr fs:[00000000h]
00ee15d0 50 push eax
00ee15d1 51 push ecx
00ee15d2 a11490ee00 mov eax,dword ptr [MDIDemo!__security_cookie (00ee9014)]
00ee15d7 33c5 xor eax,ebp
00ee15d9 50 push eax
00ee15da 8d45f4 lea eax,[ebp-0Ch]
00ee15dd 64a300000000 mov dword ptr fs:[00000000h],eax
00ee15e3 894df0 mov dword ptr [ebp-10h],ecx
00ee15e6 6a00 push 0
00ee15e8 8b4df0 mov ecx,dword ptr [ebp-10h]
source to share
No one has answered this question yet
See similar questions:
or similar: