Post

流程转移与子程序

流程转移与子程序

流程转移与子程序
目录

预备知识

立即数在机器指令中,会在内存里有体现

转移综述

  • 转移指令分类
    1. 转移行为
      • 段内转移:只修改IP,如:jmp ax
      • 段间转移:同时修改CS、IP,如:jmp 1000:0
    2. IP 修改范围
      • 段内短转移:IP修改范围为 -128 ~ 127
      • 段内近转移:IP修改范围为 -32768 ~ 32767
    3. 转移指令
      • 无条件转移指令(jmp)
      • 条件转移指令(jcxz)
      • 循环指令(loop)
      • 过程
      • 中断

jmp指令 无条件转移

注意事项: 在源程序中,不允许使用 jmp 2000:2 形式的指令

  • 可在debug中使用
  • 汇编编译器不认识、会报错

原理:对执行 IP地址 的偏移 进行转移
原理示例:
跳转到标号s 标号s对应指令地址 - 076A:000A
jmp指令地址 - 076A:0003 指令内容 - EB05

  • EB 为jmp指令
  • 05为偏移地址 = s指令地址(000A) - jmp下一条指令地址(0003+2)
jmp指令格式示例
jmp标号- 段间转移(远转移): jmp far ptr标号
- 段内短转移: jmp short标号; 8位的位移
- 段内近转移: jmp near ptr标号; 16位的位移
jmp寄存器jmp bx; 16位的位移
jmp内存单元(表示跳转到的地址)- 段内转移: jmp word ptr内存单元地址; jmp word ptr[bx]
- 段间转移: jmp dword ptr内存单元地址; jmp dword ptr[bx]
标号转移
段内转移

实质:相对当前IP的转移位移 功能:(IP) = (IP) + 位移

短转移:jmp short 标号
近转移:jmp near ptr 标号

  1. 位移=’标号’地址 - jmp后一个指令的地址
  2. (short 8位,near ptr 16位)
  3. 用补码表示(8位范围:-128-127 16位范围:-32768-32767)
  4. 若是超出范围,会报错
远转移

原理:覆盖CS:IP
jmp far ptr 标号

jmpi 于 jmp far 等价,同为远转移指令,由于历史遗留问题,存在两种写法

1
2
3
4
5
; jmp far 写法
jmp far 0x1000:0x1234

; jmpi 写法
jmpi 0x1000, 0x1234
寄存器转移

实质:IP = (16位寄存器) jmp ax

内存转移
  • jmp word ptr 内存单元地址
  • jmp dword ptr 内存单元地址

offset 操作符

使用方法:offset 标号
作用:取得 标号对应指令的偏移地址

同时,offset 可用于 数据的标号,用于赋值方便

1
2
3
4
5
6
assume cs:code
code segment
    a:db 1,2,3,4,5,6
    b:dw 0
start: mov si, offset a
    mov bx, offset b

其它条件转移/短转移指令

条件转移

  • 所有的条件转移,均为短转移指令
  • IP位移范围均为 -128-127
  • 机器码中包含的是位移、而非目的地址
jcxz

格式:jcxz 标号
功能:根据 (cx) 是否等于 0,来决定是否转移

  • 转移到标号 cx = 0
  • 向下执行 $cs\neq0$

具体位移操作:
(IP) = (IP) + 8位位移地址

  • 8位位移 = 标号地址 - jcxz后一个指令地址
  • 范围 -128-127, 用补码表示
loop

格式:loop 标号
操作:

  1. (cx)=(cx)-1
  2. (cx)$\neq0$,转移到标号

具体位移操作: 与段转移相同,用负数的补码表示位移

XCHG

(exchange)数据交换指令
格式:xchg opr1, opr2
作用: 交换两个内存单元中的内容

注意:
* 不允许使用段寄存器 * 不影响标志位 * 不能直接交换两个内存地址的值 * 需要有一个是寄存器

XLAT

(Translate Byte)换码指令
格式:xlatxlat opr
功能:计算DS:BX + AL [+ opr]指向的地址的值取出,放入 AL
操作:$(AL)\leftarrow ((BX)+(AL))$

注:

  • opr可以是数据标号(偏移地址)
  • 不影响标志位
  • 字节表格(查找长度不超过256)
  • bx 作为首地址
  • al 为位移量
lea

