【问题标题】:How to find the return address of a function in C?如何在C中找到函数的返回地址?
【发布时间】:2014-07-12 04:00:46
【问题描述】:

通过阅读 CodeProject here 上的文章,我正在尝试在 C 和 GCC 中使用少量 AT&T 样式的内联汇编。我希望这样做的主要原因是找到 EIP 寄存器的旧值,以便能够在我的代码中拥有可靠的指令地址。到目前为止,我已经编写了一个简单的示例程序来展示我对这个概念的理解:

#include <stdio.h>
#include <stdlib.h>

int mainReturnAddress = 0;

int main()
{
    asm volatile (
         "popl %%eax;"
         "pushl %%eax;"
         "movl %%eax, %0;"
         : "=r" ( mainReturnAddress )
       );

    printf( "Address : %d\n",  mainReturnAddress );
    return 0;
}

此特定示例的目的是从堆栈顶部弹出 4 个字节,表示从 EIP 寄存器保存的 32 位返回地址,然后将其推回堆栈。之后,我将它存储在全局 mainReturnAddress 变量中。最后,我打印存储在 mainReturnAddress 中的值。

我从这段代码4200560收到的输出。

这段代码是否达到了上述目的,这是Windows 32位平台上的跨处理器吗?

【问题讨论】:

  • 堆栈中发生的事情是非常特定于实现的。如果您有本地堆栈变量,它们也会在堆栈上,因此弹出堆栈顶部并不能保证得到您想要的。但是为什么你需要返回地址呢?如果你只是想得到任何指令的“可靠”地址,你可以做int mainAddress = (int) main;,也就是得到main本身的地址。有些人喜欢(int)&amp;main,但这不是必需的。
  • 除了 Mark 和 Carl 提出的优点之外,这个 asm 修改了 eax 而不告诉 gcc 你正在这样做。这是引入非常奇怪的错误的好方法。更好的解决方案是将 pushl/popl %%eax 更改为使用 %0 并删除 movl。哦,如果您打算支持 64 位,则将指针视为整数是一个坏主意。无论如何都是坏习惯。

标签: c windows gcc assembly inline-assembly


【解决方案1】:

在 GCC 中,您应该使用 __builtin_return_address 而不是尝试使用内联汇编。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 2013-11-22
  • 2017-06-04
  • 1970-01-01
  • 2014-03-30
  • 1970-01-01
相关资源
最近更新 更多