在x86(64位模式)中编码JMP

时间:2018-08-14 01:09:43

标签: assembly x86 x86-64 instruction-set

我熟悉r / m8,r / m16,imm16等,但是如何编码m16:16,m16:32和m16:64?这些在JMP和CALL指令中...

m16:16是地址位置吗?还是像直接地址一样?任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:3)

“编码”通常表示机器代码字节。但是我想您是在询问汇编器语法,因为英特尔的手册对机器代码很清楚。 (请参阅jmp的条目,或Intel's vol.2 instruction set reference manual的其余部分,以详细了解条目的格式和内容的含义。)


jmp m16:64是一个内存间接的远跳转,具有新的RIP和CS值(该顺序为x86为little-endian)。

就像间接间接跳转一样,您只需提供寻址模式,然后CPU从那里加载内存操作数。但这是一个10字节的内存操作数,而不是8个字节的内存操作数。

您可以使用任何寻址模式。我简单地使用[rdi]call far / lcall的所有这些都是相同的。

NASM / YASM语法:

jmp far [rdi]

AT&T语法:

ljmp *(%rdi)

GAS .intel_syntax noprefix的拆卸:

  400080:       ff 2f              jmp    FWORD PTR [rdi]

例如,设置CS = si和RIP = rdi

; NASM syntax
mov   [rsp], rdi
mov   [rsp+8], si     ; new CS value goes last because x86 is little-endian
jmp far  [rsp]       ; loads 10 byte from memory

push rsi / push rdi / jmp far [rsp],或您要使用的任何其他内存位置。


NASM认为,远距离的jmp需要REX.W前缀。它使用

; assembled by NASM (not YASM), disassembled with objdump -drwC -Mintel
400080:       48 ff 2f                rex.W jmp FWORD PTR [rdi]

printf '\xff\x2f' | ndisasm -b64 -向我们展示了NASM的反汇编输出:

; ndisasm -b64 output thinks it's a dword (m16:16)?
00000000  FF2F              jmp dword far [rdi]

在这一点上,英特尔的手册尚不清楚。它将jmp m16:64列为需要REX.W前缀,但是GAS / binutils认为这不是必需的。通过存储当前的CS值,我们可以轻松地在用户空间中进行测试。


jmp far ptr16:64不存在,并且ptr16:32ptr16:16在64位模式下不可用。那将是一个10字节的立即(直接)绝对跳转目标。 x86-64根本不能使用绝对直接跳转:无法将新的CS或RIP编码为jmp指令。

直接近跳使用rel32rel8,当然它们不能更改CS。 (这就是临近的意思)。

32位模式具有jmp far ptr16:32(立即数为6字节)。

jmp far的用例并不多,尤其是在64位模式下。在内核中,您将使用iretsysret返回32位用户空间,并且通常没有其他理由来切换代码段。我想您可以在内核中将内核切换到32位模式。