EXE 文件是怎样被WINDOWS 给执行的

来源:互联网 发布:绝地武士光剑淘宝 编辑:程序博客网 时间:2024/05/16 19:27

在<<深入浅出>>一书中,候先生对一个进程从诞生到死亡的流程进行了简单的阐述。虽然只有十几点,但对于初学者来说,能够完全理解其中的含义已经不是一件易事了。总结自己的一些经验,对候先生的阐述进行了一些扩充,希望对初学者有所帮助,也希望高手指正其中的错误或不妥之处。

**************************************************
我对一个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()

 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/chief1985/archive/2008/04/15/2295102.aspx

 

 

tdzl2009 发表于2008年8月25日 星期一 9:13:10  IP:举报
指出一个错误:
_DLLMainCRTStartup

WinMainCRTStartup/(MainCRTStartup)
这两个名字在DLL/EXE文件中是可以不存在的,真正决定程序开始位置的是PE文件中一个叫入口点Entry Point的东西,它直接指向二进制代码的某一个位置。
在可执行文件被链接器生成的时候,可以通过选项指定入口点,链接器会自动将入口点指向对应的函数。