【汇编】 6、流程转移和子程序 您所在的位置:网站首页 程序的转移和浮动 【汇编】 6、流程转移和子程序

【汇编】 6、流程转移和子程序

#【汇编】 6、流程转移和子程序| 来源: 网络整理| 查看: 265

目录

6.1、“转移”综述

1、转移指令

2、转移指令的分类

6.2、操作符offset

1、作用

2、练习

6.3、jmp指令

 1、无条件转移指令

2、依据位移进行转移

3、温馨提示

4、两种段内转移

5、远转移:jmp far ptr 标号

6、转移地址在寄存器中

7、转移地址在内存中

8、JMP指令小结

6.4、其他转移指令

1、JCXZ指令

2、loop指令

​编辑

3、根据位移进行相对转移的意义

6.5、call指令和ret指令

1、模块化程序设计

2、call指令

(1)格式:call 标号

(2)指令“call far ptr 标号”实现的时段间转移

(3)转移地址在寄存器中的call指令

(4)转移地址在内存中的call指令

3、返回指令:ret和retf

6.6、call和ret的配合使用

1、具有子程序的源程序框架

2、应用

6.7、mul指令

1、格式

2、应用

示例1

示例2

6.8、汇编语言的模块化程序设计

1、参数和结果传递的问题

(1)用寄存器来存储

6.9、寄存器冲突问题

1、子程序标准框架

 2、示例1

1)源码

 2)查看源码

 3)结果比较

6.10、标志寄存器

1、标志(flag)寄存器的结构

2、标志寄存器的作用作用

3、标志寄存器值得解读

4、直接访问标志寄存器得方法

5、各个标志详解

5.1、ZF-零标志(Zero Flag)

5.2、PF-奇偶标志(Parity Flag)

5.3、SF-符号标志(Sign Flag)

5.4、CF-进位标志(Carry Flag)

5.5、OF-溢出标志(Overflow Flag)

5.6、综合

6.1、“转移”综述 1、转移指令

        可以控制CPU执行内存中某处代码的指令

        可以修改IP、或同时修改CS和IP的指令

2、转移指令的分类 按转移行为按指令对IP的修改范围按转移指令段内转移段间转移段间短转移段间近转移无条件转移指令条件转移指令循环指令过程中断只修改IP同时修改CS和IPIP修改范围JMPJCXZLOOP  jmp axjmp 1000:0-128~127-32768~32768     

       

6.2、操作符offset 1、作用

用操作符offset取得标号的偏移地址

格式为:offset 标号

例如:

assume cs:code code segment start: mov ax,offset start ;相当于mov ax,0,标号所在地址为0 s:mov ax,offset s ;相当于mov ax,3,标号所在地址为3 mov ax,4c00h int 21h code ends end start

4df0615b93824696b25a0119edbf0280.png

 

2、练习

问题:有如下程序段,添加2条指令,使得该程序在运行中将s处的第一条指令复制到s0处。

assume cs:code code segment   s:mov ax,bx     mov si,offset s     mov di,offset s0

______________________________

______________________________

 s0:nop     nop code ends end s

;nop即空,机器码占一个字节,起到占位的作用

 

分析:

(1)s、s0处的指令所在的内存单元的地址分别是

        cs:offset s和cs:offset s0

(2)将s处的数据复制到s0处,等价于

        将cs:offset s处的数据复制到cs:offset s0处

(3)地址如何表示?

        段地址在cs中,偏移地址在si、di中

(4)要复制的数据有多长?

        mov ax,bx指令长度为两个字节,即一个字

 

补齐代码:

assume cs:code code segment s:mov ax,bx mov si,offset s mov di,offset s0 mov ax,cs:[si] mov cs:[di],ax s0:nop nop code ends end s

 

6.3、jmp指令  1、无条件转移指令

(1)功能:无条件转移,可以修改IP,也可以同时修改CS和IP

(2)给出的两种信息:转移的目的地址、转移的距离

段间转移(远转移)jmp 2000:1000段内短转移jmp short 标号IP(-128~127)8位转移段内近转移jmp near ptr 标号IP(-32768~32767)16位转移 2、依据位移进行转移

