最近阅读王爽《汇编语言》第二版,第九章“转移指令的原理”实验8中提到分析一个奇怪的程序,程序完整如下:
-
assume cs:codesg
-
codesg segment
-
mov ax, 4c00h
-
int 21h
-
-
start: mov ax, 0
-
s: nop
-
nop
-
-
mov di, offset s
-
mov si, offset s2
-
mov ax, cs:[si]
-
mov cs:[di], ax
-
-
s0: jmp short s
-
s1: mov ax, 0
-
int 21h
-
mov ax, 0
-
s2: jmp short s1
-
nop
-
-
codesg ends
-
end start
按照程序分析,经过如下四个语句:
-
mov di, offset s
-
mov si, offset s2
-
mov ax, cs:[si]
-
mov cs:[di], ax
意思就是将s2处的代码复制到s处。继续运行如下语句:
s0: jmp short s
程序重新跳转回到s:处,由于我们已经使用了s2出的代码替换s处的代码,所以应该就会执行s2处的代码,跳转到s1处。
可是实际问题来了,并没有发现跳转到s1处。而是直接退出。
于是使用debug对其分析,果然如标题所说,发现一个很奇怪的现象:
使用debug加载程序,然后u选项查看,嗯,汇编都能够对上,没有问题。
(图1)
然后一直t选项运行下来,重新跳转回到s处执行,问题来了,重新使用u选项查看汇编代码,尼玛,红框中竟然变成了jmp 0000指令。
(图2)
不是说好的要执行s2处的指令跳转到s1处执行的么?
于是仔细核对s2出的机器码和s0处的机器码,如图2和图3所示,都是EBF6,但是对应的汇编指令,一个是“jmp 0000”,一个是“jmp 0018”。同一个机器码竟然可以解释成为两种不同的汇编代码,不得不感叹神奇。
(图3)
无奈之下只好度娘了,答案经过整理理解如下:
1. 程序在编译时,段内直接短转移指令所对应的机器码中,并不包含转移的目的地址,而包含的是转移的位移量。这是该问题的核心。
那么在编译时,s2处的代码编译之后的机器码为EBF6,对应的EB为跳转指令,F6是-10d的掩码,即对应跳转到13f7:0018处s1的指令。此处s2的地址为13f7:0020,s1处地址为13f7:0018,正好位移量是-10d,没有问题。
2. 复制的是机器码,而不是汇编语言。
机器哪儿认识汇编语言啊,只认识机器码呀。所以我们将s2处的指令复制到s处,复制的是EBF6,而不是"JMP 0018"。
3. 跳转到s处后,当机器执行到EBF6机器码时,EB为跳转指令,F6是-10d的掩码,所以就是在ip指针的基础上减去位移为10的地址,此时ip指针为10,那么运行这条指令后,ip变为0,当然就跳转到13f7:0这个地址了。这个地址对应的代码就是程序开头的代码:
-
codesg segment
-
mov ax, 4c00h
-
int 21h
执行这两条指令后,程序正常退出。
阅读(1082) | 评论(0) | 转发(0) |