你是否想过为什么有时候main()函数是入口地址,在win32中winmain()函数又是入口地址,其实是编译器在动态链接到crt[C runtime library(part of the C standard library)]时候设置的
程序设置断点,我们来看crtexe.c代码
第一个static int __cdecl pre_c_init(void)
* The code in mainCRTStartup that was executed before executing C initializers was shifted in this function. Also this funciton is the first thing that is executed in c init section.
什么意思不用详细说,老外的注释很给力
- static int __cdecl pre_c_init(void)
- {
- /*
- * Determine if this is a managed application
- */
- managedapp = check_managed_app();
- /*
- * Set __app_type properly
- */
- #ifdef _WINMAIN_ //根据WINMAIN宏来设置应用程序是GUI程序还是控制台程序
- __set_app_type(_GUI_APP);
- #else /* _WINMAIN_ */
- __set_app_type(_CONSOLE_APP);
- #endif /* _WINMAIN_ */
- /*
- * Mark this module as an EXE file so that atexit/_onexit
- * will do the right thing when called, including for C++
- * d-tors.
- */
- __onexitbegin = __onexitend = (_PVFV *)_encode_pointer((_PVFV *)(-1));
- /*
- * Propogate the _fmode and _commode variables to the DLL
- */
- *_IMP___FMODE = _fmode;
- *_IMP___COMMODE = _commode;
- #ifdef _M_IX86
- /*
- * Set the local copy of the Pentium FDIV adjustment flag
- */
- _adjust_fdiv = * _imp___adjust_fdiv;
- #endif /* _M_IX86 */
- /*
- * Run the RTC initialization code for this DLL
- */
- #ifdef _RTC
- _RTC_Initialize();
- #endif /* _RTC */
- /*
- * Call _setargv(), which will trigger a call to __setargv() if
- * SETARGV.OBJ is linked with the EXE. If SETARGV.OBJ is not
- * linked with the EXE, a dummy _setargv() will be called.
- */
- #ifdef WPRFLAG
- _wsetargv();
- #else /* WPRFLAG */
- _setargv();
- #endif /* WPRFLAG */
- /*
- * If the user has supplied a _matherr routine then set
- * __pusermatherr to point to it.
- */
- if ( !__defaultmatherr )
- __setusermatherr(_matherr);
- #ifdef _M_IX86
- _setdefaultprecision();
- #endif /* _M_IX86 */
- /* Enable per-thread locale if user asked for it */
- if(__globallocalestatus == -1)
- {
- _configthreadlocale(-1);
- }
- return 0;
- }
第二个函数
- static void __cdecl pre_cpp_init(void)
- static void __cdecl pre_cpp_init(void)
- {
- #ifdef _RTC
- atexit(_RTC_Terminate); //注册程序退出时的清理工
- #endif /* _RTC */
- /*
- * Get the arguments for the call to main. Note this must be
- * done explicitly, rather than as part of the dll's
- * initialization, to implement optional expansion of wild
- * card chars in filename args
- */
- startinfo.newmode = _newmode;
- #ifdef WPRFLAG
- argret = __wgetmainargs(&argc, &argv, &envp,
- _dowildcard, &startinfo);
- #else /* WPRFLAG */
- argret = __getmainargs(&argc, &argv, &envp,
- _dowildcard, &startinfo);
- #endif /* WPRFLAG */
- #ifndef _SYSCRT
- if (argret < 0)
- _amsg_exit(_RT_SPACEARG);
- #endif /* _SYSCRT */
- }
- static
- int
- __tmainCRTStartup(
- void
- );
- #ifdef _WINMAIN_
- #ifdef WPRFLAG
- int wWinMainCRTStartup(
- #else /* WPRFLAG */
- int WinMainCRTStartup(
- #endif /* WPRFLAG */
- #else /* _WINMAIN_ */
- #ifdef WPRFLAG
- int wmainCRTStartup(
- #else /* WPRFLAG */
- int mainCRTStartup(
- #endif /* WPRFLAG */
- #endif /* _WINMAIN_ */
- void
- )
- {
- /*
- * The /GS security cookie must be initialized before any exception
- * handling targetting the current image is registered. No function
- * using exception handling can be called in the current image until
- * after __security_init_cookie has been called.
- */
- __security_init_cookie();
- return __tmainCRTStartup();
- }
/***
*mainCRTStartup(void)
*wmainCRTStartup(void)
*WinMainCRTStartup(void)
*wWinMainCRTStartup(void)
*
*Purpose:
* These routines do the C runtime initialization, call the appropriate
* user entry function, and handle termination cleanup. For a managed
* app, they then return the exit code back to the calling routine, which
* is the managed startup code. For an unmanaged app, they call exit and
* never return.
*
* Function: User entry called:
* mainCRTStartup main
* wmainCRTStartup wmain
* WinMainCRTStartup WinMain
* wWinMainCRTStartup wWinMain
就是为程序找到入口地址,具体的判断是在函数 __tmainCRTStartup()中
关键代码:
- #ifdef WPRFLAG
- mainret = wWinMain(
- #else /* WPRFLAG */
- mainret = WinMain(
- #endif /* WPRFLAG */
- (HINSTANCE)&__ImageBase,
- NULL,
- lpszCommandLine,
- StartupInfo.dwFlags & STARTF_USESHOWWINDOW
- ? StartupInfo.wShowWindow
- : SW_SHOWDEFAULT
- );
- #else /* _WINMAIN_ */
- #ifdef WPRFLAG
- __winitenv = envp;
- mainret = wmain(argc, argv, envp);
- #else /* WPRFLAG */
- __initenv = envp;
- mainret = main(argc, argv, envp);
- #endif /* WPRFLAG */
- #endif /* _WINMAIN_ */
我们看到,根据宏WPRFLAG来判断是wWinmain()还是WinMain(),根据_WINMAIN_来判断入口函数是main(),wmain()还是WinMain(),wWinMain()
wmain()和wWinMain()是unicode版的,main()和WinMain()是ANSI版的 不过在程序中始终没有找到宏WPRFLAG是在哪里定义的,有空了再详细研究
然后就找到对应的入口程序执行。