(Load Effective Address) 加载有效地址 格式:lea reg, src
功能:将有效地址加载到寄存器中,加载地址一般是标号或偏移地址

lds

(Load Pointer into DS)加载指针到DS
格式:lds reg, src 功能:从内存位置加载一个双字(32位),分别作为偏移地址和段地址,前2个字节放入寄存器,后2个字节放入DS段寄存器

les

(Load Pointer into ES)加载指针到ES
格式:les reg, src 功能:从内存位置加载一个双字(32位),分别作为偏移地址和段地址,前2个字节放入寄存器,后2个字节放入ES段寄存器

标志寄存器传送指令

LAHF

(Load AH from Flags)加载标志位到AH
格式:lahf
功能:把标志寄存器的低 8 位(状态标志) 加载到 AH寄存器

SAHF

(Save AH from Flags)加载标志位到AH
格式:sahf
功能:把AH寄存器的值 加载到 标志寄存器的低 8 位(状态标志)

PUSHF

(Push Flags)标志寄存器压栈
格式:pushf
操作:

  • $(SP)\leftarrow (SP)-2$
  • $((SP)+1, (SP))\leftarrow (FLAGS)$
POPF

(Pop Flags)出栈一个字到标志寄存器
格式:popf
操作:

  • $(FLAGS)\leftarrow ((SP)+1, (SP))$
  • $(SP)\leftarrow (SP)+2$

扩展指令

CBW

(Convert Byte to Word)字节转字
格式:cbw
功能:扩展 (AL)到 (AX)上,对AL进行符号扩展

  • AL最高有效位为 0时,(AH)=00H
  • AL最高有效位为 1时,(AH)=FFH

CWD

(Convert Word to Doubleword)字转双字 格式:cwd
功能:扩展 (AX)到 (DX, AX)上,对AX进行符号扩展

  • AX最高有效位为 0时,(DX)=0000H
  • AX最高有效位为 1时,(AH)=FFFFH

十进制调整指令

BCD码表示
用二进制编码的十进制数,又称二–十进制数
压缩的BCD码:用 4 位二进制数表示 1 位十进制数
例:$( 59 )10 =( 0101\ 1001 ){BCD}$
非压缩的BCD码:用 8 位二进制数表示 1 位十进制数
例:$( 59 )10 =( 0000\ 0101\ \ 0000\ 1001 )
{BCD}$
ASCII码属于非压缩的BCD码

调整指令作用:在进行2进制的算数运算后,调整为十进制的表示
(1)压缩的BCD码调整指令
 ● DAA 加法的十进制调整指令
 ● DAS 减法的十进制调整指令
 
(2)非压缩的BCD码调整指令
 ● AAA 加法的ASCII码调整指令
 ● AAS 减法的ASCII码调整指令
 ● AAM 乘法的ASCII码调整指令
 ● AAD 除法的ASCII码调整指令

使用示范

在算术运算后,使用对应指令进行调整

1
2
3
4
5
6
7
8
9
10
11
(1) 
MOV      AL, BCD1          ; BCD1=34H
ADD       AL, BCD2          ; BCD2=59H,   (AL)=8DH
DAA                                  ; 8DH+06H=93H
MOV      BCD3, AL          ; BCD3=93H
(2) 
MOV      AL, BCD1          ; BCD1=34H
SUB        AL, BCD2         ; BCD2=59H ,   (AL)=0DBH
DAS                                   ; 0DBH-60H-06H=75H
MOV      BCD3, AL          ; BCD3= 75 = - 25 

call 和 ret指令

使用必须预先设置栈空间

调用:call
返回:ret

call

实质:

  1. 将 call 后指令IP(当前IP — 执行指令时,IP会先调到下一条指令) 或 CS和IP 压入栈
    • (sp)=(sp) - 2 (若是压入CS和IP,则先压入CS后IP)
    • ((sp) $\times16$ +(sp)) = (IP)
  2. IP = IP + 位移(标号处 IP - 当前IP) / 覆写CS、IP

位移范围:16位位移 —— -32768 ~ 32767 用补码表示
该位移由编译程序在编译时自动算出

标号转移

段内转移
格式:call 标号
步骤: IP压栈 - 转移

段间转移 格式:call far ptr 标号
步骤:CS、IP压栈 - 转移

寄存器