JMP short的机器指令中,包含的是跳转到指令的相对位置,而不是转移到目的地址。

assume cs:code code segment start: mov ax,0 jmp short s add ax,1 nop nop s:inc ax code ends end start

1c662a1aaed04dc1bc628b1a7581810a.png

分析:jmp short s指令的读取和执行

(1)(IP)=0003,CS:IP指向EB 05(jmp的机器码)

(2)读取指令码EB 05进入指令缓冲器;

(3)(IP)=(IP)+所读取指令的长度 =(IP)+2 =0005,CS:IP指向add ax,0001;

(4)CPU执行指令缓冲器中的指令EB05;

(5)指令EB05执行后,(IP)=(IP)+05 = 000AH,CS:IP指向inc ax。

 

3、温馨提示

如果end start命令错写成ends start,debug挂载的时候则会出现:“access denied” 拒绝挂载的错误提示,编译连接的时候不会提示。

d1e732d26beb4a7eacd5a41606a3df14.png

 

4、两种段内转移

(1)短转移:jmp short 标号

        功能:IP=IP + 8位位移

8位位移 = 标号处的地址 - JMP指令后的第一个子节的地址 short指明此处的移位是8位位移 8位位移的范围为-128~127,用补码表示 8位位移由编译程序在编译时算出

(2)近转移:jmp near ptr 标号

        功能:IP = IP + 16位位移  

16位位移 = 标号处的地址 - JMP指令后的第一个子节的地址 near ptr指明此处的位移为16位位移,进行的是段内近转移 16位位移的范围为-32769~32767,用补码表示 16位位移由编译程序在编译时算出

 

5、远转移:jmp far ptr 标号 远转移jmp far ptr 标号进转移jmp near ptr 标号段间转移段内转移far ptr指明了跳转到的目的地址,包含了标号的段地址CS和转移地址IPnear ptr指明了相对于当前IP的转移,而不是转移的目的地址

assume cs:code

code segment

start:mov ax.0

        mov bx,0

        jmp far ptr s

        db 256 dup(0)

      s:add ax,1

        inc ax

code ends

end start

assume cs:code

code segment

start:mov ax,0

        mov bx,0

        jmp near ptr s

        db 256 dup(0)

      s:add ax,1

        inc ax

code ends

end start

6、转移地址在寄存器中

指令格式:jmp 16位寄存器

功能:(IP)=(16位寄存器)

assume cs:code code segment start: mov ax,0 mov bx,ax jmp bx mov ax,0123h code ends end start 7、转移地址在内存中 jmp word ptr 内存单元地址jmp dword ptr 内存单元地址段内转移段间转移从内存单元地址处开始存放着1个字,是转移的目的偏移地址从内存单元地址处开始存放着2个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址

mov ax.0123h

mov ds:[0],ax

jmp word ptr ds:[0]

执行后,

(IP)=0123h

 

 

 

mov ax,0123h

mov [bx],ax

jmp word ptr [bx]

执行后,

(IP)=0123h

mov ax,0123h

mov ds:[0],ax

mov word ptr ds:[2],0

jmp dword ptr ds:[0]

执行后,(CS)=0; (IP)=0123h

CS:IP指向0:0123h

 

mov ax,0123h

mov [bx],ax

mov word ptr [bx+2],0

jmp dword ptr [bx]

执行后,(CS)=0; (IP)=0123h

CS:IP指向0:0123h

 

8、JMP指令小结

a89d678d85ca4298914ce013d3307e60.png

 

6.4、其他转移指令 1、JCXZ指令

格式:jcxz 标号 (jmp cx ?= zero)

功能:若(cx)= 0,则转移到标号处执行;

          若(cx)≠ 0,则什么也不做,程序向下执行。

(cx)= 0时,(IP)=(IP)+ 8 8位位移 = 标号 处的地址 - JCXZ指令后的第一个字节的地址 8位位移的范围是-128~123,用补码表示 8位位移由编译程序在编译时算出

注释:JCXZ是有条件转移指令

(1)所有的有条件转移指令都是短转移

(2)对IP的修改范围都为-128~127

(3)在对应的机器码中包含转移的位移,而不是目的地址

