为什么堆栈帧指针(EBP)在发布版本中不正确?

时间:2017-03-27 15:34:08

标签: c++ visual-studio-2015 mfc windbg

我注意到,当实例化一个简单的MFC主应用程序对象时,堆栈框架顶部的EBP指针并不完全正确,而这只发生在发布版本中。这是代码。

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's 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;
}

WinDbg上的堆栈位于第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  ...~............

请注意,dc 0049fbdc应该已经产生了0049fbf8,而是00000e00。为什么会发生这种情况并且仅在发布版本中?它在调试版本中确实是正确的。

当我在构造函数(CMDIDemoApp::CMDIDemoApp())或任何其他函数(如CMDIDemoApp::InitInstance())中设置断点时,EFP也是正确的。所以它在任何函数中都是正确的,但在声明全局对象时却不太正确!

这与我的earlier question不同,即使在该项目中的常规函数​​(如构造函数和InitIntance())中EFP完全不正确。这个问题的目的是提供这些额外的信息,因为在这种情况下我们很清楚代码没有被破坏,它是一个默认的mfc应用程序,没有任何改变。这也是一个单独的问题。

更新

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)

构造函数程序集如下

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]

0 个答案:

没有答案