当前位置:   article > 正文

【汇编】 6、流程转移和子程序_怎么将程序转换到子程序里面

怎么将程序转换到子程序里面

目录

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 标号

例如:

  1. assume cs:code
  2. code segment
  3. start:
  4. mov ax,offset start
  5. ;相当于mov ax,0,标号所在地址为0
  6. s:mov ax,offset s
  7. ;相当于mov ax,3,标号所在地址为3
  8. mov ax,4c00h
  9. int 21h
  10. code ends
  11. 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指令长度为两个字节,即一个字

 

补齐代码:

  1. assume cs:code
  2. code segment
  3. s:mov ax,bx
  4. mov si,offset s
  5. mov di,offset s0
  6. mov ax,cs:[si]
  7. mov cs:[di],ax
  8. s0:nop
  9. nop
  10. code ends
  11. 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的机器指令中,包含的是跳转到指令的相对位置,而不是转移到目的地址。

  1. assume cs:code
  2. code segment
  3. start:
  4. mov ax,0
  5. jmp short s
  6. add ax,1
  7. nop
  8. nop
  9. s:inc ax
  10. code ends
  11. 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位位移

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

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

        功能:IP = IP + 16位位移
 

  1. 16位位移 = 标号处的地址 - JMP指令后的第一个子节的地址
  2. near ptr指明此处的位移为16位位移,进行的是段内近转移
  3. 16位位移的范围为-32769~32767,用补码表示
  4. 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位寄存器)

  1. assume cs:code
  2. code segment
  3. start:
  4. mov ax,0
  5. mov bx,ax
  6. jmp bx
  7. mov ax,0123h
  8. code ends
  9. 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,则什么也不做,程序向下执行。

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

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

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

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

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

  1. assume cs:codesg
  2. codesg segment
  3. start:
  4. mov ax,2000h
  5. mov ds,ax
  6. moc bx,0
  7. s:mov cx,[bx]
  8. jcxz ok
  9. inc bx
  10. inc bx
  11. jmp short s
  12. ok:mov dx,bx
  13. mov ax,4c00h
  14. int 21h
  15. codesg ends
  16. end start

2、loop指令

cb76f4285dae44d98ee95639c2da7292.png

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

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

  1. jmp short 标号
  2. jmp near ptr 标号
  3. jcxz 标号
  4. loop 标号

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

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

 

 

6.5、call指令和ret指令

1、模块化程序设计

调用子程序:call

返回:ret

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

  1. mov ax,0
  2. call s
  3. mov ax,4c00h
  4. innt 21h
  5. s:add ax,1
  6. ret

2、call指令

(1)格式:call 标号

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

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

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

  1. call far ptr 标号相当于
  2. push CS
  3. push IP
  4. jmp far ptr 标号

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

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

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

指令格式:call 16位寄存器

  1. 相当于进行
  2. push IP
  3. jmp 16位寄存器

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

call word ptr 内存单元地址

  1. 相当于:
  2. push IP
  3. jmp word ptr 内存单元地址

示例:

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

call dword ptr 内存单元地址

  1. 相当于
  2. push CS
  3. push IP
  4. jmp dword ptr 内存单元地址

示例:

  1. mov 10h
  2. mov ax,0123h
  3. mov ds:[0],ax
  4. ;低地址放偏移地址
  5. mov word ptr ds:[2],0
  6. ;高地址放段地址
  7. call dword ptr ds:[0]
  8. 执行后,(CS)= 0,(IP)= 0123h,(SP)= 0ch

3、返回指令:ret和retf

 ret指令retf指令
功能用栈中的数据,修改IP的内容,从而实现近转移用栈中的数据,修改CS和IP的内容,从而实现远转移
相当于pop IP

pop IP

pop CS

举例示例1示例2
  1. ;示例1
  2. ;p6-1.asm
  3. assume cs:code,ss:stack
  4. stack segment
  5. db 16 dup(0)
  6. stack ends
  7. code segment
  8. mov ax,4c00h
  9. int 21h
  10. start:
  11. mov ax,stack
  12. mov ss,ax
  13. mov sp,16
  14. mov ax,0
  15. push ax
  16. mov bx,0
  17. ret
  18. code ends
  19. end start

e80ec461f21b4fb2b1dcd01a7606be4f.png

  1. ;示例2
  2. ;p6-2
  3. assume cs:code,ss:stack
  4. stack segment
  5. db 16 dup(0)
  6. stack ends
  7. code segment
  8. mov ax,4c00h
  9. int 21h
  10. start:
  11. mov ax,stack
  12. mov ss,ax
  13. mov sp,16
  14. mov ax,0
  15. push cs
  16. push ax
  17. mov bx,0
  18. retf
  19. code ends
  20. end start

