我正在用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失望的是)将其转换为a
cfunc
,其定义为typedef void (* cfunc)();
之后,它被称为普通函数。
它通过创建一个thunk
struct
并使用以下行计算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/