assume cs:codesg codesg segment start: mov ax,2000h mov ds,ax moc bx,0 s:mov cx,[bx] jcxz ok inc bx inc bx jmp short s ok:mov dx,bx mov ax,4c00h int 21h codesg ends end start 2、loop指令 cb76f4285dae44d98ee95639c2da7292.png 3、根据位移进行相对转移的意义

对IP的修改是根据转移目的地址和转移起始地址之间的位移来进行的

jmp short 标号 jmp near ptr 标号 jcxz 标号 loop 标号

在它们对应的机器码中不包含转移的目的地址,而是包含的是到目的的地址的位移。

这样的设计,方便程序端在内存中的浮动装配。

 

 

6.5、call指令和ret指令 1、模块化程序设计

调用子程序:call

返回:ret

实质:流程转移指令,它们都修改IP,或者同时修改CS和IP

mov ax,0 call s mov ax,4c00h innt 21h s:add ax,1 ret 2、call指令 (1)格式:call 标号

CPU执行call指令,进行两步操作

(1)将当前的IP或CS和IP压入栈中 (SP)=(SP)-2 ((SS)*16 +(SP))=(IP) (2)转移到标号处执行指令 (IP)=(IP)+16位位移 #相当于 push IP jmp near ptr 标号 注释: (1)16位位移 = “标号”处的地址 - call指令后的第一个字节的地址 (2)16位位移的范围是 -32768 ~ 32767,用补码表示 (3)16位位移由编译程序再编译时算出 (2)指令“call far ptr 标号”实现的时段间转移 call far ptr 标号相当于 push CS push IP jmp far ptr 标号

指令“call 标号”类似于“jmp near ptr 标号”,对应的机器指令中为对应于当前IP的转移位移,而不是转移的目的地址,实现段内转移;

指令“call far ptr 标号”实现段间转移。

(3)转移地址在寄存器中的call指令

指令格式:call 16位寄存器

相当于进行 push IP jmp 16位寄存器 (4)转移地址在内存中的call指令

call word ptr 内存单元地址

相当于: push IP jmp word ptr 内存单元地址

示例:

mov sp:10h mov ax,0123h mov ds:[0],ax call word ptr ds:[0] 执行后,(IP)= 0123h,(SP) = 10h-2 = 0eh

call dword ptr 内存单元地址

相当于 push CS push IP jmp dword ptr 内存单元地址

示例:

mov 10h mov ax,0123h mov ds:[0],ax ;低地址放偏移地址 mov word ptr ds:[2],0 ;高地址放段地址 call dword ptr ds:[0] 执行后,(CS)= 0,(IP)= 0123h,(SP)= 0ch 3、返回指令:ret和retf  ret指令retf指令功能用栈中的数据,修改IP的内容,从而实现近转移用栈中的数据,修改CS和IP的内容,从而实现远转移相当于pop IP

pop IP

pop CS

举例示例1示例2 ;示例1 ;p6-1.asm assume cs:code,ss:stack stack segment db 16 dup(0) stack ends code segment mov ax,4c00h int 21h start: mov ax,stack mov ss,ax mov sp,16 mov ax,0 push ax mov bx,0 ret code ends end start

e80ec461f21b4fb2b1dcd01a7606be4f.png

;示例2 ;p6-2 assume cs:code,ss:stack stack segment db 16 dup(0) stack ends code segment mov ax,4c00h int 21h start: mov ax,stack mov ss,ax mov sp,16 mov ax,0 push cs push ax mov bx,0 retf code ends end start

e9b01349c217451d9c283525efb7f18d.png

 

6.6、call和ret的配合使用 1、具有子程序的源程序框架 assume cs:code code segment main:... call sub1 ;调用子程序sub1 ... mov ax,4c00h int 21h sub1:... call sub2 ;调用子程序2 ... ret sub2:... ... ret code ends end main 2、应用 ;示例 ;计算2的N次方方,计算前,N的值由CX给出 ;p6-3 assume cs:code,ss:stack stack segment db 16 dup(0) stack ends code segment start: mov ax,stack mov ss,ax mov sp,16 mov ax,1 mov cx,3 call s mov ax,4c00h add 21h s:add ax,ax loop s ret code ends end start