e9b01349c217451d9c283525efb7f18d.png

 

6.6、call和ret的配合使用

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

  1. assume cs:code
  2. code segment
  3. main:...
  4. call sub1
  5. ;调用子程序sub1
  6. ...
  7. mov ax,4c00h
  8. int 21h
  9. sub1:...
  10. call sub2
  11. ;调用子程序2
  12. ...
  13. ret
  14. sub2:...
  15. ...
  16. ret
  17. code ends
  18. end main

2、应用

  1. ;示例
  2. ;计算2的N次方方,计算前,N的值由CX给出
  3. ;p6-3
  4. assume cs:code,ss:stack
  5. stack segment
  6. db 16 dup(0)
  7. stack ends
  8. code segment
  9. start:
  10. mov ax,stack
  11. mov ss,ax
  12. mov sp,16
  13. mov ax,1
  14. mov cx,3
  15. call s
  16. mov ax,4c00h
  17. add 21h
  18. s:add ax,ax
  19. loop s
  20. ret
  21. code ends
  22. 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

  1. ;计算100*10
  2. mov al,64
  3. ;100(O) = 64(H)
  4. mov bl,a
  5. ;10(O) = a(H)
  6. mul bl

8af57a147858487bbb3c76742d61e0ed.pngdbc3896a0f964b6eb92740a7c202b9b5.png

 

示例2

  1. ;计算100*10000
  2. mov ax,64
  3. ;100 = 64(H)
  4. mov bx,2710
  5. ;10000 = 2710(H)
  6. mul bx

ed9b27104af8474d9a926bf8b06672c0.png

 

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

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

方案

用寄存器传递参数

用内存单元进行参数传递

用栈传递参数

(1)用寄存器来存储

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

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

 0123456789ABCDEF
 12345678
     
  1. ;p6-4.asm
  2. ;by c10udz
  3. assume cs:code,ds:data,ss:stack
  4. stack segment
  5. db 16 dup(0)
  6. stack ends
  7. data segment
  8. dw 1,2,3,4,5,6,7,8
  9. dd 0,0,0,0,0,0,0,0
  10. data ends
  11. code segment
  12. start:
  13. mov ax,stack
  14. mov ss,ax
  15. mov sp,16
  16. mov ax,data
  17. mov ds,ax
  18. mov si,0
  19. mov di,16
  20. mov cx,8
  21. s:mov bx,[si]
  22. call cube
  23. mov [di],ax
  24. mov [di].2,dx
  25. add si,2
  26. add di,4
  27. loop s
  28. cube:mov ax,bx
  29. mul bx
  30. mul bx
  31. ret
  32. mov ax,4c00h
  33. int 21h
  34. code ends
  35. end start

d198907a6a99447da4f838960a07f6f4.png

 

6.9、寄存器冲突问题

1、子程序标准框架

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

                      子程序内容

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

                       返回(ret、retf)

 2、示例1

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

1)源码

  1. ;p6-9.asm
  2. assume cs:code,ds:data,ss:stack
  3. data segment
  4. db 'word',0
  5. db 'unix',0
  6. db 'wind',0
  7. db 'good',0
  8. data ends
  9. stack segment
  10. db 16 dup(0)
  11. stack ends
  12. code segment
  13. start:mov ax,data
  14. mov ds,ax
  15. mov ax,stack
  16. mov ss,ax
  17. mov sp,16
  18. mov bx,0
  19. mov cx,4
  20. s:mov si,bx
  21. call capital
  22. add bx,5
  23. loop s
  24. mov ax,4c00h
  25. int 21h
  26. capital:push cx
  27. push si
  28. s0:mov cl,[si]
  29. mov ch,0
  30. jcxz ok
  31. and byte ptr [si],11011111b
  32. inc si
  33. jmp short s0
  34. ok:pop si
  35. pop cx
  36. ret
  37. ;子程序
  38. code ends
  39. 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/up
SignSFNGPL符号negative/positive
ZeroZFZRNZ零值 
ParityPFPEPO奇偶odd/even
CarryCFCYNC进位 

 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、综合

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

指令CFOFSFZFPF
sub al,al00011
mov al,10h00011
add al,90h00101
mov al,80h00101
add al,80h11011
mov al,0FCh11011
add al,05h10000
mov al,7Dh10000
add 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位)中

  1. mov ax,001E
  2. mov bx,F000
  3. add bx,1000
  4. 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中

  1. mov ax,003e
  2. mov bx,1000
  3. sub ax,0020
  4. sbb bx,2000

 

6.12、cmp和条件转移指令

 

6.13、条件转移指令应用

6.14、DF标志和串传送指令

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/486924
推荐阅读
相关标签
  

闽ICP备14008679号