我正在查看一些汇编练习代码,任务基本上是用另一个跳转点替换一个跳转点。
原始 jmp 是 SHORT jmp,而我需要到达的终点无法使用此指令。
现在我有三个选项,要么删除“SHORT”,要么插入“LONG”,要么插入“FAR”。
如果有任何说明它们之间差异的文档,我还没有找到。有人能帮忙吗?
一个SHORT
跳转:
LONG
跳转可以使用更大的偏移量。
FAR
跳转,跳转到另一个代码段。
LONG
跳转可以是相对或absolute indirect
,而FAR
跳转总是指定一个绝对地址,但LONG
跳转不是这样的。 - davmacshort
和long
/near
只是强制指令长度的选择。far
则完全不同。
jmp short foo
是 jmp rel8
。jmp long foo
或 jmp near foo
是 jmp rel16/rel32
(取决于模式)jmp far [rdi]
是跳转/调用到一个新的CS:[ER]IP。你很少需要这样做。jmp
/call
、jcc
(如jge
等条件语句)和loop
(其编码方式类似于jcc short
)。
EB 00
是使用短的jmp
进行缓慢的NOP。或者E8 00 00 00 00
/ 5B
是一个call next
(或call $+5
),next: pop ebx
,就像您在32位模式下读取EIP但实际上不去任何地方一样,其中RIP相对LEA不可用。jmp rel16
,但它会将EIP截断为16位。(并且编码使用一个66h
操作数大小前缀,因此它只比jmp rel32
少1个字节)jmp rel16/rel32
可以到达任何其他IP/EIP值,但是在64位模式下,+-2GiB范围仅占虚拟地址空间的一小部分。尽管如此,对于单个可执行文件的代码来说,假设它适合于2GiB是很正常的,因此任何代码都可以通过相对近跳转/调用到达同一库或主可执行文件中的任何其他代码。一个“大型”代码模型需要 mov reg, imm64
/ jmp reg
或类似低效的东西。甚至更糟糕的是让它成为位置无关的。
1 foo:
2 00000000 E9FBFFFFFF jmp near foo
3 00000005 EBF9 jmp foo ; optimizes to short by default
4 00000007 EBF7 jmp short foo
near
(非短)。如果您知道要链接的文件很小(或代码在特殊部分中),则可以强制执行该操作。rel32
供其他内容修改这段机器码并编写新的偏移量,则near
是一种用例。例如,在Linux上用于动态链接的PLT曾经就是这样工作的(我认为),重写jmp rel32
中的偏移量而不是使用GOT条目进行间接jmp。jcc near
仅支持386及更高版本,因此如果您希望汇编器实际发出它,您可能需要明确指出。
jmp near foo
相同的 rel16 / rel32 覆盖。请参见 https://www.felixcloutier.com/x86/jmp 以获取机器代码中可用的形式。 - Peter Cordes