我熟悉r / m8,r / m16,imm16等,但是如何编码m16:16,m16:32和m16:64?这些在JMP和CALL指令中...
m16:16是地址位置吗?还是像直接地址一样?任何帮助将不胜感激!
答案 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:32
或ptr16:16
在64位模式下不可用。那将是一个10字节的立即(直接)绝对跳转目标。 x86-64根本不能使用绝对直接跳转:无法将新的CS或RIP编码为jmp
指令。
直接近跳使用rel32
或rel8
,当然它们不能更改CS。 (这就是临近的意思)。
32位模式具有jmp far ptr16:32
(立即数为6字节)。
jmp far
的用例并不多,尤其是在64位模式下。在内核中,您将使用iret
或sysret
返回32位用户空间,并且通常没有其他理由来切换代码段。我想您可以在内核中将内核切换到32位模式。