MSVC:从 mainCRTStartup 到 main
一个程序的入口不是 main(),而是 mainCRTStartup()。在 MSVC 编译器中,mainCRTStartup() 调用 __scrt_common_main(),由这个函数最终调用 main()。
由于使用了 __forceinline,__scrt_common_main 一般会内联在 mainCRTStartup() 里
// This is the common main implementation to which all of the CRT main functions
// delegate (for executables; DLLs are handled separately).
static __forceinline int __cdecl __scrt_common_main()
{
// The /GS security cookie must be initialized before any exception handling
// targeting the current image is registered. No function using exception
// handling can be called in the current image until after this call:
__security_init_cookie();
return __scrt_common_main_seh();
}
__security_init_cookie() 随机初始化 _security_cookie 这个变量,防止栈溢出。
__scrt_common_main_seh() 是核心部分。它负责执行所有初始化、调用用户代码,处理异常等。
static __declspec(noinline) int __cdecl __scrt_common_main_seh()
{
// 初始化 crt (isa, vcrt, acrt)
if (!__scrt_initialize_crt(__scrt_module_type::exe))
__scrt_fastfail(FAST_FAIL_FATAL_APP_EXIT);
// 标记构造函数未执行
bool has_cctor = false;
__try
{
// 获取锁,防止并发初始化
bool const is_nested = __scrt_acquire_startup_lock();
// 如果当前状态是 initializing,说明有冲突,快速失败
if (__scrt_current_native_startup_state == __scrt_native_startup_state::initializing)
{
__scrt_fastfail(FAST_FAIL_FATAL_APP_EXIT);
}
// 如果当前状态是 uninitialized,执行初始化
else if (__scrt_current_native_startup_state == __scrt_native_startup_state::uninitialized)
{
// 开始初始化 initializing
__scrt_current_native_startup_state = __scrt_native_startup_state::initializing;
// 访问函数指针表,执行初始化函数
if (_initterm_e(__xi_a, __xi_z) != 0)
return 255;
_initterm(__xc_a, __xc_z);
// 初始化完成 initialized
__scrt_current_native_startup_state = __scrt_native_startup_state::initialized;
}
else
{
has_cctor = true;
}
// 释放锁
__scrt_release_startup_lock(is_nested);
// 执行 tls 初始化
_tls_callback_type const* const tls_init_callback = __scrt_get_dyn_tls_init_callback();
if (*tls_init_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_init_callback))
{
(*tls_init_callback)(nullptr, DLL_THREAD_ATTACH, nullptr);
}
// 注册 tls 析构函数
_tls_callback_type const * const tls_dtor_callback = __scrt_get_dyn_tls_dtor_callback();
if (*tls_dtor_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_dtor_callback))
{
_register_thread_local_exe_atexit_callback(*tls_dtor_callback);
}
// 初始化完成,调用 main 函数
int const main_result = invoke_main();
// main 函数返回
if (!__scrt_is_managed_app())
exit(main_result);
if (!has_cctor)
_cexit();
// 退出 crt
__scrt_uninitialize_crt(true, false);
return main_result;
}
__except (_seh_filter_exe(GetExceptionCode(), GetExceptionInformation()))
{
int const main_result = GetExceptionCode();
if (!__scrt_is_managed_app())
_exit(main_result);
if (!has_cctor)
_c_exit();
return main_result;
}
}
initterm() 调用两个参数之间的函数。区别是 _initterm() 调用的函数不会失败,_initterm_e() 调用的函数可能失败。
void __cdecl _initterm(_PVFV* const first, _PVFV* const last)
{
for (_PVFV* it = first; it != last; ++it)
{
if (*it == nullptr)
continue;
(**it)();
}
}
int __cdecl _initterm_e(_PIFV* const first, _PIFV* const last)
{
for (_PIFV* it = first; it != last; ++it)
{
if (*it == nullptr)
continue;
int const result = (**it)();
if (result != 0)
return result;
}
return 0;
}
写个程序看一下
#include <iostream>
__declspec(noinline) int f(int x)
{
int result = 0;
for (int i = 0; i < x; i++)
{
result += i * i;
}
return result;
}
int g = f(10);
int h = f(30);
int main()
{
std::cout << "f(10)=" << g << std::endl;
std::cout << "f(20)=" << f(20) << std::endl;
std::cout << "f(30)=" << h << std::endl;
std::cout << "f(40)=" << f(40) << std::endl;
return 0;
}
invoke_main 通过宏定义实现编译时多态
#if defined _SCRT_STARTUP_MAIN
using main_policy = __scrt_main_policy;
using file_policy = __scrt_file_policy;
using argv_policy = __scrt_narrow_argv_policy;
using environment_policy = __scrt_narrow_environment_policy;
static int __cdecl invoke_main()
{
return main(__argc, __argv, _get_initial_narrow_environment());
}
#elif defined _SCRT_STARTUP_WMAIN
using main_policy = __scrt_main_policy;
using file_policy = __scrt_file_policy;
using argv_policy = __scrt_wide_argv_policy;
using environment_policy = __scrt_wide_environment_policy;
static int __cdecl invoke_main()
{
return wmain(__argc, __wargv, _get_initial_wide_environment());
}
#elif defined _SCRT_STARTUP_WINMAIN
using main_policy = __scrt_winmain_policy;
using file_policy = __scrt_file_policy;
using argv_policy = __scrt_narrow_argv_policy;
using environment_policy = __scrt_narrow_environment_policy;
static int __cdecl invoke_main()
{
return WinMain(
reinterpret_cast<HINSTANCE>(&__ImageBase),
nullptr,
_get_narrow_winmain_command_line(),
__scrt_get_show_window_mode());
}
#elif defined _SCRT_STARTUP_WWINMAIN
using main_policy = __scrt_winmain_policy;
using file_policy = __scrt_file_policy;
using argv_policy = __scrt_wide_argv_policy;
using environment_policy = __scrt_wide_environment_policy;
static int __cdecl invoke_main()
{
return wWinMain(
reinterpret_cast<HINSTANCE>(&__ImageBase),
nullptr,
_get_wide_winmain_command_line(),
__scrt_get_show_window_mode());
}
#elif defined _SCRT_STARTUP_ENCLAVE || defined _SCRT_STARTUP_WENCLAVE
using main_policy = __scrt_enclavemain_policy;
using file_policy = __scrt_nofile_policy;
using argv_policy = __scrt_no_argv_policy;
using environment_policy = __scrt_no_environment_policy;
#if defined _SCRT_STARTUP_ENCLAVE
static int __cdecl invoke_main()
{
return main(0, nullptr, nullptr);
}
#else
static int __cdecl invoke_main()
{
return wmain(0, nullptr, nullptr);
}
#endif
#endif