MSVCR 和 CRT 初始化

MSVCR and CRT Initialization

本文关键字:初始化 CRT MSVCR      更新时间:2023-10-16

出于好奇,加载使用 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 加载到内存中],那么您必须确保创建和初始化对象。