汇编语言(七)—— 转移指令
转移指令
程序流程的控制转移
程序代码在代码段,CS指明代码段在主存中的段基地址,EIP给出将要执行指令的偏移地址。实现的各种指令寻址方式就是改变这两个寄存器。
- 指令顺序寻址,程序顺序执行,处理器自动增量EIP。
- 指令跳转寻址,程序控制转移,EIP(CS)随之改变(控制转移类指令:JMP, JCC, LOOP等)。
- 程序转移范围分为段内转移和段间转移:
① 段内转移:在当前代码段范围内的程序转移,不需更改CS,只要改变EIP(偏移地址)。被称为“近转移”,类型属性使用“NEAR”关键字;如果转移范围在127 ∼ \sim ∼-128字节(位移量使用一个字节表达)之间,又称为“短转移”,类型属性使用“SHORT”关键字。
② 段间转移:从当前代码段跳转到另一个代码段,需要更改CS(段地址)和EIP(偏移地址)。被称为“远转移”,类型属性使用“FAR”关键字。
JMP指令
无条件转移指令:jmp dest ; dest为要跳转到的地址。
jmp label ; 程序转向 label 标号指定的地址
; 段内相对寻址,段间直接寻址
jmp reg32/reg16 ; 程序转向寄存器指定的地址
; 寄存器间接寻址
jmp mem48/mem32/mem16 ; 程序转向存储单元指定的地址
; 存储器间接寻址
; e.g.
.data
nvar dword ?
.code
jmp labl1 ; 相对寻址,短转移,位移量一个字节
nop ; nop 空操作指令
labl1: jmp near ptr labl2 ; 相对寻址,近转移,位移量四个字节
nop
labl2: mov eax, offset labl3
jmp eax ; 跳转到 eax 的内容所指定的位置,寄存器间接寻址
nop
labl3: mov eax, offset labl4
mov nvar, eax
jmp nvar ; 跳转到 nvar 的内容所指定的位置,存储器间接寻址
; jmp 指令寻址,通过存储单元间接获得下一条指令位置;
; 指令执行过程需要获得 nvar 变量内容,数据寻址,通过存储器的直接寻址获得数据。
mov ebx, offset nvar
jmp near ptr [ebx] ; 指令的存储器间接寻址,数据的寄存器间接寻址
nop
Jcc指令
条件转移指令:jcc dest ; cc为判断的标志条件,dest为要跳转到的地址。在满足条件时实现转移,条件不满足时顺序执行,用于实现分支、循环程序结构。
jcc label ; 条件满足发生转移,否则顺序执行下条指令。
; label 表示目标地址,采用段内相对寻址
判断的标志条件cc共16条指令(助记符不止16个),分成两类:
① 单个标志状态作为条件(5个状态标志ZF、CF、OF、SF、PF的10种状态);
② 两数大小关系作为条件(比较无符号整数大小:低于、不低于、低于等于、高于;比较有符号整数大小:小于、不小于、小于等于、大于)。
利用零位标志ZF的条件转移指令
根据ZF值判断运算结果为0或两数相等,针对无符号整数加减运算,实际分别为一条指令,使用多个助记符方便使用。
-
判断条件:运算结果为0、两数相等(ZF = 1)
jz label ; jump if zero je label ; jump if eaual
-
判断条件:运算结果不为0、两数不相等(ZF = 0)
jnz label ; jump if not zero jne label ; jump if not eaual
利用进位标志CF的条件转移指令
根据CF值判断运算结果是否有进位或借位。
-
判断条件:运算结果有进位或借位(CF = 1)
jc label ; jump if carry ,等于 jb 和 jane 指令
-
判断条件:运算结果没有进位或借位(CF = 0)
jnc label ; jump if not carry , 等于 jnb 和 jae 指令
利用溢出标志OF的条件转移指令
根据OF值判断运算结果是否有溢出,针对有符号整数加减运算。
-
判断条件:运算结果有溢出(OF = 1)
jo label ; jump if overflow
-
判断条件:运算结果没有进位或借位(\textcolor{red}{OF = 0})
jno label ; jump if not overflow
利用符号标志SF的条件转移指令
根据SF值判断运算结果是正是负,有符号整数采用补码,最高位是符号位。符号位为1,表示负数;符号位为0,表示正数。
-
判断条件:运算结果有溢出(SF = 1)
js label ; jump if sign
-
判断条件:运算结果没有进位或借位(SF = 0)
jns label ; jump if not sign
利用奇偶标志PF的条件转移指令
根据PF值判断低8位结果中1的个数奇偶,实际分别为一条指令,使用多个助记符方便使用。
-
判断条件:运算结果有溢出(PF = 1)
jp label ; jump if parity jpe label ; jump if parity even
-
判断条件:运算结果没有进位或借位(PF = 0)
jnp label ; jump if not parity jpo label ; jump if parity odd
两个无符号整数大小关系的条件转移指令
① 利用CF标志判断两个无符号整数的大小关系(低于、不高于等于、不低于、高于等于),本质为与jc、jnc为对应的一条指令。
② 利用CF标志和ZF标志判断两个无符号整数的大小关系(低于等于、不高于、不低于等于、高于),高(above)低(below)。
-
判断条件:低于、不高于等于(CF = 1) —— 减法运算有借位
jb label ; jump if below , 等于 jc 指令( CF = 1 ) jnae label ; jump if not above or equal , 等于 jc 指令( CF = 1 )
-
判断条件:不低于、高于等于(CF = 0)—— 减法运算无借位
jnb label ; jump if not below , 等于 jnc 指令( CF = 0 ) jae label ; jump if above or equal , 等于 jnc 指令( CF = 0 )
-
判断条件:低于等于、不高于(CF = 1 或 ZF = 1) —— 减法运算有借位或减法运算结果为0
jbe label ; jump if below or equal jna label ; jump if not above
-
判断条件:不低于等于、高于(CF = 0 且 ZF = 0) —— 减法运算无借位且减法运算结果不为0
jnbe label ; jump if not below or equal ja label ; jump if above
两个有符号整数大小关系的条件转移指令
① 利用SF和OF标志判断两个有无符号整数的大小关系(小于、不大于等于、不小于、大于等于)。
② 利用ZF、SF和OF标志判断两个有无符号整数的大小关系(小于等于、不大于、不小于等于、大于),用大(greater)、小(less)表示。
-
判断条件:小于、不大于等于(SF 不等于 OF)
当 SF = 1 ,OF = 0 时,减法运算结果为负,且无溢出,正 - 正 = 负 或 负 - 正 = 负
当 SF = 0 ,OF = 1 时,减法运算结果为正,且有溢出,负 - 正 = 正jl label ; jump if less jnge label ; jump if not greater or equal
-
判断条件:不小于、大于等于(SF = OF)
当 SF = 1 ,OF = 1 时,减法运算结果为负,且有溢出,正 - 负 = 负
当 SF = 0 ,OF = 0 时,减法运算结果为正,且无溢出,正 - 正 = 正 或 正 - 负 = 正jnl label ; jump if not less jge label ; jump if greater or equal
-
判断条件:小于等于}、不大于(SF 不等于 OF 或 ZF = 1})
当 SF = 1 ,OF = 0 时,减法运算结果为负,且无溢出,正 - 正 = 负 或 负 - 正 = 负,ZF = 1
当 SF = 0 ,OF = 1 时,减法运算结果为正,且有溢出,负 - 正 = 正,ZF = 1jle label ; jump if less or equal jng label ; jump if not greater
-
判断条件:不小于等于、大于(SF = OF 且 ZF = 0)
当 SF = 1 ,OF = 1 时,减法运算结果为负,且有溢出,正 - 负 = 负,ZF = 0
当 SF = 0 ,OF = 0 时,减法运算结果为正,且无溢出,正 - 正 = 正 或 正 - 负 = 正,ZF = 0jnle label ; jump if not less or equal jg label ; jump if greater
产生条件的指令
- 常用指令:
① 比较指令CMP(进行减法运算,用于判断两个数据大小或是否相等);
② 测试指令TEST(进行逻辑与运算,用于判断某位为0或为1等); - 其他指令:能够影响状态标志的指令。① 加减运算指令;② 逻辑运算指令;③ 移位指令等。
比较指令CMP(compare)
将目的操作数减去源操作数,差值不回送目的操作数,按照减法结果影响状态标志。根据标志状态获知两个操作数的大小关系,给条件转移等指令使用其形成的状态标志。
指令:cmp dest, src ; dest为目的操作数,src为源操作数,减法不改变结果,只改变标志。
cmp reg, imm/reg/mem ; reg - imm/reg/mem
cmp mem, imm/reg ; mem - imm/reg
测试指令TEST
按位进行逻辑与运算,不返回逻辑结果,只修改状态标志。常用于检测一些条件是否满足,获得某些位是0是1的状态,一般后跟条件转移指令,目的是利用测试条件转向不同的分支。
指令:test dest, src ; dest为目的操作数,src为源操作数,按位逻辑与运算,不改变结果,只改变标志。
test reg, imm/reg/mem ; reg and imm/reg/mem
test mem, imm/reg ; mem and imm/reg
循环指令
最基本的循环指令为LOOP指令。
指令:loop dest ; dest 为目的操作数(目标地址采用相对短转移),默认计数器为ecx,实现 ecx = ecx - 1 ,如果 ecx
≠
\ne
= 0 , 则转移到目标操作数;否则顺序执行。
loop label ; ① ecx = exc - 1 , 即 dec ecx
; ② 当 ecx 不等于 0 时,转移到 label ;否则顺序执行。即 jnz label
-
loop是循环指令,用于实现减量计数的循环控制,典型应用形式:
mov ecx, num ; 设置循环的计数初值 num label: ... ; 循环体 loop label ; ecx - 1 ,未到 0 继续循环;到 0 结束循环,顺序执行。
-
loop指令的循环次数由ecx初值设置,循环初值与循环次数对应范围为 1 ∼ 2 32 − 1 1\sim2^{32}-1 1∼232−1,当设置初值为0时,循环 2 32 2^{32} 232次。
mov ecx, 0 ; 设置循环的计数初值 label: loop label ; ecx - 1 , 未到 0 继续循环 ; 0 - 1 = -1 ,, 未到 0 继续循环 ; -1 的 32 位补码 = FFFFFFFFH = 2^32 - 1 ; 1 + 2^32 - 1 = 2^32
-
JECXZ指令用于避免计数初值位0可能导致的程序错误。(指令形式:jecxz dest ; dest 为目的操作数(目标地址采用相对短转移))。
jecxz label ; ecx = 0 ,转移到 label ;否则,顺序执行。 ; 等价于 cmp ecx, 0 + jz label