5e01ddb0e97c4597a6c734c82d495c8a.png

 

 

6.7、mul指令 1、格式

mul 寄存器

mul 内存单元

 8位乘法16位乘法被除数ALAX除数8位寄存器或内存字节单元16位寄存器或内存字单元结果AXDX(高位)、AX(低位)示例

mul bl

--(ax)=(al)*(bl)

 

mul byte ptr ds:[0]

--(ax)=(al)*((ds)*16+0)

mul word ptr [bx+si+8]

--(ax)=(ax)*((ds)*16+(bx)+(si)+8)结果的低16位

--(dx)=(ax)*((ds)*16+(bx)+(si)+8)结果的高16位

2、应用 示例1 ;计算100*10 mov al,64 ;100(O) = 64(H) mov bl,a ;10(O) = a(H) mul bl

8af57a147858487bbb3c76742d61e0ed.pngdbc3896a0f964b6eb92740a7c202b9b5.png

 

示例2 ;计算100*10000 mov ax,64 ;100 = 64(H) mov bx,2710 ;10000 = 2710(H) mul bx

ed9b27104af8474d9a926bf8b06672c0.png

 

6.8、汇编语言的模块化程序设计 1、参数和结果传递的问题

方案

用寄存器传递参数

用内存单元进行参数传递

用栈传递参数

(1)用寄存器来存储

用寄存器来存储参数和结果是最常用使用的方法

编译任务:计算data段中第一组数据的3次方,结果保存在后面一组dword单元中。

 0123456789ABCDEF 12345678      ;p6-4.asm ;by c10udz assume cs:code,ds:data,ss:stack stack segment db 16 dup(0) stack ends data segment dw 1,2,3,4,5,6,7,8 dd 0,0,0,0,0,0,0,0 data ends code segment start: mov ax,stack mov ss,ax mov sp,16 mov ax,data mov ds,ax mov si,0 mov di,16 mov cx,8 s:mov bx,[si] call cube mov [di],ax mov [di].2,dx add si,2 add di,4 loop s cube:mov ax,bx mul bx mul bx ret mov ax,4c00h int 21h code ends end start

d198907a6a99447da4f838960a07f6f4.png

 

6.9、寄存器冲突问题 1、子程序标准框架

子程序开始:子程序中使用的寄存器入栈

                      子程序内容

                      子程序中使用的寄存器出栈

                       返回(ret、retf)

 2、示例1

编程将给出的数据改为大写格式

1)源码 ;p6-9.asm assume cs:code,ds:data,ss:stack data segment db 'word',0 db 'unix',0 db 'wind',0 db 'good',0 data ends stack segment db 16 dup(0) stack ends code segment start:mov ax,data mov ds,ax mov ax,stack mov ss,ax mov sp,16 mov bx,0 mov cx,4 s:mov si,bx call capital add bx,5 loop s mov ax,4c00h int 21h capital:push cx push si s0:mov cl,[si] mov ch,0 jcxz ok and byte ptr [si],11011111b inc si jmp short s0 ok:pop si pop cx ret ;子程序 code ends end start  2)查看源码

1e3b95c457534aaf992e493318070b67.pngf3a989200ad247b4a480da5620310650.pnge8dd3e3e707a487f9fab43d283bb790c.png

 3)结果比较

8d8c77f7b64843dfacd43034188577dd.png460078ddf4fb40cd8c55e85fa20a643d.png

 

 

6.10、标志寄存器 1、标志(flag)寄存器的结构

PSW/FLAGS、别称:程序状态字

1514131211109876543210------------OFDFIFTFSFZF---AF---PF---CF

 

 

 

flag寄存器是按位起作用的,它的每一位都有专门的含义,记录特定的信息

2、标志寄存器的作用作用

1)用来存储相关指令的某些执行结果

2)用来为CPU执行相关指令提供行为依据

3)用来控制CPU的相关工作方式

3、标志寄存器值得解读

533a238f26be4e84a80e352405ae9701.png

 标志值为1值为0意义备注OverFlowOPOVNV溢出 DirectionDFDNUP方向down/upSignSFNGPL符号negative/positiveZeroZFZRNZ零值 ParityPFPEPO奇偶odd/evenCarryCFCYNC进位   4、直接访问标志寄存器得方法