格式:call 16位寄存器
实质:将寄存器中的值,作为跳转IP
步骤:IP压栈 - jmp 16位寄存器

内存

格式:call word/dword ptr ds:[0]内存单元地址
步骤:IP 或 CS/IP 压栈 - 跳转到 jmp word/dword ptr 内存单元

ret 和 retf

实质:从栈内取出 IP 或 CS/IP, 覆写转移 格式:retretf
步骤:pop IP(ret) 或 CS/IP(retf)

格式:ret n
步骤:

  • pop ip
  • add sp, n

参数传递方法-模块化程序设计

  1. 寄存器传递
  2. 内存单元传递
  3. 栈传递

方向标志位 DF、串传送指令、重复指令rep

作用:用于复制长串数据

DF

DF(Direction Flag)
作用:标志复制的移动方向

  1. 0 – 往前移
  2. 1 – 往后移

相关指令:

  1. cld (clear direction) – DF清零
  2. std (set direction) – DF置1

串传送指令

movsb / movsw
作用:移动 ds:si 中的数据 到 es:di 中 步骤:

  1. es:di 内存单元 = ds:si
  2. di、si的值增、或减
    • df=0 增
    • df=1 减
  3. movsb – 移动一个字节 si = si $\pm$ 1
  4. movsw – 移动一个字长 si = si $\pm$ 2
  5. stosb / stosw – 存储/初始化内存指令
    • AL/AX 中的数据存储到 目标指定位置(di 指向位置)
    • 更新 di
  6. lodsb / lodsw – 从内存加载数据到寄存器
    • 将源地址(si 指向位置)处的字节数据 加载到al/ax中
    • 更新 si
  7. cmpsb / cmpsw – 比较sidi 指向的字/字节
    • 相等, 标志寄存器中,ZF位 置1
    • 不等,ZF 置0
  8. scasb / scasw – 比较al/ axdi指向的数据
    • 相等,ZF=1
    • 不等,ZF=0
    • 可与 repe / repne 结合使用

串重复前缀

  • 与 cx 组合使用,每执行 1次,cx -1
  • 条件判断: 在cx的前提下,判断条件 REP
    REPE / REPZ – 是否相等,ZF=1 执行 REPNE / REPNZ – 是否不相等,ZF=0 执行
rep

作用:重复一个指令 cx 中值的次数,通常配合串传送指令使用
等价于:

1
2
s: 指令
loop s

repe / repz
repne / repnz

寄存器冲突问题和 程序化处理字符串

字符串处理程序化

原理:设置哨兵 0
步骤:

  1. 字符串后加上 0
  2. 进行字符串操作前,复制字符到 cl, 并给 ch 置0
  3. 使用 jcxz 跳出循环
  4. 字符串操作 用 jmp 死循环

寄存器冲突问题

解决方案:
将子程序中用到的寄存器 压入栈中,退出子程序时,弹出

标志寄存器/程序状态字

标志(flag)寄存器/程序中状态字: PSW/FLAGS

结构

8086CPU中:

  • 有十六位的存储结构
  • 没有使用flag的 1、3、5、12-15位

作用

  • 存储相关指令(ALU)的执行结果
  • 控制CPU的相关工作(为其提供行为依据)

寄存器的值和直接访问

PL 是 Plus的缩写,表示正数 或 零

直接访问的方法:

  • pushf: 将标志寄存器的值压栈
  • popf: 从栈中弹出数据,送入标志寄存器中 绝大多数时候,影响标志寄存器值的是 通过 算数或逻辑运算指令 进行控制

ZF_零标志

  • 结果:0;ZF=1, 标志ZR
  • 结果:非零;ZF=0, 标志NZ

PF_奇偶标志

含义:表示结果中 1 的个数的奇偶

  • 结果:1为偶数;PF=1, 标志PE
  • 结果:1为奇数;PF=0, 标志PO

SF_符号标志

含义:

  • 作为有符号数计算结果的记录
  • 将数据看作无符号数时,则SF的值无意义

  • 结果:负;SF=1,NG
  • 结果:正;SF=0,PL

计算机中,有符号数一律使用补码表示
原码变补码:

  • 正数:与原码相同
  • 负数:将其对应的正数原码,全部取反(包括符号位) + 1

补码变原码:

  • 正数:不变
  • 负数:取反+1

CF_进位标志

