❤️💕💕汇编语言目前仍在发挥着不可替代的作用,在效率上无可替代,在底层,学习linux内核,计算机外围设备和驱动,都离不开汇编。Myblog:http://nsddd.top
[TOC]
在一般情况下,指令是按照循序逐条运行的,我们称之为这样的指令为静态指令。
而在实际中,经常需要改变程序的执行流程,此时的指令我们称之为动态指令。
mov ax, 0
jmp short s
add ax ,1 ;不执行,跳过
s: inc ax
- 可以控制CPU执行内存中某处的指令
- 可以修改IP,或者同时修改CS和IP的指令
按照转移行为分类:
- 段内转移:只修改IP,不修改CS
jmp ax
- 段间转移:同时修改CS和IP
jmp 1000:0
按照指令对IP修改的范围不同:
- 段内短转移:IP修改范围为
-128~127
(八位 – 1个字节) - 段内近转移:IP修改范围为
-32768~32767
(十六位 – 2个字节 – 1个字)
按照转移指令分类:
- 无条件转移指令:
jmp
- 带条件转移指令:
jcxz
- 循环指令:
loop
- 过程
- 中断
offset 标号
assume cs:codeseg
codeseg segment
start: ;start开始的位置 - 0
mov ax, offset start ;相当于:mov ax, 0
s: ;s的地址是3,ax是三个字节指令
mov ax, offset s ;相当于:mov ax, 3
codeseg ends
end start
无条件转移,可以只修改IP,可以同时修改IP和CS
- 短程转移(直接短转移)
指令格式:JMP SHORT OPRD
语法格式:JMP 地址标号 ;(IP)=(IP)+8位位移量
指令功能:
OPRD为转移地址的标号,指令中的SHORT规定了OPRD为有符号的8位二进制数,OPRD为转移地址的偏移量。
该指令将程序执行的顺序转移到由(IP)+OPRD形成的新的程序执行的目标地址,从而实现程序的转移。
转移的目标地址OPRD在指令中可以直接使用标号地址,但要求转移的目标地址的范围只能在JMP指令所处地址的-128~+127字节范围之内(补码表示),如超出该范围,汇编时出错 – 比如下面的代码中,越界了。
code segment start: jmp short s db 128 dup(0) ;跳转指令超出一个字节 error s:mov ax,0ffffh code ends end start
- 近程转移(段内直接转移)
指令格式:JMP NEAR PTR OPRD
语法格式:JMP 地址标号 ;(IP)=(IP)+16位位移量
指令功能:
- 与短程转移的功能和要求相同,不同之处是近程转移的OPRD为有符号的16位二进制数。
- 指令将程序执行的顺序转移到由(IP)+OPRD形成的新的程序执行的目标地址,转移的目标地址的范围只能在
- JMP指令所处地址的-32768~+32767字节范围之内,如超出该范围,汇编时出错。使用该指令时NEAR可省略。
- 段间直接转移(远程转移)
指令格式:JMP FAR PTR OPRD
语法格式:JMP 地址标号 ;(IP)= 新的偏移地址, ;(CS)= 新的代码段地址
指令功能:
- 指令中用FAR PTR规定了该指令为段间的转移,OPRD为目的地址的标号,目的地址与JMP指令所在地址不在同一段内。
- 执行该指令时要修改CS和IP的内容,将OPRD所在段的段地址送CS中,OPRD的段内偏移地址送IP中。
- 段内间接转移
指令格式:JMP WORD PTR OPRD
语法格式:JMP reg16/mem ;(IP)= 新的偏移地址
指令功能:
- 与短程转移的功能和要求相同,不同之处是段内间接转移的OPRD 可以是除立即数外的任何寄存或存储器寻址方式
- 转移的目标地址由OPRD的内容确定
远转移指明跳转到目标地址,包含了CS和IP,直接转移
近转移指明当前的IP偏移地址,而不是转移后的目的地址。
- 段间间接转移
指令格式:JMP DWORD PTR OPRD
语法格式:JMP mem32
指令功能:
- 指令中用DWORD PTR规定了该指令为段间间接转移,OPRD只能是存储器寻址方式。
- 执行该指令时将寻址到的内存单元的第一个字送入IP中,第二个字送入CS中。
-
段间转移:同时修改CS和IP
jmp 1000:0
-
段内短转移:IP修改范围为
-128~127
(八位 – 1个字节)jmp short 标号
-
段内近转移:IP修改范围为
-32768~32767
(十六位 – 2个字节 – 1个字)jmp near ptr 标号
jmp指令经常根据位移进行转移。
- 常见指令的立即数在机器指令中有所体现
jmp short指令中,包含的是跳转到指令的相对位置,而不是转移的绝对位置。
assume cs:codesg
codesg segment
start:
mov ax,0
jmp short s
add ax,1
s:inc ax
codesg ends
end start
程序执行后,ax 中的值为 1
因为执行 jmp short s
后,越过了 add ax,1
IP 指向了 标号 s 处的 inc ax
也就是说,程序只进行了一次 ax 加 1 操作
此种转移方式并没有转移的目的地址,而是相对于当前 IP 的转移位移
另外,近转移ip修改范围: -32768~32767
语法: jmp far ptr 标号
这种实现的是 段间转移 ,又称为远转移
(CS)=标号所在段的段地址; (IP)=标号在段中的偏移地址
far ptr 指明了指令用标号的段地址和偏移地址修改 CS 和 IP
比如:
assume cs:codesg
codesg segment
start:
mov ax,0
mov bx,0
jmp far ptr s
db 256 dup (0)
s:add ax,1
inc ax
codesg ends
end start
指令格式: jmp 16 位 reg
功能: (IP)=(16 位 reg)
比如:
jmp ax
指令执行前: ax=1000H ,CS=2000H ,IP=0003H
指令执行后: ax=1000H ,CS=2000H ,IP=1000H
jmp ax ,相当于: mov IP,ax
转移地址在内存中的jmp指令有两种格式
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址
内存单元地址可用寻址方式的任一格式给出。
比如:
mov ax,0123H
mov ds:[0],ax ;ds:[0]中保存0123H
jmp word ptr ds:[0] ;跳转到0123H
执行后, (IP)=0123H
又比如:
mov ax,0123H
mov [bx],ax ;以bx寻址默认的段就是ds
jmp word ptr [bx]
执行后, (IP)=0123H
功能:从内存单元地址处开始存放着两个字,
- 高地址处的字是转移的目的段地址
- 低地址处是转移的目的偏移地址
(CS) = (内存单元地址+2)
(IP) = (内存单元地址)
内存单元地址可用寻址方式的任一格式给出
比如:
mov ax,0123H
mov ds:[0],ax ;ip,偏移地址在低位
mov word ptr ds:[2],0 ;0放入CS,段地址在高位
jmp dword ptr ds:[0]
执行后, (CS)=0 ,(IP)=0123H ,CS:IP 指向 0000:0123
再比如:
mov ax,0123H
mov [bx],ax ;低地址 偏移地址:0123H
mov word ptr [bx+2],0 ;高地址 段地址:0
jmp dword ptr [bx]
执行后, (CS)=0 ,(IP)=0123H ,CS:IP 指向 0000:0123
在源程序中,不允许使用jmp 2000:0100
的转移指令实现段间转移
- 这是在debug中使用的汇编指令,汇编编译器并不认识
- 如果在源程序中使用,会报错
我们可以使用下面方式段间转移
jmp far ptr 标号
jmp dword ptr [bx]
格式:
jcxz 标号
功能:
-
如果(CS) = 0 ,则转移到标号处
(ip) = (ip) + 8 8位位移 = “标号” 处的地址 - jcxz指令后的第一个字节的地址 和jmp短指令一样
-
如果(CS) ≠ 0 ,则什么也不做(程序向下执行)
jcxz是条件转移指令
前面有讲
格式:
loop 标号
功能:
- (cx) = (cx) - 1
- 如果(CS)≠ 0 ,则转移到标号处
- 如果(CS)= 0 ,则什么也不做(程序向下执行)
上面根据位移进行“相对”转移的意义:
对IP的修改是根据转移目的地址和转移起始地址之间的唯一来进行
jmp short 标号 jmp near ptr 标号 jcxz 标号 loop 标号
短转移 :-128~127
三类:标志转移、无/有符号数比较后转移
判断单个标志位状态
- JZ/JE和JNZ/JNE:利用零标志ZF,判断结果是否为零(或相等)
- JS和JNS:利用符号标志SF,判断结果是正是负
- JO和JNO:溢出标志OF,判断结果是否产生溢出
- JP/JPE和JNP/JPO:奇偶标志PF,判断结果中最低字节“1”的个数是偶是奇
- JC/JB/JNAE和JNC/JNB/JAE:利用进位标志CF,判断结果是否进位或借位