1.33k likes | 1.45k Views
第三章习题 3-1 , 3-2 , 3-3 , 3-6 , 3-8 , 3-15 , 3-16. 汇编语言程序设计. 第四章. 本章学习目的. 1. 掌握宏汇编语言程序的 结构 ;. 2. 掌握宏汇编语言 程序设计 与 调试 方法 ; 3. 掌握宏汇编语言 语法规则 ( 语句、伪指令、表达式、运算符 ) ;. 4. 能用 MASM 、 DOS 功能调用和 BIOS 功能调用设计程序 ;. 概 述. 几个术语. ( 1 ) 汇编语言源程序 : 指按汇编语言语法规则编写的源 程序 。
E N D
第三章习题 3-1,3-2,3-3,3-6,3-8,3-15,3-16
汇编语言程序设计 第四章
本章学习目的 1.掌握宏汇编语言程序的结构; 2. 掌握宏汇编语言程序设计与调试方法; 3. 掌握宏汇编语言语法规则(语句、伪指令、表达式、运算符); 4. 能用MASM、DOS功能调用和BIOS功能调用设计程序;
概 述 几个术语 (1)汇编语言源程序:指按汇编语言语法规则编写的源 程序。 (2)汇编(过程):将汇编语言源程序翻译成机器码的过 程称为汇编过程或简称汇编。 (3)手工汇编与机器汇编: (4)小汇编与宏汇编: (5)目标程序:汇编后所得的机器码程序称为目标程 序。
机器语言 目标程序 .OBJ 机器语言 执行程序 .EXE 汇编语言 源程序 .ASM 手写汇编语 言源程序 编辑程序 编辑 连接程序 连接 汇编程序 汇编 必须按严格的语法规则和规定的格式来编写源程序,才能正确汇编以生成可执行程序。
汇编语言源程序一般结构 1、程序在内存中的段结构。 2、把程序设计成一个过程(子程序)。我们用汇编 语言设计的用户程序都是运行在操作系统下, 因此,从操作系统角度来看,用户程序都只是 操作系统中的一个子程序。 3、设计时应考虑程序运行结束后如何返回操作系 统。 4、举例:一个完整的汇编语言源程序实例。
;设置自己的堆栈 [例]在屏幕上显示字符串“Hello,this is a sample program !” DATA SEGMENT ;数据段 MSG1 DB ´Hello,this is a sample program !´,13,10,´$´ DATA ENDS STACK SEGMENT ST1 DB 100 DUP(?) ;堆栈段 TOP EQU $–ST1 STACK ENDS CODE SEGMENT ;代码段 MAIN PROC FAR ASSUME CS:CODE,DS:DATA,SS:STACK START:MOV AX,STACK MOV SS,AX MOV SP,TOP 0DH,0AH
PUSH DS;正常返回所需段地址及偏移地址 MOV AX,0 PUSH AX MOV AX,DATA;送数据段段地址 MOV DS,AX MOV AH,9;DOS 9号功能调用,显示字符串 MOV DX,OFFSET MSG1 INT 21H RET MAIN ENDP CODE ENDS END START
三段式结构:数据段、堆栈段、代码段 每段均由伪指令SEGMENT开始,ENDS结束。 整个源程序用END语句结尾,END后面可跟该程序执行的起始地址START。 这里把主程序建立为过程,由DOS调用该过程,进入程序后将DS的内容及0作段地址和偏移地址入栈,以便在程序结束时用RET指令返回DOS。 若主程序开始时没有用上面三条指令在堆栈中建立返回信息,则在程序结束时就不能用RET返回指令,而是使用4CH号DOS功能调用,如下所示: MOV AX,4C00H INT 21H
汇编语言的上机过程 1、 源程序的编辑建立:可用多种编辑程序建立 源程序,但要求源程序用ASCII码存储,程序 扩展名为.ASM。 2、 汇编 3、 连接:建立DOS格式的可执行文件。 4、 程序前缀PSP与可执行文件.COM、.EXE 5、 COMMAND.COM ——命令解释程序 6、 DOS中程序的执行过程 7、 参考文献 NEXT
编 辑 源程序的编辑建立 调用全屏幕编辑程序EDIT、PE、WS等,源程序文件的扩展名应为.ASM。 也可用WORD来编辑修改,存盘时存为扩展名为.TXT的文本文档,然后用DOS命令将其改为扩展名为.ASM即可。 返回
如一个EXAMPLE.ASM源程序的汇编过程及屏 幕显示如下:如一个EXAMPLE.ASM源程序的汇编过程及屏 幕显示如下: C:>MASM EXAMPLE; 汇 编 用MASM.EXE或ASM.EXE对源文件进行汇编: ①检查源程序中语法错误,给出出错信息; ②产生目标文件(.OBJ文件)、列表文件(.LST文 件)和对照文件(.CRF文件); ③ 展开宏指令。 回车符 返回
C:>LINK EXAMPLE; 如果连接多个目标文件,将多个目标文件名一次输入,中间用加号“+”连接。 源程序没有堆栈段,连接结果给出无堆栈段的警告错误,但不影响程序执行。 如果需要,可用EXE2BIN文件将.EXE文件转换成.COM文件,.COM文件也是可运行文件。 连 接 汇编程序产生的二进制目标文件(.OBJ文件)仍然不可执行,必须经过连接,将它转换成.EXE文件才可执行,连接程序为LINK.EXE,它可以把多个模块连接在一起,这些模块可以是库文件或汇编程序产生的目标文件。连接过程如下: 返回
程序前缀PSP • 程序段前缀(PSP)是DOS为在其下将要运行的每个程序建立的控制块。只有执行程序装入内存后才建立PSP。 • 程序段前缀包含执行程序的各种信息:一是执行程序的有关信息(如命令行参数和内存大小等);二是程序调入前DOS系统的环境信息。 • PSP总是放在程序的前面,占用可用内存低端的100H个字节。 内 容 偏移量 INT 20H指令00~01H 可用内存大小02~03H 功能调用入口06~09H 程序结束地址0A~0DH ctrl-c退出地址0E~11H 错误退出地址12~15H ┊ ┊ 环境参数地址2C~2DH 返回
可执行文件.COM与.EXE • .COM只由一个段组成,最大长度为64KB。文件装入内存后,DS、ES、CS和SS都指向PSP的首址。程序放在PSP之后(由DEBUG程序装入 .COM程序后,查看IP值为100H),程序执行时起始地址为CS:100H,具体段基址由DOS操作系统定位。 • .EXE可由多段组成,文件装入内存后,DS和ES指向PSP的首址。程序执行时起始地址为CS:00H,各段基址的实际值由DOS操作系统定位。 返回
DOS中程序的执行过程 执行DOS用户程序时,通常需要从键盘输入程序名(即命令)。COMMAND.COM是DOS的管理程序,它首先判断键盘输入命令是内部(命令对应的程序已驻留在内存)还是外部命令,若是后者,则检查可用存储区的最低和最高地址,然后在可用存储区的低端开始建立100H个单元的PSP区,在接下来的地址装入程序本身,之后转向程序入口地址开始执行该程序。 返回
本章参考文献 有关.COM与.EXE文件格式、程序前缀PSP,DOS(Disk Operation System)操作系统中程序的执行过程等内容可参考: 1.Steven Armbrust、Ted Forgeron著,舒志勇、刘东源译.DOS/BIOS使用详解.电子工业出版社,1989 2.陈文钦著.BIOS研发技术剖析.清华大学出版社,2001 3.潘名莲,马争,惠林.微计算机原理.电子工业出版社。P184~P186 返回
2.伪指令语句——不产生机器码,为汇编程序和连接程序提供某些必要的控制的管理性语句。完成数据定义、存储器分配、段定义、段设定、指示程序结束等功能。2.伪指令语句——不产生机器码,为汇编程序和连接程序提供某些必要的控制的管理性语句。完成数据定义、存储器分配、段定义、段设定、指示程序结束等功能。 格式: [名字] 伪指令指示符操作数,操作数;[注释] 汇编语言程序格式 1.指令性语句——与机器指令一一对应 格式: [标号:]指令助记符操作数,操作数;[注释] 3. 宏指令语句 宏指令语句由标号、宏指令和注释组成。宏指令是由编程者按一定的规则来定义的一种较“宏大”(MACRO)的指令。一条宏指令可包括多条指令或伪指令语句。使源程序书写精炼、可读性好。
语句中的操作数 4. 语句中操作数 汇编语言中使用的操作数,可以是常数、寄存器、存储器(变量或标号)或表达式。 (1)常数——固定值,无属性。 (2)变量——通常指存放在存储单元中的值,可修改。 变量具有三个属性: 段属性、偏移属性、类型属性 • 段属性(SEGMENT)指变量所在段的段基址,它必须在一个段寄存器中。 • 偏移属性(OFFSET)指变量所在地址与所在段的段首地址之间的地址偏移字节数。 • 类型属性(TYPE)指变量中每个元素所包含的字节数,类型包括字节变量(BYTE)、字变量(WORD)及双字变量(DWORD)等。
(3)标号——指令性语句所在地址的符号表示。 标号具有三个属性: 段属性、偏移属性、类型 • 段属性(SEGMENT)标号所在段的段基址。标号的段是它所出现的那个代码段,所以由CS指示。 • 偏移属性(OFFSET)标号所在地址与所在段的段首址之间的偏移地址字节数。 • 类型(TYPE)标号的类型属性指在转移指令中标号可转移的距离,也称距离属性。类型NEAR,只能实现本代码段内转移或调用; 类型FAR,可以作为其它代码段中的目标地址,实现段间转移或调用。
(4)表达式——由常数、寄存器、变量、标号与运 算符组合而成的运算式。(4)表达式——由常数、寄存器、变量、标号与运 算符组合而成的运算式。 (5)标识符——变量与标识符也称为标识符。 (6)保留字——汇编语言具有特殊含义的符号,只 能作为固定的用途,不能作为标识符使用。 凡是8086的指令、伪指令、寄存器名等都是保 留字。因此,标号、变量名、段名、过程名、 符号名等都不能使用保留字。
程序块定义伪指令 一、程序分段定义伪指令 1. 段定义伪指令SEGMENT/ENDS 段名SEGMENT [定位类型] [组合类型] [´类别´] ┇; 段内语句序列 段名ENDS 功能:将一个逻辑段定义成一个整体。 (1)定位类型——用来规定对段起始边界的要求, 可以有4种选择: PAGE、PARA、WORD、BYTE 若定位类型缺省,则缺省值为PARA。
组合类型和类别 (2)组合类型为连接程序提供本段与其它段的关系信息。6种类型如下: NONE、PUBLIC、STACK、COMMON、AT表达式、MEMORY。 (3)类别——编程者给各段赋予的一种名字信息。 连接程序将类别名相同的段组成一个段组,用它们共同的类别名作为这个段组的名字。类别必须用单撇号撇起来。通常使用的类别有´STACK´、´CODE´、´DATA´ 等等。 NEXT
定位类型 用来规定对段起始边界的要求,可以有4种选择: PAGE段起始地址的最低8位必须为0,即从一页(PAGE)的起点开始。 起始地址=××××××××××××00000000 PARA段起始地址的最低4位必须为0,即从某一节(PARAGRAPH)的边界开始。 起始地址=××××××××××××××××0000 WORD段始址的最低位必须为0,从偶地址开始。 起始地址=×××××××××××××××××××0 BYTE段起始地址为任意值,可从任何字节开始。 起始地址=×××××××××××××××××××× 若定位类型缺省,则缺省值为PARA。 返回
组合类型 • NONE表示本段与其它段逻辑上不发生关系,每段都有自己的基地址。这是缺省的组合类型。 • PUBLIC连接程序首先将本段与其它同名同类别的段相邻地连接在一起,然后为所有这些段指定一个共同的段基址。 • STACK与PUBLIC同样处理,但此段作为堆栈段。当多个程序模块连接在一起时,各模块中至少有一个模块内有一个STACK段。 • COMMON 表示该段与其他模块中被说明成COMMON的同名同类别段共用一个段起始地址,且相互覆盖。组合后,段的长度是各模块同名段中最大的COMMON段长度。 • AT表达式 表示该段应按绝对地址定位,段基址为数值表达式的值,位移量为0。但此方式不能用来指定代码段。 • MEMORY连接程序将把本段定位在被连接在一起的其它所有段之上。若有多个MEMORY段,汇编程序认为所遇到的第一个为MEMORY,其余为COMMON。 返回
2. 段指示伪指令ASSUME • ASSUME伪指令用来指示程序中的段与CPU中段寄存器之间的关系。格式: • ASSUME段寄存器名:段名[,段寄存器名:段名,] • 段名为程序中已定义过的任何段名或组名,也可以是表达式“SEG 变量”或“SEG 标号”,或者关键字NOTHING。 • NOTHING表示以前为段寄存器所作的指示已被取消,以后程序运行时不再需要该寄存器,除非再用ASSUME给其重新定义。 • 段寄存器必须正确赋值才能指向指定的段。
注意:使用ASSUME伪指令,仅仅告诉汇编程序哪个段寄存器设定指向哪一个段,并没有给各段寄存器装入实际的值。而段地址的真正装入还必须通过给段寄存器赋值的执行性指令来完成。所以在程序的操作部分,要用指令来完成给段寄存器赋初值。例如:注意:使用ASSUME伪指令,仅仅告诉汇编程序哪个段寄存器设定指向哪一个段,并没有给各段寄存器装入实际的值。而段地址的真正装入还必须通过给段寄存器赋值的执行性指令来完成。所以在程序的操作部分,要用指令来完成给段寄存器赋初值。例如: CODE SEGMENT ASSUME CS:CODE,DS:DATA,ES:NOTHING,SS:STOCK MOV AX,DATA MOV DS,AX ┇
一般地,由ASSUME指示过的段寄存器都应赋值。但CS寄存器是一个例外,CS值是由DOS把.EXE模块装入内存时自动设定的,而不能用上述方式装入段地址值,但ASSUME伪指令中一定要给出CS段寄存器对应的正确段名——ASSUME伪指令所在段的段名。对堆栈段若不指示不赋值,此时利用的是系统设置的堆栈。一般地,由ASSUME指示过的段寄存器都应赋值。但CS寄存器是一个例外,CS值是由DOS把.EXE模块装入内存时自动设定的,而不能用上述方式装入段地址值,但ASSUME伪指令中一定要给出CS段寄存器对应的正确段名——ASSUME伪指令所在段的段名。对堆栈段若不指示不赋值,此时利用的是系统设置的堆栈。
GROUP伪指令的格式如下: 组名GROUP段名1,段名2,… 其中段名也可为表达式: “SEG变量名”或“SEG标号”。 3. 分组伪指令GROUP GROUP是群或组的意思,它用来把程序块中若干不同名的段集合成一个组,并赋予一个组名,使它们都装入一个物理段中(64KB)。这样,组内各段间的转移都可以看作段内转移。
4. ORG和当前位置计数器$ 汇编程序汇编源程序时,为遇到的每一个新定义的段设置一个初值为0的位置计数器。对该段进行汇编时,对需要占用存储器的语句(包括伪指令及指令性语句)分配存储单元,所有被占用的存储单元数累加到一起作为位置计数器的值。“$”反映位置计数器的当前值,它的值表示汇编程序所能分配的下一个存储单元的偏移地址,$可出现在表达式中。 格式如下: ORG表达式 例: STACK SEGMENT ST1 DW 100 DUP(?) STACKPOINT DW $ ;(STACKPOINT)=0C8H STACK ENDS
下面是使用ORG伪指令语句的例子: CSEG SEGMENT ORG 2 ┇;目标代码从0002H开始产生 ORG $+3;跳过三个字节后生成目标代码 ┇ CSEG ENDS 其中,$表示位置计数器的当前值,它可以在表达式中使用,它的值是程序下一个所能分配的存储器单元的偏移地址。 表达式的值应该是非负的整数,而且要保证计数器指针定位在0~65535之间。
5.程序结束伪指令END 格式:END[标号名] 功能:标记汇编源程序结束。 END是伪指令助记符,不可缺省,放在源程序的最后一行,每个模块只有一个END。汇编程序到END语句停止汇编。 标号名是该程序中第一条可执行语句的标号名,可以缺省,若一个程序包含多个模块,END后面带的标号为主程序模块中的标号名称。
二、过程定义伪指令PROC/ENDP 在程序设计中,往往将一些重复出现的语句组定义为子程序。子程序又称为过程,可由CALL指令来调用。过程定义的格式为: 过程名PROC[NEAR]/FAR ┇;语句序列 RET n ┇;语句序列 过程名ENDP ▲注意事项: ①过程名是由用户设定的标识符,过程名在程序中 可以作为标号使用。
②PROC和ENDP必须成对出现。 ③每一过程中至少得有一个RET n语句,n可缺省, 整个过程执行的最后一条语句必须是RET n。 ④过程的类型有NEAR和FAR。缺省为NEAR类 型。 ⑤过程可以“嵌套”使用,即过程又可以调用别 的过程。 ⑥过程还可以“递归”使用,即过程又可以调用 过程本身。
SEGX SEGMENT ┇ SUB1 PROC FAR ┇ CALL SUB2 ;过程“嵌套” ┇ RET SUB1 ENDP ┇ SUB2PROC NEAR ┇ RET SUB2 ENDP ┇ CALL FAR PTR SUB1 ;段内调用但要用段间调用来实现 ┇ SEGXENDS SEGY SEGMENT ┇ CALL FAR PTR SUB1 ;段间调用 ┇ SEGY ENDS
三、程序块间通信伪指令PUBLIC和EXTRN 汇编语言程序设计可采用多模块结构,在多模块间相互访问时,应在每一模块内交待清楚以下两方面信息: ①本模块内定义的变量和标号(包括过程名),哪些 可以作为外部标识符被其它模块访问?这是PUBLIC的功能。 ②本模块将访问哪些外部标识符?这是由EXTRN提供的。
格式: PUBLIC符号1,符号2,…… EXTRN符号1:类型,符号2:类型,…… 其中符号可以是符号常数、变量、标号或过程名。 在一个模块内或者一个段内由PUBLIC定义过的符号,可以在别的模块或段内直接引用; EXTRN说明本模块中使用的符号已在别的模块或段内定义过。 类型可以是:BYTE、WORD、DWORD; NEAR、FAR等。当然,这里所有符号的类型必须和它们在其它模块内定义的类型保持一致。
分别汇编下面两个程序①、②。 ① ② EXTRN RECEIVE:FAR SUBSEG SEGMENT CSEG SEGMENT RECEIVE PROC FAR START PROC FAR PUBLIC RECEIVE ┇ ┇ CALL RECEIVE RET ┇ RECEIVE ENDP START ENDP ┇ CSEG ENDS SUBSEG ENDS END END 程序①中无RECEIVE子程序,由EXTRN声明来自外部; 程序②声明RECEIVE此子程序可以共享。
MASM中的表达式和运算符 1.算术运算符(举例) 2.逻辑运算符 3.关系运算符——结果为0FFFFH/0FFH或0(举例) 4.数值返回运算符 (1)SEG运算符(举例) (2)OFFSET运算符 (3)TYPE运算符——求变量或标号的类型值 (4)LENGTH运算符——确定某个变量所含的数据元素的个数,由DUP定义数据个数时才有效。 (5)SIZE运算符——确定变量所含的字节存储单元 的总数,由DUP定义数据个数时才有效。
表达式和运算符 5.属性修改运算符 (1)PTR运算符; (2)段超越前缀运算符; (3)SHORT运算符; (4) THIS运算符; (5) HIGH和LOW——字节分离符 6.其它运算符 7.表达式由运算对象及运算符组成。汇编程序完成 表达式的运算,运算结果作为语句的操作数使用。 NEXT
算术运算符 算术运算符完成算术运算,它包括+(加法)、–(减法)、*(乘法)、/(除)、MOD(求余)以及SHL(左移,左移1位相当于乘2)和SHR(右移,右移1位相当于除2)共七种运算。 以上七种运算可直接对数字进行运算,但对地址的运算,只用加法和减法才具有实际意义,并且要求进行加、减的两个地址应在同一段内,否则运算结果便不是一个有效地址了,对地址乘是没有意义的。 通常是在标号上加/减某一个数字量,例如DA1+2、K2–3各表示一个存储单元的地址。 返回
应用举例 DATA SEGMENT BUFFER DB 2,3,5,7,4 DATA ENDS CODE SEGMENT ┇ MOV AL,BUFFER+3 ;将BUFFER字节单元以后的第三单元的内容送AL MOV AH,3*2–5 MOD 3 ;将表达式3*2–5MOD 3的值送AL MOV BH,010lB SHL 4 ;将二进制数0101B左移四次后送BH MOV BL,01010000B SHR 4 ;将二进制数01010000B右移四次后送BL ┇ CODE ENDS 返回
逻辑运算符 逻辑运算符对其操作数进行按位操作。逻辑运算符有:AND(与)、OR(或)、XOR(异或)和NOT(非),其中NOT是单操作数其它是双操作数运算符。 ①MOV AX,0FF00H AND 10AEH;将两个数相“与”的结果送AX。 汇编成:MOV AX,1000H ②AND CX,00FFH AND 10AEH;将表达式的值算出后,再和CX相“与”。汇编成:AND CX,00AEH 从以上两例可看出: ▲逻辑运算是在汇编时完成的,表达式的值由汇编程序确定,不影响标志位,而逻辑指令是在程序执行时完成逻辑操作的。 ▲0FF00H和00FFH与一个16位数相“与”,可以分别提取其高8位和低8位,这种技术通常称为“屏蔽”。 返回
关系运算符 关系运算符有EQ(相等)、NE(不相等)、LT(小于)、GT(大于)、LE(小于或等于)、GE(大于或等于)共六种。 关系运算都是双操作数运算,它的运算对象只能是两个性质相同的项目。对两个性质不同的项目进行关系运算是无意义的。 关系运算的结果只可能是两种情况:即关系成立或不成立。当关系成立时,运算结果为0FFFFH或0FFH,否则为0。 返回
应用举例 ①MOV AX,2 LT 5 汇编成:MOV AX,0FFFFH;2小于5关系成立 ②MOV AX,2 GT 5 汇编成:MOV AX,0;2大于5关系不成立 AND AX,((NUMB LT 5) AND 30) OR ((NUMB GE 5) AND 20) 当NUMB<5时,汇编成AND AX,30 NUMB≥5时,汇编成AND AX,20 AND出现在操作符位置是助记符,出现在操作数位置是伪指令。 返回
SEG运算符 数值返回运算符是对存储器地址进行运算的。它可以将存储器地址的三个重要属性,即段、偏移量和类型分离出来。 (1)SEG 格式: SEG变量名或标号名 SEG用来求取一个变量或标号的段基址。 返回
应用举例 [例]DATA是从存储器实际地址02000H开始的一个数据段如下: DATA SEGMENT VAR1 DB 20,30 VAR2 DW 2000H,3000H VAR3 DD 22002200H,33003300H DATA ENDS ①MOV BX,SEG VAR1 汇编成: MOV BX,0200H ②MOV CX,SEG VAR2 汇编成: MOV CX,0200H ③MOV DX,SEG VAR3 汇编成: MOV DX,0200H 返回
OFFSET运算符 (2)OFFSET 格式: OFFSET变量名或标号名 OFFSET运算符返回一个变量或标号的段内偏 移地址值,是程序设计中常用的运算符。 举例 返回
应用举例 DATA SEGMENT VAR1 DB 20,30 VAR2 DW 2000H,3000H VAR3 DD 22002200H,33003300H DATA ENDS [例]对上例中定义的数据段,用OFFSET可以求出VAR2的段内偏移地址。 MOV BX,OFFSET VAR2 汇编成:MOV BX,2;变量VAR2的偏移量为2 汇编程序将变量的偏移地址送到BX中,相当于指令: LEA BX,VAR2 返回
TYPE运算符 (3)TYPE 格式:TYPE变量或标号 TYPE运算符可加在变量或标号的前面,所求出的是这些存储器操作数的类型值。 ①TYPE加在变量前面返回的是这个变量的字节数。 ②TYPE加在标号前面,返回该标号的属性是-1(NEAR)或是-2(FAR)。 举例 返回