汇编语言编程中,如果要实现类似高级语言中的分支和循环等,就必须要使用各种的转移指令,包含无条件转移指令(如jmp)、条件转移指令(如jcxz)、循环指令(如loop)、中断等。在8086CPU上,转移指令的本质是修改寄存器cs和ip的值,将其执行下一条要执行的指令,最基础的无条件跳转指令jmp,就是根据要跳转到的位置修改ip的值。

基本的jmp模式有两种:

向前跳转

1
2
3
s:
...
jmp s (jmp short sjmp near ptr sjmp far ptr s)

编译器从上到下处理每条指令,当读到s时记录下内存地址,在读到jmp s时记下内存地址,前后两个地址相减算出偏移量disp。

(1)如果disp∈[-128,127]

jmp s、jmp short s、jmp near ptr s、jmp far ptr s四种指令都会转变为机器指令:EB disp(占两个字节)

1
2
3
4
5
6
7
8
9
assume cs:code
code segment
s:
jmp s
jmp short s
jmp near ptr s
jmp far ptr s
code ends
end s

用masm编译器编译后,生成的机器指令为:

1
2
3
4
5
6
D:\asm>debug main.exe
-u
1437:0000 EBFE          JMP     0000
1437:0002 EBFC          JMP     0000
1437:0004 E9F9FF        JMP     0000
1437:0007 EA00003714    JMP     1437:0000

(2)如果disp∈[-128,127]

1
2
3
4
5
6
7
8
9
10
assume cs:code
code segment
s:
db 100 dup (0b8h,0,0)
jmp s
jmp short s
jmp near ptr s
jmp far ptr s
code ends
end s

用masm编译器编译,提示jmp short s出错。

删除jmp short s,再次编译成功,对应的机器指令为:

1
2
3
1437:012C E9D1FE        JMP     0000
1437:012F E9CEFE        JMP     0000
1437:0132 EA00003714    JMP     1437:0000

对于jmp s、jmp near ptr s产生机器码E9 disp(占三个字节)

对于jmp far ptr s产生机器码EA 偏移地址 段地址(占五个字节)

向后跳转

1
2
3
4
jmp s (jmp short sjmp near ptr sjmp far ptr s)
...
s:
...

编译器从上到下处理每条指令,先读到jmp…s指令,并不能计算出偏移量disp,根据jmp的具体写法分别做处理:

  • 对于jmp short s,编译器产生EB和1个nop指令(预留存放8位disp)
  • 对于jmp s和jmp near ptr s,编译器产生EB和2个nop指令(预留存放16位disp)
  • 对于jmp far ptr s,编译器产生EB和4个nop指令(预留存放32位偏移地址和段地址)

然后,编译器继续读取指令,当读到s时,计算出偏移地址disp,添加到预留的nop指令处。

(1)如果disp∈[-128,127]

1
2
3
4
5
6
7
8
9
10
11
assume cs:code
code segment
start:
jmp short s
jmp s
jmp near ptr s
jmp far ptr s
s:
mov ax,0
code ends
end start

对应的机器指令:

1
2
3
4
5
6
D:\asm>debug main.exe
-u
1437:0000 EB0A          JMP     000C
1437:0002 EB08          JMP     000C
1437:0004 E90500        JMP     000C
1437:0007 EA0C003714    JMP     1437:000C

(2)如果disp∈[-128,127]

1
2
3
4
5
6
7
8
9
10
11
assume cs:code
code segment
start:
jmp s
jmp near ptr s
jmp far ptr s
db 100 dup (0b8h,0,0)
s:
mov ax,0
code ends
end start

对应的机器指令:

1
2
3
4
5
D:\asm>debug main.exe
-u
1437:0000 E93401        JMP     0137
1437:0003 E93101        JMP     0137
1437:0006 EA37013714    JMP     1437:0137