slide1 n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
汇编语言程序设计 PowerPoint Presentation
Download Presentation
汇编语言程序设计

Loading in 2 Seconds...

play fullscreen
1 / 38

汇编语言程序设计 - PowerPoint PPT Presentation


  • 136 Views
  • Uploaded on

汇编语言程序设计. 吴 向 军. 中山大学计算机科学系. 2003.03.20. 第 9 章 宏. 9.1 宏的定义和引用.  宏是用来代表一个具有特定功能的程序段,它只需在源程序中定义一次,但可在源程序中引用多次。只要在编写程序时需要它,就可以直接使用它。. 9.1.1 宏的定义. 在使用宏之前,必须先定义宏。定义宏一般格式如下: 宏名 MACRO [ 形参 1, 形参 2, ……] … ; 宏的定义体 ENDM 在书写宏定义时,必须遵照下列规定:. 第 9 章 宏.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about '汇编语言程序设计' - samantha-mejia


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
slide1

汇编语言程序设计

吴 向 军

中山大学计算机科学系

2003.03.20

slide2

第9章 宏

9.1 宏的定义和引用

 宏是用来代表一个具有特定功能的程序段,它只需在源程序中定义一次,但可在源程序中引用多次。只要在编写程序时需要它,就可以直接使用它。

9.1.1 宏的定义

在使用宏之前,必须先定义宏。定义宏一般格式如下:

宏名 MACRO [形参1, 形参2, ……]

… ;宏的定义体

ENDM

在书写宏定义时,必须遵照下列规定:

slide3

第9章 宏

  • MACRO和ENDM是二个成对出现的关键字,分别表示宏定义的开始和结束;
  • MACRO和ENDM之间的部分是宏的定义体,它是由指令、伪指令或引用其它宏所组成的程序片段,是宏所包含的具体内容;
  • “宏名”是由程序员指定的一个合法的标识符,它代表该宏;
  • 宏名可以与指令助忆符、伪指令名相同。在这种情况下,宏指令优先,而同名的指令或伪指令都失效;
  • 在ENDM的前面不要再写一次宏名,这与段或子程序定义的结束方式不同;
  • 在宏定义的首部可列举若干形式参数(也称哑元),参数之间要用逗号分隔。
slide4

第9章 宏

例9.1:定义一个把16位数据寄存器压栈的宏。

PUSHR MACRO

PUSH AX

PUSH BX

PUSH CX

PUSH DX

ENDM

例9.2:定义二个字存储变量相加的宏。

MADDM MACRO OPRD1, OPRD2

MOV AX, OPRD2

ADD OPRD1, AX

ENDM

slide5

第9章 宏

9.1.2 宏的引用

  • 在源程序中,一旦定义了某宏,那么,在该程序的任何位置都可直接引用该宏,而不必重复编写相应的程序段。引用宏的一般格式如下:
  • 宏名 [实参1, 实参2, ……]
  • 其中:实参的位置要与形参的位置要对应,但实参个数可以与形参个数不相等。
  • 当实参的个数多于形参的个数时,多出的实参被忽略;
  • 当实参的个数少于形参的个数时,没有实参对应的形参用“空”来对应。

在宏展开时,所得到的指令必须是合法的汇编指令,否则,汇编程序将会给出出错信息。

slide6

第9章 宏

9.1.3 宏的参数传递方式

引用宏时,参数是通过“实参”替换“形参”的方式来实现传递的。参数形式灵活多样,参数可以是常数、寄存器、存储单元和表达式,还可以是指令的操作码。

例9.3:定义二个字存储变量相加和相减的宏。

方法1:定义二个宏,分别实现存储变量的加操作和减操作

MADDM MACRO OPRD1, OPRD2

MOV AX, OPRD2

ADD OPRD1, AX

ENDM

MSUBM MACRO OPRD1, OPRD2

MOV AX, OPRD2

SUB OPRD1, AX

ENDM

方法2:定义一个宏,把存储变量的“加”和“减”操作合并在一起

MOPM MACRO OP, OPRD1, OPRD2

MOV AX, OPRD2

OP OPRD1, AX

ENDM

其中:参数OP是一个对应于操作码的形式参数。

