我正在用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中的发现来实现这一点(我以此为基础的部分在最后。。。是的,我知道解决这个问题的方法是特定于体系结构的)。
本质上,它将athunk编码为一个压缩结构,其中包含加载环境和调用所需函数在内存中的位置所需的操作码,然后(令Dennis Ritchie的ghost失望的是)将其转换为acfunc,其定义为
typedef void (* cfunc)();

之后,它被称为普通函数。
它通过创建一个thunkstruct并使用以下行计算callq气体操作的偏移量来实现此目的:
             (Pointer to first byte of the ------+
             instruction following the CALL op)  |
                                                 |
                                                 |
          (Function to be called by CALL op)     |
                      |                          |
                      |                          |
thunk->call_offset = code - (void *)&thunk->add_esp[0];
        |
        +--- A Signed Long in the 32-bit version
             (Because Longs are 8 bits in 64-bit
              GCC, I have changed it to being a
              Signed Int)

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

最佳答案

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发现:
呼叫e8 cd
调用near,relative,相对于下一条指令的位移。在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指令”)您可能最了解自己。

关于c - 如何修复x86_64内存偏移(GAS)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27466597/

10-16 19:33