MSVCR 和 CRT 初始化
MSVCR and CRT Initialization
出于好奇,加载使用 MSVCR 编译的应用程序时究竟会发生什么,或者 Windows 的加载器如何实际初始化 CRT?对于我到目前为止收集的内容,当程序以及所有导入的库加载到内存中并完成所有重定位时,CRT 启动代码 ( _CRT_INIT()
?) 初始化 .CRT$XC*
部分中的所有全局初始值设定项并调用用户定义的main()
函数。我希望到目前为止这是正确的。
但是,为了解释起见,让我们假设一个不使用MSVCR的程序(例如,使用Cygwin GCC或其他编译器构建的应用程序)尝试在运行时加载库,需要使用自定义加载程序/运行时链接器来加载CRT,因此不涉及LoadLibrary()
。加载程序/链接器必须如何处理 CRT 初始化?它是否必须手动初始化上述部分中的所有"对象",它是否必须做其他事情以使库的内部布线正常工作,或者它是否必须只调用_CRT_INIT()
(据我所知,它在运行时本身中定义不切实际,并且没有导出到任何地方)。假设非 CRT 应用程序和 CRT 库不会在它们之间传递任何对象、异常等内容,这种混淆甚至会以任何方式起作用吗?
我很想知道,因为我无法完全弄清楚 CRT 对实际加载过程有什么影响......
任何信息都非常感谢,谢谢!
使用/ENTRY 链接器选项选择可执行映像的入口点。 它使用的默认值在 MSDN 库文章中有很好的记录。 它们是 CRT 入口点。
如果要替换 CRT,请在链接时选择相同的名称或显式使用/ENTRY 选项。 您还需要/NODEFAULTLIB 来防止它链接常规 .lib
针对C++运行时编译的每个库在加载时都会调用_DllMainCRTStartup。 _DllMainCRTStartup调用 _CRT_INIT,它初始化 C/C++ 运行时库,并调用静态非局部变量上的C++构造函数。
PE 格式包含一个可选的标头,该标头具有一个名为"地址入口点"的插槽,该插槽调用一个函数,该函数将调用触发初始化链的_DllMainCRTStartup。
_DllMainCRTStartup完成初始化阶段后,它将调用你自己实现的 DllMain() 函数。
当你学习编程时,有人会告诉你"发生的第一件事是代码在main
中运行。但这有点像你在学校里学习原子时,它们组织得相当好,并且按照严格的规则运作。如果你后来去大学上核/粒子物理课,那些简单/严格的规则要详细得多,并不总是适用,等等。
当您链接 C 或 C++ 程序时,CRT 包含一些类似这样的代码:
start()
{
CRT_init();
...
Global_Object_Constructors();
...
exit(main());
}
因此,初始化是由 C 运行时库本身完成的,在它调用 main 之前。
DLL 有一个由 LoadLibrary()
执行的DllMain
- 它负责在 DLL 中初始化/创建全局对象,如果您不使用LoadLibrary()
[例如,自己将 DLL 加载到内存中],那么您必须确保创建和初始化对象。
- 是否可以初始化不可复制类型的成员变量(或基类)
- C++使用整数的压缩数组初始化对象
- C++初始化基类
- 多成员Constexpr结构初始化
- 复制列表初始化的隐式转换的等级是多少
- 内联映射初始化的动态atexit析构函数崩溃
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 没有用于初始化C++中的变量模板的匹配构造函数
- 在未初始化映射的情况下,将值插入到映射的映射中
- C++成员初始化
- 为什么在C++中首先初始化成员类
- 同时具有"聚合初始化"和"模板推导"
- 初始化具有非默认构造函数的std::数组项的更好方法
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 我可以使用条件运算符初始化C风格的字符串文字吗
- CRT初始化:运行时错误 - CRT未初始化
- MSVCR 和 CRT 初始化
- 如何在执行加载库时初始化 CRT( "*.exe" )
- 检测CRT初始化是否在注入过程中完成