繁体   English   中英

C中的栈指针如何获取返回地址?

[英]How do I obtain the return address from the stack pointer in C?

对不起,我的 C 有点生疏了。

我想仅使用堆栈指针的地址来获得返回地址作为练习。 我知道我可以使用__builtin_return_address function 直接获取返回地址,但我想使用堆栈指针手动完成。

现在我只有指向返回地址的指针的地址,但我想获得实际地址。

void a() {
    void *sp = __builtin_frame_address(0);
    printf("%p\n", (*(&sp) + 0x8));
}

int main() {
    a();
}

来自此扩展的GNU 文档

6.51 获取 Function 的返回地址或帧地址

这些函数可用于获取有关 function 的呼叫者的信息。

内置 Function: void * __builtin_return_address (unsigned int level)

这个 function 返回当前 function 或其调用者之一的返回地址。 level 参数是扫描调用堆栈的帧数。 0产生当前 function 的返回地址,值1产生当前 function 的调用者的返回地址,依此类推。 内联时预期的行为是 function 返回返回到的 function 的地址。 要解决此问题,请使用noinline function 属性。

level 参数必须是常量 integer。

在某些机器上,可能无法确定当前地址以外的任何 function 的返回地址; 在这种情况下,或者当到达栈顶时,这个 function 返回一个未指定的值。 此外, __builtin_frame_address可用于确定是否已到达堆栈顶部。

可能需要对返回值进行额外的后处理,请参阅__builtin_extract_return_addr

memory 中返回地址的存储表示可能与__builtin_return_address返回的地址不同。 例如,在 AArch64 上,存储的地址可能会被返回地址签名破坏,而__builtin_return_address返回的地址则不会。

使用非零参数调用此 function 可能会产生不可预知的效果,包括使调用程序崩溃。 因此,当-Wframe-address选项生效时,会诊断出被认为不安全的调用。 此类调用只能在调试情况下进行。

在代码地址可表示为void *的目标上,

void *addr = __builtin_extract_return_addr(__builtin_return_address(0)); 给出当前 function 将返回的代码地址。 例如,这样的地址可以与 dladdr 或其他使用代码地址的接口一起使用。

内置 Function: void * __builtin_extract_return_addr(void *addr)

__builtin_return_address返回的地址可能必须通过这个 function 来获取实际的编码地址。 例如,在 31 位 S/390 平台上,最高位必须被屏蔽掉,或者在 SPARC 平台上,必须添加偏移量才能真正执行下一条指令。

如果不需要修正,这个 function 简单地通过addr

内置 Function: void * __builtin_frob_return_addr(void *addr)

这个 function 与__builtin_extract_return_addr相反。

内置 Function: void * __builtin_frame_address(unsigned int level)

这个 function 类似于__builtin_return_address ,但它返回 function 帧的地址而不是 function 的返回地址。调用值为0__builtin_frame_address产生当前 function 的帧地址,值为1产生帧地址当前 function 的呼叫者,依此类推。

帧是堆栈上保存局部变量和保存的寄存器的区域。 帧地址通常是由 function 压入堆栈的第一个字的地址。但是,确切的定义取决于处理器和调用约定。 如果处理器有一个专用的帧指针寄存器,并且 function 有一个帧,那么__builtin_frame_address返回帧指针寄存器的值。

在某些机器上,可能无法确定当前地址以外的任何 function 的帧地址; 在这种情况下,或者当已到达堆栈顶部时,如果启动代码正确初始化了第一个帧指针,则此 function 将返回 0。

使用非零参数调用此 function 可能会产生不可预知的效果,包括使调用程序崩溃。 因此,当-Wframe-address选项生效时,会诊断出被认为不安全的调用。 此类调用应仅在调试情况下进行。

这是修改后的代码:

#include <stdio.h>

void a() {
    printf("return address: %p\n", __builtin_extract_return_addr(__builtin_return_address(0)));
}

int main() {
    a();
    return 0;
}

从帧地址获取返回地址并不总是可能的,并且是系统特定的,它还取决于 function 调用约定。 编译器在编译内置__builtin_return_address时考虑了这些因素,尝试从__builtin_frame_address的值手动完成它是非常棘手的。

如果您的目标是构建一个内省系统,您可能必须分别存储帧和返回地址。 您将需要解析调试信息以尝试理解可通过这些指针访问的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM