ARM GCC生成函数序言

时间:2015-09-17 06:10:25

标签: c gcc assembly stack arm

我提到ARM工具链可以生成不同的函数序言。实际上,我看到两个具有完全不同功能序言的obj文件(vmlinux):

第一种情况如下:

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额外的标志来推动额外的pc和sp in function prolog?如果是的话他们是什么?。

2。)这是用来做什么的?基本上,据我所知,我只能用FP和LR展开堆栈,为什么我需要这些额外的值?

3。)如果这件事与编译标志无关 - 我怎么能强制生成这个扩展函数prolog又是什么目的?

谢谢。

1 个答案:

答案 0 :(得分:2)

  

1。)我是否正确需要一些gcc额外的标志来推动额外的pc和sp in function prolog?如果是的话他们是什么?。

有许多gcc选项会影响堆栈帧(-march-mtune等可能会影响用于的示例)。在您的情况下,它是-mapcs-frame。此外,-fomit-frame-pointer将从叶函数中删除帧。几个静态函数可以合并在一起形成单个生成函数,从而进一步减少帧数。 APCS可能导致代码稍慢,但堆栈跟踪需要。

  

2。)这是用来做什么的?基本上,据我所知,我只能用FP和LR展开堆栈,为什么我需要这些额外的值?

所有非参数的寄存器(r0-r3)需要保存,因为它们在返回调用者时需要恢复。编译器将在堆栈上分配其他本地,因此spfp更改时几乎总会更改。有关存储pc的原因,请参见下文。

  

3。)如果这件事与编译标志无关 - 我怎么能强制生成这个扩展函数prolog又是什么目的?

正如您所猜测的那样是编译器标志。

; Prologue - setup
mov     ip, sp                 ; get a copy of sp.
stm     sp!, {fp, ip, lr, pc}  ; Save the frame on the stack. See Addendum
sub     fp, ip, #4             ; Set the new frame pointer.
    ...
; Epilogue - return
ldm     sp, {fp, sp, lr}       ; restore stack, frame pointer and old link.
    ...                        ; maybe more stuff here.
bx      lr                     ; return.

典型保存为stm sp!, {fp, ip, lr, pc},还原为ldm sp, {fp, sp, lr}。如果您检查ABI / APCS文档,这是正确的。请注意,没有'!'尝试修复堆栈。它是从存储的ip值明确加载的。

此外,结尾中未使用已保存的pc。它只是堆栈中丢弃的数据。那么为什么呢?异常处理程序(中断,信号或C ++异常)和其他堆栈跟踪机制想知道谁保存了一个帧。 ARM始终只有一个函数 prologue (一个入口点)。但是,有多个退出。在某些情况下,return function();之类的回报实际上可能会变成中的b function或更多的东西。这被称为尾调用。此外,当在例程的中间调用叶函数并发生异常时,它将看到PC范围的叶,但叶可能没有调用框。通过保存pc,可以在叶子中发生异常时检查调用框架,以了解谁真正保存了堆栈。可以存储pc与析构函数等的表,以允许释放对象或者弄清楚如何调用信号处理程序。跟踪堆栈时额外的pc非常好,由于管道衬里,操作几乎是免费的。

另见:ARM Link and frame register关于编译器如何使用这些寄存器的问题。