汇编基础
结构和宏
结构
结构(structure)是一组逻辑相关变量的模板或模式。结构中的变量被称为字段(fields),程序语句可以把结构作为整体进行访问,也可以访问其中的单个字段。
使用结构包含三个连续的步骤:
1)定义结构
2)声明结构类型的一个或多个变量,称为结构变量(structure variables)
3)编写运行时指令访问结构字段
对齐结构字段
为了获得最好的内存I/O性能,结构成员应按其数据类型进行地址对齐。否则,CPU将会花更多时间访问成员。
使用ALIGN伪指令会试其后的字段或者变量按地址对齐
1 | Employee STRUCT |
则TYPE Employee
和SIZEOF Employee
均为60
需要注意对齐:9+30+1(对齐2)+2+2(对齐4)+16
Q-A
Q:根据下面代码回答问题
1 | MyStruct STRUCT |
Q1:使用默认值创建变量
Q2:声明变量,将其第一个字段初始化为0
Q3:声明变量,将第二个字段初始化为全零数组
K:使用<>来在声明变量的同时初始化结构
A1:struct1 <>
A2:struct1 <0>
A3:struct1 <,20 DUP(0)>
Q4:一数组包含20个MyStruct,将该数组声明为变量
A4:array MyStruct 20 DUP(<>)
Q5:对上一题的数组,把第一个数组元素的field1送入AX
Q6:对上一题的数组,用ESI索引第三个数组元素,并将AX送入field1
K:使用变量加点来引用成员
A5: mov ax, array[0].field1
K:同样也可以用OFFSET运算符获取结构变量中一个字段的地址,间接操作数用寄存器对结构成员寻址(变址操作),但需要注意引用间接操作数时需要PTR运算符
A6:
1 | ;写法1 |
例子
COORD结构:Windows API中定义的COORD结构确定了屏幕的X和Y坐标。相对于结构起始地址,字段X的偏移量为0,Y的偏移量为2
1 | COORD STRUCT |
用程序模拟一个不太清醒的教授从计算机科学假期聚会回家的路线,利用随机数生成器,选择该教授每一步行走的方向。使用COORD结构追踪这个人行走路径上的每一步。
1 | INCLUDE Irvine32.inc |
宏
概述
宏过程(macro procedure)是一个命名的汇编句快。一但定义好,它就可以在程序中被多次调用。在调用宏的过程时,其代码的副本将被直接插入到程序中该宏被调用的位置。这种自动插入代码也被称作内联展开(inline expansion)
宏定义一般出现在程序源代码开始的位置,或者是放在独立的文件中,再用INCLUDE伪指令复制到程序里。宏在汇编器预处理(preprocessing)阶段进行扩展。在这个阶段中,预处理程序读取宏定义并扫描程序剩余的代码。每到宏被调用的位置,汇编器就将宏的源代码复制插入到程序中。
Q(判断):
1.当一个宏被调用时,CALL和RET指令将自动插入汇编程序中
2.宏展开由汇编器的预处理程序控制
3.只要宏定义在代码段中,它就能出现在宏调用语句之前,也能出现在宏调用语句之后
4.对一个长过程而言,若用包含这个过程代码的宏来代替它,则多次调用该宏通常就会增加程序的编译代码量
5.宏不能包含数据定义
A:F T F T F
K:
定义并调用宏
定义宏使用MACRO和ENDM伪指令
macroname MACRO param1, param2…
statement-list
ENDM
在宏名前使用前缀m,形成易识别的名称
宏形参(marco parameter)是需传递给调用者的文本实参的命名占位符,该形参不包含类型信息,如下:
1 | mPutchar MACRO char |
调用时不需要call,仍以上例mPutchar 'A'
就调用了宏
通常, 与过程相比,宏执行起来更快,其原因是过程的CALL和RET指令需要额外的开销
但是,宏也存在缺点:重复使用大型宏会增加程序的大小,因为每次调用都会插入代码
其他宏特性
规定形参
利用REQ限定符,可以指定必需的宏形参。如果被调用的宏没有实参与规定形参相匹配,那么汇编器将显示出错误消息
1 | mPutchar MACRO char:REQ |
注释
如果想忽略宏展开时的注释,需要使用双分号(;😉
ECHO
程序汇编时,ECHO伪指令写一个字符串到标准输出
1 | mPutchar MACRO char:REQ |
在汇编时会显示消息“ECHO Expanding the mPutchar marco”
LOCAL
宏定义中经常含有标号,并会在代码中对这些标号进行自引用,
1 | makeString MACRO text |
但这存在一个问题,若调用两次宏,就生成了两个一样的标号,会出现错误
为了避免这种错误,对标号使用LOCAL指令,这样预处理程序就把标号名转换成唯一的标识符(生成??nnnn的形式,其中nnnn为具有唯一性的整数)
宏嵌套(nested macro)
当汇编器的预处理程序遇到对被嵌套宏的调用时,它就会展开该宏。传递给主调宏的形参也将直接传递给它的被嵌套宏
1 | mWriteIn MACRO text |
特殊运算符
运算符 | 说明 |
---|---|
& | 替换运算符 |
<> | 文字文本运算符 |
! | 文字字符运算符 |
% | 展开运算符 |
&
1 | ;X,regName被当做字符串 |
%
展开运算符展开文本宏并将常量表达式转换为文本形式
1 | count = 10 |
<>
文字文本(literal-text)运算符把一个或多个字符和符号组合成一个文字文本,以防预处理程序把列表中的成员解释为独立的参数
1 | ;mWrite接收一个字符串作为唯一实参 |
!
构造文字字符(literal-character)运算符的目的与文字文本运算符几乎完全一样:强制预处理程序把预先定义的运算符当做普通的字符。
1 | BadYValue TEXTEQU <Warning:Y-coodinate is !> 24> |
上例使用!防止>被当做文本分隔符
写在后面
题目等等再更,一口气把基础过完