C/C++启动函数
程序员文章站
2022-06-05 14:27:36
今天在看《windows核心》第四章,其中我感兴趣的是关于启动函数的描述。
启动函数的用途如下:
1,获取指向新进程的完整命令行的一个指针;
2,获取指向新进程的环境变量的一...
今天在看《windows核心》第四章,其中我感兴趣的是关于启动函数的描述。
启动函数的用途如下:
1,获取指向新进程的完整命令行的一个指针;
2,获取指向新进程的环境变量的一个指针;
3,初始化c/c++运行库的全局变量
4,初始化所有全局和静态c++类对象的构造函数。
对于一个程序而言,在执行main函数之前会执行crtexe.c文件中maincrtstartup或wmaincrtstartup函数,如下所示:
[html]
<span style="font-size:18px;">#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();
}</span>
__tmaincrtstartup函数如下所示:
[html]
<span style="font-size:18px;">__declspec(noinline)
int
__tmaincrtstartup(
void
)
{
#ifdef _winmain_
_tuchar *lpszcommandline;
startupinfo startupinfo;
bool indoublequote=false;
__try {
/*
note: msdn specifically notes that getstartupinfo returns no error, and throws unspecified seh if it fails, so
the very general exception handler below is appropriate
*/
getstartupinfo( &startupinfo );
} __except(exception_execute_handler) {
return 255;
}
#endif /* _winmain_ */
/*
* guard the initialization code and the call to user's main, or
* winmain, function in a __try/__except statement.
*/
__try
{
/*
* there is a possiblity that the module where this object is
* linked into is a mixed module. in all the cases we gurantee that
* native initialization will occur before managed initialization.
* also in anycase this code should never be called when some other
* code is initializing native code, that's why we exit in that case.
*
* do runtime startup initializers.
*
* note: the only possible entry we'll be executing here is for
* __lconv_init, pulled in from charmax.obj only if the exe was
* compiled with -j. all other .crt$xi* initializers are only
* run as part of the crt itself, and so for the crt dll model
* are not found in the exe. for that reason, we call _initterm,
* not _initterm_e, because __lconv_init will never return failure,
* and _initterm_e is not exported from the crt dll.
*
* note further that, when using the crt dll, executing the
* .crt$xi* initializers is only done for an exe, not for a dll
* using the crt dll. that is to make sure the -j setting for
* the exe is not overriden by that of any dll.
*/
void *lock_free=0;
void *fiberid=((pnt_tib)ntcurrentteb())->stackbase;
int nested=false;
while((lock_free=interlockedcompareexchangepointer((volatile pvoid *)&__native_startup_lock, fiberid, 0))!=0)
{
if(lock_free==fiberid)
{
nested=true;
break;
}
/* some other thread is running native startup/shutdown during a cctor/domain unload.
should only happen if this dll was built using the everett-compat loader lock fix in clrit.h
*/
/* wait for the other thread to complete init before we return */
sleep(1000);
}
if (__native_startup_state == __initializing)
{
_amsg_exit( _rt_crt_init_conflict);
}
else if (__native_startup_state == __uninitialized)
{
__native_startup_state = __initializing;
#ifndef _syscrt
if (_initterm_e( __xi_a, __xi_z ) != 0)
{
return 255;
}
#else /* _syscrt */
_initterm((_pvfv *)(void *)__xi_a, (_pvfv *)(void *)__xi_z);
#endif /* _syscrt */
}
else
{
has_cctor = 1;
}
/*
* do c++ constructors (initializers) specific to this exe
*/
if (__native_startup_state == __initializing)
{
_initterm( __xc_a, __xc_z );
__native_startup_state = __initialized;
}
_asserte(__native_startup_state == __initialized);
if(!nested)
{
/* for x86, the definition of interlockedexchangepointer wrongly causes warning c4312 */
#pragma warning(push)
#pragma warning(disable:4312)
interlockedexchangepointer((volatile pvoid *)&__native_startup_lock, 0);
#pragma warning(pop)
}
/*
* if we have any dynamically initialized __declspec(thread)
* variables, then invoke their initialization for the primary
* thread used to start the process, by calling __dyn_tls_init
* through a callback defined in tlsdyn.obj.
*/
if (__dyn_tls_init_callback != null &&
_isnonwritableincurrentimage((pbyte)&__dyn_tls_init_callback))
{
__dyn_tls_init_callback(null, dll_thread_attach, null);
}
/* enable buffer count checking if linking against static lib */
_crtsetcheckcount(true);
#ifdef _winmain_
/*
* skip past program name (first token in command line).
* check for and handle quoted program name.
*/
#ifdef wprflag
/* os may not support "w" flavors */
if (_wcmdln == null)
return 255;
lpszcommandline = (wchar_t *)_wcmdln;
#else /* wprflag */
lpszcommandline = (unsigned char *)_acmdln;
#endif /* wprflag */
while (*lpszcommandline > spacechar ||
(*lpszcommandline&&indoublequote)) {
/*
* flip the count from 1 to 0 or 0 to 1 if current character
* is doublequote
*/
if (*lpszcommandline==dquotechar) indoublequote=!indoublequote;
#ifdef _mbcs
if (_ismbblead(*lpszcommandline)) {
if (lpszcommandline) {
lpszcommandline++;
}
}
#endif /* _mbcs */
++lpszcommandline;
}
/*
* skip past any white space preceeding the second token.
*/
while (*lpszcommandline && (*lpszcommandline <= spacechar)) {
lpszcommandline++;
}
#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;
mainmainret = main(argc, argv, envp);
#endif /* wprflag */
#endif /* _winmain_ */
/*
* note that if the exe is managed app, we don't really need to
* call exit or _c_exit. .cctor should be able to take care of
* this.
*/
if ( !managedapp )
exit(mainret);
if (has_cctor == 0)
_cexit();
}
__except ( _xcptfilter(getexceptioncode(), getexceptioninformation()) )
{
/*
* should never reach here
*/
mainret = getexceptioncode();
/*
* note that if the exe is managed app, we don't really need to
* call exit or _c_exit. .cctor should be able to take care of
* this.
*/
if ( !managedapp )
_exit(mainret);
if (has_cctor == 0)
_cexit();
} /* end of try - except */
return mainret;
}</span>
我关心的是对于如下程序,类的构造和析构程序执行的时机:
[html]
<span style="font-size:18px;">class csayhello
{
public:
csayhello()
{
cout<<"constructor csayhello"<<endl;
}
~csayhello()
{
cout<<"deconstructor csayhello"<<endl;
}
};
csayhello sayhello;
int main()
{
csayhello sayhello1;
return 0;
}
</span>
很显然输出结果为:
[html]
<span style="font-size:18px;">constructor csayhello // 1</span>
[html]
<span style="font-size:18px;">constructor csayhello // 2</span>
[html]
<span style="font-size:18px;">deconstructor csayhello // 3</span>
[html]
<span style="font-size:18px;">deconstructor csayhello // 4</span>
第1句在__tmaincrtstartup中的_initterm( __xc_a, __xc_z )函数中输出
第2句进入main主函数后输出
第3句在执行到return 0时输出
第4句在退出main函数时,进入tmaincrtstartup函数中的exit函数中执行。
摘自 xudacheng06的专栏
启动函数的用途如下:
1,获取指向新进程的完整命令行的一个指针;
2,获取指向新进程的环境变量的一个指针;
3,初始化c/c++运行库的全局变量
4,初始化所有全局和静态c++类对象的构造函数。
对于一个程序而言,在执行main函数之前会执行crtexe.c文件中maincrtstartup或wmaincrtstartup函数,如下所示:
[html]
<span style="font-size:18px;">#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();
}</span>
__tmaincrtstartup函数如下所示:
[html]
<span style="font-size:18px;">__declspec(noinline)
int
__tmaincrtstartup(
void
)
{
#ifdef _winmain_
_tuchar *lpszcommandline;
startupinfo startupinfo;
bool indoublequote=false;
__try {
/*
note: msdn specifically notes that getstartupinfo returns no error, and throws unspecified seh if it fails, so
the very general exception handler below is appropriate
*/
getstartupinfo( &startupinfo );
} __except(exception_execute_handler) {
return 255;
}
#endif /* _winmain_ */
/*
* guard the initialization code and the call to user's main, or
* winmain, function in a __try/__except statement.
*/
__try
{
/*
* there is a possiblity that the module where this object is
* linked into is a mixed module. in all the cases we gurantee that
* native initialization will occur before managed initialization.
* also in anycase this code should never be called when some other
* code is initializing native code, that's why we exit in that case.
*
* do runtime startup initializers.
*
* note: the only possible entry we'll be executing here is for
* __lconv_init, pulled in from charmax.obj only if the exe was
* compiled with -j. all other .crt$xi* initializers are only
* run as part of the crt itself, and so for the crt dll model
* are not found in the exe. for that reason, we call _initterm,
* not _initterm_e, because __lconv_init will never return failure,
* and _initterm_e is not exported from the crt dll.
*
* note further that, when using the crt dll, executing the
* .crt$xi* initializers is only done for an exe, not for a dll
* using the crt dll. that is to make sure the -j setting for
* the exe is not overriden by that of any dll.
*/
void *lock_free=0;
void *fiberid=((pnt_tib)ntcurrentteb())->stackbase;
int nested=false;
while((lock_free=interlockedcompareexchangepointer((volatile pvoid *)&__native_startup_lock, fiberid, 0))!=0)
{
if(lock_free==fiberid)
{
nested=true;
break;
}
/* some other thread is running native startup/shutdown during a cctor/domain unload.
should only happen if this dll was built using the everett-compat loader lock fix in clrit.h
*/
/* wait for the other thread to complete init before we return */
sleep(1000);
}
if (__native_startup_state == __initializing)
{
_amsg_exit( _rt_crt_init_conflict);
}
else if (__native_startup_state == __uninitialized)
{
__native_startup_state = __initializing;
#ifndef _syscrt
if (_initterm_e( __xi_a, __xi_z ) != 0)
{
return 255;
}
#else /* _syscrt */
_initterm((_pvfv *)(void *)__xi_a, (_pvfv *)(void *)__xi_z);
#endif /* _syscrt */
}
else
{
has_cctor = 1;
}
/*
* do c++ constructors (initializers) specific to this exe
*/
if (__native_startup_state == __initializing)
{
_initterm( __xc_a, __xc_z );
__native_startup_state = __initialized;
}
_asserte(__native_startup_state == __initialized);
if(!nested)
{
/* for x86, the definition of interlockedexchangepointer wrongly causes warning c4312 */
#pragma warning(push)
#pragma warning(disable:4312)
interlockedexchangepointer((volatile pvoid *)&__native_startup_lock, 0);
#pragma warning(pop)
}
/*
* if we have any dynamically initialized __declspec(thread)
* variables, then invoke their initialization for the primary
* thread used to start the process, by calling __dyn_tls_init
* through a callback defined in tlsdyn.obj.
*/
if (__dyn_tls_init_callback != null &&
_isnonwritableincurrentimage((pbyte)&__dyn_tls_init_callback))
{
__dyn_tls_init_callback(null, dll_thread_attach, null);
}
/* enable buffer count checking if linking against static lib */
_crtsetcheckcount(true);
#ifdef _winmain_
/*
* skip past program name (first token in command line).
* check for and handle quoted program name.
*/
#ifdef wprflag
/* os may not support "w" flavors */
if (_wcmdln == null)
return 255;
lpszcommandline = (wchar_t *)_wcmdln;
#else /* wprflag */
lpszcommandline = (unsigned char *)_acmdln;
#endif /* wprflag */
while (*lpszcommandline > spacechar ||
(*lpszcommandline&&indoublequote)) {
/*
* flip the count from 1 to 0 or 0 to 1 if current character
* is doublequote
*/
if (*lpszcommandline==dquotechar) indoublequote=!indoublequote;
#ifdef _mbcs
if (_ismbblead(*lpszcommandline)) {
if (lpszcommandline) {
lpszcommandline++;
}
}
#endif /* _mbcs */
++lpszcommandline;
}
/*
* skip past any white space preceeding the second token.
*/
while (*lpszcommandline && (*lpszcommandline <= spacechar)) {
lpszcommandline++;
}
#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;
mainmainret = main(argc, argv, envp);
#endif /* wprflag */
#endif /* _winmain_ */
/*
* note that if the exe is managed app, we don't really need to
* call exit or _c_exit. .cctor should be able to take care of
* this.
*/
if ( !managedapp )
exit(mainret);
if (has_cctor == 0)
_cexit();
}
__except ( _xcptfilter(getexceptioncode(), getexceptioninformation()) )
{
/*
* should never reach here
*/
mainret = getexceptioncode();
/*
* note that if the exe is managed app, we don't really need to
* call exit or _c_exit. .cctor should be able to take care of
* this.
*/
if ( !managedapp )
_exit(mainret);
if (has_cctor == 0)
_cexit();
} /* end of try - except */
return mainret;
}</span>
我关心的是对于如下程序,类的构造和析构程序执行的时机:
[html]
<span style="font-size:18px;">class csayhello
{
public:
csayhello()
{
cout<<"constructor csayhello"<<endl;
}
~csayhello()
{
cout<<"deconstructor csayhello"<<endl;
}
};
csayhello sayhello;
int main()
{
csayhello sayhello1;
return 0;
}
</span>
很显然输出结果为:
[html]
<span style="font-size:18px;">constructor csayhello // 1</span>
[html]
<span style="font-size:18px;">constructor csayhello // 2</span>
[html]
<span style="font-size:18px;">deconstructor csayhello // 3</span>
[html]
<span style="font-size:18px;">deconstructor csayhello // 4</span>
第1句在__tmaincrtstartup中的_initterm( __xc_a, __xc_z )函数中输出
第2句进入main主函数后输出
第3句在执行到return 0时输出
第4句在退出main函数时,进入tmaincrtstartup函数中的exit函数中执行。
摘自 xudacheng06的专栏
上一篇: 历史上和珅都担任过哪些官职?相当于现在的什么职位?
下一篇: Python中的可变参数和关键字参数