slide7

第9章 宏

9.1.5 宏与子程序的区别

宏和子程序都是为了简化源程序的编写,提高程序的可维护性,但是它们二者之间存在着以下本质的区别:

  • 在源程序中,通过书写宏名来引用宏,而子程序是通过CALL指令来调用;
  • 汇编程序对宏通过宏扩展来加入其定义体,宏引用多少次,就相应扩展多少次,所以,引用宏不会缩短目标程序;而子程序代码在目标程序中只出现一次,调用子程序是执行同一程序段,因此,目标程序也得到相应的简化;
  • 宏引用时,参数是通过“实参”替换“形参”来实现传递的,参数形式灵活多样,而子程序调用时,参数是通过寄存器、堆栈或约定存储单元进行传递的;
  • 宏引用语句扩展后,目标程序中就不再有宏引用语句。运行时,不会有额外的时间开销,而子程序调用指令存在于目标程序之中,执行调用指令需要时间。

总之,当程序片段不长,速度是关键因素时,可采用宏来简化源程序,但当程序片段较长,存储空间是关键因素时,可采用子程序来简化源程序和目标程序。

slide8

第9章 宏

9.2 宏参数的特殊运算符

9.2.1 连接运算符

在宏定义中,如果形式参数与其它字符连接在一起,或形式参数出现在字符串之中,那么,就必须使用连接运算符(&)。

例9.5:定义一个转移宏JUMP,其一个参数决定转移类别,另一个参数指定转移目标。

解:

JUMP MACRO CON, here

J&CON here

ENDM

slide9

第9章 宏

例9.6:定义一个问候性的字符串宏GREETING,其一个参数说明字符串的变量名,另一个参数指名问候的对象。

解:

GREETING MACRO MSG, name

MSG DB ‘Hello, &name’

ENDM

假设有下面引用语句,

GREETING STR1, 张三

GREETING MSG1, John

那么,它们宏扩展时将会得到如下三个问候性的字符串定义。

GREETING STR1, 张三

1 STR1 DB ‘Hello, 张三’

GREETING MSG1, John

1 MSG1 DB ‘Hello, John’

slide10

第9章 宏

9.2.2 字符串整体传递运算符

 字符串整体传递运算符是一对尖括号<>,用它括起来的内容将作为一个字符串来进行形式参数的整体替换。

 在宏引用时,如果实参内包含逗号、空格等间隔符,则必须使用该操作符,以保证实参的完整性。如果实参是某个具有特殊含义的字符,为了使它只表示该字符本身,也需要用该运算符括起来。

假设有下面定义字符串的宏DEFMSG,

DEFMSG MACRO MSG

DB ‘&MSG’, 0DH, 0AH, ‘$’

ENDM

那么,使用和不使用该运算符的引用宏及其宏扩展如下所示:

DEFMSG <Are you ready?>

1 DB ‘Are you ready?’, 0DH, 0AH, ‘$’

DEFMSG Are you ready?

1 DB ‘Are’, 0DH, 0AH, ‘$’

slide11

第9章 宏

9.2.3 字符转义运算符

在引用宏时,如果实参中含有特殊字符,而又要该特殊字符当作普通字符来出来,那么,就必须在该特殊字符前加上字符转义运算符“!”。

DEFMSG <Input one number(>90):>

1 DB ‘Input one number(90):’, 0DH, 0AH, ‘$’

DEFMSG <Input one number(!>90):>

1 DB ‘Input one number(>90):’, 0DH, 0AH, ‘$’

在第一个引用宏的语句中,汇编程序会把第一个“>”字符与字符“<”相比配,而不会把它当作“大于号”字符来处理。

在第二个引用宏的语句中,由于在第一个“>”字符前面加了字符转义运算符“!”,所以,汇编程序会把第一个“>”当作“大于号”字符来处理,而把最后面的字符“>”当作是与前面“<”相比配的结束符。

slide12

第9章 宏

9.2.4 计算表达式运算符

在引用宏时,使用计算表达式运算符“%”表示把其后面表达式的结果当作实参进行替换,而不是该表达式的整个式子。

DEFMSG %200+23-100

