简介
结构(srtucture)是逻辑上相互联的一组变量的模板,结构中的单个变量称为域(field),程序的语句可以把结构作为一个实体进行访问,也可以对结构中的单个域进行访问。结构通常包含不同类型的域。联合(union)同样是把多个标识符组合在一起,不过这些标识符公用同一块内存区域。
结构为归集数据以及在过程间进行传递提供方便。假设一个过程的输入参数是由 20 个与磁盘驱动器相关的数据构成的,调用过程时要想正确地传递所需参数是非常困难的,相反,应该把所有的相关数据存放在一个数据结构中,然后向过程传递结构的地址,这只需使用极少的堆栈空间(一个地址),被调用过程同时还能够修改结构的内容。
定义结构
结构使用 STRUCT 和ENDS 伪指令定义。在结构内部,使用与定义普通变量一样的格式来定义域。基本格式如下:
1 | 名字 STRUCT |
域的初始化
如果结构的域有初始值,在定义结构变量时这些初始值就成了结构变量域的默认值。结构中可以使用多种类型的初始值:
- 未定义:使用 “?” 表示域的额内容未定义
- 字符串:用引号包围的字符串
- 整数:整数常量或整数表达式
- 数组:当域是一个数组时,可使用DUP操作符初始化数组
结构中域的初始化
为取得最佳的I/O性能,结构的成员根据其数据类型进行对齐,否则CPU在访问结构的成员时就要花费更多的时间。例如,双字成员应该对齐在双字边界上。下表列出了Microsoft C/C++ 编译器对不同的数据类型对齐方式是的处理。在汇编语言中,ALIGN 伪指令设置下一个域或变量的地址对齐方式:
1 | ALIGN datatype |
在下列中,myVar 对齐在双字地址边界上:
1 | .data |
下面定义 Employee 结构:使用 ALIGN 伪指令使得成员 Years 对齐在字边界上、成员 SalaryHistory 对齐在双字边界上,各个域的大小在注释中给出:
1 | Employee STRUCT |
声明结构变量
1 | INCLUDE Irvine32.inc |
引用结构变量
循环遍历数组: 可以使用循环及间接寻址、变址寻址方式呢来操作结构数组。下面的程序(AllPoints.asm)为 AllPoints 数组赋坐标值:
1 | ;--------------------------- |
结构成员对齐与否对性能的影响
下面使用两个版本的 Employee 结构进行简单的测试,研究对齐结构对于未对齐结构的时效性影响有多大。
1 | ;--------------------------- |
在我的笔记本(i7 12代的处理器)中,未对齐的结构体访问起来更花时间。
例子:显示系统时间
程序清单:下面的程序(ShowTime.asm)获取当前的系统时间并在指定的屏幕位置上显示,该程序只能在保护模式下运行。
1 | ;--------------------------- |
结构的嵌套
醉汉走路
1 | ;--------------------------- |
联合的声明和使用
宏
宏过程(macro procedure)是一个命名的汇编语句块。一旦定义之后,宏过程就可以在程序中被调用任意多次。
声明的位置: 宏可以直接在程序的头部定义,或者也可以放在单独的文本文件中,通过 INCLUDE 伪指令把宏定义复制(插入)到源程序中。宏是在汇编器的预处理阶段展开的。在预处理阶段,预处理器读取宏的定义并扫描程序中其余的代码,在调用宏的地方插入宏代码的一份副本。汇编器在试图汇编任何调用宏的而语句前,必须首先找到宏的定义。如果程序定义了宏但没有调用,那么编译后的程序内不会包含宏的代码。
宏的定义
宏的调用
宏的其他特性
本书附带的宏库
这些宏的具体使用,请看书中相关章节。
例子程序
下面的程序(Wraps.asm)演示书中封装的宏,本书中的宏基本在 Macros.inc 文件中定义。
1 | ;--------------------------- |
条件汇编伪指令
条件汇编伪指令和宏联合使用可以使得宏更加灵活,条件汇编伪指令的一半格式是:
1 | IF condition |
本章介绍的常量条件伪指令和前面介绍的运行时伪指令(.IF和.ENDIF)是不一样的。运行时伪指令是基于存储在寄存器或变量中的运行时值对表达式的求值。
下表列出常用的条件汇编伪指令,当说明中提到一条伪指令 “允许汇编” 的时候,就意味着其后直到下一个相邻的 ELSE 或 ENDIF 伪指令之间的所有语句都会被编译,这里必须强调的是,表中列出的伪指令是在编译时求值的。
检查缺少的参数
宏可以检查其任何一个参数是否为空。通常如果一个宏接收了空参数,预处理器展开宏的时候就会导致生成无效指令。例如,如果调用宏 mWriteString 的时候不传递参数,在宏展开的时候,把字符串偏移送 EDX 的指令就成了无效指令。如下图所示,编译产生了错误信息:
为防止缺少参数产生的错误,可使用 IFB(if blank)伪指令,该伪指令在宏参数为空时返回真;也可以使用 IFNB(if not blank)伪指令,它在宏参数非空时返回真。
1 | ;--------------------------- |
EXITM 伪指令告诉预处理器退出宏,不要再展开宏中其后的语句。
默认的参数初始化值
布尔表达式
IF,ELSE和ENDIF伪指令
例子:mGotoxyConst 宏。mGotoxyConst 宏使用 LT 和 GT 操作符对传递给宏的参数进行范围检查,参数 X 和 Y 必须是常量。另一个符号常量 ERRS 用于统计发现的错误次数,检查 ERRS 可能被设置为 1;检查 Y 参数时,可能会再对 ERRS 加 1,最后 ERRS 的值大于 0,那么使用 EXITM 伪指令来退出宏:
1 | ;------------------------------------------------- |
IFIDN 和 IFIDNI 伪指令
1 | ;--------------------------- |
例子:对矩阵行求和
1 | ;--------------------------- |
特殊操作符
替换操作符
展开操作符(%)
文本操作符(<>)
宏函数
1 | ;--------------------------- |
定义重复块
WHILE 指令
只要在特定常量表达式为真,WHILE 伪指令就重复语句块。格式如下:
1 | WHILE constExpression |
REPEAT 伪指令
FOR 伪指令
FORC 伪指令
链表
1 | ;--------------------------- |
- 本文标题:80386汇编-结构和宏
- 本文作者:9unk
- 创建时间:2023-04-01 10:45:00
- 本文链接:https://9unkk.github.io/2023/04/01/80386-hui-bian-jie-gou-he-hong/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!