函数调用中传递了多少个参数?

时间:2016-12-18 20:48:45

标签: function assembly call reverse-engineering

我希望分析调用函数的汇编代码,并为每个'call'找出传递给函数的参数数量。我假设我无法访问目标函数,只能访问调用代码。 我将自己限制为仅使用GCC编译的代码,以及System V ABI调用约定。 我尝试从每个“调用”指令进行扫描,但是我没有找到足够好的约定(例如,在哪里停止扫描?在具有相同参数的两个后续调用中会发生什么?)。非常感谢协助。

1 个答案:

答案 0 :(得分:4)

将我的评论作为答案重新发布。

您无法可靠地告知优化代码。即使在大多数时间做得很好,也可能需要人工智能AI。例如一个函数在RSI中保留一个值,因为它是第二个参数,还是在计算RDI的值(第一个参数)时它只是使用RSI作为临时寄存器?正如Ross所说,gcc生成的stack-args调用约定代码有更明显的模式,但仍然没有什么容易检测。

也很难区分将本地人泄漏到堆栈的商店与将args存储到堆栈的商店之间的区别(因为gcc可以并且确实有时会使用mov存储堆栈args :见-maccumulate-outgoing-args)。区分不同的一种方法是稍后将重新加载本地人,但总是假定args被破坏。

  

在具有相同参数的两个后续调用中会发生什么?

编译器总是在进行另一次调用之前重写args,因为他们认为函数会破坏它们的args(甚至在堆栈上)。 ABI说功能"拥有"他们的args。编译器确实生成了执行此操作的代码(请参阅注释),但编译器生成的代码并不总是愿意重新使用堆栈内存来保存其args以存储完全不同的args,以便启用尾调用优化。 :(这很浪漫,因为我不记得我错过尾调优化的机会。

  

然而,如果参数由堆栈传递,那么它可能是更容易的情况(我得出结论,所有6个寄存器也被使用)。

即便这样也不可靠。 System V x86-64 ABI 不是简单。

int foo(int, big_struct, int)将在regs中传递两个整数args,但是在堆栈上按值传递大结构。 FP args也是一个主要的复杂因素。你不能得出结论,看到堆栈上的东西意味着使用了所有6个整数arg传递槽。

Windows x64 ABI有很大不同:例如,如果第二个arg(在需要时添加隐藏的返回值指针之后)是整数/指针,它总是在RDX中,无论第一个arg是否进入RCX ,XMM0或堆栈。它还要求呼叫者离开"阴影空间"。

因此,您可以提出一些启发式方法,以便对未优化的代码起作用。即使这样也很难做到。

对于不同编译器生成的优化代码,我认为实现任何与您相比有用的任何东西都会更有效。

相关问题