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

2
1
3

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
posted @ 2025-09-28 21:49  矛盾空间  阅读(11)  评论(0)    收藏  举报