如何修复x86_64内存偏移量(GAS)?

时间:2014-12-14 05:18:05

标签: c gdb x86-64 gas opcode

我正在研究C中的一个项目,我遇到了一个问题。我正在尝试对x86_64指令进行硬编码,但内存地址不是很正确。真的,问题本身很简单;我只是想弄清楚它的解决方案。

在GDB中,我得到以下内容:

(gdb) x /7ib f
...
0x7ffff7ff7005: callq  0x80000040072b`

这很好,除了一件事:根据GDB,我想要的地址是0x40072b(在相关的注释中,出于好奇,为什么是内存地址f这么高?)我该如何解决这个问题?作为参考,这里是我正在处理的部分的十六进制(只有这六个字节):

(gdb) x /6xb 0x7ffff7ff7005
0x7ffff7ff7005: 0x48    0xe8    0x20    0x97    0x40    0x08

感谢您提供的任何帮助。

更新

有人要求我解释我如何提出这种抵消:

以下是我正在处理的内容:我想实现一种方法让我在C中使用closures,我试图通过实现我在this article中找到的内容来实现我的基础是最终的......是的,我知道这个解决方案将是特定于架构的。

本质上,它将thunk编码为一个打包结构,其中包含必要的操作码以加载环境并在内存中调用所需函数的位置,然后(令Dennis Ritchie的鬼魂沮丧)被转换为{ {1}},定义为

cfunc

之后,它被称为普通函数。

它通过创建thunk typedef void (* cfunc)(); 并在一两个其他事项中使用以下行计算struct GAS操作的偏移量来完成此操作:

callq

我知道这是可行的,因为它实际上在32位模式下编译原始代码时有效。我想要做的是修改代码以在64位模式下工作。我假设我需要用某种值填充偏移量,以使其指向正确的内存地址,但我不确定该值是什么。那,或者可能有另一种编写调用操作码的方法,我可以使用它来指向正确的内存地址。

1 个答案:

答案 0 :(得分:2)

  

0x48 0xe8 0x20 0x97 0x40 0x08

转换为:

48 e8 20974008
 |  |    |
 |  |    +------ Offset (As of opcode)
 |  +----------- Opcode (CALL)
 +-------------- REX prefix

48:REX前缀

  0100 1000
    |  ||||
    |  |||+-- B - Extension to MODRM.rm or SIB.base
    |  ||+--- X - Extension to SIB.index
    |  |+---- R - Extension to MODRM.reg
    |  +----- W - 64-bit operand size, else (usually) 32-bit
    +-------- Fixed bit pattern

换句话说:64位操作数大小。

e8:操作码

查看instruction manual一个查找:

  

CALL e8 cd

     

拨打附近, 相对,置换相对到下一条指令。在64位模式下,32位位移符号扩展为64位。

其中:

  

cd - 操作码后面的4字节值。该值用于指定代码段寄存器的代码偏移量和可能的新值。

cd 就是这种情况:

  

20 97 40 08

从小到大的顺序我们得到:

  

08409720 + 6

我们加6,因为偏移是相对于下一条指令。因为指令是六个字节。

  

0x48 0xe8 0x20 0x97 0x40 0x08

换句话说:

callq fun_08409726

在打印出来的GDB中:

(gdb) x /7ib f
...
0x7ffff7ff7005: callq  0x80000040072b`

您可以通过以下地址获取地址0x7ffff7ff7005的偏移量:

0x7ffff7ff7005 + 0x08409726 = 0x80000040072b
      |              |              |
      |              |              +-------- Result address (same as in GDB).
      |              +----------------------- The offset we calculated above.
      +-------------------------------------- Memory offset of the instruction.

GDB可能会发生一些事情,但这看起来不太合适。

(虚拟)地址0x000080000040072b高于0x00007fffffffffff。地址的原因是由指令偏移引起的。现在如何生成此偏移量。 (正如你所说“我正在尝试对x86_64指令进行硬编码”)你可能最了解自己。