420 likes | 627 Views
第 5 章 程序设计基本技术 (1). 分支结构程序设计. 教学重点. 综合应用第 3 章硬指令和第 4 章伪指令,第 5 章从程序结构角度展开程序设计,重点掌握: 分支结构程序设计. 5.1 概 述. 重点介绍:. 1 汇编语言程序设计基本步骤 2 结构化程序的概念 3 流程图画法规定. 5.2 顺序程序设计. 顺序程序完全按指令书写的前后顺序执行每一条指令,是最基本、最常见的程序结构. 例 5.1 计算. 例 5.2 移位. 5.3 分支程序设计. 分支程序根据条件是真或假决定执行与否
E N D
第5章 程序设计基本技术(1) 分支结构程序设计 教学重点 综合应用第3章硬指令和第4章伪指令,第5章从程序结构角度展开程序设计,重点掌握: 分支结构程序设计
5.1 概 述 重点介绍: • 1 汇编语言程序设计基本步骤 • 2 结构化程序的概念 • 3 流程图画法规定
5.2 顺序程序设计 • 顺序程序完全按指令书写的前后顺序执行每一条指令,是最基本、最常见的程序结构 例5.1 计算 例5.2 移位
5.3 分支程序设计 • 分支程序根据条件是真或假决定执行与否 • 判断的条件是各种指令,如CMP、TEST等执行后形成的状态标志 • 转移指令Jcc和JMP可以实现分支控制;还可以采用MASM 6.x提供的条件控制伪指令实现 单分支:求绝对值等 双分支:例5.3等 多分支:例5.4等
一 转移指令 • 控制转移类指令用于实现分支、循环、过程等程序结构,是仅次于传送指令的最常用指令 重点掌握:JMP/Jcc • 转移类指令通过改变IP(和CS)值,实现程序执行顺序的改变
1 无条件转移指令 JMP JMP label ;程序转向label标号指定的地址 • 只要执行无条件转移指令JMP,就使程序转到指定的目标地址处,从目标地址处开始执行那里的指令 • 操作数label是要转移到的目标地址(目的地址、转移地址) • JMP指令分成4种类型: ⑴ 段内转移、直接寻址 ⑵ 段内转移、间接寻址 ⑶ 段间转移、直接寻址 ⑷ 段间转移、间接寻址
目标地址的寻址方式 JMP 用标号表达 • 直接寻址方式 • 转移地址象立即数一样,直接在指令的机器代码中,就是直接寻址方式 • 间接寻址方式 • 转移地址在寄存器或主存单元中,就是通过寄存器或存储器的间接寻址方式 用寄存器或存储器操作数表达
目标地址的范围:段内 代码段 代码段 JMP • 段内转移——近转移(near) • 在当前代码段64KB范围内转移( ±32KB范围) • 不需要更改CS段地址,只要改变IP偏移地址 • 段内转移——短转移(short) • 转移范围可以用一个字节表达,在段内-128~+127范围的转移
目标地址的范围:段间 JMP • 段间转移——远转移(far) • 从当前代码段跳转到另一个代码段,可以在1MB范围 • 需要更改CS段地址和IP偏移地址 • 目标地址必须用一个32位数表达,叫做32位远指针,它就是逻辑地址 代码段 代码段 • 实际编程时,汇编程序会根据目标地址的距离,自动处理成短转移、近转移或远转移 • 程序员可用操作符short、near ptr 或far ptr 强制
段内转移、直接寻址 JMP 实际为相对寻址 JMP label ;IP←IP+位移量 • 位移量是紧接着JMP指令后的那条指令的偏移地址,到目标指令的偏移地址的地址位移 • 当向地址增大方向转移时,位移量为正;向地址减小方向转移时,位移量为负 jmp again;转移到again处继续执行 …… again:dec cx;标号again的指令 …… jmp output;转向output …… output:mov result,al;标号output的指令
段内转移、间接寻址 JMP r16/m16 ;IP←r16/m16 • 将一个16位寄存器或主存字单元内容送入IP寄存器,作为新的指令指针,但不修改CS寄存器的内容 jmp ax ;IP←AX jmp word ptr [2000h] ;IP←[2000h] JMP JMP
段间转移、直接寻址 JMP JMP far ptr label ;IP←label的偏移地址 ;CS←label的段地址 • 将标号所在段的段地址作为新的CS值,标号在该段内的偏移地址作为新的IP值;这样,程序跳转到新的代码段执行 jmp far ptr otherseg ;远转移到代码段2的otherseg
段间转移、间接寻址 JMP JMP far ptr mem ;IP←[mem],CS←[mem+2] • 用一个双字存储单元表示要跳转的目标地址。这个目标地址存放在主存中连续的两个字单元中的,低位字送IP寄存器,高位字送CS寄存器 mov word ptr [bx],0 mov word ptr [bx+2],1500h JMP far ptr [bx] ;转移到1500h:0
2 条件转移指令 Jcc Jcc label ;条件满足,发生转移:IP←IP+8位位移量 ;条件不满足,顺序执行 • 指定的条件cc如果成立,程序转移到由标号label指定的目标地址去执行指令;条件不成立,则程序将顺序执行下一条指令 • 操作数label是采用短转移,称为相对寻址方式
相对寻址方式 Jcc • Jcc指令的操作数label是一个标号 • 一个8位位移量,表示Jcc指令后的那条指令的偏移地址,到目标指令的偏移地址的地址位移 • 8位位移量是相对于当前IP的,且距当前IP地址-128~+127个单元的范围之内,属于段内短距离转移 • Jcc目标地址就采用这种相对寻址方式 • Jcc指令为2个字节,条件不满足时的顺序执行就是当前指令偏移指针IP加2
Jcc指令的分类 Jcc • Jcc指令不影响标志,但要利用标志(下表)。根据利用的标志位不同,16条指令分成3种情况: 1. 判断单个标志位状态 2. 比较无符号数高低 3. 比较有符号数大小
Jcc 条件转移指令中的条件cc • 实际虽然指令只有16条,但却有30个助记符 • 采用多个助记符,只是为了方便记忆和使用
1. 判断单个标志位状态 Jcc • 这组指令单独判断5个状态标志之一 ⑴JZ/JE和JNZ/JNE:利用零标志ZF,判断结果是否为零(或相等) ⑵JS和JNS:利用符号标志SF,判断结果是正是负 ⑶JO和JNO:利用溢出标志OF,判断结果是否产生溢出 ⑷JP/JPE和JNP/JPO:利用奇偶标志PF,判断结果中“1”的个数是偶是奇 ⑸JC/JB/JNAE和JNC/JNB/JAE:利用进位标志CF,判断结果是否进位或借位 例题5.38 例题5.39 例题5.40 例题5.41 例题5.42
2 比较无符号数高低 Jcc • 无符号数的大小用高(Above)低(Below)表示 • 利用CF确定高低、利用ZF标志确定相等(Equal) • 两数的高低分成4种关系: ⑴ 低于(不高于等于):JB(JNAE) ⑵ 不低于(高于等于):JNB(JAE) ⑶ 低于等于(不高于):JBE(JNA) ⑷ 不低于等于(高于):JNBE(JA)
例5.43a:比较无符号数 cmp ax,bx ;比较ax和bx jnb next;若ax≥bx,转移 xchg ax,bx ;若ax<bx,交换 next: ... 结果:AX保存较大的无符号数
3 比较有符号数大小 Jcc • 有符号数的大(Greater)小(Less)需要组合OF、SF标志,并利用ZF标志确定相等(Equal) • 两数的大小分成4种关系: ⑴ 小于(不大于等于):JL(JNGE) ⑵ 不小于(大于等于):JNL(JGE) ⑶ 小于等于(不大于):JLE(JNG) ⑷ 不小于等于(大于):JNLE(JG)
例5.43b:比较有符号数 cmp ax,bx ;比较ax和bx jnl next;若ax≥bx,转移 xchg ax,bx ;若ax<bx,交换 next: ... 结果:AX保存较大的有符号数
第5章 二 单分支程序设计 • 条件成立跳转,否则顺序执行分支语句体;注意选择正确的条件转移指令和转移目标地址
例题 求绝对值 • Good ;计算AX的绝对值 cmp ax,0 jns nonneg ;分支条件:AX≥0 neg ax ;条件不满足,求补 nonneg:mov result,ax ;条件满足 ;计算AX的绝对值 cmp ax,0 jl yesneg ;分支条件:AX<0 jmp nonneg yesneg:neg ax ;条件不满足,求补 nonneg: mov result,ax ;条件满足 • Bad
例题 无符号数除以2 ;将AX中存放的无符号数除以2,如果是奇数,则加1后除以2 test ax,01h ;测试AX最低位 jz even ;最低位为0:AX为偶数 add ax,1 ;最低位为1:AX为奇数,需要加1 even: rcr ax,1 ;AX←AX÷2 ;如果采用SHR指令,则不能处理AX=FFFFH的特殊情况
第5章 三 双分支程序设计 条件成立跳转执行第2个分支语句体,否则顺序执行第1个分支语句体。注意第1个分支体后一定要有一个JMP指令跳到第2个分支体后
例题 显示BX最高位 对比 shl bx,1 ;BX最高位移入CF jc one ;CF=1,即最高位为1,转移 mov dl,’0’ ;CF=0,即最高位为0,DL←’0’ jmp two;一定要跳过另一个分支体 one: mov dl,’1’;DL←’1’ two: mov ah,2 int 21h ;显示 • 双分支程序改为单分支程序
例题 显示BX最高位 对比 shl bx,1 ;BX最高位移入CF jnc one ;CF=0,即最高位为0,转移 mov dl,’1’ ;CF=1,即最高位为1,DL←’1’ jmp two;一定要跳过另一个分支体 one: mov dl,’0’;DL←’0’ two: mov ah,2 int 21h ;显示 • 双分支程序改为单分支程序
例题 显示BX最高位 mov dl,’0’;DL←’0’ shl bx,1 ;BX最高位移入CF jnc two ;CF=0,最高位为0,转移 mov dl,’1’;CF=1,最高位为1,DL←’1’ two: mov ah,2 int 21h ;显示 • 编写分支程序,需留心分支的开始和结束
例题 单分支和双分支 ;寄存器AL中是字母Y或y,则令AH=0;否则令AH=-1 cmp al,’Y’;AL是大写Y否? jz next ;是,转移 cmp al,’y’;AL是小写y否? jz next ;是,转移 mov ah,-1 ;不是Y或y,则AH=-1,结束 jmp done;一定要跳过另一个分支体 next: mov ah,0 ;是Y或y,则AH=0,结束 done: ...
第5章 四 多分支程序设计 图示 • 多个条件对应各自的分支语句体,哪个条件成立就转入相应分支体执行。多分支可以化解为双分支或单分支结构的组合,例如: or ah,ah ;等效于cmp ah,0 jz function0 ;ah=0,转向function0 dec ah ;等效于cmp ah,1 jz function1 ;ah=1,转向function1 dec ah ;等效于cmp ah,2 jz function2 ;ah=2,转向function2
地址表 分支1地址 分支2地址 ... Table dw disp1, disp2, disp3, disp4, ... 地址表形成多分支 • 需要在数据段事先安排一个按顺序排列的转移地址表 • 输入的数字作为偏移量。因为只有2个字节16位偏移地址,所以偏移量需要乘2 • 关键是要理解间接寻址方式JMP指令
此处等同于 offset disp1 例5.4 数据段-1/4 Data segment msg db 'Input number(1~8):',0dh,0ah,'$' msg1 db 'Chapter 1 : ...',0dh,0ah,'$' msg2 db 'Chapter 2 : ...',0dh,0ah,'$‘ ... msg8 db 'Chapter 8 : ... ',0dh,0ah,'$' table dw disp1,disp2,disp3,disp4 dw disp5,disp6,disp7,disp8 Data ends ;取得各个标号的偏移地址
例5.4 代码段-2/4 Code segment assume cs:code,ds:data start: mov ax,data mov ds,ax mov dx,offset msg ;提示输入数字 mov ah,9 int 21h mov ah,1 ;等待按键 int 21h
可以改为 call table[bx] 例5.4 代码段-3/4 cmp al,'1' ;数字 < 1? jb start cmp al,'8' ;数字 > 8? ja start and ax,000fh ;将ASCII码转换成数字 dec ax shl ax,1 ;等效于add ax,ax mov bx,ax jmp table[bx] ;(段内)间接转移:IP←[table+bx]
对应修改为 ret 例5.4 代码段-4/4 start2: mov ah,9 int 21h mov ah,4ch int 21h disp1: mov dx,offset msg1 ;处理程序1 jmp start2 ... Code ends end start