ARM:链接寄存器和帧指针

use*_*706 28 c arm

我试图理解链接寄存器和帧指针在ARM中是如何工作的.我去过几个网站,我想确认一下我的理解.

假设我有以下代码:

int foo(void)
{
    // ..
    bar();
    // (A)
    // ..
}

int bar(void)
{
    // (B)
    int b1;
    // ..
    // (C)
    baz();
    // (D)
}

int baz(void)
{
    // (E)
    int a;
    int b;
    // (F)
}
Run Code Online (Sandbox Code Playgroud)

我叫foo().将链接寄存器包含在点(A)的地址码和帧指针包含在代码点(B)的地址?在声明了所有本地人之后,堆栈指针可以是bar()内的任何位置吗?

[编辑]添加了另一个函数调用baz()

art*_*ise 67

一些寄存器调用约定依赖于ABI(应用程序二进制接口).这FPAPCS标准所要求的,而不是新的AAPCS(2003).对于AAPCS(GCC 5.0以上)在FP具有被使用,但可以肯定是,调试信息使用堆栈和帧指针进行注释,用于堆栈跟踪和使用AAPCS展开代码.如果函数是static,编译器实际上不必遵守任何约定.

通常,所有ARM寄存器都是通用的.该lr(链接寄存器,也R14)和pc(程序计数器也R15)是特殊的,在指令集供奉.你lr指出A是正确.该pclr是相关的.一个是"你在哪里",另一个是"你在哪里".它们是函数的代码方面.

通常,我们有sp(堆栈指针,R13)和fp(帧指针,R11).这两者也有关系.这个 Microsoft布局很好地描述了一些事情.该堆栈用于存储临时数据或当地人在你的函数.在任何变量foo()bar(),都存储在这里,在堆栈或可用寄存器.该fp跟踪变量从功能功能.它是该功能的堆栈上的或图片窗口.在ABI定义此的布局.通常,lr编译器和其他寄存器在幕后保存,以及之前的值fp.这将生成堆栈帧的链接列表,如果您需要,可以一直追溯到它main().该fp,它指向一个堆栈帧(如struct)与一个变量在struct为前fp.您可以沿着列表一直到fp正常的决赛NULL.

所以sp堆栈的位置和fp堆栈的位置,很像pclr.每个旧的lr(链接寄存器)都存储在旧的fp(帧指针)中.的spfp是一个数据的功能方面.

你点是活动pcsp.A点实际上是fplr; 除非你调用另一个函数然后编译器可能已准备好设置fp指向B中的数据.

以下是一些ARM汇编程序,可能会演示这一切是如何工作的.根据编译器的优化方式,这将有所不同,但它应该给出一个想法,

; Prologue - setup
mov     ip, sp                 ; get a copy of sp.
stmdb   sp!, {fp, ip, lr, pc}  ; Save the frame on the stack. See Addendum
sub     fp, ip, #4             ; Set the new frame pointer.
    ...
; Maybe other functions called here.
; Older caller return lr stored in stack frame. bl baz ... ; Epilogue - return ldm sp, {fp, sp, lr} ; restore stack, frame pointer and old link. ... ; maybe more stuff here. bx lr ; return.
这就是foo()看起来像.如果不调用bar(),则编译器执行叶优化,不需要保存 ; 只bx lr需要.最有可能的原因可能是您对Web示例感到困惑.它并不总是一样的.

外卖应该是,

  1. pc并且lr是相关的代码寄存器.一个是"你在哪里",另一个是"你在哪里".
  2. sp并且fp是相关的本地数据寄存器.
    一个是"本地数据在哪里",另一个是"最后一个本地数据在哪里".
  3. 参数传递一起工作以创建功能机器.
  4. 很难描述一般情况,因为我们希望编译器尽可能,因此他们可以使用每一个技巧.

这些概念对所有CPU和编译语言都是通用的,但细节可能有所不同.使用链接寄存器,帧指针函数序言和结尾的一部分,如果你理解了所有内容,你就知道堆栈溢出是如何在ARM上运行的.

另请参见:ARM调用约定.
                MSDN ARM堆栈文章
                剑桥大学APCS概述
                ARM堆栈跟踪博客
                Apple ABI链接

基本框架布局是,

  • 保存了fp [-0] pc,我们存储了这个帧.
  • fp [-1]保存lr,此函数的返回地址.
  • fp [-2] previous sp,在此函数堆栈之前.
  • fp [-3] previous fp,最后一个堆栈帧.
  • 许多可选寄存器......

一个ABI可以使用其它的值,但以上是典型的大多数设置.

附录: 这不是汇编程序中的错误; 这是正常的.解释是在ARM生成的序言问题中.