1 DB ‘123’, 0DH, 0AH, ‘$’

DEFMSG (200+23-100)

1 DB ‘(200+23-100)’, 0DH, 0AH, ‘$’

前者是先计算出表达式200+23-100的值,然后再把该值作为参数进行替换,而后者是把表达式(200+23-100)当作一个字符串来进行参数替换。

slide13

第9章 宏

9.3 与宏有关的伪指令

9.3.1 局部标号伪指令

在宏定义体中,如果存在标号,则该标号要用伪指令LOCAL说明为局部标号,否则,当在源程序中,有多于一次引用该宏时,汇编程序在进行宏扩展后将会给出:标号重复定义的错误。

伪指令LOCAL的一般格式如下:

LOCAL 标号1, 标号2, ……

伪指令LOCAL必须是伪指令MACRO后的第一条语句,在MACRO和LOCAL之间也不允许有注释和分号标志。

汇编程序在每次进行宏扩展时,总是把由LOCAL说明的标号用一个唯一的符号(从??0000到??FFFF)来代替,从而避免标号重定义的错误。

slide14

第9章 宏

例9.7:编写求一个求绝对值的宏。

解:

方法1:

ABS MACRO word1

CMP word1, 0

JGE next

NEG word1

next:

ENDM

假设对宏ABS有以下两次引用,

ABS BX

ABS AL

汇编程序将显示“标号重复定义”的错误,我们需要用下面的方法定义该宏。

slide15

第9章 宏

方法2:

ABS MACRO word1

LOCAL next

CMP word1, 0

JGE next

NEG word1

next:

ENDM

假设有下面两次宏ABS的引用,

ABS BX

汇编程序对它们进行宏扩展时,将得到下列程序片段:

ABS BX

1 CMP BX, 0

1 JGE ??0000

1 NEG BX

1 ??0000:

slide16

第9章 宏

伪指令LOCAL在子程序中也可起作用,但它的作用与宏定义的作用是不同的,有关该伪指令在子程序和宏定义中功能的主要差异如下表所列。

表9.1 伪指令LOCAL在子程序和宏中的比较

slide17

第9章 宏

9.3.2 取消宏定义伪指令

伪指令PURGE的一般格式如下:

PURGE 宏名1, 宏名2, ……

该伪指令通知汇编程序取消“宏名1, 宏名2, ……”宏名表中的宏定义。

在此语句后,如果还有这些宏的引用语句,则汇编程序不会把它们当作宏引用来进行扩展,并且还将显示出错信息。

slide18

第9章 宏

9.3.3 中止宏扩展伪指令

伪指令EXITM的一般格式如下:

EXITM

该伪指令书写在宏定义体中,用来告诉汇编程序:如果遇到该伪指令,那么,立即中止对该伪指令之下语句的扩展。如果在嵌套的内层宏中遇到了该伪指令,则退出到宏嵌套的外层。

在一般情况下,伪指令EXITM与条件伪指令一起使用,以便在不同的条件下挑选出不同的语句。

slide19

第9章 宏

9.4 重复汇编伪指令

在编写源程序时,有时会出现连续相同或相似的语句(组)。当出现这种情况时,可利用重复伪指令来重复语句,从而达到简化程序的目的。

重复汇编伪指令所定义的重复块是宏的一种特殊形式,也是由伪指令ENDM来结束重复块。用重复汇编伪指令定义的重复块也可带有参数,并在汇编过程中参数被实参代替,但重复块不会被命名,不能在程序的其它地方引用。

9.4.1 伪指令REPT

伪指令REPT的作用是把一组语句重复指定的次数,该重复次数由伪指令后面的数值表达式来确定。其一般使用格式如下:

REPT 数值表达式

重复的语句组

ENDM

slide20

第9章 宏

例9.8:定义100个初值为32的字节单元,该存储单元的起始符号地址为Table。

解:

方法1:用伪指令REPT来实现

Table LABEL TYPE

REPT 100

DB 32

ENDM

上述重复块的汇编结果如下:

Table LABEL TYPE

DB 32

DB 32

DB 32 ;上述字节定义重复100次

slide21

第9章 宏

