【问题标题】:Why can't I save the value of rip? [duplicate]为什么我不能保存 rip 的值? [复制]
【发布时间】:2023-03-22 12:23:01
【问题描述】:
#include <stdint.h>
uint64_t rip;
int main()
{
    asm(
        "movq %%rip, %0\n" : "=m" (rip)
        );

    sleep(10);
}

当我编译时我得到

cc -m64    rip.c   -o rip
/tmp/ccwNbZi1.s: Assembler messages:
/tmp/ccwNbZi1.s:12: Error: suffix or operands invalid for `movq'
make: *** [rip] Error 1

【问题讨论】:

标签: assembly x86


【解决方案1】:

您无法读取(E|R)IP,因为没有 x86(/64) 指令可以直接读取它。

“读取”它的唯一方法是使用CALL 指令进行调用。它会将返回地址保存在堆栈中,并且您可以读取该地址。

更新:在 64 位模式下,您可以利用 RIP 相对寻址,因此 LEA RAX, [RIP] 将在 RAX 中为您提供其自身的地址。另一种解决方法是在汇编中使用MOV RAX, $

【讨论】:

  • mov rax, $ 要么由链接器硬编码,消除位置无关性,要么在运行时需要重定位。我强烈建议改用lea rax, [rip]
  • @ughoavgfhw 没有关于位置-(内)依赖性的问题。
  • 这就是为什么我只是强烈建议它。此外,位置独立性是现代程序中非常常见的目标,主要是出于安全原因 (ASLR)。至少 Apple 的编译器/汇编器需要 64 位程序。
  • @AlexeyFrunze 当然,mov rax,$ 仍可重定位,但不再与位置无关。只需考虑一个汇编例程,它将代码块移动几个字节:移动后lea rax,[rip] 仍然有效,但mov rax,$ 不再有效。
  • 是的,这正是我的意思。装配通常用于这种事情。它是“加载一个常量,它恰好是重定位后指向当前执行地址的指针”而不是“加载 rip”。
【解决方案2】:

我能想到的在 x86_64 下获取/设置 %rip 的唯一方法是使用 ptrace()。 下面是从ltrace的源代码复制过来的。

void* addr = ptrace(PTRACE_PEEKUSER, pid, (8 * RIP), 0);
ptrace(PTRACE_POKEUSER, pid, (8 * RIP), addr);

其中 RIP 是在 /usr/include/sys/reg.h 中定义的宏

【讨论】:

  • RIP-relative lea 读取它,jmp 写入它。这个问题是关于当前线程的 RIP,而不是其他进程。
猜你喜欢
  • 2018-07-06
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 2020-12-13
  • 2015-11-14
  • 1970-01-01
  • 2021-10-25
  • 1970-01-01
相关资源
最近更新 更多