我提到过ARM工具链可以生成不同的函数prolog,实际上,我看到了两个obj文件(vmlinux),它们具有完全不同的函数prolog:
第一种情况如下所示:
push {some registers maybe, fp, lr} (lr ommited in leaf function)
字符串
第二种情况如下:
push {some registers maybe, fp, sp, lr, pc} (i can confuse the order)
型
所以,我看到第二个额外推送pc和sp。我还看到崩溃实用程序(kdump项目)中的一些注解,其中指出,内核堆栈帧应该有格式{...,fp,sp,lr,pc},这让我更困惑,因为我看到在某些情况下,这是不正确的。
1.)我说的对吗,一些gcc额外的标志需要在函数prolog中额外推送pc和sp?如果是,它们是什么?
2.)这是做什么用的?基本上,就我所知,我可以只用FP和LR来展开堆栈,为什么我需要这些额外的值?
3.)如果这个东西没有编译标志,我怎么能强制生成这个扩展函数的prolog,目的是什么?
谢谢
1条答案
按热度按时间gudnpqoy1#
1.)我说的对吗,一些gcc额外的标志需要在函数prolog中额外推送pc和sp?如果是,它们是什么?
有许多gcc选项会影响堆栈帧(
-march
,-mtune
等可能会影响例如使用的指令)。在您的情况下,它是-mapcs-frame
。此外,-fomit-frame-pointer
将从叶函数中删除帧。几个静态函数可以合并到一个生成的函数中,以进一步减少帧的数量。APCS可能会导致代码稍微变慢但是对于简单的堆栈跟踪是需要的。2.)这是做什么用的?基本上,就我所知,我可以只用FP和LR来展开堆栈,为什么我需要这些额外的值?
所有不是参数的寄存器(r 0-r3)都需要保存,因为它们需要在返回给调用者时恢复。编译器将在堆栈上分配额外的局部变量,因此当
fp
更改时,sp
几乎总是会更改。关于存储pc
的原因,请参阅下文。3.)如果这个东西没有编译标志,我怎么能强制生成这个扩展函数的prolog,目的是什么?
正如您所猜测的那样,它是编译器标志。
字符串
典型的保存是
stm sp!, {fp, ip, lr, pc}
,恢复是ldm sp, {fp, sp, lr}
。如果您检查ABI/APCS文档,这是正确的。注意,没有“!”来尝试和修复堆栈。它是从存储的ip
值显式加载的。另外,保存的
pc
并没有在尾声中使用。它只是堆栈上丢弃的数据。那么为什么要这样做呢?异常处理程序(中断、信号或C++异常)和其他堆栈跟踪机制都想知道谁保存了一个帧。(一个入口)。然而,有多个出口。在某些情况下,像return function();
这样的返回实际上可能会变成b function
,在 * 这里可能有更多的东西 *。这被称为尾调用。同样,当在例程中间调用叶函数并发生异常时,它将看到叶的PC
范围,但叶可能没有调用帧。通过保存pc
,当在leaf中发生异常时,可以检查 call frame,以知道是谁真正保存了堆栈。pc
与析构函数的表,等,可以存储以允许 * 对象 * 释放或弄清楚如何调用信号处理程序。额外的pc
在跟踪堆栈时非常好,由于管道衬里,操作几乎是免费的。参见:ARM Link and frame register问题,了解编译器如何使用这些寄存器。