• 沒有找到結果。

Windows 汇编语言程序设计

前面介绍了基于DOS 的 8086 汇编语言程序设计,了解了 8086 汇编语言程序设计的思路 和方法。本节对Windows 下的汇编程序设计进行简要介绍。

在Windows 环境下,不需要掌握更多的硬件知识就能够应用 Win32 汇编语言编制应用程 序。在DOS 系统中用汇编语言编制程序是借助中断来调用操作系统内核提供的功能,而 Win32 汇编是借助应用编程接口API(Application Program Interface)去调用操作系统内核。Windows 环境下的很多高级语言对功能调用与实现的细节进行了不同程度的封装,如多线程处理和消息 循环等都被隐藏封装起来。虽然能够使用它们进行可视化编程,却无法全面了解 Win32 操作 系统程序的具体运行方式。由于封装使操作出现了某种缺陷和不足。如VB 不支持指针,而程 序员编程需要有指针的API,结果操作起来十分不方便,使多线程一类特征在 VB 中无法实现。

但用Win32 汇编语言能洞察到操作系统的真实工作情况,充分发挥 Windows 系统的各种功能,

如对Windows 环境的文件进行加密保护,编制出在 Windows 操作系统管理下各种文件的防病 毒程序。

5.4.1 Windows 汇编语言程序的例子

在Windows 操作系统下用消息框显示一个字符串“Good morning!”的汇编程序如下:

.386

.MODEL FLAT,STDCALL OPTION CASEMAP:NONE INCLUDE WINDOWS.INC INCLUDE USER32.INC INCLUDELIB USER32.LIB INCLUDE KERNEL32.INC INCLUDELIB KERNEL32.LIB .DATA

GDCAPTION DB "A Good cation!",0 GOOD DB "Good morning!",0 .CODE

START:

INVOKE MessageBox,NULL,OFFSET GOOD,OFFSET GDCAPTION,MB_YESNO INVOKE ExitProcess,NULL

END start 1.386 伪指令

在上述程序中,首先进行模式定义。“.386”表明 Win32 汇编程序工作于 80386 及以上的 处理器。也可以使用. 486、. 586、. 686 等伪指令。但是,如果程序没有使用特定的基于 386 以上CPU 的指令,从软件的兼容性考虑,建议使用.386。

2.MODEL 伪指令

.MODEL 是用来指定内存模式的伪指令,在 Win32 下,只有一种内存模式,即 FLAT。

Windows 操作系统为每一个应用程序建立一个 4GB 的线性空间。代码段、数据段和堆栈段都 使用同一个段,内存寻址从0 到 4GB,没有 64KB 的段大小限制。汇编程序自动为各段寄存 器做如下段约定:

ASSUME CS:FLAT,DS;FLAT,SS:FLAT,ES:FLAT

即CS、DS、ES、SS 指向同一段 FLAT,FS 和 GS 在 Win32 汇编中不用。STDCALL 用于指出 调用子程序或编程接口API 时参数传递的次序和堆栈平衡的方法。

3.OPTION 伪指令

语句OPTION CASEMAP:NONE,用以说明程序中的变量和子程序名是不分大小写的。与 DOS 汇编程序不同,Win32 汇编程序不考虑堆栈,系统会为程序分配一个向下扩展的段作为 堆栈段,因此,堆栈段定义会被忽略。

4.INCLUDE 伪指令

MASM32 工具包包含有各种 DLL 的 API 函数声明列表,每个 DLL 都有相对应的 DLL.INC 文件,程序中如果用到某个DLL 文件中包含的函数,必须用 INCLUDE 语句将其包含进来,如:

INCLUDE USER32.INC INCLUDE KERNEL32.INC 5.INCLUDELIB 伪指令

不同类的API 函数存放在不同的动态链接库 DLL 中,为了让连接程序快速地搜索到 API 函数在哪个DLL 库,Win32 还定义了一种库文件,称为导入库文件。一个 DLL 库对应一个导

