我知道为本地 Windows 编译的程序有一种称为可移植可执行文件 (PE)的格式,它允许操作系统将程序加载到内存中。
但是我对它被加载到内存然后执行的过程很感兴趣,也就是说,它发生在我在资源管理器进程中单击直到通过调用 winmain 创建应用程序本身的窗口(这是在代码中完成的)程序如文档中所示):
LONG APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
这两个事件之间会发生什么?
这个过程解释起来比较简单,但执行起来并不那么简单。
首先:CPU 有一系列要求才能执行任何一段代码:某些寄存器必须指向有效的内存地址。
此外,必须遵守操作系统的值班规则:某块内存只能由某个程序以某种方式(读、写、执行)访问。
基本执行过程(不加载)包括准备 CPU 的内存和寄存器以满足强加的要求。这是由操作系统执行的。
对于上述内容,参考了要执行的文件的某些数据。
一旦内存准备好,代码本身就会被加载,每个部分都是必要的部分。程序数据段装入专用数据存储区,可执行代码段装入代码区,...
在这里,充电的东西可能会产生误导。通过“内存文件映射”的过程,可以将前面提到的加载推迟到 CPU实际不需要访问相关内存区域时。
一旦代码被加载,它就会被动态链接。即,查阅包含所需库名称的文件段
.dll
。有些已经加载(在共享内存区域中,为所有人运行)。其他的则不需要,并且有必要为它们重复加载过程(具有它们的特性;例如,库不需要堆栈)。最后,一切都被加载(或*内存映射)。现在,您必须用它们的实际地址覆盖程序代码中调用某些导入函数的点。
这也是误导。有一些机制可以避免遍历整个内存,使用内存区域作为中间表。然而,最终结果是相同的:所有调用都
.dll
指向所需的代码。现在,是的,您可以开始执行程序,强制 CPU 创建一个新进程,并使用精心准备的内存区域。
通常,执行本身不会直接转到函数
WinMain
,或main
,或其他任何东西。首先调用编译器放置的一段代码,它负责执行数据初始化任务。例如,在 C++ 中,正是这个pre-main代码负责调用静态实例构造函数。是现在; 最后,我们调用我们的
WinMain( )
.我们可以在内部做的一件事
WinMain( )
是注册我们的窗口函数,Windows 将使用它来传递消息。这些消息是独立于我们生成的,其中大部分是人为的(由系统本身生成)。但那是另一个话题,将在另一个场合讲述......