首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在x86-64中编码JMP FAR和CALL FAR

在x86-64中编码JMP FAR和CALL FAR
EN

Stack Overflow用户
提问于 2018-08-14 01:09:43
回答 1查看 4.9K关注 0票数 3

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

m16:16是地址位置吗?或者是一个即时地址?任何帮助都将不胜感激!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-14 01:57:46

“编码”通常是指机器代码字节。但我想你是在问汇编程序语法,因为Intel的手册对机器代码很清楚。(有关如何格式化条目和内容的更多信息,请参见jmp的条目或英特尔第2版指令集参考手册的其余部分。)

jmp m16:64是一个内存-间接跳远,有一个新的RIP和CS值(按顺序排列,因为x86是小端的)。

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

您可以使用任何寻址模式。我简单地使用了[rdi]。所有这些在call far / lcall中也是一样的。

NASM语法:

代码语言:javascript
运行
复制
jmp far [rdi]        ; for YASM, you need a manual REX prefix somehow

AT&T语法:

代码语言:javascript
运行
复制
rex64 ljmp *(%rdi)        # force REX prefix which buggy GAS omits
ljmpq *(%rdi)             # clang accepts this, GAS doesn't.

GAS .intel_syntax noprefix反汇编为“`objdump -Mintel”:

代码语言:javascript
运行
复制
  400080:       48 ff 2f        rex.W jmp FWORD PTR [rdi]

或者从llvm-objdump -d到AT&T语法:

代码语言:javascript
运行
复制
  400080:  48 ff 2f             ljmpq   *(%rdi)

GNU错误的,它需要一个48 REX.W前缀来将操作数设置为64位。(关于内存源操作数,我认为。)

FWORD (48位远距离字= m16:32)可能实际上是正确的,没有REX前缀,这就是为什么它不是我们想要的,如果指向内存实际上是一个m16:64,它会在没有REX.W的情况下崩溃。我们需要一个TWORD (m16:64)内存操作数的48 ff 2f

天然气不会组装ljmpq *(%rdi),但是气体会聚集。

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

代码语言:javascript
运行
复制
; 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知道,far jmp需要一个REX.W前缀,这与YASM和GNU Binutils不同。它用

代码语言:javascript
运行
复制
; 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的拆卸输出:

代码语言:javascript
运行
复制
; ndisasm -b64 output thinks it's a dword (m16:16)?
00000000  FF2F              jmp dword far [rdi]

英特尔的手动条目将jmp m16:64 列为REX.W前缀,但GAS / binutils错误地认为这是不必要的。还请参阅关于https://lkml.org/lkml/2012/12/23/164内核代码使用lretrex64 ljmp *initial_code(%rip)的讨论,并猜测AMD是否支持带有REX.W前缀的FF /5。因为AMD文档没有明确提到它。

实验测试:跳远/呼叫所需的REX前缀

我在GNU/Linux上的静态饼可执行文件中测试了这个(因此它将被加载到低32位之外),在Inteli7-6700kSkylake上:

代码语言:javascript
运行
复制
default rel
foo:
    mov  eax, 231
    syscall              ; exit_group(edi)

global _start
_start:

    mov  eax, cs
    push rax             ; push cs is gone in x86-64
    lea  rax, [foo]
    push rax
    call far [rsp]
代码语言:javascript
运行
复制
$ nasm -felf64 farjmp.asm          # or yasm
$ gcc -nostdlib -static-pie farjmp.o  -o farjmp
$ ./farjmp
or  gdb ./farjmp
  • 由YASM (无REX.W)组装,在call far [rsp]上进行分段故障。
  • 由NASM组装,(用REX.W)成功地到达foo:

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

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

32位模式有jmp far ptr16:32 (6字节直接).

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51832437

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档