汇编教程之动态链接库

本课中,我们将学习DLLs,它们到底是什么和如何创建它们。

理论:

如果您编程的时间非常长,就会发现很多的程序之间其实有相当多的重复代码。每编一个程序就重写一遍这些代码既没必要又浪费时间。在DOS时代,一般的做法是把这些重复的代码写成一个个的函数,然后把它们按类别放到不同的库文件中去。当要使用这些函数时,只要把您的目标文件(.obj)文件和先前存放在库文件中的函数进行链接,链接时链接器会从库文件中抽取相关的信息并把它们插入到可执行文件中去。这个过程叫做静态链接。C运行时库就是一个好例子。这样的库的缺点是您在每一个调用库函数的程序中都必须嵌入同一函数的拷贝,这显然很浪费磁盘。在DOS时代毕竟每一时刻仅有一个程序在运行,所以浪费的还只是磁盘而已,在多任务的WINDOWS时代就不仅浪费磁盘,还要浪费宝贵的内存了。

在WINDOWS中,由于有多个程序同时运行,如果您的程序非常大的话,那将消耗相当多的内存。WINDOWS的解决办法是:使用动态链接库。动态链接库从表面上看也是一大堆的通用函数,不过即使有多个程序调用了它,在内存中也仅仅只有动态链接库的唯一一份拷贝。WINDOWS是通过分页机制来作到这一点的。当然,库的代码只有一份,但是每一个应用程序要有自己单独的数据段,要么就会乱掉。

不象旧时的静态链接库,它并不会把这些函数的可执行代码放入到应用程序中去,而是当程序已经在内存中运行时,如果需要调用该函数时才调入内存也即链接。这也就是为什么把它叫做“动态”的原因所在。另外您还可以动态地卸载动态链接库,当然要求这时没有其它的应用程序在使用它,否则就要一直等到最后一个使用它的函数也不再使用该动态链接库时才能去卸载它。

为了正确的调用库和给库函数分配内存空间,在编译和链接应用程序时,必须把重定位等一些消息插入到执行代码中去,以便载入正确的库,并给库函数分配正确的地址。

那么这些信息从哪里得到呢?引入库。引入库包含足够的信息,链接器从中抽取足够的信息(注意区别:静态链接库放入的是可执行代码)把它们放入到可执行文件中去。当WINDOWS的加载器装入应用程序查看到有DLL时,它会查找该库文件,如果没有查到,就报错退出,否则就把它映射进进程的地址空间,并修正函数调用语句的地址。

如果没有引入库呢?当然我们也可以调用动态链接库中的任意函数。只不过您必须知道调用的函数是否在库中而且是否在库的引出名字表中,另外还需要知道该函数的参数个数和参数的类型。

(译者加:说到这里,让我想起了一件很有名的事。<<Undocumented Windows>>一书的作者Angel Schudleman 曾经利用此方法来跟踪微软Win3x系统动态链接库中未公开的函数,因为在微软给程序员提供的系统动态链接库的引入库中没有提供这些函数的原型,所以您无法在链接时把这些函数的信息链接到可执行文件中去,而为了某种目的您又要使用这些函数,您就可以在执行时加载动态链接库并得到这些函数的地址,从而和调用其它的库函数一样使用这些未公开的函数。由于这本书的巨大影响,当时许多程序员纷纷在它们的程序中调用未公开函数,甚至在写商业程序时也这么做。这种走偏峰的做法引起了微软的反感,后来微软在它Win3x的改进版中不再把那些未公开函数列入系统动态链接库的引出名字表,这样也就无法再利用这种方法来调用未公开的函数了。)

当您让系统的加载器为您加载动态库时,如果不能找到库文件,它就会提示一条“A required .DLL file, xxxxx.dll is missing”,这样您的应用程序就无法运行,即使该库对您的应用程序来说并不重要。

如果您选择在程序运行时自己加载该库,就没有这种问题了。

如果您知道足够的信息,就可以调用系统未公开的函数。

如果您调用LoadLibrary函数加载库,就必须再调用GetProcAddress函数来得到每一个您想调用的函数的地址,GetProcAddress会在动态链接库中查找函数的入口地址。由于多余的步骤,这样您的程序执行起来会慢一点,但是并不明显。

明白了LoadLibrary函数的优缺点,下面我们就来看看如何产生一个动态链接库。下面的代码是一个动态链接库的框架:

;--------------------------------------------------------------------------------------
; DLLSkeleton.asm
;--------------------------------------------------------------------------------------
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
.code
DllEntry proc hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD
mov eax,TRUE
ret
DllEntry Endp
;---------------------------------------------------------------------------------------------------
;下面是一个空函数,您可以象下面一样插入您的函数。
;----------------------------------------------------------------------------------------------------
TestFunction proc
ret
TestFunction endp
End DllEntry
;-------------------------------------------------------------------------------------
; DLLSkeleton.def
;-------------------------------------------------------------------------------------
LIBRARY DLLSkeleton
EXPORTS TestFunction

时间: 2024-10-03 08:47:29

汇编教程之动态链接库的相关文章

汇编教程:连接数据源

