汇编语言笔记9转移指令的原理
汇编语言笔记9转移指令的原理
0x00 转移指令的类型
可以修改ip或者同时修改cs和ip的指令统称为转移指令
8086cpu的转移指令有以下几类:
(1)只修改ip的 比如段内转移,jmp ax
(2)同时修改cs和ip 称为段间转移 比如 jmp 1000:0
由于转移指令对ip的修改范围不同,段内转移又分为:短转移和近转移
(1)短转移ip的修改范围-128-127(相对)
(2)近转移修改范围-32768-32767
8086cpu转移指令分为以下几类:
(1)无条件转移指令 jmp
(2)条件转移指令 jcxz
(3)循环指令
(4)过程
(5)中断
0x01 操作符offset
offset是伪指令,由编译器处理,他的功能是取得标号的偏移地址比如:
assume cs:code
code segment
start: mov ax,offset start
s: mov ax,offset s
code ends
end start
在上面程序中 offset取得了start和s的偏移地址 分别是0和3(和所在指令偏移地址相同)
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 start
上述代码运行正确
0x02 jmp指令深入
jmp指令为无条件转移指令,可以只修改ip,也可以同时修改cs和ip
jmp指令要给出两种信息:(1)转移的目的地址 (2)转移的距离
不同的给出目的地址的方法和不同的转移位置,对应由不同格式的jmp指令
保存相对地址的jmp指令
jmp short 标号 这种格式的jmp指令实现的是段内短转移,它对ip的相对修改范围为-128-127
assume cs:code
code segment
start: mov ax,0
jmp short s
add ax,1
s: inc ax
code ends
end start
对其机器码进行分析 jmp short s 中并没有s标号的偏移地址08h 是eb03h,原因在于它实际上只保存了相对的地址03h为什么相对地址会是03h呢?因为当执行到jmp这句时,ip已经指向了下一条语句add ax,1了 而这条语句的偏移地址是05h,与要跳转的08h只相差03h
jmp near ptr 标号 类似 不过修改的相对范围是-32768-32767 同样是保存的16为的相对修改地址而不是偏移地址
保存目的地址的jmp指令
jmp far ptr 标号 实现的是段间的转移,又称远转移,其修改cs为标号所在段的地址 修改ip为标号所在段的偏移地址
assume cs:code
code segment
start: mov ax,0
jmp far ptr s
db 256 dup (0)
s: add ax,1
inc ax
code ends
end start
通过对应的机器码可以知道保存的是标号的物理地址
转移地址在寄存器中的jmp指令
jmp 16位reg 直接修改ip位寄存器中的内容
转移地址在内存中的jmp指令
(1)jmp word ptr 内存单元地址(段内转移) 修改ip为内存单元的内容
(2)jmp dword ptr 内存单元地址 (段间转移) 同时修改cs和ip 内存单元的高字节对应cs 地直接对应ip
jmp word ptr [..]指令只修改ip因此要想指向第一条指令,即ip要为0 那么[bx+1]对应的 ds:[1]这个字节要为0
因此data 区 db 0,0即可
要使cs:ip指向第一条程序 那么ds:[0] 这个字应该是 ip 0000h ds:[2]这个字对应的是cs 但是我们没有cs 只知道ds 那么 我们知道 cs=ds+1 (因为data区不满16字节 所以填充到16),那么 我们可以让 ds:[2]为ds ds:[0]为 10h 这样物理地址也是一样的
所以答案是
该程序运行正确,这里就不放截图了
0x03 jcxz指令
jcxz是有条件转移指令 ,所有有条件转移指令都是短转移,机器码中只包含相对位移,不是目的地址
jcxz 标号 如果cx=0就转移到标号执行 否则就不跳转继续执行下面的
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s: mov cl,[bx]
mov ch,0
jcxz ok
inc bx
jmp short s
ok: mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
2000:0h处的数据设置
运行结果正确
0x04 loop指令
loop 标号 作用 在执行到loop时 cx先自减1 再判断cx是否为0 不为零跳转到标号,为0不跳转执行下面的代码
所有的循环指令都是短转移,对应的机器码只包含相对位移,不包含目的地址
假如 2000:0处是1 那么到横线之前cl为1 cx为1 如果横线处不补充代码,那么loop前cx为1 到loop时cx先减一 cx为0 就跳转到了ok 这样bx就为0 认为2000:0处 是第一个0,而实际上为1 所以呢 横线处应该让cx加一 所以是 inc cx
0x05 为什么使用相对位移以及跳转越界检测
简单来说使用先对位移是为了代码的可移植性和鲁棒性
注意 jmp 2000:0没有这种写法 我们可以 jmp dword ptr [bx] 让ds指向2000 bx指向0 这样才可以