例9.9:定义100个初值分别为1,2,…,100的字节单元,该存储单元的起始符号地址为Table。

解:

Table LABEL TYPE

COUNT = 1

REPT 100

DB COUNT

COUNT = COUNT + 1

ENDM

上述重复块的汇编结果相当于:

Table LABEL TYPE

DB 1

DB 2

DB 100

slide22

例9.10:计算1+2+…+1000,并把其值存入寄存器AX。例9.10:计算1+2+…+1000,并把其值存入寄存器AX。

解:

方法1:用伪指令REPT来实现

MOV AX, 0

COUNT = 1

REPT 1000

ADD AX, COUNT

COUNT = COUNT + 1

ENDM

上述重复块的汇编结果与下面程序段相一致:

MOV AX, 0

ADD AX, 1

ADD AX, 2

ADD AX, 1000

虽然上面这些语句的执行能完成本例所指定的功能,但它是用1000条加法指令来直接计算的,这1000条指令无疑会大大增加目标代码的长度。

slide23

第9章 宏

方法2:用循环指令LOOP来实现

MOV AX, 0

MOV CX, 1000

again: ADD AX, CX

LOOP again

slide24

第9章 宏

伪指令REPT与循环指令起作用的时期和方式是截然不同的。

表9.2 伪指令REPT与循环指令LOOP之间的主要差异

slide25

第9章 宏

9.4.2 伪指令IRP

伪指令IRP的作用是用每个参数创建一组语句,其重复次数由伪指令后面参数表中参数的个数来确定。其一般使用格式如下:

IRP 形式参数, <实参1, 实参2, ……, 实参n>

重复的语句组

ENDM

例9.11:把16位通用寄存器之值相加,并把结果存入寄存器AX。

解:由于16位通用寄存器名是一些不同的符号,不能用计数的方法来依次访问它们,所以,我们需要用伪指令IRP来实现。

IRP REG, <BX, CX, DX, SP, BP, SI, DI>

ADD AX, REG

ENDM

slide26

第9章 宏

9.4.3 伪指令IRPC

伪指令IRPC的作用与IRP相似,其实参表是一个字符串,并对字符串中的每个字符创建一组语句,所以,其重复次数是由该字符串中的字符数来确定。

IRPC 形式参数, 字符串

重复的语句组

ENDM

例9.13:把16位数据寄存器之值相加,并把结果存入寄存器DI。

解:由于16位数据寄存器是AX、BX、CX和DX,它们的名称中只有第一个字符不同,所以,可以用伪指令IRPC来实现。

XOR DI, DI

IRPC REG, ABCD

ADD DI, REG&X ;符号&是连接运算符

ENDM

slide27

第9章 宏

9.5 条件汇编伪指令

9.5.1 条件汇编伪指令的功能

条件汇编伪指令的一般格式如下:

IFnnnn 条件表达式

语句组1

[ELSE

语句组2]

ENDIF

其中:IFnnnn是表9.3中的伪指令,“[…]”内的语句是可选的。

条件汇编伪指令是在汇编程序把源程序转换成目标程序时起作用,其一般含义是:若条件汇编伪指令后面的“条件表达式”为真,那么,语句组1将被汇编;否则,语句组2将被汇编(如果含有ELSE伪指令)。

slide29

第9章 宏

9.5.2 条件汇编伪指令的举例

例9.14:编写一个可用DOS或BIOS功能调用输入字符的宏定义。

解:

方法1:使用条件汇编伪指令IF

INPUT MACRO

IF DOS ;当符号DOS不为0时,则使用DOS的功能调用

MOV AH, 1H

INT 21H

ELSE ;否则,将使用BIOS的功能调用

MOV AH, 10H

INT 16H

ENDIF

ENDM

在引用宏INPUT时,汇编程序会根据DOS是否为0来生成不同的程序段。

slide30

第9章 宏

例9.15:编写一个可用功能调用输入字符的宏定义。

解:

READCH MACRO char

MOV AH, 1H

INT 21H ;接受一个字符,并存入AL中

IFNB <char> ;若参数char有实参与之对应

IFDIF <char>, <AL> ;若参数char≠AL,则把字符保存到实参中

MOV char, AL

ENDIF