含义:

  • 记录 无符号数运算结果
  • 表示是否有 进位 或 错位

  • 结果:有进位或错位;CF=1,CY
  • 结果:无进位或错位;CF=0,NC

对于n位的无符号数来说,n-1是最高位
当发生向n位 进位 或 错位时,CF置1

OF_溢出标志

含义:

  • 仅对于有符号数而言
  • 结果超出表示范围

  • 结果:溢出;OF=1,OV
  • 结果:无溢出;OF=0,NV

OF与CF的区别

  • CF 是对于 无符号数有意义的 进/错位标志位
  • OF 是对于 有符号数有意义的 溢出标志位

带进、借位的加减法

作用:可用于更多位的数值运算
原理:操作数$1\pm$操作数$2\pm$CF

CF进/错位清零的方法:sub ax, ax
在循环自增或自减时,可以通过 inc / dec 指令,不会改变CF标志

用法:与 addsub 相同

加法:adb 操作数
减法:sbb

cmp及 条件转移指令的运用

cmp 使用
本质:做减法,只改变标志位,不改变数值
格式: cmp 统计数值, 比较数值
cmp byte ptr 统计数值, 比较数值
默认格式 cmp word ptr 统计数值,比较数值

原理:

1
cmp ax, dx;计算 ax - dx 根据标志位做出判断

条件转移
含义:见名思意,条件转移
cmp 和 带条件的 jmp 组合使用
条件:

  1. JE/JZ (Jump if Equal/Zero)

    • 单词:Jump Equal/Zero
    • 含义:如果两个操作数相等(或结果为零),则跳转。
  2. JNE/JNZ (Jump if Not Equal/Not Zero)

    • 单词:Jump Not Equal/Not Zero
    • 含义:如果两个操作数不相等(或结果不为零),则跳转。
  3. JA/JNBE (Jump if Above/Not Below or Equal)

    • 单词:Jump Above/Not Below or Equal
    • 含义:如果第一个操作数大于第二个(无符号),则跳转。
  4. JAE/JNB (Jump if Above or Equal/Not Below)

    • 单词:Jump Above or Equal/Not Below
    • 含义:如果第一个操作数大于或等于第二个(无符号),则跳转。
  5. JB/JNAE (Jump if Below/Not Above or Equal)

    • 单词:Jump Below/Not Above or Equal
    • 含义:如果第一个操作数小于第二个(无符号),则跳转。
  6. JBE/JNA (Jump if Below or Equal/Not Above)

    • 单词:Jump Below or Equal/Not Above
    • 含义:如果第一个操作数小于或等于第二个(无符号),则跳转。
  7. JG/JNLE (Jump if Greater/Not Less or Equal)

    • 单词:Jump Greater/Not Less or Equal
    • 含义:如果第一个操作数大于第二个(有符号),则跳转。
  8. JGE/JNL (Jump if Greater or Equal/Not Less)

    • 单词:Jump Greater or Equal/Not Less
    • 含义:如果第一个操作数大于或等于第二个(有符号),则跳转。
  9. JL/JNGE (Jump if Less/Not Greater or Equal)

    • 单词:Jump Less/Not Greater or Equal
    • 含义:如果第一个操作数小于第二个(有符号),则跳转。
  10. JLE/JNG (Jump if Less or Equal/Not Greater)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
*   单词:Jump Less or Equal/Not Greater
*   含义:如果第一个操作数小于或等于第二个(有符号),则跳转。 11.  **JC (Jump if Carry)**

*   单词:Jump Carry
*   含义:如果进位标志(CF)被设置,则跳转。 12.  **JNC (Jump if Not Carry)**

*   单词:Jump Not Carry
*   含义:如果进位标志(CF)未设置,则跳转。 13.  **JO (Jump if Overflow)**

*   单词:Jump Overflow
*   含义:如果溢出标志(OF)被设置,则跳转。 14.  **JNO (Jump if Not Overflow)**

*   单词:Jump Not Overflow
*   含义:如果溢出标志(OF)未设置,则跳转。 15.  **JS (Jump if Sign)**

*   单词:Jump Sign
*   含义:如果符号标志(SF)被设置,则跳转。 16.  **JNS (Jump if Not Sign)**

*   单词:Jump Not Sign
*   含义:如果符号标志(SF)未设置,则跳转。
This post is licensed under CC BY 4.0 by the author.