dll的隐式链接

     在应用程序(或另一个D L L)能够调用D L L中的函数之前,D L L文件映像必须被映射到调用进程的地址空间中。若要进行这项操作,可以使用两种方法中的一种,即加载时的隐含链接或运行期的显式链接。 这里主要介绍隐式链接。

若要创建D L L模块,必须执行下列操作步骤:
1) 首先必须创建一个头文件,它包含你想要从D L L输出的函数原型、结构和符号。D L L的所有源代码模块均包含该头文件,以帮助创建D L L。后面将会看到,当创建需要使用D L L中包含的函数和变量的可执行模块(或多个模块)时,也需要这个头文件。
2) 要创建一个C / C + +源代码模块(或多个模块),用于实现你想要在D L L模块中实现的函数和变量。由于这些源代码模块在创建可执行模块时是不必要的,因此创建D L L的公司能够保护公司的秘密。
3) 创建D L L模块,将使编译器对每个源代码模块进行处理,产生一个. o b j模块(每个源代码模块有一个. o b j模块)。
4) 当所有的. o b j模块创建完成后,链接程序将所有. o b j模块的内容组合在一起,产生一个D L L映象文件。该映像文件(即模块)包含了用于D L L的所有二进制代码和全局/静态数据变量。为了执行这个可执行模块,该文件是必不可少的。
5) 如果链接程序发现D L L的源代码模块至少输出了一个函数或变量,那么链接程序也生成一个. l i b文件。这个. l i b文件很小,因为它不包含任何函数或变量。它只是列出所有已输出函数和变量的符号名。为了创建可执行模块,该文件是必不可少的。
一旦创建了D L L模块,就可以创建可执行模块。其创建步骤是:
6) 在引用函数、变量、数据、结构或符号的所有源代码模块中,必须包含D L L开发人员创建的头文件。
7) 要创建一个C / C + +源代码模块(或多个模块),用于实现你想要在可执行模块中实现的函数和变量。当然该代码可以引用D L L头文件中定义的函数和变量。
8) 创建可执行模块,将使编译器对每个源代码模块进行处理,生成一个. o b j模块(每个源代码模块有一个. o b j模块)。
9) 当所有. o b j模块创建完成后,链接程序便将所有的. o b j模块的内容组合起来,生成一个可执行的映像文件。该映像文件(或模块)包含了可执行文件的所有二进制代码和全局/静态变量。该可执行模块还包含一个输入节,列出可执行文件需要的所有D L L模块名。此外,对于列出的每个D L L名字,该节指明了可执行模块的二进制代码引用了哪些函数和变量符号。下面你会看到操作系统的加载程序将对该输入节进行分析。一旦D L L和可执行模块创建完成,一个进程就可以执行。当试图运行可执行模块时,操作系统的加载程序将执行下面的操作步骤:

10) 加载程序为新进程创建一个虚拟地址空间。可执行模块被映射到新进程的地址空间。加载程序对可执行模块的输入节进行分析。对于该节中列出的每个D L L名字,加载程序要找出用户系统上的D L L模块,再将该D L L映射到进程的地址空间。注意,由于D L L模块可以从另一个D L L模块输入函数和变量,因此D L L模块可以拥有它自己的输入节。若要对进程进行全面的初始化,加载程序要分析每个模块的输入节,并将所有需要的D L L模块映射到进程的地址空间。如你所见,对进程进行初始化是很费时间的。

1。输出的真正含义是什么

介绍一个真正有意思的东西是_ _ d e c l s p e c ( d l l e x p o r t )修改符。当M i c r o s o f t的C / C + +编译器看到变量、函数原型或C + +类之前的这个修改符的时候,它就将某些附加信息嵌入产生的. o b j文件中。当链接D L L的所有. o b j文件时,链接程序将对这些信息进行分析。当D L L被链接时,链接程序要查找关于输出变量、函数或C + +类的信息,并自动生成一个. l i b文件。该. l i b文件包含一个D L L输出的符号列表。当然,如果要链接引用该D L L的输出符号的任何可执行模块,该. l i b文件是必不可少的。除了创建. l i b文件外,链接程序还要将一个输出符号表嵌入产生的D L L文件。这个输出节包含一个输出变量、函数和类符号的列表(按字母顺序排列)。该链接程序还将能够指明在何处找到每个符号的相对虚拟地址( RVA)放入D L L模块。

2。创建可执行模块

当创建可执行源代码文件时,必须加上D L L的头文件。如果没有头文件,输入的符号将不会被定义,而且编译器将会发出许多警告和错误消息。

可执行源代码文件被编译时,使用_ _ d e c l s p e c ( d l l i m p o r t )进行定义。当编译器看到修改变量、函数或C + +类的_ _ d e c l s p e c ( d l l i m p o r t )时,它知道这个符号是从某个D L L模块输入的。它不知道是从哪个D L L模块输入的,并且它也不关心这个问题。编译器只想确保你用正确的方法访问这些输入的符号。现在你在源代码中可以引用输入的符号,一切都将能够正常工作。

接着,链接程序必须将所有. o b j模块组合起来,创建产生的可执行模块。该链接程序必须确定哪些D L L包含代码引用的所有输入符号的D L L。因此你必须将D L L的. l i b文件传递给链接程序。如前所述, . l i b文件只包含D L L模块输出的符号列表。链接程序只想知道是否存在引用的符号和哪个D L L模块包含该符号。如果连接程序转换了所有外部符号的引用,那么可执行模块就因此而产生了。

3。输入的真正含义是什么

上一节介绍了修改符- - d e c l s p e c ( d l l i m p o r t )。当输入一个符号时,不必使用关键字- -d e c l s p e c ( d l l i m p o r t ),只要使用标准的C关键字e x t e r n即可。但是,如果编译器预先知道你引用的符号将从一个D L L的. l i b文件输入,那么编译器就能够生成运行效率稍高的代码。因此建议你尽量将- - d e c l s p e c ( d l l i m p o r t )关键字用于输入函数和数据符号。当你调用标准Wi n d o w s函数中的任何一个时,M i c r o s o f t将为你进行这项设置。
当链接程序进行输入符号的转换时,它就将一个称为输入节的特殊的节嵌入产生的可执行模块。输入节列出了该模块需要的D L L模块以及由每个D L L模块引用的符号。

4。运行可执行模块

当一个可执行文件被启动时,操作系统加载程序将为该进程创建虚拟地址空间。然后,加载程序将可执行模块映射到进程的地址空间中。加载程序查看可执行模块的输入节,并设法找出任何需要的D L L,并将它们映射到进程的地址空间中。

由于该输入节只包含一个D L L名而没有它的路径名。因此加载程序必须搜索用户的磁盘驱动器,找出D L L。下面是加载程序的搜索顺序:
1) 包含可执行映像文件的目录。
2) 进程的当前目录。
3) Wi n d o w s系统目录。
4) Wi n d o w s目录。
5) PAT H环境变量中列出的各个目录。
应该知道其他的东西也会影响加载程序对一个D L L的搜索(详细说明参见第2 0章)。当D L L模块映射到进程的地址空间中时,加载程序要检查每个D L L的输入节。如果存在输入节(通常它确实是存在的),那么加载程序便继续将其他必要的D L L模块映射到进程的地址空间中。加载程序将保持对D L L模块的跟踪,使模块的加载和映射只进行一次(尽管多个模块需要该模块)。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值