本教程中,我们将学习使用ODBC APIs的细节. 因为我们的程序并不与ODBC驱动程序直接通信,而是通过ODBC管理器来定义一系列APIs供你的程序调用以完成工作,所以我们需要包含odbc32.inc和odbc32.lib文件,当然还有windows.inc. 连接数据源需要以下几步: 分配一个环境句柄(environment handle). 在进行每个ODBC任务(session)时仅需这样做一次.一旦获得了句柄,我们就可修改环境属性来适合我们的需要.你可以把这想象为在DB工作中创建一个w

汇编教程:控制转移(2)

2.关于实例三的说明 有些步骤的实现方法已在前面的实例中做过介绍,下面就任务内无特权级变换的转移和使用局部描述符LDT等作些说明: (1)实模式下初始化LDT 演示任务使用了局部描述符表LDT,本实例中该LDT在实模式下初始化(当然,也可以在使用LDT前的保护模式初始化).为了简便,LDT中各描述符的界限和属性值在定义时预置,利用一个子程序设置各段的段基地址.为方便起见,在定义时把各段的段值安排在相应描述符的段基地址低16位字段中.由于实例中各段在实模式下定位(这是因为程序是从实模式下启动执行的

汇编教程:虚拟设备驱动程序结构

现在大家对vmm和vxd有了一定的了解,接下来我们来看一看如何编写vxd代码.首先,你必须具备Windows 95/98 Device Driver Development Kit.Window95 ddk只有MSDN 订户才能拿到,但Windows98 ddk却可以免费从Microsoft公司取得.尽管Windows 98 ddk是面向WDM的,但你还是可以用它来开发VxD程序.你可以从 http://www.microsoft.com/hwdev/ddk/install98ddk.htm?下

汇编教程:客户寄存器结构

我们将学习本教程中另外一个重要的结构,叫客户寄存器结构.在本文中,V86指虚拟8086模式.在这里下载例子程序 理论 VxDs与正常的win32/win16/DOS应用程序有很大不同.大多数情况下,当其他应用程序正常工作时,它们是休眠的.它们象一个监管者一样工作,其作用是监视ring-3应用程序并在其出错时改正它们.下面是其工作时的典型的情况: 1.中断发生时 2.VMM得到控制权时 3.VMM存贮寄存器组的值时 4.VMM服务于中断或调用其他VxDs完成此工作时 5.VMM交还控制权给被中断的

汇编教程:ODBC基础

这是使用 win32asm进行数据库编程系列的第一份教程.在如今的IT界,数据库编程变的越来越重要,所以我们不能再忽视它.但如今有很多种数据库在使用,如果我们为了实现win32下数据库汇编语言编程而学习各种数据库文件格式,所花时间大概称得上"永恒". 幸运的是,Microsoft的一项技术使得我们得以摆脱这个大麻烦.它被称为ODBC,是开放式数据库互连(Open Database Connectivity)的缩写,这是一族API,与Windows API相似.它主要与数据库打交道.就是

汇编教程:多文档界面(MDI)

本教程告诉你怎样创建MDI应用程序.事实上并不是很困难. 理论: 多文档界面(MDI)是同一时刻处理多个文档的应用程序的一个规范. 你很熟悉记事本.它是单文档界面(SDI)的一个例子.记事本在一个时候只能处理一个文档.假如你希望打开另一个文档,你首先必须关闭你前面打开的那一个.你可以想象这有多麻烦. 和Microsoft Word相比:Word可以随心所欲的在同一时刻打开任意多个文档,而且可以让用户选择使用哪一个文档.Microsoft Word 是多文档界面(MDI)的一个例子. MDI应用程

汇编教程:Win32调试API(3)

在本章中,我们将继续探讨win32调试api.特别地,我们将学习如何去跟踪被调试程序. 理论: 如果你以前使用过调试器,那么你应对跟踪比较熟悉.当"跟踪"一个程序时,程序在每执行一条指令后将会停止,这使你有机会去检查寄存器/内存中的值.这种单步运行的官方定义为跟踪(tracing). 单步运行的特色是由CPU本身提供的.标志寄存器的第8位称为陷阱标志trap flag.如果该位设置,则CPU运行于单步模式.CPU将在每条指令后产生一个debug异常.当debug 异常产生后,陷阱标志自

汇编教程:Win32调试API(1)

在本教程中,我们将学习Win32提供给开发者的用于调试的原语. 在教程的结尾,我们将学习如何调试一个进程. 理论: Win32有一些供程序员使用的API,它们提供相当于调试器的功能. 他们被称作Win32调试API(或原语).利用这些API,我们可以: 加载一个程序或捆绑到一个正在运行的程序上以供调试 获得被调试的程序的低层信息,例如进程ID,进入地址,映像基址等. 当发生与调试有关的事件时被通知,例如进程/线程的开始/结束, DLL的加载/释放等. 修改被调试的进程或线程 简而言之,我们可以用

汇编教程之基本概念(win32)

我们先假设您已知道了如何使用MASM.如果您还不知道的话,请下载 win32asm.exe ,并请仔细研读其中所附带的文档资料.好,如果您已准备就绪,我们这就开始吧! 理论: WIN32 程序运行在保护模式下的,保护模式的历史可以追溯到 80286.而今 80286 已成为了历史.所以我们将只把精力集中于 80386 及后续的X86 系列 CPU.Windows 把每一个 Win32 应用程序放到分开的虚拟地址空间中去运行,也就是说每一个应用程序都拥有其相互独立的 4GB 地址空间,当然这倒不是