第 8章 高级汇编技术第 8章 高级汇编技术
8.1 宏汇编
8.2 重复汇编和条件汇编
8.3 汇编语言与高级语言的混合编程第 8章 高级汇编技术
8.1 宏汇编
8.1.1 宏指令的定义、调用和展开
1.宏定义伪指令宏的概念与过程很相似,也是用一个宏名字来代替源程序中经常需要用到的一个程序模块 (代码段 ),宏定义语句格式与过程定义语句格式也相似。
格式:
宏名 MACRO [形式参数表 ];宏体
ENDM ;宏定义结束功能:定义一个宏。
…
第 8章 高级汇编技术说明:
① 宏名必须是惟一的,它代表着所定义的宏体的内容,在其后面的源程序中,可通过该名字来调用宏。
② 形式参数表是用逗号 (或空格,或制表符 )分隔的一个或多个形式参数。它是可选项。选用了形式参数时,所定义的宏称为带参数的宏。当调用宏时,需用对应的实际参数去取代,
以实现向宏中传递信息。
第 8章 高级汇编技术
③ 宏体可以是汇编语言所允许的任意指令和伪指令语句序列,它决定了宏的功能。在宏体中还可以定义或调用另一个宏,
这就是宏嵌套。
④ 宏一经定义,就像为指令系统增加了新的指令一样,在程序中就可像指令一样通过宏名对它进行任意次的调用,故又称为宏指令或宏调用。要注意的是,宏定义必须放在第一条调用它的指令之前,一般都将它放在程序的开头。
第 8章 高级汇编技术
2.宏的调用与展开
(1) 在汇编语言源程序中,为了使在源程序中不重复书写需要多次使用的程序段,可以用一条宏指令来代替,由汇编程序在汇编时产生所需要的代码。
例如,为了实现 ASCII码与 BCD码之间的相互转换,往往需要把 AL中的内容左移 4位或右移 4位,可以用 80x86的指令来实现。
若要左移 4位,可用:
MOV CL,4
SAL AL,CL
第 8章 高级汇编技术若要多次使用,就可以用一条宏指令来代替,宏定义是:
SHIFT MACRO
MOV CL,4
SAL AL,CL
ENDM
这样,以后凡要使 AL中的内容左移 4位,就可以用这条宏指令 SHIFT来代替。
第 8章 高级汇编技术宏定义中,SHTFT是宏指令名,MACRO是宏定义的定义符,ENDM是宏定义的结束符,这两者必须成对出现。
宏汇编一般由可执行的指令语句和管理语句 (即由伪指令构成的语句 )所构成。经宏定义后,就可以引用宏指令,这称作宏调用。宏汇编程序遇到这样的调用时,就用对应的宏体来代替这条宏指令,以产生目的代码,这称作宏展开。
第 8章 高级汇编技术
(2) 宏定义不但能使源程序的书写简洁,而且由于宏指令具有接收参量的能力,所以功能就更灵活。
例如,上述的宏指令只能使 AL中的内容左移 4位。若每次使用时,要移位的次数不同,或要使不同的寄存器移位,就不方便了。但是,若在宏定义中引入参量,就可以满足上述要求。
第 8章 高级汇编技术例 8-1 定义满足不同移位次数要求的宏。
SHIFT MACRO X
MOV CL,X
SAL CL,CL
ENDM
其中,X是一个形式参量 (此处用来代表移位次数 )。在调用时可把实际要求的移位次数作为实在参量代入。如
SHIFT 4
就可以用实在参量 4代替在宏定义体中出现的形式参量 X,从而实现左移 4位的功能。
第 8章 高级汇编技术又如:
SHIFT 6
就可以左移 6次。这样,就可以由调用时的实在参数来规定任意的移位次数。
第 8章 高级汇编技术例 8-2 定义满足使用不同寄存器实现移位要求的宏,可再引入一个形式参量 Y。
SHIFT MACRO X,Y
MOV CL,X
SAL Y,CL
ENDM
用形式参量 Y来代替需要移位的寄存器。只要在调用时,把要移位的寄存器作为实在参量代入,就可以对任一个寄存器实现指定的左移次数。
SHIFT 4,AL
SHIFT 4,BX
SHIFT 6,DI
第 8章 高级汇编技术在汇编这些宏指令时,分别产生以下指令语句,宏汇编程序在每一条由宏展开产生的指令前冠以加号,+”:
+MOV CL,4
+SAL AL,CL
+MOV CL,4
+SAL BX,CL
+MOV CL,6
+SAL DI,CL
第一条宏指令使 AL左移 4位;第二条宏指令使 16位寄存器
BX左移 4位;第三条宏指令使 DI左移 6位。
第 8章 高级汇编技术
(3) 形式参量不仅可以出现在操作数部分,也可以出现在操作码部分。
例 8-3 用宏指令定义操作码。
SHIFT MACRO X,Y,Z
MOV CL,X
S&Z Y,CL
ENDM
其中第三个形式参量 Z代替操作码中的一部分。若在宏定义体中的形式参量没有适当的分隔符,则不被看作为形式参量,
调用时也不被实在参量所代替。
第 8章 高级汇编技术例如,上例中的操作码部分 S&Z中,若 Z与 S之间没有分隔,
则此处的 Z就不被看作形式参量。要定义它为形式参量,必须在其前面加上符号 &。所以 S&Z中 Z就被看作是形式参量。若有以下调用:
SHIFT 4,AL,AL
SHIFT 6,BX,AR
SHIFT 8,SI,HR
第 8章 高级汇编技术在汇编这些宏指令时,分别产生以下指令语句。
+MOV CL,4
+SAL AL,CL
+MOV CL,6
+SAR BX,CL
+MOV CL,8
+SHR SI,CL
这里的 SHIFT宏指令可以对任一个寄存器进行任意的移位操作 (算术左移、算术右移、逻辑右移、可移任意指定的位数 )。
第 8章 高级汇编技术
8.1.2 宏操作符主要的宏操作伪指令有:
1) MACRO
格式:
宏指令名 MACRO <形式参量表 >;宏体
ENDM
…
第 8章 高级汇编技术宏指令名是一个宏定义调用的依据,也是不同宏定义相互区分的标志,是必须要有的。对于宏指令名的规定与对标识符的规定是一致的。宏定义中的形式参量表是任选的,可以没有形式参量,也可以有若干形式参量。若有一个以上的形式参量时,它们之间必须用逗号分隔。对形式参量的规定与对标识符的规定是一致的。形式参量的个数没有限制,只要一行限制在 152个字符以内就行。在调用时的实在参量多于 1个时,也要用逗号分隔,它们与形式参量在顺序上相对应。但 IBM宏汇编并不要求它们在数量上必须一致。若调用时的实在参量多于形式参量,则多余的部分被忽略;若实在参量少于形式参量,则多余的形式参量变为
NULL(空 )。
第 8章 高级汇编技术
2) PURGE
一个宏指令名,可以用伪指令 PURGE来取消,然后就可以重新定义。
格式:
PURGE 宏指令名 [,…]
功能:取消多个宏定义。
第 8章 高级汇编技术
3) REPT
格式:
REPT <表达式 >;指令体
ENDM
功能:重复执行在它的指令体部分所包含的语句。重复执行的次数,由表达式的值所决定。
…
第 8章 高级汇编技术例 8-4
X=0
REPT 10
X=X+1
DB X
ENDM
实现的功能是把 1到 10分配给 10个连续的内存单元。
第 8章 高级汇编技术
4) IRP
格式:
IRP 形式参量,<参数表 >;指令体
ENDM
功能:重复执行指令体部分所包含的语句,重复的次数由参数表中的参数的个数决定 (参数表中的参数必须用两个尖括号括起来,参数间用逗号分隔 ),且每重复一次,依次用参数表中的参数来代替形式参量。
…
第 8章 高级汇编技术例 8-5
IRP X,<1,2,3,4,5,6,7,8,9,10>
DB X
ENDM
因为参数表中的参数个数为 10,故指令体部分重复执行 10
次。例 8-4中的指令体部分只有一条伪指令 DB X,其中 X为形式参量。在第一次执行时用参数表中的第一个参数 1代替形式参量,
就为 DB 1;第二次执行时,用参数表中的第二个参数 2代替形式参量,就为 DB 2; …… 所以例 8-4也是把 1到 10分配给 10个连续的内存单元。
第 8章 高级汇编技术
5) IRPC
格式:
IRPC 形式参量,字符串 (或 <字符串 >);指令体
ENDM
功能:重复执行指令体部分所包含的语句。重复执行的次数,取决于字符串中的字符个数,每次重复时,依次用字符串的字符代替形式参量。
IRPC伪指令与 IRP伪指令很类似,只是用字符串 (此字符串可以包括在两个三角括号中,也可以不包括 )代替了 IRP指令中的参数表。
…
第 8章 高级汇编技术例 8-6
IRPC X,<ABCDEF>
DB X
ENDM
实现的功能是:把字符 A到 F分配给内存中的 6个连续单元。
以上 MACRO,REPT,IRP和 IRPC 4个宏定义的伪指令都必须以伪指令 ENDM作为它的结束符。
第 8章 高级汇编技术有两点需要特别指出:
① 宏定义也可以像程序设计语言中的标准函数一样,构成一个标准函数库,供其他源程序使用。以文件的形式组织若干个宏定义即形成宏程序库。程序设计中使用了宏程序库中的宏定义时,在源程序中应使用 INCLUDE伪指令。宏汇编程序在汇编源程序时,当遇到该伪指令,就把 INCLUDE伪指令所包含的宏程序库中的文件扫描一遍,如同在程序中使用自己定义的宏一样,
在后面的程序中就可以对宏库中的宏定义直接进行宏调用了。
第 8章 高级汇编技术
② 与子程序一样,宏定义也可以嵌套。宏定义的嵌套有两种方式:宏定义嵌套和宏定义内嵌套宏调用。在一个宏定义中包含了另一个宏定义,则称为宏定义嵌套;在一个宏定义的宏体内有宏调用,则称为宏定义内嵌套宏调用。在宏定义内嵌套宏调用中,被调用的宏指令必须是已定义的。宏定义嵌套常用于产生一些新的宏定义,而宏定义内嵌套宏调用则可以使宏定义简化,功能单一,便于通过组合的方法实现一个功能较为复杂的宏定义。
第 8章 高级汇编技术
8.1.3 LOCAL伪指令如果宏定义中含有变量名或标号,且在同一源程序中又多次被宏调用,那么宏汇编程序在宏展开时,产生多个相同的变量名或标号,这就不能满足变量名和标号在同一程序中必须惟一的要求,从而产生汇编出错,即产生,ERROR A2005:
SYMBOL IS MULTIDEFINED”的错误。为达到在宏定义中使用变量名和标号,又能避免这个错误的目的,可在宏定义中使用局部符号伪指令 LOCAL对变量名或标号进行说明。
第 8章 高级汇编技术格式:
LOCAL <符号表 >
功能:对在符号表中的每个符号,在汇编时每扩展一次便建立一个,XXXX”惟一的符号,保证汇编时生成名字的惟一性。
说明:
(1) 符号表是在宏定义中定义的变量名和标号,多个符号之间用逗号分隔。
(2) LOCAL伪指令指定的变量名和标号自动生成格式为
,XXXX”,符号的后四位顺序使用 0000~ FFFF的十六进制数字。
第 8章 高级汇编技术
8.1.4 宏和过程的比较宏和过程都可用来简化源程序,并可使程序多次对它们进行调用,从而使程序结构简洁清晰,符合结构化程序设计风格。
因此,对于那些需重复使用的程序模块,既可用过程也可用宏来实现。
第 8章 高级汇编技术宏和过程的主要区别在于:
(1) 宏操作可以直接传递和接收参数,它不需通过栈等其他媒介来进行,因此编程比较容易。而过程不能直接带有参数,
当过程之间需要传递参数时,必须通过栈、寄存器或存储器来进行,所以相对于宏而言,它的编程要复杂一些。
第 8章 高级汇编技术
(2) 宏调用只能简化源程序的书写,缩短源程序长度,它并没有缩短目标代码的长度,汇编程序处理宏指令时,是把宏体插入到宏调用处,所以目标程序占用内存空间并不因宏操作而减少。而过程 (子程序 )调用却能缩短目标程序的长度,因为过程在源程序的目标代码中只有一段,无论主程序调用多少次,除了增加 CALL和 RET指令的代码外,并不增加子程序段代码。
(3) 引入宏操作并不会在执行目标代码时增加额外的时间开销。相反,过程调用由于需要保护和恢复现场及断点,因而有额外的时间开销,会延长目标程序的执行时间。
第 8章 高级汇编技术若在一个源程序中多次调用一段程序,则可用子程序,也可以用宏指令来简化源程序。用子程序的方法,汇编后产生的目标代码少,即目标程序占用的内存空间少,节约内存空间。
但是,子程序在执行时,每调用一次都要先保护断点,通常在程序中还要保护现场。同样,在返回时,先要恢复现场,然后恢复断点 (返回 )。这些操作都额外增加了时间,因而执行时间长,速度慢。而宏指令恰好相反,它的目标程序长,占用的内存单元多,但在执行时不需要保护断点、现场以及恢复、返回等这些额外操作,因而执行时间短,速度快。
第 8章 高级汇编技术所以,当要代替的程序段较短,速度是主要矛盾时,通常用宏指令。而当要代替的程序段较长,额外操作所附加的时间不明显,节省存储空间是主要矛盾时,通常用子程序。宏指令是机器的指令系统中没有的,但又可以作为一条指令使用。所以,从形式上看,宏指令扩充了机器的指令系统。
第 8章 高级汇编技术
8.2 重复汇编和条件汇编
8.2.1 重复汇编在汇编程序设计中,经常要连续地重复相同的或几乎完全相同的代码序列,这时可以使用重复伪指令。
1.重复伪指令宏汇编语言提供的重复伪指令包括 REPT,IRP,IRPC,其格式、功能及使用说明在 8.1.2节中已讲述,这里不再赘述。
第 8章 高级汇编技术
2.重复伪指令应用举例例 8-7 使用不同重复伪指令定义 10个数据,使其内容分别为 0,1,…,9。
第一种方法,使用 REPT伪指令:
COUNT= 0
REPT 10
DB COUNT
COUNT= COUNT+1
ENDM
第 8章 高级汇编技术第二种方法,使用 IRP伪指令:
IRP X,<0,1,2,3,4,5,6,7,8,9>
DB X
ENDM
第三种方法,使用 IRPC伪指令:
IRPC X 0123456789
DB X
ENDM
第 8章 高级汇编技术以上三种方法具有同样的功能,汇编后产生的代码如下:
+ DB 0
+ DB 1
+ DB 2
+ DB 3
+ DB 4
+ DB 5
+ DB 6
+ DB 7
+ DB 8
+ DB 9
第 8章 高级汇编技术例 8-8 下面两条重复伪指令具有相同的功能。
(1) IRP指令:
IRP REG,<AX,BX,CX,DX>
POP REG
ENDM
第 8章 高级汇编技术
(2) IRPC指令:
IRPC R ABCD
POP R& X
ENDM
汇编后它们产生的代码如下:
+ POP AX
+ POP BX
+ POP CX
+ POP DX
第 8章 高级汇编技术
8.2.2 条件汇编条件汇编伪指令可使汇编程序根据某种条件对某部分源程序有选择地进行汇编,在形式上和高级语言中的条件语句类似,
但实质不同。条件汇编语句是一种说明性语句,其功能由汇编系统实现;而一般高级语言的条件语句是执行性语句,其功能由目标程序实现。
条件汇编语句通常在宏定义中使用,使得宏定义的适用范围更广。一般情况下,使用条件汇编语句可使一个源文件产生几个不同的源程序,它们可有不同的功能。
第 8章 高级汇编技术格式,IF 条件语句序列 1
[ELSE
语句序列 2]
ENDIF
功能:当条件为真 (满足 )时执行汇编语句序列 1,否则执行汇编语句序列 2。
第 8章 高级汇编技术说明:“条件”为 IF伪指令说明符的一部分,ELSE伪指令及其后面的语句序列 2是可选择部分,表示条件为假 (不满足 )时的情况。如果属于非完全分支的判断,就不用这部分。整个条件汇编最后必须用 ENDIF伪指令来结束。语句序列 1和语句序列
2中的语句是任意的,也可为条件汇编语句。
以下 5组条件汇编开始语句均可选用 ELSE语句,以便汇编条件为假时执行语句序列 2,但一个 IF语句只能有一个 ELSE与之对应。
第 8章 高级汇编技术
1) 是 0否条件语句语句有,IF和 IFE。
① IF语句。
格式,IF 表达式功能:表达式值非 0,则条件为真,执行汇编语句序列 1。
② IFE语句。
格式,IFE 表达式功能:表达式值为 0,则条件为真,执行汇编语句序列 1。
第 8章 高级汇编技术
2) 扫描 1否条件语句语句有,IF1和 IF2。
① IF1语句。
格式,IF1
功能:汇编处于第一次扫描时条件为真。
② IF2语句。
格式,IF2
功能:汇编处于第二次扫描时条件为真。
第 8章 高级汇编技术
3) 符号有定义否条件语句语句有,IFDEF和 IFNDEF。
① IFDEF语句。
格式,IFDEF 符号功能:符号已被定义或已由 EXTRN伪指令说明,则条件为真。
② IFNDEF语句。
格式,IFNDEF 符号功能:符号未被定义或未由 EXTRN伪指令说明,则条件为真。
第 8章 高级汇编技术
4) 空否条件语句语句有,IFB和 IFNB。
① IFB语句。
格式,IFB <参数 >
功能:参数为空格,则条件为真。尖括号不能省略。
② IFNB语句格式,IFNB <参数 >
功能:参数不为空格,则条件为真。尖括号不能省略。
第 8章 高级汇编技术
5) 字符串比较条件语句语句有,IFIDN和 IFDEF。
① IFIDN语句。
格式,IFIDN <字符串 1>,<字符串 2>
功能:字符串 1与字符串 2相同,则条件为真。
第 8章 高级汇编技术
② IFDIF语句格式,IFDIF <字符串 1>,<字符串 2>
功能:字符串 1与字符串 2不相同,则条件为真。
说明:这两条语句只能在宏定义中使用,检查传送给两个参数的实参是否相同。
例 8-9 将输入及输出字符的 DOS功能调用放在一个宏定义中,通过判断参数为 0还是非 0值来选择是执行汇编输入还是输出的 DOS功能。
第 8章 高级汇编技术所编制的程序描述如下,其中含有条件汇编的语句。
INOUT MACRO X
IF X
MOV AH,2
INT 21H ;输出 DL中的字符
ELSE
MOV AH,1
INT 21H ;输入一个字符到 AL
ENDIF
ENDM
第 8章 高级汇编技术当宏调用为 INOUT 0时,表明传递给参数 X的值为 0,此时 IF X
的条件为假,因此汇编程序只汇编 ELSE与 ENDIF之间的语句,
这样,对该宏调用来说,实际上是执行下面的两条指令:
MOV AH,1
INT 21H
而当宏调用为 INOUT 1时,实际上是执行这样两条指令:
MOV AH,2
INT 21H
第 8章 高级汇编技术
8.3 汇编语言与高级语言的混合编程
8.3.1 调用协议汇编程序和汇编语言常常以在线汇编语言代码的形式,通过过程同高级语言,如 C/C++,BACIC,PASCAL及 FORTRAN一起使用。需要指出的是,这里尽管讲的是使用 Microsoft汇编语言过程,但只要提供兼容的调用协议,大多数其他语言也能够使用。
在与高级语言接口时,汇编程序使用两种调用协议:一是用于 C/C++语言的 C语言调用协议,二是用于 BASIC,PASCAL和
FORTRAN语言的 PASCAL语言调用协议。调用协议语言在
MODEL语句中或与 PROC语句相联系的 OPTION指示符中指定。
除用这些语句以外还可以用完全段定义指定。
第 8章 高级汇编技术
1,C语言调用协议
C语言调用协议从右到左压入参数,像它们在参数表里放的那样,带着放在栈上的参数从汇编语言过程返回,返回结果或者放在 AX中或者放在 DX∶ AX中。在 BP,DI,SI,DS,SS和方向标志位被改动之前应使用汇编语言过程保存起来。这些寄存器是高级语言能用到的。图 8-1给出了 C语言调用协议下近调用和远调用的栈。
第 8章 高级汇编技术图 8-1 使用 C语言调用协议时的栈内容
(a) 近程调用; (b) 远程调用参数 2
参数 1
IP ( 返回地址) (S P)
存储器
(a)
参数 2
参数 1
IP ( 返回地址) (S P)
存储器
(b )
CS ( 返回地址)
第 8章 高级汇编技术对栈内参数的访问由 C语言调用协议提供,如例 8-10所示。
带 *号的语句是汇编程序加上的,以保持与 C语言调用协议的一致。注意搞清楚 BP的内容如何被压入栈中,以及 BP是如何被装入 SP值以访问由 C语言程序放在栈中的参数这两个问题。
第 8章 高级汇编技术例 8-10
.LISTALL
.MODEL SMALL,C
SSS PROTO C,A,SWORD,A,SWORD
.CODE
SSS PROC C,A,SWORD,B,SWORD
PUSH BP ;保存 BP
MOV BP,SP ;栈地址存入 BP
MOV AX,A ;使用参数 A
ADD AX,B ;使用参数 B
POP BP ;恢复 BP
RET 00000H
SSS ENDP
END
第 8章 高级汇编技术根据 C语言调用协议编写的汇编语言过程通过指令 INVOKE
而被调用。 INVOKE用来替代标准的 CALL指令。 INVOKE遵循
C语言调用协议,允许汇编语言程序访问 C语言程序和函数。
INVOKE指令被用来访问例 8-10中的过程,例如,INVOKE SSS,
20,30实现把 30加上 20后,结果放入 AX中并返回。 INVOKE与
CALL的不同之处,按照调用协议的要求,INVOKE指令必须将参数从栈中全部移出。 INVOKE指令的语法要求过程名后必须跟着全部的参数,参数间用逗号隔开。
第 8章 高级汇编技术
2,INVOKE指令的使用用 PUSH把参数压入堆栈,如果不小心把参数个数搞错了,
就会使堆栈不平衡,从而使程序从堆栈中取出错误的返回地址,
引起不可预料的后果。所以有必要用一条语句来完成自动检验的任务。 INVOKE语句是能自动将所有的参数压入栈中,并检测参数个数、类型是否正确,使用 CALL来调用的一个宏指令。
INVOKE在汇编程序中调用子程序时,其参数的传递是通过堆栈来进行的。例如,MessageBox()函数在 USER32.INC文件中是这样声明的:
MESSAGEBOX(HWND HWND,LPCTSTR LPTEXT,
LPCTSTR LPCAPTION,UINT UTYPE),
第 8章 高级汇编技术在汇编程序中可这样调用它:
PUSH UTYPE
PUSH LPCAPTION
PUSH LPTEXT
PUSH HWND
CALL MessageBox
PUSH为汇编语言中的进栈指令。上面语句的原理是先将函数所需要的参数,压入到堆栈中去,然后再用 CALL指令来调用该函数。
第 8章 高级汇编技术需要注意的是,在上述的参数进栈过程中,是从左到右依次压入的,即最右面的参数是最后一个进堆栈,采用的是
PASCAL规则。引入 INVOKE语句后,就可自动的将所调用子程序中的参数压入堆栈中,而无须编程者用手工压入。所以上面的代码就可以变为
INVOKE MessageBox,NULL,addr szText,addr szCaption,
MB_OK。
addr是用来把变量参数的地址传递给被调用的函数 (注意,是所指变量在内存中的地址,而不是变量中的值 ),它只能在
INVOKE语句中使用。
第 8章 高级汇编技术
3,PASCAL语言调用协议
PASCAL语言调用协议用于 BASIC,PASCAL和 FORTRAN
语言,在 WINDOWS中,它也被用于访问 WINDOWS库文件
(WINH.LIB)中的函数。 PASCAL语言调用协议与 C语言调用协议的差异在于:参数是自左至右压入栈中。如果用在汇编语言过程中时,PASCAL语言调用协议也需要保存寄存器 SI,DI,DS和 SS
的内容。方向标志位在登录时要被清零,并以清除状态被返回。
和在 C语言调用协议中一样,INVOKE语句也用于由汇编语言进出高级语言过程。
第 8章 高级汇编技术这一点在汇编语言同 WINDOWS一起使用时格外重要,以
INVOKE MessageBeep,-1为例,如果 WINH.LIB库文件已被程序装载,则该指令使扬声器发出“嘀”的一声。其他参数也可与 MessageBeep一起使用,从而由 WINDOWS发出各种失败提示音。在 C语言程序中,通过在 C语言程序的开头使用指令
#INCLUDE <WINDOWS.H>,就可以访问 WINDOWS应用程序接口 (API)。
第 8章 高级汇编技术图 8-2 使用 PASCAL语言调用协议时栈内容参数 1
参数 2
IP ( 返回地址)
( B P )
存储器
CS ( 返回地址)
BP
第 8章 高级汇编技术图 8-2给出了从 PASCAL中调用函数时的栈,注意:所有这些语言调用的函数都被认为是远程调用,BP给出了存储参数的栈的地址。最右边的参数的地址为 BP+6,这一点与 C语言调用协议正好相反。同 C语言调用协议一样,隐蔽的指令将 BP压入栈,并将 SP写入 BP。
第 8章 高级汇编技术
4.数据类型 表 8-1 各种数据类型的比较
MASM数据类型 C语言数据类型 PASCAL数据类型
BYTE unsigned char —
SBYTE char —
WORD unsigned short STRING*1
SWORD short int INTEGER
DWORD unsigned long —
SDWORD long LONG(&)
REAL4 float SINGLE(!)
REAL8 double DOUBLE(#)
REAL10 long double —
第 8章 高级汇编技术
8.3.2 与 C语言的接口例 8-11 本例给出了一个被 C语言程序调用的过程,该过程使用 MODEL语句指示内存模型 (本例为小模型 )和相应的调用协议语言 (C语言 )。 PROTO语句把本过程作为外部函数声明,并指定了全部与本过程相关的参数的大小和名称。本过程被作为一个近程调用
.MODEL SMALL,C
X1 PROTO C,l,SWORD,F,SWORD
.CODE
第 8章 高级汇编技术
X1 PROC C,l,SWORD,LSWORD
FILDPI ;取出
FADD ST,ST(0) ;计算 2× pi
MOV AX,1 ;取 1
MOV TEMP,AX
FILD TEMP ;取 l
FMUL ;计算 2× pi× l
MOV AX,F ;取 F
MOV TEMP,AX
FILD TEMP ;取 F
FMUL ;计算 2× pi× l× f
FISTP TEMP ;保存结果第 8章 高级汇编技术
MOV AX,TEMP ;取结果用以返回 C
RET
X1 ENDP
TEMP DW? ;暂存区
END
第 8章 高级汇编技术本过程使用数值协处理器计算电抗值,使用公式 X1=2πlF。
其中,参数 F和 l从 C语言程序中传送到汇编语言过程中,返回值
(X1)作为一个字长的整型变量由 AX传回 C语言程序。通过 BP+4
和 BP+6给出的地址,可以从栈中取出 l和 F的数据。本例中的
MOV AX,l指令,若转换为代码应为 MOV AX,[BP+4],通过该指令可从栈中取出 l值。
第 8章 高级汇编技术例 8-12 本例给出了主模块的 C语言调用顺序,该程序顺序打印出电感系数为 4H,频率为 1000 Hz的电抗值。注意:本程序中的计算结果被变换为整型。
#include <stdio.h>
extern int xl(int l,int f);
void main()
{
printf("The inductive reactance of 4 H at 1000 Hz is% d\ n",
xl(4,1000));
}
第 8章 高级汇编技术
8.3.3 与 PASCAL语言的接口
1.有关的 PASCAL语句和调用约定
PASCAL语言没有提供 CALL调用语句。 PASCAL主程序对汇编语言子程序的调用是通过外部过程和外部函数调用的形式来实现的。为了保证调用的正确实施,PASCAL主程序和被调用的汇编语言子程序都要遵从一定的调用约定。 PASCAL语言中的过程和函数有所不同。
第 8章 高级汇编技术
1) 过程方式在 PASCAL程序中,对要调用的汇编语言过程必须预先采用
PROCEDURE说明语句加以定义说明。 PROCEDURE语句的格式为:
PROCEDURE过程名 (参数表 ):过程属性;
这样,PROCEDURE语句将向 PASCAL编译程序提供如下信息:
(1) 被调用的过程名;
(2) 此过程是内部过程还是外部过程;
(3) 过程的参数名和类型;
(4) 是“数值参数”还是“引用参数”。
第 8章 高级汇编技术由于汇编语言子程序是单独编写和汇编的,它相对 PASCAL
主程序而言总是外部的。所以,其“过程属性”为 EXTERN。
并且,过程名必须在汇编语言程序中用 PUBLIC伪指令加以说明。
第 (3)项的过程参数名和类型是符合 PASCAL要求的变量标识符和数据类型。在进行 PASCAL过程调用时,过程参数也是通过栈来进行传递的。第 (4)项的“数值参数”和“引用参数”涉及到是传递参数变量值,还是传递参数变量地址的问题。当一个变量是数值参数时,主程序把此变量的值入栈,即传递给被调用过程;否则,主程序把此变量的地址入栈。作为引用参数的变量,在 PROCEDURE语句中须用 VAR或 VARS来加以说明。两者的区别在于:对由 VAR说明的参数,主程序须将其变量地址的偏移量入栈;而对由 VARS说明的参数,除变量地址的偏移量外,
主程序还要将此变量地址的段地址入栈。语句:
第 8章 高级汇编技术
PROCEDURE ADDP(A,B,INTEGER; VAR C,INTEGER),EXTERN;
定义了一个有 3个参数的外部过程 ADDP。其中,变量 A和 B是整型数值参数,而变量 C是整型引用参数;一旦汇编语言过程在
PASCAL主程序中经由 PROCEDURE语句定义说明后,PASCAL
主程序就可以采用相应的过程调用语句来调用此汇编语言过程了,
过程调用语句的格式为过程名 (参数表 )
对上面的 ADDP过程,其相应的过程调用语句为
ADDP(A,B,C)
其中,A,B,C是 PASCAL主程序中的整型变量。
第 8章 高级汇编技术在被调用的汇编语言子程序中,PASCAL对过程的要求是:
(1) 由于寄存器 SP不能用于一般的寻址方式,通常用 BP来存取传递的调用参数。所以,在过程程序开始时要先把 BP的原有内容入栈保存,并在返回 PASCAL主程序之前恢复内容。另外,
若要在子程序中改变 DS和 SS等寄存器的内容,也须加以保存和恢复。
(2) 由于是外部过程,在返回 PASCAL主程序时应采用长返回指令,即进行段间返回。
(3) 在返回时,应取消栈参数,即主程序传递给此过程的所有调用参数。
第 8章 高级汇编技术下面是用汇编语言编写的 ADDP过程程序,在程序中,
PUBLIC指令将过程名 ADDP存放。
CODE SEGMENT
ASSUME CS∶ CODE
ADDP PROC FAR
PUBLIC ADDP
PUSH BP
MOV BP,SP
PUSH AX
第 8章 高级汇编技术
PUSH BX
MOV AX,[BP+10]
ADD AX,[BP+8]
MOV BX[BP+6]
MOV [BX],AX
POP BX
POP AX
POP BP
RET 6
ADDP ENDP
第 8章 高级汇编技术过程的 FAR属性使得后面的 RET指令成为长返回指令。 RET
指令中的整数用于消去栈参数,它在返回后将自动加入到 SP寄存器中。程序的,RET 6”指令执行前后栈内容的变化如图 8-3所示。
当 ADDP过程的 C变量为 VARS引用参数时,相应的汇编语言程序有所不同。由于 C的段地址,A和 B的地址由 [BP+10]和
[BP+8]变为 [BP+12]和 [BP+10]。同时,,RET 6”变为,RET 8”。
除此之外,由于 C变量不是当前 DS寄存器所指数据段中的变量,
对它的存取方式也与前不同,如图 8-4所示。
第 8章 高级汇编技术图 8-3 栈变化
(SP)
A 的内容
C 的偏移量返回段地址 CS
B 的内容
…
返回偏移量 IP
6
X X X X X
执行,R E T 6,
(SP) X X X X X
…
第 8章 高级汇编技术图 8-4 C变量为 VARS引用参数时的堆栈结构
(S P )
A 的内容
C 的偏移量
CS
IP
B 的内容
…
第 8章 高级汇编技术
CODE SEGMENT
ASSUME CS∶ CODE
ADDP PROC FAR
PUBLIC ADDP
PUSH BP
MOV BP,SP
PUSH AX
PUSH BX
PUSH ES
MOV AX,[BP+12]
第 8章 高级汇编技术
ADD AX,[BP+10]
LES BX,[BP+6]
MOV ES∶ [BX],AX
POP ES
POP BX
POP AX
POP BP
RET 8
ADDP ENDP
CODE ENDS
END
第 8章 高级汇编技术
2) 函数方式函数方式同过程方式很相似。在 PASCAL程序中,对要调用的汇编函数也必须预先加以说明。不过,此时采用的是
FUNCTION说明语句,而不是 PROCEDURE说明语句。
FUNCTION语句的格式为
FUNCTION 函数名 (参数表 ):函数类型;函数属性;
在 FUNCTION语句中,除增加了一个“函数类型”外,其余同
PROCEDURE语句一样。“函数类型”符合 PASCAL要求的数据类型的语句。如:
FUNCTION ADDF(A,B,INTEGER),INTEGER,EXTERN;
说明定义了一个名为 ADDF的外部整型函数。
第 8章 高级汇编技术
PASCAL对汇编函数的要求,除在程序完成后必须返回函数值外,其余同过程完全一样。一般来说,函数可通过 AL,AX、
ES∶ BX或调用者提供的缓冲区来返回其值。具体使用时应根据函数的类型和语言编译程序版本的要求来选择。下面是 ADDF函数的汇编程序。通过和本节给出的第一个程序比较可知,ADDP
和 ADDF的功能是一样的,都是求 A,B之和,不同的是,ADDF
函数是通过 AX直接返回结果值,而 ADDP过程则是通过设置的
VAR参数 C来返回的。
第 8章 高级汇编技术
CODE SEGMENT
ASSUMEE CS,CODE
ADDF PROC FAR
PUBLIC ADDF
PUSH BP
MOV BP,SP
PUSH AX
MOV AX,[BP+8]
ADD AX,[BP+6]
POP BP
RET 4
ADDF ENDP
CODE ENDS
END
第 8章 高级汇编技术
2.连接方法
PASCAL主程序和汇编语言子程序通过连接程序 LINK连为一体,形成可执行文件。连接的具体过程如下:
(1) 汇编源程序 ADDP.ASM,得到相应的目标文件
ADDP.OBJ:
C>MASM ADDP;
(2) 汇编源程序 ADDF.ASM,得到相应的目标文件
ADDF.OBJ:
C> MASM ADDF;
第 8章 高级汇编技术
(3) 编译源程序 MAIN.PAS,得到相应的目标文件 MAIN.OBJ:
C> PAS1 MAIN;
C> PAS2
(4) 连接目标模块 ADDF.OBJ,ADDP.OBJ和 MAIN.OBJ,生成可执行文件 MAIN.EXE:
C> LINK MAIN+ADDP+ADDF;
执行可执行文件 MAIN.EXE将得到如下结果:
C>MAIN
3 3
第 8章 高级汇编技术下面是 PASCAL主程序 MAIN.PAS。
PROGRAM MAIN (OUTPUT);
PROCEDURE ADDP(A,B,INTEGER; VAR C,INTEGER); EXTERN;
FUNCTION ADDF(A,B,INTEGER),INTEGER; EXTERN;
VAR A,B,C,INTEGER;
BEGIN
A∶ =1;
B∶ =2;
ADDP(A,B,C);
A∶ =ADDF(A,B);
WRITE(A,C)
END.{MAIN}
第 8章 高级汇编技术习 题 八
8.1 在代码段中,开始的一段程序有通用性,试将此段程序定义为一条宏指令。
8.2 定义 — 条宏指令,它可以实现任一数据块的传送 (假设无重叠 ),只要给出源和目的数据块的首地址以及数据块的长度即可。如果 — 条宏指令既可以从数据块的首地址又可从其末地址开始传送这个数据块,应如何定义这条宏指令?
第 8章 高级汇编技术
8.3 编写实现下述功能的宏指令。
(1) 清屏。
(2) 设置光标,要求光标的行、列号用形式参数表示;
(3) 字符串的逆序存放,要求原字符串及逆序串的首地址用形式参数表示。
8.4 试用调用宏指令的方法计算 Y= (A2+B2),要求计算 X2
用累加的方法实现,并用宏指令表示。
第 8章 高级汇编技术
8.5 STORE宏指令定义如下:
STORE MACRO X,N
MOV X+I,I
I= I+1
IF I-N
STORE X,N
ENDIF
ENDM
有以下宏调用:
I= 0
STORE TAB,6
试对其进行宏扩展。
第 8章 高级汇编技术
8.6 试编写一段程序完成以下功能:若给定名为 X的字符串长度大于 5时,对 DEC CX指令汇编 4次。
8.1 宏汇编
8.2 重复汇编和条件汇编
8.3 汇编语言与高级语言的混合编程第 8章 高级汇编技术
8.1 宏汇编
8.1.1 宏指令的定义、调用和展开
1.宏定义伪指令宏的概念与过程很相似,也是用一个宏名字来代替源程序中经常需要用到的一个程序模块 (代码段 ),宏定义语句格式与过程定义语句格式也相似。
格式:
宏名 MACRO [形式参数表 ];宏体
ENDM ;宏定义结束功能:定义一个宏。
…
第 8章 高级汇编技术说明:
① 宏名必须是惟一的,它代表着所定义的宏体的内容,在其后面的源程序中,可通过该名字来调用宏。
② 形式参数表是用逗号 (或空格,或制表符 )分隔的一个或多个形式参数。它是可选项。选用了形式参数时,所定义的宏称为带参数的宏。当调用宏时,需用对应的实际参数去取代,
以实现向宏中传递信息。
第 8章 高级汇编技术
③ 宏体可以是汇编语言所允许的任意指令和伪指令语句序列,它决定了宏的功能。在宏体中还可以定义或调用另一个宏,
这就是宏嵌套。
④ 宏一经定义,就像为指令系统增加了新的指令一样,在程序中就可像指令一样通过宏名对它进行任意次的调用,故又称为宏指令或宏调用。要注意的是,宏定义必须放在第一条调用它的指令之前,一般都将它放在程序的开头。
第 8章 高级汇编技术
2.宏的调用与展开
(1) 在汇编语言源程序中,为了使在源程序中不重复书写需要多次使用的程序段,可以用一条宏指令来代替,由汇编程序在汇编时产生所需要的代码。
例如,为了实现 ASCII码与 BCD码之间的相互转换,往往需要把 AL中的内容左移 4位或右移 4位,可以用 80x86的指令来实现。
若要左移 4位,可用:
MOV CL,4
SAL AL,CL
第 8章 高级汇编技术若要多次使用,就可以用一条宏指令来代替,宏定义是:
SHIFT MACRO
MOV CL,4
SAL AL,CL
ENDM
这样,以后凡要使 AL中的内容左移 4位,就可以用这条宏指令 SHIFT来代替。
第 8章 高级汇编技术宏定义中,SHTFT是宏指令名,MACRO是宏定义的定义符,ENDM是宏定义的结束符,这两者必须成对出现。
宏汇编一般由可执行的指令语句和管理语句 (即由伪指令构成的语句 )所构成。经宏定义后,就可以引用宏指令,这称作宏调用。宏汇编程序遇到这样的调用时,就用对应的宏体来代替这条宏指令,以产生目的代码,这称作宏展开。
第 8章 高级汇编技术
(2) 宏定义不但能使源程序的书写简洁,而且由于宏指令具有接收参量的能力,所以功能就更灵活。
例如,上述的宏指令只能使 AL中的内容左移 4位。若每次使用时,要移位的次数不同,或要使不同的寄存器移位,就不方便了。但是,若在宏定义中引入参量,就可以满足上述要求。
第 8章 高级汇编技术例 8-1 定义满足不同移位次数要求的宏。
SHIFT MACRO X
MOV CL,X
SAL CL,CL
ENDM
其中,X是一个形式参量 (此处用来代表移位次数 )。在调用时可把实际要求的移位次数作为实在参量代入。如
SHIFT 4
就可以用实在参量 4代替在宏定义体中出现的形式参量 X,从而实现左移 4位的功能。
第 8章 高级汇编技术又如:
SHIFT 6
就可以左移 6次。这样,就可以由调用时的实在参数来规定任意的移位次数。
第 8章 高级汇编技术例 8-2 定义满足使用不同寄存器实现移位要求的宏,可再引入一个形式参量 Y。
SHIFT MACRO X,Y
MOV CL,X
SAL Y,CL
ENDM
用形式参量 Y来代替需要移位的寄存器。只要在调用时,把要移位的寄存器作为实在参量代入,就可以对任一个寄存器实现指定的左移次数。
SHIFT 4,AL
SHIFT 4,BX
SHIFT 6,DI
第 8章 高级汇编技术在汇编这些宏指令时,分别产生以下指令语句,宏汇编程序在每一条由宏展开产生的指令前冠以加号,+”:
+MOV CL,4
+SAL AL,CL
+MOV CL,4
+SAL BX,CL
+MOV CL,6
+SAL DI,CL
第一条宏指令使 AL左移 4位;第二条宏指令使 16位寄存器
BX左移 4位;第三条宏指令使 DI左移 6位。
第 8章 高级汇编技术
(3) 形式参量不仅可以出现在操作数部分,也可以出现在操作码部分。
例 8-3 用宏指令定义操作码。
SHIFT MACRO X,Y,Z
MOV CL,X
S&Z Y,CL
ENDM
其中第三个形式参量 Z代替操作码中的一部分。若在宏定义体中的形式参量没有适当的分隔符,则不被看作为形式参量,
调用时也不被实在参量所代替。
第 8章 高级汇编技术例如,上例中的操作码部分 S&Z中,若 Z与 S之间没有分隔,
则此处的 Z就不被看作形式参量。要定义它为形式参量,必须在其前面加上符号 &。所以 S&Z中 Z就被看作是形式参量。若有以下调用:
SHIFT 4,AL,AL
SHIFT 6,BX,AR
SHIFT 8,SI,HR
第 8章 高级汇编技术在汇编这些宏指令时,分别产生以下指令语句。
+MOV CL,4
+SAL AL,CL
+MOV CL,6
+SAR BX,CL
+MOV CL,8
+SHR SI,CL
这里的 SHIFT宏指令可以对任一个寄存器进行任意的移位操作 (算术左移、算术右移、逻辑右移、可移任意指定的位数 )。
第 8章 高级汇编技术
8.1.2 宏操作符主要的宏操作伪指令有:
1) MACRO
格式:
宏指令名 MACRO <形式参量表 >;宏体
ENDM
…
第 8章 高级汇编技术宏指令名是一个宏定义调用的依据,也是不同宏定义相互区分的标志,是必须要有的。对于宏指令名的规定与对标识符的规定是一致的。宏定义中的形式参量表是任选的,可以没有形式参量,也可以有若干形式参量。若有一个以上的形式参量时,它们之间必须用逗号分隔。对形式参量的规定与对标识符的规定是一致的。形式参量的个数没有限制,只要一行限制在 152个字符以内就行。在调用时的实在参量多于 1个时,也要用逗号分隔,它们与形式参量在顺序上相对应。但 IBM宏汇编并不要求它们在数量上必须一致。若调用时的实在参量多于形式参量,则多余的部分被忽略;若实在参量少于形式参量,则多余的形式参量变为
NULL(空 )。
第 8章 高级汇编技术
2) PURGE
一个宏指令名,可以用伪指令 PURGE来取消,然后就可以重新定义。
格式:
PURGE 宏指令名 [,…]
功能:取消多个宏定义。
第 8章 高级汇编技术
3) REPT
格式:
REPT <表达式 >;指令体
ENDM
功能:重复执行在它的指令体部分所包含的语句。重复执行的次数,由表达式的值所决定。
…
第 8章 高级汇编技术例 8-4
X=0
REPT 10
X=X+1
DB X
ENDM
实现的功能是把 1到 10分配给 10个连续的内存单元。
第 8章 高级汇编技术
4) IRP
格式:
IRP 形式参量,<参数表 >;指令体
ENDM
功能:重复执行指令体部分所包含的语句,重复的次数由参数表中的参数的个数决定 (参数表中的参数必须用两个尖括号括起来,参数间用逗号分隔 ),且每重复一次,依次用参数表中的参数来代替形式参量。
…
第 8章 高级汇编技术例 8-5
IRP X,<1,2,3,4,5,6,7,8,9,10>
DB X
ENDM
因为参数表中的参数个数为 10,故指令体部分重复执行 10
次。例 8-4中的指令体部分只有一条伪指令 DB X,其中 X为形式参量。在第一次执行时用参数表中的第一个参数 1代替形式参量,
就为 DB 1;第二次执行时,用参数表中的第二个参数 2代替形式参量,就为 DB 2; …… 所以例 8-4也是把 1到 10分配给 10个连续的内存单元。
第 8章 高级汇编技术
5) IRPC
格式:
IRPC 形式参量,字符串 (或 <字符串 >);指令体
ENDM
功能:重复执行指令体部分所包含的语句。重复执行的次数,取决于字符串中的字符个数,每次重复时,依次用字符串的字符代替形式参量。
IRPC伪指令与 IRP伪指令很类似,只是用字符串 (此字符串可以包括在两个三角括号中,也可以不包括 )代替了 IRP指令中的参数表。
…
第 8章 高级汇编技术例 8-6
IRPC X,<ABCDEF>
DB X
ENDM
实现的功能是:把字符 A到 F分配给内存中的 6个连续单元。
以上 MACRO,REPT,IRP和 IRPC 4个宏定义的伪指令都必须以伪指令 ENDM作为它的结束符。
第 8章 高级汇编技术有两点需要特别指出:
① 宏定义也可以像程序设计语言中的标准函数一样,构成一个标准函数库,供其他源程序使用。以文件的形式组织若干个宏定义即形成宏程序库。程序设计中使用了宏程序库中的宏定义时,在源程序中应使用 INCLUDE伪指令。宏汇编程序在汇编源程序时,当遇到该伪指令,就把 INCLUDE伪指令所包含的宏程序库中的文件扫描一遍,如同在程序中使用自己定义的宏一样,
在后面的程序中就可以对宏库中的宏定义直接进行宏调用了。
第 8章 高级汇编技术
② 与子程序一样,宏定义也可以嵌套。宏定义的嵌套有两种方式:宏定义嵌套和宏定义内嵌套宏调用。在一个宏定义中包含了另一个宏定义,则称为宏定义嵌套;在一个宏定义的宏体内有宏调用,则称为宏定义内嵌套宏调用。在宏定义内嵌套宏调用中,被调用的宏指令必须是已定义的。宏定义嵌套常用于产生一些新的宏定义,而宏定义内嵌套宏调用则可以使宏定义简化,功能单一,便于通过组合的方法实现一个功能较为复杂的宏定义。
第 8章 高级汇编技术
8.1.3 LOCAL伪指令如果宏定义中含有变量名或标号,且在同一源程序中又多次被宏调用,那么宏汇编程序在宏展开时,产生多个相同的变量名或标号,这就不能满足变量名和标号在同一程序中必须惟一的要求,从而产生汇编出错,即产生,ERROR A2005:
SYMBOL IS MULTIDEFINED”的错误。为达到在宏定义中使用变量名和标号,又能避免这个错误的目的,可在宏定义中使用局部符号伪指令 LOCAL对变量名或标号进行说明。
第 8章 高级汇编技术格式:
LOCAL <符号表 >
功能:对在符号表中的每个符号,在汇编时每扩展一次便建立一个,XXXX”惟一的符号,保证汇编时生成名字的惟一性。
说明:
(1) 符号表是在宏定义中定义的变量名和标号,多个符号之间用逗号分隔。
(2) LOCAL伪指令指定的变量名和标号自动生成格式为
,XXXX”,符号的后四位顺序使用 0000~ FFFF的十六进制数字。
第 8章 高级汇编技术
8.1.4 宏和过程的比较宏和过程都可用来简化源程序,并可使程序多次对它们进行调用,从而使程序结构简洁清晰,符合结构化程序设计风格。
因此,对于那些需重复使用的程序模块,既可用过程也可用宏来实现。
第 8章 高级汇编技术宏和过程的主要区别在于:
(1) 宏操作可以直接传递和接收参数,它不需通过栈等其他媒介来进行,因此编程比较容易。而过程不能直接带有参数,
当过程之间需要传递参数时,必须通过栈、寄存器或存储器来进行,所以相对于宏而言,它的编程要复杂一些。
第 8章 高级汇编技术
(2) 宏调用只能简化源程序的书写,缩短源程序长度,它并没有缩短目标代码的长度,汇编程序处理宏指令时,是把宏体插入到宏调用处,所以目标程序占用内存空间并不因宏操作而减少。而过程 (子程序 )调用却能缩短目标程序的长度,因为过程在源程序的目标代码中只有一段,无论主程序调用多少次,除了增加 CALL和 RET指令的代码外,并不增加子程序段代码。
(3) 引入宏操作并不会在执行目标代码时增加额外的时间开销。相反,过程调用由于需要保护和恢复现场及断点,因而有额外的时间开销,会延长目标程序的执行时间。
第 8章 高级汇编技术若在一个源程序中多次调用一段程序,则可用子程序,也可以用宏指令来简化源程序。用子程序的方法,汇编后产生的目标代码少,即目标程序占用的内存空间少,节约内存空间。
但是,子程序在执行时,每调用一次都要先保护断点,通常在程序中还要保护现场。同样,在返回时,先要恢复现场,然后恢复断点 (返回 )。这些操作都额外增加了时间,因而执行时间长,速度慢。而宏指令恰好相反,它的目标程序长,占用的内存单元多,但在执行时不需要保护断点、现场以及恢复、返回等这些额外操作,因而执行时间短,速度快。
第 8章 高级汇编技术所以,当要代替的程序段较短,速度是主要矛盾时,通常用宏指令。而当要代替的程序段较长,额外操作所附加的时间不明显,节省存储空间是主要矛盾时,通常用子程序。宏指令是机器的指令系统中没有的,但又可以作为一条指令使用。所以,从形式上看,宏指令扩充了机器的指令系统。
第 8章 高级汇编技术
8.2 重复汇编和条件汇编
8.2.1 重复汇编在汇编程序设计中,经常要连续地重复相同的或几乎完全相同的代码序列,这时可以使用重复伪指令。
1.重复伪指令宏汇编语言提供的重复伪指令包括 REPT,IRP,IRPC,其格式、功能及使用说明在 8.1.2节中已讲述,这里不再赘述。
第 8章 高级汇编技术
2.重复伪指令应用举例例 8-7 使用不同重复伪指令定义 10个数据,使其内容分别为 0,1,…,9。
第一种方法,使用 REPT伪指令:
COUNT= 0
REPT 10
DB COUNT
COUNT= COUNT+1
ENDM
第 8章 高级汇编技术第二种方法,使用 IRP伪指令:
IRP X,<0,1,2,3,4,5,6,7,8,9>
DB X
ENDM
第三种方法,使用 IRPC伪指令:
IRPC X 0123456789
DB X
ENDM
第 8章 高级汇编技术以上三种方法具有同样的功能,汇编后产生的代码如下:
+ DB 0
+ DB 1
+ DB 2
+ DB 3
+ DB 4
+ DB 5
+ DB 6
+ DB 7
+ DB 8
+ DB 9
第 8章 高级汇编技术例 8-8 下面两条重复伪指令具有相同的功能。
(1) IRP指令:
IRP REG,<AX,BX,CX,DX>
POP REG
ENDM
第 8章 高级汇编技术
(2) IRPC指令:
IRPC R ABCD
POP R& X
ENDM
汇编后它们产生的代码如下:
+ POP AX
+ POP BX
+ POP CX
+ POP DX
第 8章 高级汇编技术
8.2.2 条件汇编条件汇编伪指令可使汇编程序根据某种条件对某部分源程序有选择地进行汇编,在形式上和高级语言中的条件语句类似,
但实质不同。条件汇编语句是一种说明性语句,其功能由汇编系统实现;而一般高级语言的条件语句是执行性语句,其功能由目标程序实现。
条件汇编语句通常在宏定义中使用,使得宏定义的适用范围更广。一般情况下,使用条件汇编语句可使一个源文件产生几个不同的源程序,它们可有不同的功能。
第 8章 高级汇编技术格式,IF 条件语句序列 1
[ELSE
语句序列 2]
ENDIF
功能:当条件为真 (满足 )时执行汇编语句序列 1,否则执行汇编语句序列 2。
第 8章 高级汇编技术说明:“条件”为 IF伪指令说明符的一部分,ELSE伪指令及其后面的语句序列 2是可选择部分,表示条件为假 (不满足 )时的情况。如果属于非完全分支的判断,就不用这部分。整个条件汇编最后必须用 ENDIF伪指令来结束。语句序列 1和语句序列
2中的语句是任意的,也可为条件汇编语句。
以下 5组条件汇编开始语句均可选用 ELSE语句,以便汇编条件为假时执行语句序列 2,但一个 IF语句只能有一个 ELSE与之对应。
第 8章 高级汇编技术
1) 是 0否条件语句语句有,IF和 IFE。
① IF语句。
格式,IF 表达式功能:表达式值非 0,则条件为真,执行汇编语句序列 1。
② IFE语句。
格式,IFE 表达式功能:表达式值为 0,则条件为真,执行汇编语句序列 1。
第 8章 高级汇编技术
2) 扫描 1否条件语句语句有,IF1和 IF2。
① IF1语句。
格式,IF1
功能:汇编处于第一次扫描时条件为真。
② IF2语句。
格式,IF2
功能:汇编处于第二次扫描时条件为真。
第 8章 高级汇编技术
3) 符号有定义否条件语句语句有,IFDEF和 IFNDEF。
① IFDEF语句。
格式,IFDEF 符号功能:符号已被定义或已由 EXTRN伪指令说明,则条件为真。
② IFNDEF语句。
格式,IFNDEF 符号功能:符号未被定义或未由 EXTRN伪指令说明,则条件为真。
第 8章 高级汇编技术
4) 空否条件语句语句有,IFB和 IFNB。
① IFB语句。
格式,IFB <参数 >
功能:参数为空格,则条件为真。尖括号不能省略。
② IFNB语句格式,IFNB <参数 >
功能:参数不为空格,则条件为真。尖括号不能省略。
第 8章 高级汇编技术
5) 字符串比较条件语句语句有,IFIDN和 IFDEF。
① IFIDN语句。
格式,IFIDN <字符串 1>,<字符串 2>
功能:字符串 1与字符串 2相同,则条件为真。
第 8章 高级汇编技术
② IFDIF语句格式,IFDIF <字符串 1>,<字符串 2>
功能:字符串 1与字符串 2不相同,则条件为真。
说明:这两条语句只能在宏定义中使用,检查传送给两个参数的实参是否相同。
例 8-9 将输入及输出字符的 DOS功能调用放在一个宏定义中,通过判断参数为 0还是非 0值来选择是执行汇编输入还是输出的 DOS功能。
第 8章 高级汇编技术所编制的程序描述如下,其中含有条件汇编的语句。
INOUT MACRO X
IF X
MOV AH,2
INT 21H ;输出 DL中的字符
ELSE
MOV AH,1
INT 21H ;输入一个字符到 AL
ENDIF
ENDM
第 8章 高级汇编技术当宏调用为 INOUT 0时,表明传递给参数 X的值为 0,此时 IF X
的条件为假,因此汇编程序只汇编 ELSE与 ENDIF之间的语句,
这样,对该宏调用来说,实际上是执行下面的两条指令:
MOV AH,1
INT 21H
而当宏调用为 INOUT 1时,实际上是执行这样两条指令:
MOV AH,2
INT 21H
第 8章 高级汇编技术
8.3 汇编语言与高级语言的混合编程
8.3.1 调用协议汇编程序和汇编语言常常以在线汇编语言代码的形式,通过过程同高级语言,如 C/C++,BACIC,PASCAL及 FORTRAN一起使用。需要指出的是,这里尽管讲的是使用 Microsoft汇编语言过程,但只要提供兼容的调用协议,大多数其他语言也能够使用。
在与高级语言接口时,汇编程序使用两种调用协议:一是用于 C/C++语言的 C语言调用协议,二是用于 BASIC,PASCAL和
FORTRAN语言的 PASCAL语言调用协议。调用协议语言在
MODEL语句中或与 PROC语句相联系的 OPTION指示符中指定。
除用这些语句以外还可以用完全段定义指定。
第 8章 高级汇编技术
1,C语言调用协议
C语言调用协议从右到左压入参数,像它们在参数表里放的那样,带着放在栈上的参数从汇编语言过程返回,返回结果或者放在 AX中或者放在 DX∶ AX中。在 BP,DI,SI,DS,SS和方向标志位被改动之前应使用汇编语言过程保存起来。这些寄存器是高级语言能用到的。图 8-1给出了 C语言调用协议下近调用和远调用的栈。
第 8章 高级汇编技术图 8-1 使用 C语言调用协议时的栈内容
(a) 近程调用; (b) 远程调用参数 2
参数 1
IP ( 返回地址) (S P)
存储器
(a)
参数 2
参数 1
IP ( 返回地址) (S P)
存储器
(b )
CS ( 返回地址)
第 8章 高级汇编技术对栈内参数的访问由 C语言调用协议提供,如例 8-10所示。
带 *号的语句是汇编程序加上的,以保持与 C语言调用协议的一致。注意搞清楚 BP的内容如何被压入栈中,以及 BP是如何被装入 SP值以访问由 C语言程序放在栈中的参数这两个问题。
第 8章 高级汇编技术例 8-10
.LISTALL
.MODEL SMALL,C
SSS PROTO C,A,SWORD,A,SWORD
.CODE
SSS PROC C,A,SWORD,B,SWORD
PUSH BP ;保存 BP
MOV BP,SP ;栈地址存入 BP
MOV AX,A ;使用参数 A
ADD AX,B ;使用参数 B
POP BP ;恢复 BP
RET 00000H
SSS ENDP
END
第 8章 高级汇编技术根据 C语言调用协议编写的汇编语言过程通过指令 INVOKE
而被调用。 INVOKE用来替代标准的 CALL指令。 INVOKE遵循
C语言调用协议,允许汇编语言程序访问 C语言程序和函数。
INVOKE指令被用来访问例 8-10中的过程,例如,INVOKE SSS,
20,30实现把 30加上 20后,结果放入 AX中并返回。 INVOKE与
CALL的不同之处,按照调用协议的要求,INVOKE指令必须将参数从栈中全部移出。 INVOKE指令的语法要求过程名后必须跟着全部的参数,参数间用逗号隔开。
第 8章 高级汇编技术
2,INVOKE指令的使用用 PUSH把参数压入堆栈,如果不小心把参数个数搞错了,
就会使堆栈不平衡,从而使程序从堆栈中取出错误的返回地址,
引起不可预料的后果。所以有必要用一条语句来完成自动检验的任务。 INVOKE语句是能自动将所有的参数压入栈中,并检测参数个数、类型是否正确,使用 CALL来调用的一个宏指令。
INVOKE在汇编程序中调用子程序时,其参数的传递是通过堆栈来进行的。例如,MessageBox()函数在 USER32.INC文件中是这样声明的:
MESSAGEBOX(HWND HWND,LPCTSTR LPTEXT,
LPCTSTR LPCAPTION,UINT UTYPE),
第 8章 高级汇编技术在汇编程序中可这样调用它:
PUSH UTYPE
PUSH LPCAPTION
PUSH LPTEXT
PUSH HWND
CALL MessageBox
PUSH为汇编语言中的进栈指令。上面语句的原理是先将函数所需要的参数,压入到堆栈中去,然后再用 CALL指令来调用该函数。
第 8章 高级汇编技术需要注意的是,在上述的参数进栈过程中,是从左到右依次压入的,即最右面的参数是最后一个进堆栈,采用的是
PASCAL规则。引入 INVOKE语句后,就可自动的将所调用子程序中的参数压入堆栈中,而无须编程者用手工压入。所以上面的代码就可以变为
INVOKE MessageBox,NULL,addr szText,addr szCaption,
MB_OK。
addr是用来把变量参数的地址传递给被调用的函数 (注意,是所指变量在内存中的地址,而不是变量中的值 ),它只能在
INVOKE语句中使用。
第 8章 高级汇编技术
3,PASCAL语言调用协议
PASCAL语言调用协议用于 BASIC,PASCAL和 FORTRAN
语言,在 WINDOWS中,它也被用于访问 WINDOWS库文件
(WINH.LIB)中的函数。 PASCAL语言调用协议与 C语言调用协议的差异在于:参数是自左至右压入栈中。如果用在汇编语言过程中时,PASCAL语言调用协议也需要保存寄存器 SI,DI,DS和 SS
的内容。方向标志位在登录时要被清零,并以清除状态被返回。
和在 C语言调用协议中一样,INVOKE语句也用于由汇编语言进出高级语言过程。
第 8章 高级汇编技术这一点在汇编语言同 WINDOWS一起使用时格外重要,以
INVOKE MessageBeep,-1为例,如果 WINH.LIB库文件已被程序装载,则该指令使扬声器发出“嘀”的一声。其他参数也可与 MessageBeep一起使用,从而由 WINDOWS发出各种失败提示音。在 C语言程序中,通过在 C语言程序的开头使用指令
#INCLUDE <WINDOWS.H>,就可以访问 WINDOWS应用程序接口 (API)。
第 8章 高级汇编技术图 8-2 使用 PASCAL语言调用协议时栈内容参数 1
参数 2
IP ( 返回地址)
( B P )
存储器
CS ( 返回地址)
BP
第 8章 高级汇编技术图 8-2给出了从 PASCAL中调用函数时的栈,注意:所有这些语言调用的函数都被认为是远程调用,BP给出了存储参数的栈的地址。最右边的参数的地址为 BP+6,这一点与 C语言调用协议正好相反。同 C语言调用协议一样,隐蔽的指令将 BP压入栈,并将 SP写入 BP。
第 8章 高级汇编技术
4.数据类型 表 8-1 各种数据类型的比较
MASM数据类型 C语言数据类型 PASCAL数据类型
BYTE unsigned char —
SBYTE char —
WORD unsigned short STRING*1
SWORD short int INTEGER
DWORD unsigned long —
SDWORD long LONG(&)
REAL4 float SINGLE(!)
REAL8 double DOUBLE(#)
REAL10 long double —
第 8章 高级汇编技术
8.3.2 与 C语言的接口例 8-11 本例给出了一个被 C语言程序调用的过程,该过程使用 MODEL语句指示内存模型 (本例为小模型 )和相应的调用协议语言 (C语言 )。 PROTO语句把本过程作为外部函数声明,并指定了全部与本过程相关的参数的大小和名称。本过程被作为一个近程调用
.MODEL SMALL,C
X1 PROTO C,l,SWORD,F,SWORD
.CODE
第 8章 高级汇编技术
X1 PROC C,l,SWORD,LSWORD
FILDPI ;取出
FADD ST,ST(0) ;计算 2× pi
MOV AX,1 ;取 1
MOV TEMP,AX
FILD TEMP ;取 l
FMUL ;计算 2× pi× l
MOV AX,F ;取 F
MOV TEMP,AX
FILD TEMP ;取 F
FMUL ;计算 2× pi× l× f
FISTP TEMP ;保存结果第 8章 高级汇编技术
MOV AX,TEMP ;取结果用以返回 C
RET
X1 ENDP
TEMP DW? ;暂存区
END
第 8章 高级汇编技术本过程使用数值协处理器计算电抗值,使用公式 X1=2πlF。
其中,参数 F和 l从 C语言程序中传送到汇编语言过程中,返回值
(X1)作为一个字长的整型变量由 AX传回 C语言程序。通过 BP+4
和 BP+6给出的地址,可以从栈中取出 l和 F的数据。本例中的
MOV AX,l指令,若转换为代码应为 MOV AX,[BP+4],通过该指令可从栈中取出 l值。
第 8章 高级汇编技术例 8-12 本例给出了主模块的 C语言调用顺序,该程序顺序打印出电感系数为 4H,频率为 1000 Hz的电抗值。注意:本程序中的计算结果被变换为整型。
#include <stdio.h>
extern int xl(int l,int f);
void main()
{
printf("The inductive reactance of 4 H at 1000 Hz is% d\ n",
xl(4,1000));
}
第 8章 高级汇编技术
8.3.3 与 PASCAL语言的接口
1.有关的 PASCAL语句和调用约定
PASCAL语言没有提供 CALL调用语句。 PASCAL主程序对汇编语言子程序的调用是通过外部过程和外部函数调用的形式来实现的。为了保证调用的正确实施,PASCAL主程序和被调用的汇编语言子程序都要遵从一定的调用约定。 PASCAL语言中的过程和函数有所不同。
第 8章 高级汇编技术
1) 过程方式在 PASCAL程序中,对要调用的汇编语言过程必须预先采用
PROCEDURE说明语句加以定义说明。 PROCEDURE语句的格式为:
PROCEDURE过程名 (参数表 ):过程属性;
这样,PROCEDURE语句将向 PASCAL编译程序提供如下信息:
(1) 被调用的过程名;
(2) 此过程是内部过程还是外部过程;
(3) 过程的参数名和类型;
(4) 是“数值参数”还是“引用参数”。
第 8章 高级汇编技术由于汇编语言子程序是单独编写和汇编的,它相对 PASCAL
主程序而言总是外部的。所以,其“过程属性”为 EXTERN。
并且,过程名必须在汇编语言程序中用 PUBLIC伪指令加以说明。
第 (3)项的过程参数名和类型是符合 PASCAL要求的变量标识符和数据类型。在进行 PASCAL过程调用时,过程参数也是通过栈来进行传递的。第 (4)项的“数值参数”和“引用参数”涉及到是传递参数变量值,还是传递参数变量地址的问题。当一个变量是数值参数时,主程序把此变量的值入栈,即传递给被调用过程;否则,主程序把此变量的地址入栈。作为引用参数的变量,在 PROCEDURE语句中须用 VAR或 VARS来加以说明。两者的区别在于:对由 VAR说明的参数,主程序须将其变量地址的偏移量入栈;而对由 VARS说明的参数,除变量地址的偏移量外,
主程序还要将此变量地址的段地址入栈。语句:
第 8章 高级汇编技术
PROCEDURE ADDP(A,B,INTEGER; VAR C,INTEGER),EXTERN;
定义了一个有 3个参数的外部过程 ADDP。其中,变量 A和 B是整型数值参数,而变量 C是整型引用参数;一旦汇编语言过程在
PASCAL主程序中经由 PROCEDURE语句定义说明后,PASCAL
主程序就可以采用相应的过程调用语句来调用此汇编语言过程了,
过程调用语句的格式为过程名 (参数表 )
对上面的 ADDP过程,其相应的过程调用语句为
ADDP(A,B,C)
其中,A,B,C是 PASCAL主程序中的整型变量。
第 8章 高级汇编技术在被调用的汇编语言子程序中,PASCAL对过程的要求是:
(1) 由于寄存器 SP不能用于一般的寻址方式,通常用 BP来存取传递的调用参数。所以,在过程程序开始时要先把 BP的原有内容入栈保存,并在返回 PASCAL主程序之前恢复内容。另外,
若要在子程序中改变 DS和 SS等寄存器的内容,也须加以保存和恢复。
(2) 由于是外部过程,在返回 PASCAL主程序时应采用长返回指令,即进行段间返回。
(3) 在返回时,应取消栈参数,即主程序传递给此过程的所有调用参数。
第 8章 高级汇编技术下面是用汇编语言编写的 ADDP过程程序,在程序中,
PUBLIC指令将过程名 ADDP存放。
CODE SEGMENT
ASSUME CS∶ CODE
ADDP PROC FAR
PUBLIC ADDP
PUSH BP
MOV BP,SP
PUSH AX
第 8章 高级汇编技术
PUSH BX
MOV AX,[BP+10]
ADD AX,[BP+8]
MOV BX[BP+6]
MOV [BX],AX
POP BX
POP AX
POP BP
RET 6
ADDP ENDP
第 8章 高级汇编技术过程的 FAR属性使得后面的 RET指令成为长返回指令。 RET
指令中的整数用于消去栈参数,它在返回后将自动加入到 SP寄存器中。程序的,RET 6”指令执行前后栈内容的变化如图 8-3所示。
当 ADDP过程的 C变量为 VARS引用参数时,相应的汇编语言程序有所不同。由于 C的段地址,A和 B的地址由 [BP+10]和
[BP+8]变为 [BP+12]和 [BP+10]。同时,,RET 6”变为,RET 8”。
除此之外,由于 C变量不是当前 DS寄存器所指数据段中的变量,
对它的存取方式也与前不同,如图 8-4所示。
第 8章 高级汇编技术图 8-3 栈变化
(SP)
A 的内容
C 的偏移量返回段地址 CS
B 的内容
…
返回偏移量 IP
6
X X X X X
执行,R E T 6,
(SP) X X X X X
…
第 8章 高级汇编技术图 8-4 C变量为 VARS引用参数时的堆栈结构
(S P )
A 的内容
C 的偏移量
CS
IP
B 的内容
…
第 8章 高级汇编技术
CODE SEGMENT
ASSUME CS∶ CODE
ADDP PROC FAR
PUBLIC ADDP
PUSH BP
MOV BP,SP
PUSH AX
PUSH BX
PUSH ES
MOV AX,[BP+12]
第 8章 高级汇编技术
ADD AX,[BP+10]
LES BX,[BP+6]
MOV ES∶ [BX],AX
POP ES
POP BX
POP AX
POP BP
RET 8
ADDP ENDP
CODE ENDS
END
第 8章 高级汇编技术
2) 函数方式函数方式同过程方式很相似。在 PASCAL程序中,对要调用的汇编函数也必须预先加以说明。不过,此时采用的是
FUNCTION说明语句,而不是 PROCEDURE说明语句。
FUNCTION语句的格式为
FUNCTION 函数名 (参数表 ):函数类型;函数属性;
在 FUNCTION语句中,除增加了一个“函数类型”外,其余同
PROCEDURE语句一样。“函数类型”符合 PASCAL要求的数据类型的语句。如:
FUNCTION ADDF(A,B,INTEGER),INTEGER,EXTERN;
说明定义了一个名为 ADDF的外部整型函数。
第 8章 高级汇编技术
PASCAL对汇编函数的要求,除在程序完成后必须返回函数值外,其余同过程完全一样。一般来说,函数可通过 AL,AX、
ES∶ BX或调用者提供的缓冲区来返回其值。具体使用时应根据函数的类型和语言编译程序版本的要求来选择。下面是 ADDF函数的汇编程序。通过和本节给出的第一个程序比较可知,ADDP
和 ADDF的功能是一样的,都是求 A,B之和,不同的是,ADDF
函数是通过 AX直接返回结果值,而 ADDP过程则是通过设置的
VAR参数 C来返回的。
第 8章 高级汇编技术
CODE SEGMENT
ASSUMEE CS,CODE
ADDF PROC FAR
PUBLIC ADDF
PUSH BP
MOV BP,SP
PUSH AX
MOV AX,[BP+8]
ADD AX,[BP+6]
POP BP
RET 4
ADDF ENDP
CODE ENDS
END
第 8章 高级汇编技术
2.连接方法
PASCAL主程序和汇编语言子程序通过连接程序 LINK连为一体,形成可执行文件。连接的具体过程如下:
(1) 汇编源程序 ADDP.ASM,得到相应的目标文件
ADDP.OBJ:
C>MASM ADDP;
(2) 汇编源程序 ADDF.ASM,得到相应的目标文件
ADDF.OBJ:
C> MASM ADDF;
第 8章 高级汇编技术
(3) 编译源程序 MAIN.PAS,得到相应的目标文件 MAIN.OBJ:
C> PAS1 MAIN;
C> PAS2
(4) 连接目标模块 ADDF.OBJ,ADDP.OBJ和 MAIN.OBJ,生成可执行文件 MAIN.EXE:
C> LINK MAIN+ADDP+ADDF;
执行可执行文件 MAIN.EXE将得到如下结果:
C>MAIN
3 3
第 8章 高级汇编技术下面是 PASCAL主程序 MAIN.PAS。
PROGRAM MAIN (OUTPUT);
PROCEDURE ADDP(A,B,INTEGER; VAR C,INTEGER); EXTERN;
FUNCTION ADDF(A,B,INTEGER),INTEGER; EXTERN;
VAR A,B,C,INTEGER;
BEGIN
A∶ =1;
B∶ =2;
ADDP(A,B,C);
A∶ =ADDF(A,B);
WRITE(A,C)
END.{MAIN}
第 8章 高级汇编技术习 题 八
8.1 在代码段中,开始的一段程序有通用性,试将此段程序定义为一条宏指令。
8.2 定义 — 条宏指令,它可以实现任一数据块的传送 (假设无重叠 ),只要给出源和目的数据块的首地址以及数据块的长度即可。如果 — 条宏指令既可以从数据块的首地址又可从其末地址开始传送这个数据块,应如何定义这条宏指令?
第 8章 高级汇编技术
8.3 编写实现下述功能的宏指令。
(1) 清屏。
(2) 设置光标,要求光标的行、列号用形式参数表示;
(3) 字符串的逆序存放,要求原字符串及逆序串的首地址用形式参数表示。
8.4 试用调用宏指令的方法计算 Y= (A2+B2),要求计算 X2
用累加的方法实现,并用宏指令表示。
第 8章 高级汇编技术
8.5 STORE宏指令定义如下:
STORE MACRO X,N
MOV X+I,I
I= I+1
IF I-N
STORE X,N
ENDIF
ENDM
有以下宏调用:
I= 0
STORE TAB,6
试对其进行宏扩展。
第 8章 高级汇编技术
8.6 试编写一段程序完成以下功能:若给定名为 X的字符串长度大于 5时,对 DEC CX指令汇编 4次。