微机原理与接口技术 第三章 8086CPU指令系统 - Xidian2018/11/06 · 4.9...
Transcript of 微机原理与接口技术 第三章 8086CPU指令系统 - Xidian2018/11/06 · 4.9...
汇编语言基本概念1
2
3
8086的六类指令4
总结5
汇编语言指令分类
数据与转移地址的寻址方式
汇编语言基本概念1
2
3
8086的六类指令4
总结5
汇编语言指令分类
数据与转移地址的寻址方式
4. 8086的指令系统
b 数据传送指令
b 算术运算指令
b 逻辑运算指令
b 移位、循环指令
b 串操作指令
b 控制转移指令
b 处理器控制指令
子程序调用返回指令
• 3.11子程序的调用返回指令
• 4.5子程序设计技术
4.9 子程序调用和返回指令
子程序:功能确定、且独立的程序段。
缺点:
采用子程序设计后。由于调用子程序和从子程序中返回需要执行指令,并且为保护某些寄存器的内容,需要进行压入堆栈和弹出堆栈的操作,
因此会使程序执行速度受到一定的影响。
优点:
1.可以将任何一段独立的程序归整为一个子程序,当需要该段程序时,只需调用子程序即可,调用后会自动返回到调用指令的下一条指令。因此采用子程序设计时,可以简化程序设计。
2.从调试程序的角度,由于原本在多处出现的程序段,缩减为子程序调用指令,使调试程序更加方便。
1.子程序(过程)的概念
4.9 子程序调用和返回指令
过程定义格式:
过程名 PROC [类型]
……
RET
过程名 ENDP
• PROC与ENDP成对使用;
• PROC与ENDP左侧过程名字一致;
• RET:近程返回;RETF:远程返回,但RETF可以写成RET
2.子程序(过程)的定义
4.9 子程序调用和返回指令2.子程序(过程)的定义
一个子程序名一但定义,就具有以下三个属性
段地址
段内偏移地址
类型
FAR
NEAR(可缺省)
就是子程序第一条指令的地址
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
实现:
子程序调用是通过自动修改(IP)和/或(CS)的内容实现的。
为了确保子程序调用后能够返回到调用指令之后
CALL指令会自动保存返回地址,CS、IP分别入栈
而RET指令会自动返回到CALL指令的下一条指令。
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
• 子程序调用指令CALL
子程序调用指令CALL(Call procedure)有两种格式:
CALL LABEL ;直接调用,调用入口地址为标号
LABEL的子程序
CALL OPR ;间接调用,调用入口地址为操作出OPR
的内容
CALL指令与JMP指令本质都为无条件跳转指令。
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
• 子程序调用指令CALL
对于以下格式:
CALL LABEL ;调用入口地址为标号LABEL的
子程序
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
分两种情况:
(1)指令的寻址方式为段间直接寻址,即当标号LABEL
与CALL指令不在同一个段内时,子程序调用在段间
进行;
其完成的操作有:
CS入栈,IP入栈;
(IP)←LABEL的偏移地址;
(CS)←LABEL的段地址。
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
分两种情况:
(2)指令的寻址方式为段内直接寻址,也称为相对寻址。
即当标号LABEL与CALL指令在同一个段内,且可以
采用8位/16位有符号数表示其相对位移量时,则子程
序调用在段内进行;
其完成的操作有:
IP入栈;
(IP)←(IP)+DISP8/DISP16 。
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
• 子程序调用指令CALL
对于以下格式:
CALL OPR ;调用子程序,其入口地址为操
作数OPR的内容
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
分两种情况:
(1)指令的寻址方式为段内间接寻址,即当OPR为16位
的通用REG/ 16位MEM单元时,则子程序调用在段内
进行;
其完成的操作有:
IP入栈;
(IP)←(REG16)/MEM。
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
分两种情况:
(2)指令的寻址方式为段间间接寻址,即当OPR为32位
的MEM单元时,则子程序调用在段间进行;
其完成的操作有:
CS入栈,IP入栈;
(IP)←(MEM),(CS)←(MEM+2)。
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
• 子程序返回指令RET
子程序返回指令RET(Return from procedure)有三种格式:
RET ;用于段内子程序的返回,完成IP 出栈,
即(IP)←(SP)
RETF ;用于段间子程序的返回,完成IP 出栈,CS 出栈
RET n ;完成RET(或RETF)指令功能后,(SP)←(SP)+n
补充内容
系统占用
INT 20H程序段前缀
用户数据区
用户堆栈区
用户代码段
…………
系统和ROM占用
• 用户程序的代码前一定有100个字节的程序段
前缀(Program Segment Prefix, 简称PSP),PSP
给出了用户的可执行文件(.EXE)的若干控制信
息。
• 其中PSP的开始处(第1,2字节)有一条中断指
令INT 20H的代码,通过它可以结束用户程序,
返回操作系统。
• 在用户程序执行完以后,通过执行INT 20H指
令就可以返回DOS。
4.1.3 8086汇编语言的完整结构
00000H
100个
字节
用户程
序空间
FFFFFH
4.1.3 8086汇编语言的完整结构每当一个用户的可执行文件.EXE装入内存后,存储器的分配情况如图:
系统占用
程序段前缀
用户数据区
用户堆栈区
用户代码段
…………
系统和ROM占用
DAT1 SEGMENTBUFFER DB ‘??????’
DAT1 ENDSCODE SEGMENT
ASSUME DS:DAT1, CS:CODE START:
……CALL NEAR PTR SUB1
…SUB1 PROC NEAR…RET ;SUB1 ENDP
CODE ENDSEND START
逐行编译
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回-段内调用与返回
DATA SEGMENT
DATA ENDSCODE SEGMENT
ASSUME DS:DATA, CS:CODE
START:MOV AX, DATA MOV DS, AX
CODE ENDS
END START
……
……
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回-段内调用与返回
……
…
;子程序SUB1SUB1 PROC NEAR
RET ;SUB1 ENDPCODE ENDSEND START
CALL NEAR PTR SUB1……
可以省略
• IP←((SP)) • SP←(SP)+2
① SP←(SP)-2② ((SP))←返回地址(IP)③ IP←(IP)+16位DISP
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回-段内调用与返回
4. 8086的指令系统
;主程序CODEP SEGMENT
ASSUME CS:CODEMSTART:
CALL FAR PTR SUB2
MOV AH,4CHINT 21H
CODEP ENDS
……
;子程序CODES SEGMENT
ASSUME CS:CODESSUB2 PROC FAR
RETF ;也可以写成RETSUB2 ENDPCODES ENDS
END START
……
①IP←((SP));SP←(SP)+2②CS←((SP));SP←(SP)+2
①SP←(SP)-2;((SP))←返回地址(CS)②SP←(SP)-2;((SP))←返回地址(IP)③IP←OFFSET SUB2; CS←SEG SUB2
3.子程序(过程)的调用与返回-段间调用与返回
4.9 子程序调用和返回指令4.信息的保护与恢复
必要性:
1. CS/IP是子程序正确返回的必要条件
2. 主程序/子程序运行时,其他REG均有可能存有数据,
后被子程序/主程序使用
实现:
1. 信息的保护与恢复可在主程序或者子程序中完成;
2. 信息的保护与恢复常在子程序中进行,利用PUSH-
POP指令在Stack中进行
3. PUSH-POP指令应成对使用,确保RET指令正确返回
4.9 子程序调用和返回指令5.主程序与子程序间参数的传递
入口参数:在设计子程序时,需要从主程序获取数据
出口参数:子程序执行后可能有结果数据要送给主程序
• 主程序与子程序之间对入口参数和出口参数的传递有四种
情况(一般在子程序中完成):
(一)不进行任何参数传递
(二)寄存器参数传递方式(简单,但数量有限)
(三)存储单元参数传递方式(麻烦,需CODE段预定义)
(四)堆栈参数传递方式(麻烦,需注意SP的变化)
4.9 子程序调用和返回指令5.主程序与子程序见参数的传递
不进行任何参数传递
例:一个延时子程序,其过程可定义如下:
SOFTDLY PROCPUSH BXPUSH CXMOV BL,10 ;粗调
DELAY:MOV CX,2801 ;细调
WAIT: LOOP WAITDEC BLJNZ DELAY
POP CXPOP BXRET
SOFTDLY ENDP
4.9 子程序调用和返回指令6.子程序说明文件
为使子程序对任一程序员有可读性、可维护性、可扩展性,
应该及时给子程序编写相应的说明文件。
其内容应该包含下列6个部分(必须用;隔开):
;1、子程序名:便于理解、阅读
;2、子程序所完成的功能:便于判断是否符合自己需求
;3、入口参数及其传递方式(三种传递方式)
;4、出口参数及其传递方式(三种传递方式)
;5、子程序用到的寄存器/MEM单元:便于做信息保护
;6、典型例子(通常省略)
4.9 子程序调用和返回指令7.子程序的嵌套
在子程序中还可以调用其他的子程序,这时就形成子程序的嵌
套。
在设计嵌套子程序时:从上到下设计
调试时嵌套子程序时:由下至上进行,保证下方子程序返回的
结果正确
当前IP当前IP
4.9 子程序调用和返回指令8.子程序的递归(在实际设计中很少使用)
在嵌套调用中,被调用的子程序为其他子程序。当被调用的子程序是其自身时,就形成了递归调用,这种子程序称为递归子程序。不是所有的子程序都可以递归调用的,设计递归子程序是一个较为复杂的过程,递归子程序必须具备两个基本条件:(1)采用堆栈参数传递方式,这样才能保证本次调用与下
次调用采用不同的参数,即每次调用给入口和出口参数都分配不同的存储区域。(2)必须设定递归结束条件。设计递归子程序还应该有清晰的编程思路和明确的程序结
构。设计递归子程序可以降低程序对存储容量需求(但现在计算机的存储容量已经不是问题了)
用户应该尽量避免采用递归子程序。
4.9 子程序调用和返回指令9.子程序的可再入性
在执行子程序期间,CPU可能会因为有中断请求而转向中断服务子程序,如果在中断服务程序中又调用了该子程序,这样就形成了如图所示的情况(①②③为执行流程),子程序的一次调用还没有执行完成,又调用了该子程序,如果这两次调用都能够得到正确的结果,则该子程序称为可再入性子程序。
子
程
序
第一次调用
X发生中断
1
23
第二次调用
图4.4 可再入性子程序执行流程
• 可再入性子程序也需要采用堆栈参数传递方式,
而且设计过程较为复杂,因此建议用户尽量避免设计可再入性子程序。
• 回避方式:将原本要求为可再入性的子程序复制一份,专门供中断服务子程序调用,这样可以巧妙地回避可再入性子程序的设计。
4.9 子程序调用和返回指令
【P63】例3.32 子程序设计,编写子程序实现统计一个
字(AX)中“1”的个数。
解1:利用移位指令或循环移位指令,每次对CF位进行
检测位:
当CF=1时,则总个数加1;
当CF=0时,则总个数不变。
这种操作可以采用有条件转移指令来实现
但更方便的方式是采用ADC指令实现。
子程序如下:
10.应用举例
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回
COUNTER1 PROC NEARPUSH AXPUSH CX
MOV CX,16XOR BL,BL
COU1:SHR AX,1ADC BL,0LOOP COU1
POP CXPOP AXRET
COUNTER1 ENDP
4.6 循环指令
【P63】例3.32:统计(BX)中‘1’的个数
解2:MOV CX,16
MOV AX,0
L2: SHR BX,1
JNC L1
INC AX
L1:LOOP
解3:MOV CX,16MOV AX,0
L2: CMP BX,0JZ EXIT SHR BX,1 JNC L1INC AX
L1: LOOP L2 EXIT:
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回-段内调用与返回
【P63】例3.33 子程序应用。利用上例设计的子程序,统计字型变量VAR1中1的个数。解:在数据段中定义变量VAR1和CounterVar1:
VAR1 DW 1234HCounterVar1 DB ?
则可在代码段中编写程序:MOV AX, VAR1CALL COUNTER1MOV CounterVar1,BL
执行后,结果单元CounterVar1的值为5,说明1234H中包含有5个“1”。
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回-段内调用与返回
【P64】例3.34 编写以十六进制数显示AL和AX内容的子
程序(DISPAL、DISPAX)。
解:先编写显示AL寄存器内容的子程序DISPAL。
(1)如何将一个十六进制数转换成ASCII码
(2)AL中有两位十六进制数,如何分别显示
(3)如何在屏幕上显示一个ASCII码字符
调用INT 21H的02H号功能进行显示。
需要考虑三个方面
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回-段内调用与返回
CHANG PROC NEAR ;CMP AL,10JNGE CHANG1; ‘0’~‘10’ADD AL,7 ; ‘A’~‘F’
CHANG1:ADD AL,30H; 将数字转换为ASCII码RET
CHANG ENDP
子程序1:CHANG,十六进制数变换成ASCII码
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回-段内调用与返回
DISPAL PROC NEARPUSH AXPUSH CXPUSH DXPUSH AXMOV CL,4 ;处理高位十六进制数SHR AL,CLCALL CHANG ;十六进制数变换成ASCII码MOV AH,02HMOV DL,ALINT 21H
DOS 系统中断功能
P 381 附录B;显示DL中的一位ASCII码
代表功能
子程序2:DISPAL, 通过调用CHANG将AL的内容显示出来
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回-段内调用与返回
POP AXAND AL,0FH ;处理低位十六进制数CALL CHANG ;十六进制数变换成ASCII码MOV AH,02MOV DL,ALINT 21H ;显示一位字符POP DXPOP CXPOP AXRET
DISPAL ENDP
4.9 子程序调用和返回指令3.子程序(过程)的调用与返回-段内调用与返回
DISPAX PROC NEARXCHG AL,AHCALL DISPALXCHG AH,ALCALL DISPAL
RETDISPAX ENDP
子程序3:DISPAX, 通过调用DISPAL,实现将AX的内容显示出来
4.9 子程序调用和返回指令10.应用举例
【P109】例4.9 编写子程序实现给缓冲区BUF中的一组字符的
ASCII码加上偶校验位。
1. 缓冲区位置:MEM单元中;
2. ASCII码:每个字符的ASCII码只占用7位二进制数,其
最高位为0;
3. 偶校验:根据这7位二进制数中“1”的个数,给最高位
加上“0”或“1”,使得一个字节内容的“1”个数为偶
数,这称为偶检验;
4. 未定义字符的长度:自己定义
4.9 子程序调用和返回指令10.应用举例
【P109】例4.9 编写子程序实现给缓冲区BUF中的一组字符的
ASCII码加上偶校验位。
设计的子程序(SETEVEN)用于对BUFFER中的字符
ASCII码加上偶检验位
其入口参数为:DI(缓冲区首地址,默认为DS段),
(CX)缓冲区长度;
出口参数:无(实际上是缓冲区的内容);
用到的寄存器:无。
汇编语言程序如下:
4.9 子程序调用和返回指令
程序基本结构
循环检测+置0/1SETEVEN
“1”奇偶数个判断COUNTBYTE
4.9 子程序调用和返回指令
开始
结束
右移一位
右移位相加
SHR (CF)
BL
BL
CX
开始
取一个DB单元
判断奇偶(子)
重置原MEM单元
结束
CX奇(OR) 置1 偶不变
AX
BL
LOOP
SUB2:COUNTBYTE
JZ
AX/DI
BL
DI/AX 保持原MEM单元
SUB 1:SETEVEN
4.9 子程序调用和返回指令
程序基本结构可直接转化为代码
循环检测+置0/1SETEVEN
“1”奇偶数个判断COUNTBYTE
4.9 子程序调用和返回指令STACK SEGMENT STACK 'STACK'
DW 100H DUP(?)
TOP LABEL WORD
STACK ENDS
N=22
DATA SEGMENT
BUFFER DB 'xidian university '
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
ASSUME ES:DATA,SS:STACK
4.9 子程序调用和返回指令START:
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV AX,STACK
MOV SS,AX
LEA SP,TOP
MOV CX,N
LEA DI,BUFFER
CALL SETEVEN
MOV AH,4CH
MOV AL,0
INT 21H
子程序SETEVEN
……
CALL COUNTBYTE
子程序COUNTBYTE
……
CODE ENDS
END START
段定义
设置子程序1入口参数
返回DOS
子程序1
子程序2
代码段完
4.9 子程序调用和返回指令
开始
结束
右移一位
右移位相加
SHR (CF)
BL
BL
CX
AX
SUB2:COUNTBYTE
COUNTBYTE PROC NEAR;
PUSH AX
PUSH CX
MOV CX,8
XOR BL,BL
COU1: SHR AL,1
ADC BL,0
LOOP COU1
POP CX
POP AX
RET
COUNTBYTE ENDP
CODE ENDS
END START
信息保护
信息恢复
4.9 子程序调用和返回指令
开始
取一个DB单元
重置原MEM单元
结束
CX奇(OR) 置1 偶不变
BL
LOOP
JZBL
保持原MEM单元
SUB 1:SETEVEN
判断奇偶(子)
SETEVEN PROC NEAR;PUSH AXPUSH BXPUSH CXPUSH DI
SETEVEN1:MOV AL,[DI]CALL COUNTBYTEAND BL,01H;JZ SETEVEN2OR AL,80H; 最高位置入“1”MOV [DI],AL
SETEVEN2:INC DILOOP SETEVEN1POP DIPOP CXPOP BXPOP AXRET
SETEVENENDP
信息保护
信息恢复
4.5 子程序设计
SETEVEN PROC NEAR;偶校验子程序PUSH AXPUSH BXPUSH CXPUSH DI
SETEVEN1:MOV AL,[DI]CALL COUNTBYTEAND BL,01H;测试“1”的个数
;是否为偶数JZ SETEVEN2OR AL,80H;最高位置入“1”MOV [DI],AL
SETEVEN2:INC DILOOP SETEVEN1POP DIPOP CXPOP BXPOP AXRET
SETEVENENDP
COUNTBYTE PROC NEAR;子程序:统计一个字
;节内容中“1”的个数PUSH AXPUSH CXMOV CX,8XOR BL,BL
COU1: SHR AL,1ADC BL,0LOOP COU1POP CXPOP AXRET
COUNTBYTE ENDPCODE ENDS
END START
被子程序调用的子程序,参数传
递用的BL
用REG做子程序间参数传递
请注意观察堆栈的变化
4.9 子程序调用和返回指令STACK SEGMENT STACK 'STACK'
DW 100H DUP(?)
TOP LABEL WORD
STACK ENDS
N=22
DATA SEGMENT
BUFFER DB 'xidian university '
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
ASSUME ES:DATA,SS:STACK
4.9 子程序调用和返回指令START:
MOV AX,DATAMOV DS,AXMOV ES,AXMOV AX,STACKMOV SS,AXLEA SP,TOPMOV CX,NLEA DI,BUFFERCALL SETEVENMOV AH,4CH MOV AL,0INT 21H
子程序SETEVEN……CALL COUNTBYTE
子程序COUNTBYTE……
CODE ENDSEND START
COUNTBYTE PROC NEAR;
PUSH AX
PUSH CX
……
POP CX
POP AX
RET
COUNTBYTE ENDP
CODE ENDS
END START
SETEVEN PROC NEAR;
PUSH AX
PUSH BX
PUSH CX
PUSH DI
……
CALL COUNTBYTE
……
POP DI
POP CX
POP BX
POP AX
RET
SETEVENENDP
用MEM单元做子程序间参数传递
请注意观察堆栈的变化
4.9 子程序调用和返回指令STACK SEGMENT STACK 'STACK'
DW 100H DUP(?)TOP LABEL WORDSTACK ENDS
N=22DATA SEGMENT
BUFFER DB 'xidian university ‘DATA1 DW ?DATA2 DW ?
DATA ENDSCODE SEGMENT
ASSUME CS:CODE,DS:DATA ASSUME ES:DATA,SS:STACK
4.9 子程序调用和返回指令START:
段初始化MOV CX, NMOV DAT2, CXLEA DI,BUFFER MOV DAT1, DICALL SETEVENMOV AH,4CH MOV AL,0INT 21H
子程序SETEVEN……CALL COUNTBYTE
子程序COUNTBYTE……
CODE ENDSEND START
COUNTBYTE PROC NEAR;
PUSH AX
PUSH CX
……
POP CX
POP AX
RET
COUNTBYTE ENDP
CODE ENDS
END START
SETEVEN PROC NEAR;
PUSH AX
PUSH BX
PUSH CX
PUSH DI
MOV CX, DAT2
MOV SI, DAT1……
CALL COUNTBYTE……POP DI
POP CX
POP BX
POP AX
RET
SETEVENENDP
用STACK做子程序间参数传递
请注意观察堆栈的变化
4.9 子程序调用和返回指令STACK SEGMENT STACK 'STACK'
DW 100H DUP(?)TOP LABEL WORDSTACK ENDS
N=22DATA SEGMENT
BUFFER DB 'xidian university ‘DATA ENDSCODE SEGMENT
ASSUME CS:CODE,DS:DATA ASSUME ES:DATA,SS:STACK
4.9 子程序调用和返回指令START:
段初始化MOV CX, NPUSH CXLEA DI,BUFFER PUSH DICALL SETEVENMOV AH,4CH MOV AL,0INT 21H
子程序SETEVEN……CALL COUNTBYTE
子程序COUNTBYTE……
CODE ENDSEND START
对需要传递的参数(CS、SI)进
行压栈之后,堆栈如何变化?
CXSI
IPAXBX
CXSIBP
SETEVEN PROC NEAR;PUSH AXPUSH BXPUSH CXPUSH DIPUSH BPMOV BP, SPMOV DI, [BP]+0CHMOV CX, [BP]+0EH……
CALL COUNTBYTE……POP BPPOP DIPOP CXPOP BXPOP AXRET
SETEVEN ENDP
SS:(BP)
(BP)+2
(BP)+4
(BP)+6
(BP)+8
(BP)+AH
(BP)+CH
(BP)+EH4
4.9 子程序调用和返回指令
例:CPU执行RET 4时,SP=?
CPU执行RET 4后,SP=?
CPU执行段间返回指令RET 4后,SP=?
【P63】3.11.2 带参数的返回指令
RET n
例:语句 RET 3是否正确?为什么?
;n肯定为偶数
4.9 子程序调用和返回指令COUNTBYTE PROC NEAR;
PUSH AX
PUSH CX
……
POP CX
POP AX
RET
COUNTBYTE ENDP
CODE ENDS
END START
第二段子程序也可以实现用堆栈传递参数,不详解