入库。INCLUDELIB 语句用于指定链接时所用的导入库,以便通知连接程序在哪个 DLL 库中 去找连接所需的API 函数。例如,USER32.DLL 对应的导入库是 USER32.LIB,导入 USER32DLL 中的API 函数可通过语句 INCLUDELIB USER32.DLL 来实现。

LIBC.LIB 库中包含了大部分的运行库函数连接信息,程序的入口函数_main 也是在 LIBC.

LIB 中声明的。因此在程序中包含“INCLUDELIB LIBC.LIB”伪指令是非常有必要的,否则 连接时将会出现无法解析外部符号的错误。

6.“分段”伪指令

.DATA、.DATA?、.CONST 和.CODE 是 4 个“分段”伪指令。

Win32 FLAT 内存模式隐藏了分段机制,因此只有两种性质的“分段”:DATA 和 CODE。

在程序的.CODE 分段中,包括函数定义,是程序“代码”部分。对于 Win32 控制台程序,

入口函数名必须是_main,而不能像 DOS 汇编程序那样自定义入口函数名称。在 Win32 环境 中,可以像DOS 汇编那样对程序入口进行定义。本 Win32 例程入口为标号 START,程序结束 处用END 语句加标号“START”来实现,其用法与 DOS 汇编中完全相同。

Win32 汇编程序的数据段有 3 类:.DATA、.DATA?和.CONST,在生成的可执行文件中不 同的数据会被放在相应的节区中。

第一类是可读写的已定义变量,这些数据必须定义在.DATA 段中;第二类是可读写的未 定义变量,这些数据一般定义在.DATA?段中,也可以定义在.DATA 段中;第三类是常量,这 些数据在程序装入时已经有效,在执行过程中也不需要修改,可以放在.CONST 段中。.CONST 段作为常量段,它是可读不可写的。当然,也可以像本例一样把常量放到.DATA 段中。

7.END 伪指令

指示汇编结束位置,其后的任何文本(包括指令和伪指令)都会被汇编程序忽略。

再次强调,由于Win32 控制台程序的入口函数名必须是_main,所以 end 伪指令不能像在 DOS 汇编程序中那样指定除_main 外的任何其他标号。

8.Windows API 调用

Win32 环境中的编程接口 API 代替了 DOS 调用系统功能的中断方式。但和 DOS 不同,

Win32 把系统功能模块放在 Windows 的动态链接库中,Win32 汇编程序中的功能实现是通过 编程接口API 调用存放在 DLL 中的函数,从而完成 DOS 环境中借助中断方式来调用系统的 功能。

在本例中以INVOKE 伪操作指令实现对 MessageBox 的调用:

INVOKE MessageBox,NULL,OFFSET GOOD,OFFSET GDCAPTION,MB_YESNO

需要指出的是,INVOKE 并不是 80386 处理器的指令,而是宏汇编 MASM 编译器的伪指 令,它完成了汇编调用 MessageBox 函数的功能。此外,本例还用到另外一个 API 函数:

ExitProcess,它位于 KERNEL32.DLL 中。

通过以上实例,可以了解在Windows 环境下应用汇编语言编程的方法,以及 Win32 汇编 程序的基本结构。

5.4.2 Windows 程序设计的特点

汇编语言和微处理器及操作系统是紧密相关的。随着 Windows 操作系统占领市场,汇编 语言程序设计也相应地从DOS 下的实地址模式过渡到 Windows 下的 32 位保护模式。Windows 汇编程序设计和DOS 汇编程序设计有许多相似之处,如它们有相同的指令系统、类似的寻址

方式等。但也有不少根本性的区别,如内存管理、寻址模式、中断和异常处理等。与DOS 汇 编程序设计相比,Windows 汇编程序设计主要有以下不同特点:

