版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、微机原理与接口技术,第四章 汇编语言程序设计,主要内容,汇编语言源程序格式 指示性语句 系统功能调用方法 汇编程序设计方法 综合举例,汇编语言源程序格式,完整的汇编语言源程序由逻辑段组成。 一个汇编语言源程序可以包含若干个代码段、数据段、附加段或堆栈段。 段与段之间的顺序可随意排列。 需独立运行的程序必须包含一个代码段,并指示程序执行的起始点,一个程序只有一个起始点。 通常,程序还需要一个堆栈段。 段由若干语句组成,一条语句通常写成一行。,一个完整的汇编语言源程序,DATA SEGMENT MINUS DB ? NUMBER DB 100DUP(?) DATA ENDS CODE SEGMEN
2、T ASSUME CS:CODE, DS:DATA COUNT EQU 100 START:MOV AX, DATA MOV DS, AX MOV MINUS, 0 LEA SI, NUMBER MOV CX,COUNT AGAIN:MOV AL, SI OR AL, AL JNS NOT_MINUS,INC MINUS NOT_MINUS:LOOP AGAIN MOV AH, 4CH INT 21H CODE ENDS END START,汇编语言的语句格式,指令性语句指令性语句用于表达处理器指令,汇编后对应一条指令代码(目标代码),因而是可执行语句 标号: 操作数 ;注释 指示性语句指示性
3、语句指示源程序如何汇编、变量怎样定义、过程怎么设置,也称为伪指令,汇编时不产生目标代码,是不可执行语句 名字 参数 ;注释,每个部分称为“项”或“域”、“场”。,指令与伪指令,指令(Instruction) 让CPU产生动作,在程序执行时才处理。 指令就是第3章学习的处理器指令,与具体的处理器有关、与汇编程序无关。 伪指令(Directive) 不产生CPU动作,在程序执行前由汇编程序处理。 伪指令与具体的处理器类型无关,但与汇编程序有关。不同版本的汇编程序支持不同的伪指令。,指令和伪指令采用易于记忆的符合表达,这就是助记符,标号、名字与标识符,标号是反映指令位置(逻辑地址)和属性的标识符,后
4、跟一个冒号分隔 名字是反映伪指令位置(逻辑地址)和属性的标识符,后跟空格或制表符分隔,没有冒号 标识符(Identifier)一般最多由31个字母、数字及规定的特殊符号(如 _、$、?、)组成,不能以数字开头。 默认情况下,汇编程序不区别标识符中的字母大小写 一个源程序中,每个标识符的定义是唯一的,还不能是汇编语言采用的保留字,保留字,保留字(Reserved Word)是汇编程序已经利用的标识符(也称为关键字),主要有: 指令助记符例如:MOV、ADD 伪指令助记符例如:DB、DW 操作符例如:OFFSET、PTR 寄存器名例如:AX、CS,汇编语言大小写不敏感,操作数和参数,处理器指令的操
5、作数可以是立即数、寄存器和存储单元 伪指令的参数可以是常数、变量名、表达式等,可以有多个,参数之间用逗号分隔,注释,语句中由分号“;”开始的部分为注释内容,用以增加源程序的可读性 必要时,一个语句行也可以由分号开始作为阶段性注释 汇编程序在翻译源程序时将跳过该部分,不对它们做任何处理,分隔符,语句的4个组成部分要用分隔符分开 标号后用冒号,注释前用分号 操作数之间和参数之间使用逗号分隔 其他部分通常采用空格或制表符 多个空格和制表符的作用与一个相同,常量、变量和标号,汇编语言的数据可以简单分为常量和变量 常量可以作为指令的立即数或伪指令的参数,变量主要作为存储器操作数 汇编语言语句中的名字和标
6、号具有逻辑地址和类型属性,主要用做地址操作数,也可以作为立即数和存储器操作数,常量,常量表示一个固定的数值,它又分成多种形式 常数 字符串 符号常量 数值表达式,(1) 常数,指由10、16、2和8进制形式表达的数值,各种进制的数据以后缀字母区分,默认不加后缀字母的是十进制数,(2) 字符串,字符串常量是用单引号或双引号括起来的单个字符或多个字符 其数值是每个字符对应的ASCII码值 例如: d(等于64H) AB(等于4142H) Hello, Assembly !,(3) 符号常量,符号常量使用标识符表达一个数值 用来为常量定义符号名 符号定义伪指令有“等价EQU”和“等号”: 符号名 E
7、QU 数值表达式 符号名 数值表达式 EQU不能重复定义符号名,但“”允许重复定义。例如: X = 7;等效于:X equ 7 X = X+5;“X EQU X+5”是错误的,举例,NUMBER EQU200 COUNT EQU6*9 ADDR EQUES:DI+2 MV EQUMOV STRW EQUWORD PTR STRING COUNT = 123 COUNT = COUNT +1,(4) 表达式,表达式一般是由运算符连接的各种常量所构成 汇编程序在汇编过程中计算表达式,最终得到一个确定的数值,所以也是常量 表达式的数值在程序运行前的汇编阶段计算,所以组成表达式的各部分必须在汇编时就能
8、确定 经常使用的是加减乘除( * / ) 例如: mov ax,3*4+5;等价于:mov ax,17 and ax, 3 and 5 ;等价于:and ax, 1,变量,变量实质上是指内存单元的数据,虽然内存单元地址不变,但其中存放的数据可以改变 变量需要事先定义才能使用 变量定义(Define)伪指令为变量申请固定长度为单位的存储空间,并可以同时将相应的存储单元初始化 定义后的变量可以利用变量名等方法引用其中的数据,即变量的数值,(1) 变量的定义,变量定义的汇编语言格式为: 变量名 伪指令 初值表 变量名为用户自定义标识符,表示初值表首元素的逻辑地址,常称为符号地址。变量名也可以没有 初
9、值表是用逗号分隔的参数,主要由常量、数值表达式或“?”组成。其中“?”表示未赋初值 多个存储单元如果初值相同,可以用复制操作符DUP进行定义: 重复次数 DUP(重复参数) 变量定义伪指令有DB、DW、DD等,字节变量的定义DB,DB伪指令用于分配一个或多个字节单元,并可以将它们初始化为指定值 初值表中每个数据一定是字节量,存放一个8位数据: 可以是0255的无符号数 或是128127带符号数 也可以是字符串常数,字节变量定义实例,;数据段 Xdb a,-5 db 2 dup(100),? Ydb ABC,应用,字节变量的应用,mov al,X ;此处X表示它的第1个数据,故ALa dec X
10、+1 ;对X为始的第2个数据减1,故成为6 mov Y,al ;现在Y这个字符串成为 aBC,字变量的定义DW,DW伪指令用于分配一个或多个字单元,并可以将它们初始化为指定值 初值表中每个数据是字量,一个字单元可用于存放任何16位数据: 一个段地址 一个偏移地址 两个字符 065535之间的无符号数 3276832767之间的带符号数,字变量定义实例,;数据段 countdw 8000h,?,AB maxintequ 64h numberdw maxint arraydw maxint dup(0),双字变量的定义DD,DD伪指令用于分配一个或多个双字单元,并可以将它们初始化为指定值 初值表中
11、每个数据是一个32位的双字量: 可以是有符号或无符号的32位整数 也可以用来表达16位段地址(高位字)和16位的偏移地址(低位字)的远指针 varddDD 0,?,12345678h farpointDD 00400078h,(2)变量的应用,变量具有存储单元的逻辑地址 程序代码中 通过变量名引用其指向的首个数据 通过变量名加减位移量存取以首个数据为基地址的前后数据,变量的定义,bvar1db 100,01100100b,64h,d ;字节变量:不同进制表达同一个数值,内存中有4个64H minint= 5 ;符号常量:minint数值为5,不占内存空间 bvar2db -1,minint,m
12、inint+5 ;内存中数值依次为FFH,5,0AH db ?,2 dup(20h) ;预留一个字节空间,重复定义了2个数值20H wvar1dw 2010h,4*4 ;字变量:两个数据是2010H、0010H,共占4个字节 wvar2dw ? ;wvar2是没有初值的字变量,变量的定义(续),dvardd 12347777h,87651111h,? ;双字变量:2个双字数据,一个双字空间 abcdb a,b,c,?;定义字符,实际是字节变量 maxint equ 0ah;符号常量:maxint10 stringdb ABCDEFGHIJ ;定义字符串:使用字节定义DB伪指令 crlfsdb
13、13,10,$ ;回车符0DH、换行符0AH和字符$24H array1dw maxint dup(0) ;10个初值为0的字量,可以认为是数组 arraydb 2 dup(2,3,2 dup(4) ;6个字节内容依次为:02 03 04 04 02 03 04 04,变量的应用,;代码段 mov dl,bvar1;DL100 dec bvar2+1;bvar2+14 mov abc+3,dl;abcabcd mov ax,word ptr dvar;取双字到DX.AX mov dx,word ptr dvar+2 add ax,word ptr dvar+4;加双字到DX.AX adc dx
14、,word ptr dvar+6 mov word ptr dvar+8,ax;保存双字的求和结果 mov word ptr dvar+10,dx,(3) 变量的定位,汇编程序按照指令的先后顺序一个接着一个分配存储空间 定位伪指令ORG控制数据或代码所在的偏移地址 ORG 参数 ORG伪指令是将当前偏移地址指针指向参数表达的偏移地址。例如: ORG 100h ;从100H处安排数据或程序 ORG $+10 ; 偏移地址加10,即跳过10个字节空间 汇编语言程序中,符号“$”表示当前偏移地址值,程序计数器$,汇编程序有一个当前位置计数器,用来记录正在汇编的数据或指令目标代码存放在当前段内的偏移量
15、。 $表示位置计数器的当前值。例如: BLOCK DB Hello NUM EQU $-BLOCK,名字和标号的属性,名字和标号是用户自定义的标识符。名字指向一条伪指令,标号指向一条指令。名字和标号一经使用便具有两类属性: 逻辑地址名字和标号对应存储单元的逻辑地址,含有段地址和偏移地址; 类型变量名的类型可以是BYTE、WORD和DWORD等;标号、段名、子程序名的类型可以是NEAR和FAR,分别表示段内或段间调用 汇编程序提供操作符TYPE,以便获取这些属性值,(1) 地址操作符,地址操作符取得名字或标号的段地址和偏移地址,举例,; 数据段 BUFFER DB ? ; 代码段 MOV BX,
16、 OFFSET BUFFER MOV BX, SEG BUFFER,LEA BX, BUFFER,(2) 类型操作符,类型操作符对名字或标号的类型属性进行设置 类型名 PTR 名字/标号 其中类型名可以是BYTE、WORD、DWORD, 或者是NEAR、FAR 操作符 SHORT 对变量: LENGTH 操作符获知某变量名指向多少个数据项 SIZE 操作符获知它共占用多少字节空间 TYPE 操作符获取变量类型值,举例,; 数据段 BUFFER DW ? STRING DB Hello, 10 DUP(?) RESULT DB 10 DUP(1,?) ; 代码段 MOV BX, TYPE BUF
17、FER MOV BX, TYPE STRING MOV BX, TYPE RESULT,; (BX)=2,; (BX)=1,; (BX)=1,举例,; 数据段 BUFFER DW ? STRING DB Hello, 10 DUP(?) RESULT DB 10 DUP(1,?) ; 代码段 MOV BX, LENGTH BUFFER MOV BX, LENGTH STRING MOV BX, LENGTH RESULT,; (BX)=1,; (BX)=1,; (BX)=10,举例,; 数据段 BUFFER DW ? STRING DB Hello, 10 DUP(?) RESULT DB 1
18、0 DUP(1,?) ; 代码段 MOV BX, SIZE BUFFER MOV BX, SIZE STRING MOV BX, SIZE RESULT,; (BX)=2,; (BX)=15,; (BX)=20,举例,;数据段 STUFF DD 12345678H ;代码段 MOV CL, BYTE PTR STUFF MOV CH, BYTE PTR STUFF+1 MOV AX, WORD PTR STUFF MOV DX, WORD PTR STUFF+2,; (CL)=78H,; (CH)=56H,; (AX)=5678H,; (DX)=1234H,段名 SEGMENT 段名 ENDS
19、,段定义语句,(1) SEGMENT定义一个逻辑段,并给逻辑段赋予一个段名。 (2) 常见的段名如:CODE, DATA, STACK,格式 ASSUME 段寄存器名:段名,段寄存器名:段名 如 ASSUME CS:CODE,DS:DATA,SS:STACK 作用 明确段寄存器与逻辑段之间的关系,并不是给段寄存器赋初值。,ASSUME,完整段定义格式,完整段定义利用SEGMENT和ENDS一对伪指令定义逻辑段 同时需要配合ASSUME伪指令指明逻辑段是代码段、堆栈段、数据段还是附加段 完整段定义的优势是可以指明逻辑段的定位、组合、类别等属性 而简化段定义只能采用系统默认的属性,过程名 PROC
20、 NEAR/FAR RET 过程名 ENDP 调用过程: CALL 过程名,过程定义语句,伪指令小结,符号定义语句 EQU = 数据定义语句 DB DW DD DUP 段定义语句 SEGMENT/ENDS ASSUME 过程定义语句 PROC/ENDP 其他 ORG $ END 常用运算符 AND OR XOR NOT OFFSET SEG LENGTH SIZE TYPE PTR SHORT,程序开始,为了指明程序开始执行的位置,需要使用一个标号(例题中采用了start标识符) 连接程序会根据程序起始点正确地设置CS和IP值,根据程序大小和堆栈段大小设置SS和SP值 连接程序没有设置DS和E
21、S值。程序如果使用数据段或附加段,必须明确给DS或ES赋值 大多数程序需要数据段,程序的执行开始应是: start:mov ax, data;data表示数据段的段地址 mov ds,ax;设置DS,程序终止,应用程序执行结束,应该将控制权交还操作系统 汇编语言程序设计中,有多种返回DOS的方法,但一般利用DOS功能调用的4CH子功能实现,它需要的入口参数是AL返回数码(通常用0表示程序没有错误) 于是,应用程序的终止代码就是: mov ax,4c00h int 21h,汇编结束,汇编结束表示汇编程序到此结束将源程序翻译成目标模块代码的过程 源程序的最后必须有一条END伪指令 END 标号 可
22、选的“标号”参数指定程序开始执行点,连接程序据此设置CS和IP值(例题中采用了start标识符),不要糊涂 程序终止和汇编结束是两码事,系统功能调用方法,汇编程序提供给汇编语言程序员的功能非常有限 程序员需要利用ROM-BIOS和操作系统提供的资源 系统功能调用是程序设计的一个重要方面,系统功能调用步骤,通常按照如下4个步骤进行: 在AH寄存器中设置系统功能调用号 在指定寄存器中设置入口参数 用中断调用指令( INT i8)执行功能调用 根据出口参数分析功能调用执行情况,DOS输入输出功能调用,DOS利用21H号中断提供给用户近百个系统功能,主要包括设备管理、目录管理和文件管理三个方面的功能
23、重点掌握: 输入一个字符,01H号功能调用 输出一个字符,02H号功能调用 输出一个字符串,09H号功能调用,02H号DOS功能调用,输出一个字符 功能调用号:AH02H 入口参数:DL欲显示字符的ASCII码 功能调用:INT 21H 出口参数:无,;显示一个问号“ ?” mov ah,02h;设置功能调用号 mov dl,?;设置入口参数 int 21h;功能调用,例题-回车换行的子程序,crlfproc push ax;保护寄存器 push dx mov ah,2 mov dl,0dh;回车功能的ASCII码是0DH int 21h mov ah,2 mov dl,0ah;换行功能的AS
24、CII码是0AH int 21h pop dx;恢复寄存器 pop ax ret crlfendp,09H号DOS功能调用,输出一个字符串 功能调用号:AH09H 入口参数: DS:DX欲显示字符串在内存中的首地址(逻辑地址形式:DS段地址,DX偏移地址) 内存中的字符串以ASCII码形式保存,最后必须添加一个“$”结尾(并不显示) 功能调用:INT 21H 出口参数:无,例题-在屏幕上显示一段信息,;数据段(定义要显示的字符串) stringdb Hello, Assembly !,0dh,0ah,$ ;代码段(显示字符串的程序) mov dx,offset string mov ah,9
25、int 21h,Hello, Assembly !,01H号DOS功能调用,输入一个字符 功能调用号:AH01H 入口参数:无 功能调用:INT 21H 出口参数:AL键入字符的ASCII码,;输入一个字符 mov ah,01h;设置功能调用号 int 21h;功能调用 mov dl,al;使用出口参数,结束用户程序的方法,START PROC FAR BEGIN: PUSH DS MOV AX, 0 PUSH AX . RET START ENDP,推荐采用第1种方法。,顺序程序设计,没有分支、循环等转移指令的程序,会按指令书写的前后顺利依次执行,这就是顺序程序 顺序结构是最基本的程序结构
26、完全采用顺序结构编写的程序并不多见,例题,STACK SEGMENT STACK STACK DW 64DUP(?) ;定义堆栈段 STACK ENDS DATA SEGMENT X DW 0010H Y DW 0123H Z DW 7890H V DW 3456H ;分配变量X、Y、Z、V QR DW ? ;存放商 REMAINDER DW ?;存放余数 DATA ENDS,要求:计算(V(X*YZ540)/X,例 代码段,CODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STACK MAIN PROC START: MOV AX,DATA MOV DS,AX ;
27、初始化DS MOV AX,X ;AXX IMUL Y;DX:AXX*Y MOV CX,AX MOV BX,DX;暂存在BX,CX中 MOV AX,Z CWD;Z扩展 ADD CX,AX ADC BX,DX;BX:CXX*YZ,例 代码段(续1),SUB CX,540 SBB BX,0;可能有借位 MOV AX,V CWD;扩展V SUB AX,CX SBB DX,BX IDIV X MOV QR,AX ;保存商 MOV REMAINDER,DX;保存余数,例 代码段(续2),MOV AH,4CH INT 21H;程序结束,返回到DOS MAIN ENDP;过程结束 CODE ENDS;码段结束
28、 END START;结束汇编,指定程序入口地址,举例顺序程序设计实例,data segment ASCIIdb 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h ;对应0 9的ASCII码 db 41h,42h,43h,44h,45h,46h ;对应A F的ASCII码 hexdb 04h,0bh ;假设两个数据 data ends,采用查表法,实现一位16进制数 转换为ASCII码显示,例代码段,code segment assume cs:code, ds:data start: mov ax, data mov ds, ax mov bx, offset
29、ASCII ;BX指向ASCII码表 mov al, hex ;AL取得一位16进制数 ;恰好就是ASCII码表中的位移 and al, 0fh ;只有低4位是有效的,高4位清0 xlat ;查表:ALDS:BXAL,例代码段(续),mov dl, al;入口参数:DLAL mov ah, 2;02号DOS功能调用 int 21h;显示一个ASCII码字符 mov al, hex+1;转换并显示下一个数据 and al, 0fh xlat mov dl, al mov ah, 2 int 21h mov ah, 4ch int 21h code ends end start,分支程序设计,分支
30、程序根据条件是真或假决定执行与否 判断的条件是各种指令,如CMP、TEST等执行后形成的状态标志 转移指令Jcc和JMP可以实现分支控制 分支结构有 单分支结构 双分支结构 多分支结构,单分支结构,条件成立跳转,否则顺序执行分支语句体 注意选择正确的条件转移指令和转移目标地址,实例:求绝对值,例计算AX中有符号数的绝对值,cmp ax,0 jge nonneg;条件满足(AX0),转移 neg ax;条件不满足,求补 nonneg:mov result,ax;条件满足,;不恰当的分支 cmp ax,0 jl yesneg;条件满足(AX0),转移 jmp nonneg yesneg:neg a
31、x;条件不满足,求补 nonneg:mov result,ax;条件满足,双分支结构,条件成立跳转执行第2个分支语句体,否则顺序执行第1个分支语句体 注意第1个分支体后一定要有一个JMP指令跳到第2个分支体后,实例:显示BX的最高位,例 显示BX的最高位,shl bx,1;BX最高位移入CF标志 jc one;CF1,即最高位为1,转移 mov dl,30h ;CF0,即最高位为0:DL30H0 jmp two;一定要跳过另一个分支体 one:mov dl,31h;DL 31H1 two:mov ah,2 int 21h;显示,可以用JNC替换JC,例显示BX的最高位(续),shl bx,1;
32、BX最高位移入CF标志 jnc one;CF0,即最高位为0,转移 mov dl,31h ;CF1,即最高位为1:DL31H1 jmp two;一定要跳过另一个分支体! one:mov dl,30h;DL 30H0 two:mov ah,2 int 21h;显示,转换为单分支结构,例 显示BX的最高位(另解),mov dl,0 ;DL30H0 shl bx,1;BX最高位移入CF标志 jnc two;CF0,即最高位为0,转移 mov dl,1 ;CF1,即最高位为1:DL31H1 two:mov ah,2 int 21h;显示,编写分支程序,需留心分支的开始和结束,例 显示BX的最高位(无分
33、支),mov dl,0 shl bx,1;BX最高位移入CF标志 adc dl,30h ;CF0,DL030h030H0 ;CF1,DL030h131H1 two:mov ah,2 int 21h;显示,例 显示压缩BCD码,无前导0,;数据段 BCDdb 04h ;代码段 mov dl,BCD test dl,0ffh;如果BCD码为0,显示0 jz zero;双分支结构 test dl,0f0h;如果BCD码高位为0,不显示0 jz one;单分支结构,例 显示压缩BCD码,无前导0(续),mov cl,4;处理高位 shr dl,cl or dl,30h;转换为ASCII码 mov ah
34、,2;显示高位 int 21h mov dl,BCD and dl,0fh one:or dl,30h;处理低位 jmp two zero:mov dl,0 two:mov ah,2 int 21h,多分支结构,多分支结构是多个条件对应各自的分支语句体,哪个条件成立就转入相应分支体执行,cmp ah,0 jz function0 cmp ah,1 jz function1 cmp ah,2 jz function2,例大小写字母转换,;如果DL是一个小写字母,则转换为大写 cmp dl,a;小于小写字母a,不需要处理 jb disp cmp dl,z;大于小写字母z,也不需要处理 ja dis
35、p sub dl,20h;是小写字母,则转换为大写 disp:,循环程序设计,循环程序结构是满足一定条件的情况下,重复执行某段程序 循环结构的程序通常有3个部分: 循环初始部分为开始循环准备必要的条件,如循环次数、循环体需要的数值等 循环体部分指重复执行的程序部分,其中包括对循环条件等的修改程序段 循环控制部分判断循环条件是否成立,决定是否继续循环,关键是什么?,循环控制,循环结构程序的设计关键是循环控制部分 循环控制可以在进入循环之前进行,也可以在循环体后进行,于是形成两种结构: “先判断、后循环”结构 “先循环、后判断”结构 循环结束的控制可以用循环次数,还可以用特定条件等,于是又有: 计
36、数控制循环 条件控制循环,先循环后判断的循环结构,计数控制循环,计数控制循环利用循环次数作为控制条件 易于采用循环指令LOOP和JCXZ实现 初始化:将循环次数或最大循环次数置入CX 循环体 循环控制:用LOOP指令对CX减1,并判断是否为0,例-用二进制显示BL内容,mov cx,8;CX8(循环次数) again:shl bl,1;左移进CF,从高位开始显示 mov dl,0;MOV指令不改变CF adc dl,30h;DL030HCF ;CF若是0,则DL 0 ;CF若是1,则DL 1 mov ah,2 int 21h;显示 loop again ;CX减1,如果CX未减至0,则循环,计
37、数控制循环 先循环后判断,例-求最大最小值,在16位带符号数中找出其中的最大值和最小值,分别放在MAX和MIN单元中。,again,next1,next2,BX-存储单元地址 AX-最大值 DX-最小值 CX-循环次数,例-求最大最小值(续),DATA SEGMENT BUFFER DW 100DUP(?);自定义N个数 COUNT EQU $-BUFFER MAX DW ?;保存最大值 MIN DW ?;保存最小值 DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA,定义数据,例-求最大最小值(续),START:MOV AX, DATA MOV DS
38、, AX MOV CX, COUNT SHR CX, 1 ;计算个数 LEA BX, BUFFER MOV AX, BX ;AX最大值初值 MOV DX, BX;DX最小值初值 DEC CX;循环次数减1,初始化,例-求最大最小值(续),AGAIN:ADD BX, 2 CMP AX, BX ;比较 JGE NEXT1 MOV AX, BX ;AX取得更大的数据 JMP NEXT2 NEXT1: CMP DX, BX JL NEXT2 MOV DX, BX;BX取得更小的数据 NEXT2:LOOP AGAIN;计数循环 MOV MAX, AX;保存最大值 MOV MIN, DX;保存最小值 MO
39、V AH, 4CH INT 21H CODE ENDS END START,循环体,条件控制循环,条件控制循环需要利用特定条件判断循环是否结束 条件控制循环用条件转移指令判断循环条件 转移指令可以指定目的标号来改变程序的运行顺序,如果目的标号指向一个重复执行的语句体的开始或结束,便构成了循环控制结构,例-显示以0结尾的字符串,;数据段 stringdb Let us have a try !,0 ;代码段 mov bx,offset string again:mov dl,bx cmp dl,0 jz done;为0结束 mov ah,2;不为0,显示 int 21h inc bx;指向下一个
40、字符 jmp again done:,条件控制循环 先判断后循环,例- 记录某个字存储单元数据中1的个数,;数据段 numberdw 1110111111100100B ;代码段 mov bx,number xor dl,dl;循环初值:DL0 again:cmp bx,0;也可以用test bx,0ffffh jz done ;全部是0就可以退出循环,减少循环次数 shl bx,1;用指令shr bx,1也可以 adc dl,0 ;利用ADC指令加CF的特点进行计数 jmp again,条件控制循环 先判断后循环,子程序设计,把功能相对独立的程序段单独编写和调试,作为一个相对独立的模块供程序
41、使用,就形成子程序 子程序可以实现源程序的模块化,可简化源程序结构,可以提高编程效率 主程序(调用程序)需要利用CALL指令调用子程序(被调用程序) 子程序需要利用RET指令返回主程序,过程定义和子程序编写,汇编语言中,子程序要用一对过程伪指令PROC和ENDP声明,格式如下: 过程名PROC NEAR|FAR ;过程体 过程名ENDP 可选的参数指定过程的调用属性。没有指定过程属性,则采用默认属性 NEAR属性(段内近调用)的过程只能被相同代码段的其他程序调用 FAR属性(段间远调用)的过程可以被相同或不同代码段的程序调用,子程序编写注意事项,子程序要利用过程定义伪指令声明 子程序最后利用R
42、ET指令返回主程序,主程序执行CALL指令调用子程序 子程序中对堆栈的压入和弹出操作要成对使用,保持堆栈的平衡 子程序开始应该保护使用到的寄存器内容,子程序返回前相应进行恢复 子程序应安排在代码段的主程序之外,最好放在主程序执行终止后的位置(返回DOS后、汇编结束END伪指令前),也可以放在主程序开始执行之前的位置,例用显示器功能调用输出一个字符的子程序,;主程序 mov al,?;主程序提供显示字符 call dpchar;调用子程序 ;子程序:显示AL中的字符 dpcharproc;过程定义,过程名为dpchar push ax;顺序入栈,保护寄存器 push dx mov dl,al m
43、ov ah,02h;02H号输出一个字符功能 int 21h pop dx;逆序出栈,恢复寄存器 pop ax ret;子程序返回 dpcharendp;过程结束,源程序,stack segment stack stack db 100 dup(?) stack ends data segment data ends code segment assume cs:code,ds:data,ss:stack start:mov ax, data mov ds,ax mov al,?;主程序提供显示字符 call dpchar;调用子程序 mov ax,4c00h int 21h,主程序部分,本程
44、序可不需要数据段,源程序(续),dpcharproc;过程定义,过程名为dpchar push ax;顺序入栈,保护寄存器 push dx mov dl,al mov ah,02h;02H号输出一个字符功能 int 21h pop dx;逆序出栈,恢复寄存器 pop ax ret;子程序返回 dpcharendp;过程结束 code ends end start,子程序安排在主程序执行终止后的位置,子程序编写注意事项(续),子程序允许嵌套和递归 子程序可以与主程序共用一个数据段,也可以使用不同的数据段(注意修改DS),还可以在子程序最后设置数据区(利用CS寻址) 子程序的编写可以很灵活,例如具
45、有多个出口(多个RET指令)和入口,但一定要保证堆栈操作的正确性 处理好子程序与主程序间的参数传递问题 提供必要的子程序说明信息,含数据区的子程序,;子程序HTOASC:十六进制数转换为ASCII码 HTOASCproc push bx mov bx,offset ASCII and al,0fh xlat CS:ASCII;换码:ALCS:BXAL pop bx ret ;数据区 ASCIIdb 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h db 41h,42h,43h,44h,45h,46h HTOASCendp,多出口子程序,;子程序HTOASC:十六进
46、制数转换为ASCII码 HTOASCproc and al,0fh cmp al,9 jbe htoasc1 add al,37h;是A F,加37H ret;子程序返回 htoasc1:add,30h;是0 9,加30H ret;子程序返回 HTOASCendp,参数传递,主程序与子程序间一个主要问题是参数传递 入口参数(输入参数) :主程序调用子程序时,提供给子程序的参数 出口参数(输出参数) :子程序执行结束返回给主程序的参数 参数的具体内容 传数值:传送数据本身 传地址:传送数据的主存地址 常用的参数传递方法 寄存器 共享变量 堆栈,(1) 用寄存器传递参数,最简单和常用的参数传递方法
47、是通过寄存器,只要把参数存于约定的寄存器中就可以了 由于通用寄存器个数有限,这种方法对少量数据可以直接传递数值,而对大量数据只能传递地址 采用寄存器传递参数,注意带有出口参数的寄存器不能保护和恢复,带有入口参数的寄存器可以保护、也可以不保护,但最好能够保持一致,(2) 用共享变量传递参数,子程序和主程序使用同一个变量名存取数据就是利用共享变量(全局变量)进行参数传递 如果主程序还要利用原来的变量值,则需要保护和恢复 利用共享变量传递参数,子程序的通用性较差,但特别适合在多个程序段间、尤其在不同的程序模块间传递数据,利用存储单元传递参数举例,例:数据块间的搬移。,利用子程序来实现数据块间的搬移。
48、 设参数传递采用指定内存单元传递方式,且SRCADR中存放源数据块首地址,DSTADR中存放目的数据块首地址,LEN中存放数据块字节数。,数据块之间的三种情况,数据块之间的三种情况(续),对于(A)的情况可分别从首(末)地址开始传送; 而对(B)、(C) 两种情况由于有重叠区,应分别对待。 当源数据块首址大于目标块首址时,应从数据首址开始传数,如(C) 当源数据块首址小于目标块首址时,应从数据末址开始传数,如(B) 目的在于避免在传数时将重叠区源数据块的数据冲掉。,主程序,STACK SEGMENT PARA STACK STACK DB 100 DUP (?) STACK ENDS DATA
49、 SEGMENT DAT DB 100 DUP (?) SRCADR DD DAT DSTADR DD DAT+20 ;注意有重叠! LEN DW 50 DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA, ES:DATA, SS:STACK START: MOV AX, DATA MOV DS, AX MOV ES, AX CALL MYMOVE MOV AH, 4CH INT 21H,子程序,MYMOVE PROC LDS SI, SRCADR; SI源数据块首地址 LES DI, DSTADR; DI目的数据块首地址 MOV CX, LEN; C
50、X长度 CLD CMP SI, DI ; (SI)大于(DI)吗? JA DONE ;大于,则转至DONE,首址传数(如C) STD ;小于,末址传数(如B) ADD SI, CX DEC SI ADD DI, CX DEC DI DONE: REP MOVSB RET MYMOVE ENDP CODE ENDS END START,3. 用堆栈传递参数,参数传递还可以通过堆栈这个临时存储区。主程序将入口参数压入堆栈,子程序从堆栈中取出参数;子程序将出口参数压入堆栈,主程序弹出堆栈取得它们 采用堆栈传递参数是程式化的,它是编译程序处理参数传递、以及汇编语言与高级语言混合编程时的常规方法,利用堆栈传递参数举例,例:求两个16位数的和。,CODE SEGMENT ASSUME CS:CODE, DS:CODE, SS:CODE START: JMP MAIN DAT1 DW 100 DAT2 DW 200 SUM DW ? MAIN: MOV AX, CODE MOV DS, AX MOV AX, DAT1;将DAT1压入堆栈 PUSH AX MOV AX, DAT2;将DAT2压入堆栈 PUSH AX CALL ADDITI
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 专业中介合同范本
- 联营服装合同范本
- 修建木房合同范本
- 减肥合同范本6
- 危房鉴定合同范本
- 卸车合同范本
- 大鹏新区打井施工合同范本
- 酒吧消防合同范本
- 三峡工程水泥购销合同范本
- wuhan 租房合同范本
- 小学生劳动课炒菜教案(精选8篇)
- 高考作文模拟写作:“德”与“得”导写及范文
- 江苏专转本《大学语文》考纲
- 中国青瓷艺术鉴赏智慧树知到答案章节测试2023年丽水学院
- 2023年小学数学手抄报比赛活动总结(3篇)
- 2023年版一级建造师-水利工程实务电子教材
- 中国当代文学智慧树知到答案章节测试2023年青岛滨海学院
- 新生儿窒息复苏抢救流程演练
- 项目管理 项目管理
- GB/T 5668.1-1995旋耕机械
- GB/T 3634.2-2011氢气第2部分:纯氢、高纯氢和超纯氢
评论
0/150
提交评论