我对一个PROCESS (例App.exe)诞生/死亡的理解

han012 2001-07-20 11:29:08
自己当年学习VC及Windows OS时,经常苦于对某些问题只能片面的理解,而不能从全局或更高的层次进行理解。经过几年实践由衷感到,要做一个编程高手,不能只会做界面Dlg框,必须深入到系统内部,了解其中的缘由,把握它的来龙去脉,才能提高自己的理论水平。感谢候先生的<<深入浅出>>,让我在学习VC中学会了用脑子思考,知道了学习VC的方法。
在<<深入浅出>>一书中,候先生对一个进程从诞生到死亡的流程进行了简单的阐述。虽然只有十几点,但对于初学者来说,能够完全理解其中的含义已经不是一件易事了。总结自己的一些经验,对候先生的阐述进行了一些扩充,希望对初学者有所帮助,也希望高手指正其中的错误或不妥之处。

**************************************************
我对一个PROCESS (例App.exe)的诞生/死亡的理解:

1.Shell调用CreateProcess启动App.exe

2.系统产生一个“进程核心对象”,计数值为1

3.系统分配4GB进程空间

4.系统载入器(loader)将EXE文件映象和所有需要隐式加载的DLL文件映象映射到进程地址空间中。在此期间,要完成模块基址重定位, IAT(import address table)表转向,并且分配EXE及DLL中的全局和静态变量空间。注意只是分配空间,并没有执行初始化(包括执行C++对象的构造函数,已初始化数据除外)。下表给出了一些常见的节名和内容

节名(Segment) 内容
.text 应用程序或DLL的代码
.bss 未初始化的数据
.rdata 只读的运行时数据
.rsrc 资源
.edata 输出名字表
.data 初始化的数据
.xdata 异常处理表
.idata 引入名字表
.CRT 只读的C运行时数据
.reloc 修正表信息
.debug 调试信息
.tls 线程局部存储

5.系统创建了进程的主线程(primary thread)

6.主线程为每个DLL调用_DLLMainCRTStartu() 函数。
当链接DLL时,链接器在生成的DLL文件映象中嵌入了DLL的进入/退出函数的地址。缺省时为,链接器假设进入函数名为:_DLLMainCRTStartup。该函数包含在C运行时库文件中,当链接DLL时被静态的链接到DLL文件的映象中。即使使用的是C运行时库的DLL版本,该函数也会被静态的链接。
当DLL文件被映射到进程地址空间时,系统实际调用的是该函数_DLLMainCRTStartup, 而不是你的DLLMain函数。该函数执行:
a.初始化C运行时库。
// Do runtime startup initializers.
_initterm( &__xi_a, &__xi_z );
b.确保收到DLL_PROCESS_ATTACH通知时,DLL的所有全局或静态C++对象都被初始化。
(调用C++对象的Constructor函数)
// Do C++ constructors (initializers) specific to this DLL
_initterm( &__xc_a, &__xc_z );
c.完成初始化后,该函数调用你的DLLMain函数。
retcode = DllMain(hDllHandle, dwReason, lpreserved);

7.主线程根据EXE文件中的子系统值GUI/(CUI),执行WinMainCRTStartup/(MainCRTStartup)
a.得到一个新进程的全部命令行的指针。
b.得到一个新进程的环境变量指针。
c.通过STDLIB.H来初始化能被应用访问的C运行时全局变量。例
_osver, _winmajor, _winminor, _winver, _argc, _argv, _environ.
// Do runtime startup initializers.
_initterm( __xi_a, __xi_z );
d.执行EXE的全局或静态C++对象的构造函数(初始化)。
// Do C++ constructors (initializers) specific to this EXE
_initterm( __xc_a, __xc_z );
c.调用WinMain函数。
mainret = WinMain(
GetModuleHandle(NULL), //EXE映象文件基地址
NULL,
lpszCommandLine,
StartupInfo.dwFlags & STARTF_USESHOWWINDOW
? StartupInfo.wShowWindow: SW_SHOWDEFAULT
);

8.至此,主线程启动工作完成,执行进入WinMain() 。在WinMain() 中执行MFC的消息循环,驱动主线程运行,直至消息循环终止。

--------------------------------
以下为退出过程

9.主线程继续WinMainCRTStartup() 执行exit(mainret)-> doexit()函数。执行一些清理工作。
a.除主线程外,锁其它线程。Makes sure only one thread is in the exit code at a time.
#ifdef _MT //多线程
_lockexit(); // assure only 1 thread in exit path
#endif
b.执行EXE中全局或静态C++对象的析构函数,在doexit() 中。例 MyApp::~MyApp()
c.对应于启动过程中通过STDLIB.H来初始化能被应用访问的C运行时全局变量,要执行清理工作
do pre-terminators,do terminators
d.调用ExitProcess(uExitCode)
终止除主线程之外的所有未结束的其它线程(包括在DLL中启动的线程)。由于调用ExitProcess() 而被强制终止的线程将造成内存泄漏。所以应在此之前的适当地方正确结束所有其它线程。
为每个DLL调用_DllMainCRTStartup() ,当所有DLL的DLLMain() 执行后,终止进程。

其中_DllMainCRTStartup(被ExitProcess()调用)中执行
a.调用你的DLL的DLLMain()函数,REASON为DLL_PROCESS_DETACH
b.调用_CRT_INIT() 函数 ,执行DLL中全局或静态C++对象的析构函数。例 MyDll::~MyDll()


...全文
52 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
han012 2001-10-16
  • 打赏
  • 举报
回复
谁对对系统加载过程有所了解,请看看我的理解是否正确?谢谢

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