(1)工作模式不同。DOS 应用程序工作在实模式方式下。Windows 应用程序工作在保护 模式下,系统的一些重要资源对Windows 应用程序来说是受保护的,Windows 应用程序不能 直接访问这些资源,而必须通过某种方式进行间接访问。

(2)内存使用方式不同。DOS 汇编采用分段机制,通过段地址加偏移地址得到相应内存 单元的物理地址。在Windows 中,则使用了“平坦”内存模型,每个 Windows 应用程序都可 以使用32 位地址来访问 4GB 空间的内存单元,不过这个地址一般是虚地址,需要经过分段和 分页机构的转换才能得到相应的物理地址。

(3)提供丰富的 API 函数。与 DOS 提供的中断调用类似,Windows 系统提供了丰富的 API 函数供选用。Windows API 支持上千种函数的调用,涉及网络、消息、文件处理、打印、

文本、字体、菜单、位图、图标、光栅运算、绘图、设备场景、硬件与系统、进程和线程、控 件与消息等各个方面,从而使程序员可以把更多的时间放在程序的逻辑结构和用户界面上。

(4)基于事件的消息驱动机制。Windows 应用程序的重要特点是采用基于事件的消息驱 动机制。应用程序对象的每一次操作都对应一个事件的发生,该事件完成应用程序的相关操作,

如鼠标的移动、窗口的缩小和关闭等。消息实际上就是Windows 系统预先定义的常量标识,

它具有唯一性。消息发生时,该消息被送往消息队列,应用程序或操作系统依据消息的种类调 用相应的事件处理过程。

Windows 的消息种类繁多,大致有以下 4 种:

z 控件消息,主要是控件子窗口向父窗口发送的消息,如WM_COMMAND。

z 菜单、快捷键等的WM_COMMAND 消息。

z 标准消息,除以上消息外,多为“WM_”的格式,如 WM_CHAR、WM_NOTIFY。

另外,各控件也具有自身的特定消息,如“LB_”开头的列表框消息、“TV_”开头 的树形视图消息等。各控件消息不可混用,其使用情况可参考 MSDN(Microsoft Development Network)相关文档。

z 自定义消息,该类消息的消息号不小于400H。

在 Windows 应用程序中,消息产生源相对固定,程序设计的重点是完善消息对应的事件 处理过程。

(5)应用程序独立于硬件设备。Windows 提供了图形设备接口(GDI)技术,使应用程 序能够真正独立于硬件设备,与设备无关,从而方便程序的移植。在Windows 中,相关设备 的驱动程序安装完毕并置于当前设备状态后,会形成一个相关设备的环境,即设备上下文DC

(Device Context)。当应用程序需要与相关设备通信时,只要获得 DC 并与之通信即可,其余 的全部交由操作系统去处理。

(6)中断。保护模式下的微处理器设置了 4 个特权级,从高到低分别为特权级 0、1、2、

3 级。Windows 操作系统只使用了其中的两个级别,操作系统内核及各种设备驱动程序运行在 最高级(0 级),应用程序运行在最低级(3 级)。

在Windows 操作系统中,使用 API 来代替中断服务子程序提供的系统功能,所以在 Win32 汇编中,INT n 指令失去了存在的意义。Windows 的 API 函数能够被应用程序直接调用,并且 它比DOS 下的中断调用具有更丰富的功能。

(7)程序结构不同。DOS 程序普遍采用结构化程序设计方法,程序整体通常采用顺序执

行的方式,中间穿插有分支结构和循环结构。Windows 应用程序一般不采用顺序执行的方式,

而是采用 GUI(图形用户界面)和基于消息的机制,应用程序的主要任务是捕获用户在图形 用户界面触发的消息并对其做出响应。

(8)资源丰富,使用方便。Windows 提供了丰富的资源,如菜单、对话框、字符串表、

(8)资源丰富,使用方便。Windows 提供了丰富的资源,如菜单、对话框、字符串表、

相關文件