目录 |
导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。
目前以lib后缀的库有两种,一种为静态链接库(Static Library,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(ImportLibrary,以下简称“导入库”)。
静态库是一个或者多个obj文件的打包,所以有人干脆把从obj文件生成lib的过程称为Archive,即合并到一起。比如你链接一个静态库,如果其中有错,它会准确的找到是哪个obj有错,即静态lib只是壳子。
动态库一般会有对应的导入库,方便程序静态载入动态链接库,否则你可能就需要自己LoadLibrary调入DLL文件,然后再手工GetProcAddress获得对应函数了。有了导入库,你只需要链接导入库后按照头文件函数接口的声明调用函数就可以了。
导入库和静态库的区别很大,他们实质是不一样的东西。静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。
这也是实际上很多开源代码发布的惯用方式:
1.预编译的开发包:包含一些.dll文件和一些.lib文件。其中这里的.lib就是导入库,而不要错以为是静态库。但是引入方式和静态库一样,要在链接路径上添加找到这些.lib的路径。而.dll则最好放到最后产生的应用程序exe执行文件相同的目录。这样运行时,就会自动调入动态链接库。
2.用户自己编译:下载的是源代码,按照readme自己编译。生成很可能也是.dll+.lib(导入库)的库文件
3.如果你只有dll,并且你知道dll中函数的函数原型,那么你可以直接在自己程序中使用LoadLibary调入DLL文件,然后使用GetProcAddress调用DLL中的函数。
当DLL被链接时,链接程序要查找关于输出变量,函数,或C++类的信息,并自动生成一个lib文件。该lib文件包含一个DLL输出的符号列表。如果要链接引用该DLL的输出符号的任何可执行模块,该lib文件是必不可少的(使用GetProcAddress除外)。
其实导入库中并不含RVA(每个符号的相对虚拟地址),只是一些符号而已,还有关于这个lib所对应的DLL的名字等。(这只是我现在的理解)
那当应用程序调用一个DLL的函数时,是怎么进行的呢?(使用lib的情况下)
答案是在进程的主线程开始运行之前,由加载器完成。
加载器根据输入节中DLL的名字按照windows的搜索路径搜索DLL,找到后DLL映射到进程的地址空间,这是DLL中对应于输入节中的各个符号的地址就可以确定了,加载器在这个时候将地址重新填入可执行模块的输入节中,动态连接完成。