ENDIF

ENDM

slide31

第9章 宏

9.6 宏的扩充

MASM 6.11编程系统对宏定义及其相关语句进行了一定程度的扩充。虽然这些扩充给编程带来了一些方便,但它们不一定能被其它的汇编语言编程系统所接受,所以,程序员在使用这些方便的扩充功能时,要注意到可能带来的限制。

有关内容见书,在此从略。

slide32

第10章 应用程序的设计

10.1 字符串的处理程序

例10.1 编写一个求字符串长度的子程序Strlen,要求字符串的首地址为入口参数,且以ASCII码0为结束符,CX为出口参数,其存放该字符串的长度。

例10.2 编写一个把字符串中的所有小写字符转换成大写字符的子程序Strupr,要求字符串的首地址和结束符为其入口参数。

例10.3 编写一个从字符串中拷贝子串的子程序Strncpy,它有四个参数str1、str2、idx和num,其具体功能为把字符串str2中从第idx个(从0开始记数)字符开始、num个字符传送给str1,字符串str1和str2都是以ASCII码0为结束符。

例10.4 编写一个把字符串中空格和TAB压缩掉的子程序Compress,字符串String是以ASCII码0为结束符。

slide33

第10章 应用程序的设计

10.2 数据的分类统计程序

例10.5 统计从地址0040H:0000H开始的100个字中,把正数和负数按照它们先后出现的次序分别存储在缓冲区Data1和Data2,并把每类的个数存入相应缓冲区的第一个字单元中。

例10.6 用键盘输入任意一字符串,分类统计该字符串中每个数字和字母的出现次数。

slide34

第10章 应用程序的设计

10.3 数据转换程序

例10.7 编写一个程序,它能把字类型变量的数值以十进制形式输出出来。若该数值为负数,则需要输出负号“-”,否则,不输出符号。

例10.8 编写一个程序,它能把字类型变量的数值以二进制形式输出出来。若该数值为负数,则需要输出负号“-”,否则,不输出符号。

例10.9 编写一个子程序,该子程序能把32位二进制变量的数值以十进制形式输出出来。若该数值为负数,则需要输出负号“-”,否则,不输出符号。

例10.10 编写一个程序,它能把用键盘输入的字符串转化成相应的数值。具体功能如下:

1、输入的数据字符串可以带正、负符号,如:1234、+1234或-1234;

2、字符串的最后一个字符表示数据的进制,默认的进制为十进制,如:1234H表示十六进制数1234,1234为十进制数;

3、对于任何进制的数据,当遇到一个非进制范围内的字符时,则显示出错信息,并以数值0为其转换结果来结束该类型转换过程。

slide35

第10章 应用程序的设计

10.4 文件操作程序

例10.11 假设有一个简单的学生结构类型student,其包括:学号、姓名和年龄等信息,要求编写一个程序,该程序接受从键盘输入的学生记录信息,并把它们保存在文件students.dat之中。

例10.12 编写一个程序显示由例10.11建立的记录文件students.dat中的学生信息。

10.5 动态数据的编程

例10.13 编写一个程序用动态链表存储20,19,……,1,并用遍历链表的方法来显示每个结点的数值。

slide36

第10章 应用程序的设计

10.6 COM文件的编程

COM文件和EXE文件都是可执行文件,典型的COM文件是Command.COM。COM文件的主要特点如下:

1、COM文件只有一个段,其字节数不会超过64K;

2、当操作系统装入COM文件时,四个段寄存器(CS、DS、ES和SS)都用PSP的段值来初始化;

3、必须用伪指令ORG 100H来说明空出前256个字节。

slide37

第10章 应用程序的设计

例10.14 编写一个显示字符串“Hello”的COM类型的程序。

解:

CSEG SEGMENT 'CODE'

ORG 100H ;空出前256个字节

start: LEA DX, MSG

MOV AH, 09H

INT 21H

MOV AX, 4C00H

INT 21H

MSG DB "Hello$" ;定义字符串

CSEG ENDS

END start

对上面程序,其生成的COM文件只有23个字节,而其EXE文件的字节数会超过1K。

slide38

谢 谢

计算机科学系

2003年03月20日