pushf:将标志寄存器的值压栈      

popf:从栈中弹出数据,送入标志寄存器中。

5、各个标志详解 5.1、ZF-零标志(Zero Flag)

ZF标记相关指令的计算结果是否为0

1)ZF=1,表示“结果为0”,1表示逻辑真

2)ZF=0,表示“结果非0”,0表示逻辑假

 5.2、PF-奇偶标志(Parity Flag)

PF记录指令执行后,结果的所有二进制位中1的个数

1)1的个数是偶数,PE=1

2)1的个数是奇数,PE=0

指令执行结果

mov al,1

add al,10

结果为0000 1011B = 0000 0001B + 0000 1010B

其中有3个1,则PF=0

mov al,1

or al,2

结果为0000 0011B = 0000 0001B or 0000 0010B

结果中有2个1,则PF=1

5.3、SF-符号标志(Sign Flag)

SF记录指令执行后,将结果视为有符号数

1)结果为负,SF=1

2)结果为非负,SF=0

 

另外:有符号数与补码

计算机中有符号数一律使用补码来表示和存储

1)正整数的补码使用二进制表示,与原码相同

2)负数的补码,将其对应的正数二进制的所有位取反,后加一

5.4、CF-进位标志(Carry Flag)

在进行无符号数运算时,CF记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。

CF记录指令执行后,

1)有进位或借位,CF=1

2)无进位或借位,CF=0

5.5、OF-溢出标志(Overflow Flag)

在进行有符号数运算的时候,如果结果超过了机器所能表示的范围称为溢出。

OF记录有符号数操作指令执行后,

1)有溢出,OF=1

2)无溢出,OF=0

 

另外,CF和OF的区别

1)CF是对无符号数运算有意义的进/借位标志位

2)OF是对有符号数运算有意义的溢出标志位

6、综合

一条指令会带来多个标志寄存器的变化

指令CFOFSFZFPFsub al,al00011mov al,10h00011add al,90h00101mov al,80h00101add al,80h11011mov al,0FCh11011add al,05h10000mov al,7Dh10000add al,0Bh01101

 b87dde7ec98a42eca7a91f721883361e.png

8753b1713c9f4d1c982f8afee74b8582.pngc5857d7fcc0f46dc9cb664a9dcacfa9c.png

 

 

6.11、带进位的加减法  1、adc指令

adc是带进位加法指令,它利用CF位上记录的进位值

1)格式:adc 操作对象1,操作对象2

2)功能:操作对象1 = 操作对象1 + 操作对象2+CF

3)例:adc ax,bx实现的功能是:(ax)=(ax)+(bx)+CF

指令

mov al,98H

add al,al

adc al,3

mov ax,1

add ax,ax

adc ax,3

mov ax,2

mov bx,1

sub bx,ax

adc ax,1

结果(al)=34H(ax)=5(ax)=4解释

=(al)+3+CF

=30H+3+1=34H

=(ax)+3+CF

=2+3+0=5

=(ax)+1+CF

=2+1+1=4

2、应用(大数相加)

例如:编程计算1EF000H + 201000H,结果放在ax(高16位)和bx(低16位)中

mov ax,001E mov bx,F000 add bx,1000 adc,ax,0020

58766cd4ac294eb790baeae8a2cce2a0.png955c4e189802419bb0847156cc6c6567.png

 结果:1E F000H + 20 1000H = 3F 0000H

 3、sbb指令

sbb是带进位减法指令,它利用CF位上记录的借位值

1)格式:sbb 操作对象1,操作对象2

2)功能:操作对象1 = 操作对象1 - 操作对象2 - CF

3)例:sub ax,bx实现的功能是:(ax)=(ax)-(bx)-CF

应用:对任意大的数据进行减法运算

例如:计算003E 1000H - 0020 2000H,结果放在ax,bx中

mov ax,003e mov bx,1000 sub ax,0020 sbb bx,2000

 

6.12、cmp和条件转移指令

 

6.13、条件转移指令应用

6.14、DF标志和串传送指令

 

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有