1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | assume cs:code code segment mov ax, 04c00h 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 code ends end start |
说这个程序奇怪,是因为用来结束程序并返回的两个语句:
mov ax, 04c00h int 21h
没有放在程序结束处,而是放在的代码段的起始位置,更甚,由于程序是从start开始执行的,似乎永远不会执行到这两行,程序也永远不会结束。但是这个程序却能正常结束,而且是由我们的这两行代码来结束执行的。
其中的猫腻就在于短转移指令jmp short s1。jmp指令是用来更改寄存器CS:IP来实现程序的转移的,汇编语言中一般是以标号来指明跳转的目的地址的。对于长转移指令,例如jmp dword ptr ds:[0],CPU确实是以目标地址的段基址和段内偏移来修改CS:IP的。但是对于短转移来说,却是利用当前IP与目标地址之间的的偏移量来确定的。上例中,执行jmp short s1时,IP指向下一条指令nop,与目标地址s1之间偏移量为10:
CS:IP 机器码 汇编指令(编译器将标号进行了替换) 0B80:0018 B80000 MOV AX,0000 ;s1 0B80:001B CD21 INT 21 0B80:001D B80000 MOV AX,0000 0B80:0020 EBF6 JMP 0018 ; jmp short s1 0B80:0022 90 NOP
s1与s2之间的机器指令整好是10个字节,-10(向低地址方向转移)的补码是0xF6h,看汇编指令jmp short s1对应的机器指令EBF6,发现什么了吗?F6就指明了偏移量!
再回到正题,程序中将jmp short s1原封不动地复制到了s处,当程序执行到s处时,向前跳转10个字节,恰好是本文开始提到的那两条用来结束程序的指令!
其实,这个程序没有任何的实际意义,但却能加深我对汇编指令内部机理的理解。
你好!除了代码,此处没有多少原创之物,皆为本人搜集、整理、总结之记录与心得,欢迎转载分享!转载时请尽量注明出处,将不胜感激。祝你健康、快乐!
RFC: Request For Comments. Orz..
Be the first to comment on this entry.