ARM GCC生成函数序言
我提到ARM工具链可以生成不同的函数序言。 实际上,我看到了两个完全不同的function序言的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在functionprolog? 如果是的话他们是什么?
2.)这是用来做什么的? 基本上,据我所知,我可以只用FP和LR展开堆栈,为什么我需要这个额外的值?
3.)如果这个事情与编译标志没有任何关系 – 我怎么能强制生成这个扩展函数prolog,又是什么目的?
谢谢。
1.)我是否正确需要一些gcc额外的标志来推动额外的pc和sp在functionprolog? 如果是的话他们是什么?
有许多gcc选项会影响堆栈帧( -march
, -mtune
等可能会影响用于的指令)。 在您的情况下,它是-mapcs-frame
。 此外, -fomit-frame-pointer
将从叶子函数中删除帧。 几个静态函数可以合并在一起形成单个生成函数,从而进一步减少帧数。 APCS可能导致稍慢的代码,但堆栈跟踪需要。
2.)这是用来做什么的? 基本上,据我所知,我可以只用FP和LR展开堆栈,为什么我需要这个额外的值?
所有非参数的寄存器(r0-r3)都需要保存,因为它们在返回调用者时需要恢复。 编译器将在堆栈上分配其他本地,因此当fp
更改时sp
几乎总是会更改。 有关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}
的恢复ldm sp, {fp, sp, lr}
。 如果您检查ABI / APCS文档,这是正确的。 注意,没有’!’ 尝试修复堆栈。 它是从存储的ip
值显式加载的。
此外,结尾没有使用保存的pc
。 它只是堆栈中丢弃的数据。 那么为什么呢? exception处理程序(中断,信号或C ++exception)和其他堆栈跟踪机制想知道谁保存了一个帧。 ARM始终只有一个函数序言 (一个入口点)。 但是,有多个出口。 在某些情况下,返回类似return function();
实际上可能在这里可能更多的东西变成b function
。 这称为尾调用。 此外,当在例程的中间调用叶函数并发生exception时,它将看到PC
范围的叶,但叶可能没有调用帧。 通过保存pc
,可以在叶子中发生exception时检查调用帧 ,以了解谁真正保存了堆栈。 可以存储pc
与析构函数等的表,以允许释放对象或者弄清楚如何调用信号处理程序。 跟踪堆栈时额外的pc
非常好,并且由于管道衬里,操作几乎是免费的。
另请参阅: ARM链接和帧寄存器问题,了解编译器如何使用这些寄存器。