使用 Intel Pin 时跟踪不匹配的 CALL 和 RET 指令数
Posted
技术标签:
【中文标题】使用 Intel Pin 时跟踪不匹配的 CALL 和 RET 指令数【英文标题】:Number of CALL and RET instructions tracking mismatch while using Intel Pin 【发布时间】:2015-06-25 01:45:55 【问题描述】:我正在尝试使用 Intel Pintool 来监控 x86-64 机器 (Mac Pro) 上的 CALL
和 RET
指令。我将IARG_INST_PTR
(下面提到)传递给docount
函数并使用指令指针通过检查操作码来推断指令(CALL
是0xe8,RET
是来自Intel x86-64 manual的0xc3。但是,似乎此检查并不完全准确,因为对于任何使用此逻辑检测的给定二进制文件,我注意到 RET
的数量比 CALL
的数量要多。
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_CONTEXT,
IARG_INST_PTR, IARG_END);
谁能指点一下我做错了什么?
我从/tools/ManualExamples/inscount0.cpp
借来了模板。要找到它,请搜索文件名here。
【问题讨论】:
编译后的代码真的有可能比call
拥有更多的ret
吗?如果 (a) 返回 1;否则,如果 (b) 返回 2;否则返回 3;内部函数可能会生成多个ret
除非代码有问题,否则不应该有任何不匹配。这意味着我的 CALL/RET 检测逻辑一定是有缺陷的。我希望得到一些指示来纠正同样的问题。
@SeverinPappadeux - 多个返回语句不会导致单独的 RET 指令,而是会导致 JMP 指令到 RET,并在 RAX 寄存器中具有适当的返回值。
嗯,执行时间会更长,因为它是 JMP+RET 而不是 RET。但是代码大小会更大。我猜想在某些优化设置下,编译器可能更喜欢到处发出 RET 而不是 JMP+RET
@user1983710 我之前的例子是完全错误的。我对其进行了重新设计,CALL 和 RET 之间的差异很大,CALL 比 RET 多(在 Windows 上的简单控制台程序上测试,即ipconfig.exe
):CALL: 176298
,RET: 170374
。我仍在试图找出原因(尽管它可能与系统内部有关)。我会尝试构建一个 pintool 来记录可能不匹配的 CALL/RET 对。你有我的 +1!
【参考方案1】:
call 和 ret 指令之间并不总是匹配,因为函数可能会被异常、goto-like 语句、longjumps、信号等中断......所以如果你想重新协调调用和 ret,你可以想要考虑所有这些。
这已经讨论过好几次了,尤其是here
【讨论】:
【参考方案2】:有various versions of CALL
s with different opcodes,所以你不能只检查0xE8
。完整列表可在 Intel 手册的调用程序部分中找到:
同RET
请注意,上面包含相同操作码的行仅适用于不同的模式(16/32/64 位)
【讨论】:
嗨,我试过这些(我不确定如何匹配 REX.W + FF 指令),但现在 - 调用计数为 68183,RET 计数为 44971 bool isRet(unsigned int valAtInstrPtr)无符号整数 foo = (valAtInstrPtr & 0xFF);返回 foo == 0xc3 ||富== 0xcb ||富== 0xc2 ||富== 0xca; bool isCall(unsigned int valAtInstrPtr) unsigned int foo = (valAtInstrPtr & 0xFF);返回 foo == 0xe8 ||富== 0xff ||富== 0x9a; 把代码放到backticks
或者几乎没有人能读到你写的东西。 REX prefix 是 0x4X。 0xFF 不是前缀,而是表示 2 字节操作码,因此您需要检查下一个字节。但是为什么不将二进制/十六进制输出输入反汇编程序并计数呢?如果你想自己解析它,你必须了解 x86_64 指令格式。它们不仅仅是一个操作码字节,然后是许多参数
你应该区分远调用和近调用;主流操作系统的普通用户空间代码不会有任何远调用。以上是关于使用 Intel Pin 时跟踪不匹配的 CALL 和 RET 指令数的主要内容,如果未能解决你的问题,请参考以下文章