1 / 30

第四章 汇编程序设计

第四章 汇编程序设计. 4.1 常量、变量和标号 4.2 汇编语言源程序格式 4.3 伪指令 4.4 顺序程序设计 4.5 分支程序设计 4.6 循环程序设计 4.7 子程序. 4 . 1 常量、变量和标号. 汇编语言的数据可以分为常量和变量。常量可以作为指令的立即数或者伪指令的参数,变量作为存储器的操作数。汇编语言中的标号、名字,具有逻辑地址和类型属性,主要用于作地址操作数。 4.1.1 常量表示一个固定的值 ,有 4 种形式; 1. 常量 由二进制、八进制、十进制和十六进制形式表达的数值。

chavi
Download Presentation

第四章 汇编程序设计

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. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第四章 汇编程序设计 4.1 常量、变量和标号 4.2 汇编语言源程序格式 4.3 伪指令 4.4 顺序程序设计 4.5 分支程序设计 4.6 循环程序设计 4.7 子程序

  2. 4.1 常量、变量和标号 汇编语言的数据可以分为常量和变量。常量可以作为指令的立即数或者伪指令的参数,变量作为存储器的操作数。汇编语言中的标号、名字,具有逻辑地址和类型属性,主要用于作地址操作数。 • 4.1.1常量表示一个固定的值,有4种形式; • 1.常量 由二进制、八进制、十进制和十六进制形式表达的数值。 (1)二进制由0、1两个数字组成,以字母B(或b)结尾;例如101101011B。 (2)八进制由0—7这8个数字组成,以字母Q(或q)结尾;例如456701Q。 (3)十进制由0—9这10个数字组成,以字母D(或d)结尾;例如126789D。但十进制可以省略后缀字母。因此,默认的不加后缀字母的数就是十进制数。 (4)十六进制由0—9、A—F组成,以字母H(或h)结尾;例如456ABH。以字母A—F开头时,数的前面要加0,以示与标识符加以区别。 2.字符串 字符串常以单引号或双引号括起来的单个字符或者多个字符,例如:‘fg1256K^&*KK’;其数值是每个字符对应的ASC码;ASC码表见附录。

  3. 3.符号常量 符号常量使用标识符来表达一个数值;符号定义伪指令有 “EQU” 和 “=” 格式为: 符号名 EQU 数值表达式 符号名 EQU <字符串> ;或者用引号 符号名 = 表达式 例如: X EQU 56 ;含义为 MOV X, 56 Y EQU “ hello” ;含义为 MOV Y,“hello” Z = 13 ;含义为 MOV Z, 13 4.数字表达式 数字表达式由操作符连接的各种常量所构成表达式;汇编语言进行汇编过程中,最终得到一个确定的数值,因此,也称为常量。 例如: MOV AL,1*2+3 ;(AL)= 1*2+3 = 5 MOV AH,13H OR 45H MOV BH,110110B SHL 2 汇编所用的运算符,见表4.1。

  4. 4.1.2 变量 变量就是内存单元;变量先定义后使用。 格式: 变量名 伪指令 初值 (1)变量名是用户自己定义的标识符,这个符号表示内存地址,常称为 符号地址。当然,变量名可以没有,初值分配的地址称为无符号地址。 (2)初值是用逗号分开的参数,主要由常量、表达式、?、DUP 组成 其中:?表示初值不确定或未赋初值。 DUP(5)表示重复初值 5 次。 (3)变量定义的伪指令有 DB、DW、DD、DF、DQ、DT 例如: DATA SEGMENT     ;数据段 X DB -56H    ;X的值=-56H Y DB 80H,?,“W”,3 DUP(0) ; Z DW ?   ;Z无初值 DATA ENDS 变量定义在数据段 DATA SEGMENT内;X 为字节型数据,值为-56H; Y为字节型;Z单元为字型数据,没有初值。 本例在内存的分配方法见图4.1 。

  5. 以一个完整的汇编语言程序来说明; DATA SEGMENT ;定义数据段,段名为DATA X DB 34H ;定义各种数据 Y DW “HH” …….. DATA ENDS ;数据段定义结束 STACK SEGMENT ;定义堆栈段,段名为STACK DB 100 DUP(0) ;开辟堆栈区域100,初值为0 STACK ENDS ;堆栈段定义结束 CODE SEGMENT ;定义代码段,段名为CODE ASSUME CS:CODE,DS:DATA,SS:STACK START:MOV AX,DATA MOV DS,AX ;这两条给DS赋初值 ……;为源程序指令序列 MOV AH,4CH ;DOS调用INT 21H,功能号4CH INT 21H ;程序终止 CODE ENDS ;代码段结束 END START ;汇编结束 返回本章目录

  6. 4.2 汇编语言的源程序格式 以一个完整的汇编语言程序来说明; DATA SEGMENT ;定义数据段,段名为DATA X DB 34H ;定义各种数据 Y DW “HH” …….. DATA ENDS ;数据段定义结束 STACK SEGMENT ;定义堆栈段,段名为STACK DB 100 DUP(0) ;开辟堆栈区域100,初值为0 STACK ENDS ;堆栈段定义结束 CODE SEGMENT ;定义代码段,段名为CODE ASSUME CS:CODE,DS:DATA,SS:STACK START:MOV AX,DATA MOV DS,AX ;这两条给DS赋初值 ……;为源程序指令序列 MOV AH,4CH ;DOS调用INT 21H,功能号4CH INT 21H ;程序终止 CODE ENDS ;代码段结束 END START ;汇编结束

  7. 汇编语言源程序应包括: (1)汇编语言源程序存入内存时,分四个段进行存放;程序中一般有二个段:数据段、代码段;而附加数据段用于存放字符串数据,当程序没有用到字符串数据时可省略,堆栈段在内存中建立堆栈区,用于中断、子程序的调用,当程序没有用到中断、子程序时可省略;数据段在内存中建立工作区,存放程序需要进行操作的数据、变量等;代码段存放程序执行的指令集合,完成程序的操作。段与段之间随意存放。 (2)每个段以 “段标识符 SEGMENT” 开始,以 “段标识符 END” 结束START:MOV AX,DATA 表示程序操作指令开始,整个程序以 “END START” 结束,两个 START 相对应,当然可用你感兴趣的标识符。 (3)伪指令 ASSUME 告诉汇编程序,段地址与段寄存器之间的关系,各段在内存的起始地址。源程序要对数据段寄存器 DS 进行初始化,采用两条指令MOV AX,DATA 和MOV DS,AX实现。 (4)如果要对指令进行说明,在一条指令后加 “;” 接着写说明部分;汇编语言在编译时,对此不作处理。操作数之间、参数之间用 “,” 号分隔;其它部分一般用多个空格分隔符,标号后加 “:” 号,表示逻辑地址;原则上一条指令书写一行。 返回本章目录

  8. 4.3 伪指令 伪指令是用来对相关指令进行说明;主要有段定义、过程定义,数据定义、符号定义,模块定义、程序结构定义等,由于不产生代码,因此称为伪指令。常用的有下几种: 1.变量定义伪指令:为变量申请固定长度的内存空间; (1)定义字节变量:用于分配一个或多个字节单元 例如: X DB ‘a’;分配一个字节单元  Y DB 10 DUP(0) 连续分配11个字节单元 (2) 定义字变量:用于分配一个或多个字单元 例如: Z DW 8080H ;分配1个字单元,一个字2个字节 W DW ?,‘ABC’;分配多个字单元 (3)DD 定义双字变量,DQ 定义 4 字变量,DT 定义 10字变量 2.符号定义伪指令:为程序中的表达式赋予一个名字 (1)EQU 伪指令:将表达式的值赋给其前面的名字,以名字来代替表达式;程序中不允许对已经定义过的名字重新赋新的值。 例如: X EQU 100 ;将 100 赋给 X (2)= 伪指令:将表达式的值赋给其前面的名字,与 EQU 区别在于:= 伪指令定义后,可以多次改变,重新给变量赋新的值。

  9. 3.ASSUME段分配伪指令:设定四个段与对应的寄存器之间的关系3.ASSUME段分配伪指令:设定四个段与对应的寄存器之间的关系 例如: ASSUME CS:CODE1,DS:DATA1,SS:STACK1 4.SEGMENT/ENDS段定义伪指令:对数据段、代码段、堆栈段、附加数据段进行定义和赋予一个名字,指明类型、类别等; 例如: AA SEGMENT …….. AA ENDS 这里SEGMENT表示定义的一个逻辑段开始,ENDS 表示所定义的逻辑段结束,逻辑段的名称为 AA。类型、类别等不作介绍。 5.ORG定位伪指令:ORG 是起始位置设定; 6.程序计数器伪指令$:表示当前偏移地址的值。 例如:DATA SEGMENT Y DW 8899H BUF DB 10,-45H,66H,“A” N = $ - BUF ;当前地址$-BUF的偏移地址,BUF数据的个数 X DB 12 ORG $ + 10 ;设置Z的地址偏移量为当前位置后移10个单元 Z DW “ABCDEF” DATA ENDS 7.PROC过程定义伪指令:PROC定义一个过程。 返回本章目录

  10. 4.4 顺序程序设计 顺序程序结构是最基本、最常见的结构,完全按照指令书写的 顺序执行每条指令。顺序程序结构在程序中都会出现,是复杂结构 的一部分;是分支程序的其中一个分支;循环程序的循环体内就是 顺序程序构成。   例如:有三个变量 A、B、C,其值分别为 3、4、5,求出 A、B、 C 的和,将和存入变量 SUM中。 DATA SEGMENT ;定义数据段 A DB 3 B DB 4 C DB 5 ;给 A,B,C赋初值 SUM DB ? ;存放和,无初值 DATA ENDD CODE SEGMENT ASSUME CS:CODE,DS:DATA ;本程序只需两个段 START:MOV AX,DATA ;初始化 DS

  11. START:MOV AX,DATA  ;初始化DS MOV DS,AX MOV BH,A       ;将 A的值送到 BH寄存器 ADD BH,B      ;进行求和 ADD BH,C MOV SUM,AH     ;存入运算结果 MOV AH,4CH     ;返回 DOS INT 21H CODE ENDS    ;代码段结束 END START      ;汇编结束  本例子,源程序仅由代码段和数据段两部分组成。在数据段,定义了变量 A、B、C,即内存中数据段的三个连续的单元,并赋给了初值,接着定义了存储和的变量 SUM,即数据段中的第四个单元,由于没有初值,用?表示,当然也可赋初值 0。 执行代码段中的指令,对于顺序程序结构,从第一条指令开始执行,依次执行第二条,……直至最后一条指令。 返回本章目录

  12. 4.5 分支程序设计    汇编语言中,使用无条件指令 JMP 和条件转移指令 JCC来实现 分支程序设计。条件转移指令的条件指的是:FLAG 的标志位。影响 FLAG、设置 FLAG 标志位的指令主要有算术运算指令、比较指令 CMP、测试指令 TEST;因此,JCC 前面一般有影响标志位的指令。 分支程序结构有单分支和多分支两种。 1.单分支程序设计 例如:内存单元X中存放一个数据,求出X的绝对值,存入内存 单元 Y中。见示意图4.2 。 DATA SEGMENT X DB —23D ;请随意存入一个数据 Y DB ? ;存放 X的绝对值 DATA ENDS CODE SEGMENT ASSUME DS:DATA,CS:CODE

  13. 见示意图4.2 START:MOV AX,DATA MOV DS,AX MOV AH,X ;取出X单元的值 CMP AH,0 ;判断X值 JGE LP1 ;X为正数,直接存放 NEG AH ;X为负数,求绝对值(补码) LP1: MOV Y,AH ;存入X的绝对值 MOV AH,4CH ;返回DOS INT 21H CODE ENDS ;代码段结束 END START ;汇编结束 单分支程序设计,当条件满足(成立)时,发生转移,跳过分支体;当条件不满足(不成立)时,按程序书写的顺序向下执行分支体。

  14. 2.多分支程序设计 实际问题存在多个条件,进行不同的操作时,用到多分支程序。 例如:键盘上输入一个字符,如果是数字字符,将之对应的十进 制数据, 存入内在单元 D,否则,将 ‘X’字符存入单元 D,流程见图4.3 。 D DB ? ;根据输入的结果存放DX的值 START:MOV AX,DATA MOV DS,AX MOV AH,01H ;从键盘输入一个字符 INT 21H CMP AL,‘0’;输入的字符与‘0’比较 JB LP1 ;小于‘0’,不是数字字符 CMP AL,‘9’;与‘9’比较 JA LP1 ;大于‘9’,不是数字字符 SUB AL,30H ;将输入的数字字符转为对应的数据 MOV D,AL JMP EXIT LP1:MOV D,‘X’;输入的不是数字字符,将‘X’存入D单元 EXIT:MOV AH,4CH ;返回DOS INT 21H CODE ENDS ;代码段结束 END START ;汇编结束 返回本章目录

  15. 4.6 循环结构程序设计 循环结构程序是指满足条件时,重复执行一段指令,称为循环 体;不满足条件时,绕过循环体。循环结构一般由三个部分组成: (1)循环初始化部分:为循环开始作准备。赋循环次数、处理 多个数据时的初地址、所用内存数据单元的初始化、所用寄存器的 初始化等; (2)循环体:重复执行的指令序列;还包括修改控制循环所用 的参数,如计数器、操作时所用地址的指针等。 (3)循环控制部分:判断循环条件是否成立,确定循环是否继 续。循环的控制方法有两种; 先执行循环体,然后判断循环条件是否成立;循环体一定要执 行一次。这点设计程序时要留意,否则,程序执行结果出错。 先判断循环条件是否成立,如果成立,进入循环体,不成立, 不进入循环体;循环体可能一次都不执行。 循环结构程序设计的几种常用的控制循环方法:

  16. 1.计数控制循环 计数控制循环这种方式,事先就知道要循环的次数,将要循环的次数先存入 CX中,每执行一次循环,CX 的值减1,当(CX)= 0时,结束循环。次数来作为控制循环,最好的方法是利用 8086 汇编系统提供的循环指令LOOP 和 JCXZ 来实现。 例如:内存 BUF 区域,存放有10个带符号的字节数据,将它们求和,存入字节单元 SUM 中(和不超过字节)。 BUF DB 23,-45,-56,0,21,34,78,9,8,-32 SUM DB 0 ;不考虑和超过字节     START:MOV AX,DATA MOV DS,AX MOV CX,10 ;循环次数赋初值 MOV SI,OFFSET BUF ;第一个数据单元的地址初值 MOV AH,0 ;累加寄存清0

  17. LP1:ADD AH,[ SI ] ;求和 INC SI ;指向下个单元 DEC CX ;循环次数修改 CMP CX,0 ;循环条件判断 JNZ LP1 ;次数未到,循环继续 MOV SUM,AH ;循环结束,存放结果 EXIT:MOV AH,4CH ;返回DOS INT 21H CODE ENDS ;代码段结束 END START ;汇编结束

  18. 2.条件控制循环 实际应用中,循环次数是无法事先知道的,计数控制循环受到很大的局限性;循环次数是实际问题中的某个条件来控制,以结束循环,控制循环的。 例如:内存BUF区域有多个带符号的数据,以回车结束,统计正数的个数,并将统计的个数存入内存SUM单元。 工作流程见图4.4。 BUF DB 23,-45,-56,0,21,34,78,9,8,-32….,0DH SUM DW 0 START:MOV AX,DATA MOV DS,AX MOV SI,OFFSET BUF ;第一个数据单元的地址初值

  19. 工作流程见图4.4。 LP1:MOV AH,[ SI ] ;取出当前单元的数据 CMP AH,0DH ;当前单元的数据是回车符吗 JZ EXIT ;是回车符,循环结束 CMP AH ,0 JS LP2 ;是负数,不统计,进入下个单元 INC SUM ;是正数,统计 LP2 INC SI ;进入下一个单元 JMP LP1 ;继续循环 EXIT: MOV AH,4CH ;返回DOS INT 21H CODE ENDS ;代码段结束 END START ;汇编结束 返回本章目录

  20. 4.7 子程序 程序中一段指令是实现固定的功能,而每次调用的参数不同,这些功能经常用到,这时采用子程序。这样设计结构清楚,程序的维护方便。当主程序需要执行这个子程序功能时,通过调用该子程序,执行子程序,子程序完成后返回主程序调用处,继续主程序后面的指令的执行。与子程序有关的指令有子程序的调用CALL、子程序返回RET两条指令。 4.6.1 子程序的调用指令 子程序的调用有4种情况,类似于无条件的转移JMP的情况。 (1) 段内调用,直接寻址 格式: CALL label ; 当前IP入栈,实现转移,转到偏移地址为label处执行 (2) 段内调用,间接寻址 格式: CALL r16/m16 ; 当前 IP入栈,转到偏移地址为 r16/m16 的内容指示的位置执行 (3) 段间调用,直接寻址 格式: CALL far ptr label ; 当前IP入栈,实现转移,转到 label所在的段,偏移地址为label处执行 (4) 段间调用,间接寻址 格式: CALL far ptr mem ; 当前 IP入栈,实现转移,转到 mem 所在的段,偏移地址为mem处执行

  21. 4.7.3子程序定义伪指令 子程序在汇编语言中称为过程,每个子程序过程有一个唯一的过程名; 由一对伪指令 PROC和ENDP定义。格式为: 过程名 PROC(属性) 指令系列 ;过程体 过程名 ENDP 例如:编写将寄存器AL的低4位的一个16进制数,转换成相应的ASCII码 的子程序 HEXASC PROC ;定义一个过程,名为HEXASC AND AL,0FH ;截取AL的低4位 OR AL,30H ;0-9的ASC码为30-39H CMP AL,39H ;判断是0-9,还是A-F JBE LP1 ;AL内容<39H,AL为0-9 ADD AL,7 ;A-F的ASC码,比9D大7 LP1:RET HEXASC ENDP ;名为HEXASC的过程结束

  22.  通过上面的子程序的例子,看出过程编写的规则: 通过上面的子程序的例子,看出过程编写的规则: (1)以 “过程名 PROC” 开始,以 “过程名 ENDP” 结束;子程序过程体内包含有 RET指令,遇到此指令,即返回主程序,从而结束了子程序的执行。 (2)子程序所用到的寄存器,子程序开始时,都应该利用堆栈来保护,防止子程序使用时破坏其原来的数据;子程序返回调用者前进行恢复原来的数据。 (3)子程序安排在主程序的代码段之外,最好放在主程序终止执行的位置,也可放在主程序开始执行之前。 (4)子程序允许与主程序共用一个数据段;也可以使用不同的数据段。 (5)子程序可以有多个出口(即内有多个 RET 指令);多个入口,即主程序与子程序多个参数传递。

  23. 4.7.4 子程序参数的传递   主程序与子程序的参数传递,指主程序要子程序处理的数据通过什 么途径、方式、方法传送给子程序。方法有:用寄存器、用变量、用堆 栈。 1.寄存器法 主程序需要子程序处理的数据,存放在一个事先约定的寄存器中, 子程序到这个寄存器中取出数据进行处理,结果传给调用者。 2.内存单元变量法 主程序需要子程序处理的数据,存放在一个事先约定的内存单元变 量中。 3.堆栈法 主程序将要转换的数据压入堆栈内,再调用子程序,子程序从堆栈 弹出数据,处理的结果也可压入堆栈返回给调用者。 举一个完整的包括主程序、子程序及调用的例子,来进行整体说明。 例如:将内存单元 X 的一个一位十进制数据显示出来;将一位十进制数 据转为对应的 ASC 码用子程序,主程序决定X单元的数据及显示这个数。

  24. DATA SEGMENT X DB ? ;存放被显示的数 Y DB 0 ;存放此数转换好的ASC码 DATA ENDS CODE SEGMENT ASSUME DS:DATA,CS:CODE START:MOV AX,DATA MOV DS,AX MOV X,9D ;十进制数存入X单元 CALL DTOA ;调用子程序DTOA进行转换 MOV AH,02H ;显示一个字符用02H号功能调用 MOV DL,Y ;Y为要显示的数的ASC码 INT 21H EXIT: MOV AH,4CH ;返回DOS INT 21H CODE ENDS ;代码段结束

  25. DTOA PROC ;定义一个子程序,名为 DTOA PUSH AX ; 子程序要用AX,保护AX原来的数 MOV AH,X ;从 X取出参数 ADD AH,30H ;转换 9D的 ASC为 39H MOV Y,AH ;ASC 码存入 Y单元 POP AX ;恢复 AX寄存器 RET ;返回调用者 DTOA ENDP ;子程序 DTOA结束 END START ;汇编结束 返回本章目录

  26. 图4.1 数据变量定义的存储格式 返回4

  27. 图4.2 单项分支程序结构图 返回12 返回13

  28. 图4.3 多分支程序结构示意图 返回14

  29. 图4.4 条件控制控制循环示意图 返回18 返回19

  30. 表4.1 8086汇编运算符 返回3

More Related