应用程序的源代码里引用了DLL的符号,加载程序会自动将DLL加载到进程的地址空间中。所以应用程序需要包含模块的头文件。
应用程序主动调用LoadLibrary将DLL载入到进程的地址空间中。
GetProcAddress引用该dll导出的符号。
程序开始运行首先加载DLL,然后执行主线程。
在程序运行到LoadLibrary函数的时候加载DLL。
__declspec(dllexport) 1.创建dll时会创建相应.lib文件,保存dll导出的变量和函数的符号。 2.dll文件也会有导入段、导出段,保存dll导入导出的变量和函数符号。 3.exe可执行文件里的导入段记录需要导入的dll文件和变量函数符号。
1.启动应用程序时,系统的加载程序会先为进程创建虚拟地址空间,接着把可执行模块映射到进程地址空间,之后检查可执行模块的导入段,把所需的dll定位并映射到进程的地址空间。同时会检查所需dll是否需要dll。
2.由于导入段里没有dll在硬盘中的路径,所以加载程序会按一定顺序搜索文件。
3.将所以dll模块载入到进程空间后,加载程序检查模块的导入段符号是否存在于相应dll的导出段中,存在则计算符号在进程空间中的地址,并把该地址写入到导入段中。
1.当系统第一次载入dll或LoadLibrary,映射到进程的地址空间,进程主线程会调用该入口点函数并传入DLL_PROCESS_ATTACH,执行相关操作例如创建一个进程堆,当映射完成调用C/C++运行时的启动代码,然后调用可执行模块的入口点函数_tmain。
2.当系统将dll的映射撤销出地址空间,例如ExitProcess或FreeLibrary,调用dllMain并传入DLL_PROCESS_DETACH参数。
3.创建线程时,线程执行进程中的所有DLL入口点函数,并传入DLL_THREAD_ATTACH参数。
4.ExitThread终止线程时,调用各个dll入口点函数。
对于隐式链接,只有当我们的代码引用DLL里的符号时,系统才会载入该DLL。
可执行文件和DLL模块都有一个在进程地址空间中的首选基地址,如果该地址已被其他模块占用,则加载程序需要修改模块代码,对该模块中任何地址操作进行重定位。应选择合适的dll基地址,防止重定位。
绑定一个模块即修改他导入表中的符号在进程空间中的实际地址。