【发布时间】:2020-12-10 14:05:45
【问题描述】:
我做了什么?
我在每条指令后运行qemu-x86_64 -singlestep -d nochain,cpu ./dummy 转储虚拟程序的所有寄存器,并使用 grep 将所有 RIP 值保存到文本文件 (qemu_rip_dump.txt) 中。然后,我使用 ptrace 单步执行虚拟程序,并将每条指令后的 RIP 值转储到另一个文本文件 (ptrace_rip_dump.txt) 中。然后我将这两个 .txt 文件与diff 进行了比较。
我期待什么结果?
我希望虚拟程序的两次运行都执行相同的指令,因此两个转储文件都是相同的(相同的 rip 值和相同数量的 rip 值)。
我实际得到了什么结果?
Ptrace 转储了大约 33.500 个 RIP 值,Qemu 转储了 29.800 个 RIP 值。两个文本文件的 RIP 值开始不同于 240. 指令,大多数 rip 值是相同的,但 ptrace 执行大约 5500 条指令 qemu 不执行,qemu 执行大约 1800 条指令 ptrace 不执行因此导致大约 3700 条指令的差异。两次运行似乎在整个程序中执行的事情都不同,例如有一个来自 26.500-30.000 指令(清理?)的 3500 条指令块,本机运行执行但不执行 qemu。
我的问题是什么
为什么在整个程序执行过程中 RIP 值不一样,最重要的是:我必须做些什么才能使两次运行相同?
额外信息
- 虚拟程序是一个返回 0 的主函数,但这个问题存在于我跟踪的每个可执行文件中
- 我尝试使用带有
-L /lib64/的ld-linux-x86-64.so.2链接器强制qemu - 这没有效果 - 如果我多次运行 qemu,转储是相同的(RIP 的数量和值相同),ptrace 也是如此
【问题讨论】:
-
当你在两个不同的系统上本地运行同一个程序时会发生什么?
-
@stark 在不同系统上运行代码会稍微改变执行的指令数量,但 ptrace 和 qemu 之间的差异保持大致相同
-
您需要分析实际的执行运行(如果它们相差 insn 240 左右,这不会很困难)以确定原因。可能的原因包括 QEMU 为程序提供的环境与本机版本不完全相同——例如它放在辅助向量中的一组东西有点不同,所以如果动态链接器迭代 auxv 那么它将循环不同的次数。
-
顺便说一句,除非你真的关心动态链接器,否则你可能会丢弃 main() 中第一个 insn 之前的所有 RIP 值——我怀疑这更有可能在两者中给出相同的结果情况下,尽管在 main() 之后肯定有一些访客程序也会显示出不同。
-
好的,所以第一部分确实是动态链接器正在查看辅助向量的地方。其他一些看起来像是客户代码正在查看 CPU 支持的功能的地方——在您的主机 CPU 上,有 SSE2 支持,因此客户 libc 选择使用它的函数的优化版本,如 strlen 和 memcpy,但 QEMU 没有'不支持 SSE2 仿真,因此来宾 libc 使用不同的版本。
标签: linux dynamic linker qemu ptrace