C ARM:链接寄存器和帧指针
我试图理解链接寄存器和帧指针在ARM中是如何工作的。我去过几个网站,我想确认我的理解 假设我有以下代码:C ARM:链接寄存器和帧指针,c,arm,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;
int foo(void)
{
// ..
bar();
// (A)
// ..
}
int bar(void)
{
// (B)
int b1;
// ..
// (C)
baz();
// (D)
}
int baz(void)
{
// (E)
int a;
int b;
// (F)
}
我称之为foo()。链接寄存器是否包含点(A)处代码的地址,帧指针是否包含点(B)处代码的地址?声明所有局部变量后,堆栈指针可以是bar()内的任何位置?一些寄存器调用约定依赖于(应用程序二进制接口)。
FP
在APCS标准中是必需的,而在较新的AAPCS(2003)中不是必需的。对于AAPC(GCC 5.0+)而言,FP
没有可供使用,但肯定可以使用;带有堆栈和帧指针,用于堆栈跟踪和使用AAPCS展开代码。如果函数是静态的,编译器实际上不必遵守任何约定
通常,所有ARM寄存器都是通用的。lr
(链接寄存器,也称为R14)和pc
(程序计数器,也称为R15)是特殊的,并在指令集中体现出来。您认为lr
将指向A是正确的。pc
和lr
是相关的。一个是“你在哪里”,另一个是“你在哪里”。它们是函数的代码方面
通常,我们有sp
(堆栈指针,R13)和fp
(,R11)。这两者也有关联。这
描述事物做得很好。堆栈用于在函数中存储临时数据或局部变量。foo()
和bar()
中的任何变量都存储在堆栈或可用寄存器中。fp
跟踪函数之间的变量。它是堆栈上用于该函数的帧或图片窗口。ABI定义了此框架的布局。通常,编译器将lr
和其他寄存器以及先前的fp
值保存在后台。这将生成堆栈帧的链接列表,如果需要,可以一直跟踪到main()
。根是fp
,它指向一个堆栈帧(如struct
),其中struct
中的一个变量是前一个fp
。您可以沿着列表一直到最后一个fp
,通常为NULL
因此,sp
是堆栈所在的位置,fp
是堆栈所在的位置,非常类似于pc
和lr
。每个旧的lr
(链接寄存器)存储在旧的fp
(帧指针)中。sp
和fp
是功能的数据方面
您的点B是活动的pc
和sp
。点A实际上是fp
和lr
;除非您调用另一个函数,然后编译器可能准备设置fp
以指向B中的数据
下面是一些ARM汇编程序,可以演示这一切是如何工作的。这将根据编译器的优化方式有所不同,但它应该给出一个想法
;序言-设置
mov-ip,sp;获取sp的副本。
stmdb sp!,{fp,ip,lr,pc};将帧保存在堆栈上。见附录
副fp,ip,#4;设置新的帧指针。
...
; 可能在这里调用了其他函数。
; 较旧的调用方返回存储在堆栈帧中的lr
。
比尔巴兹
...
; 结语-返回
ldm-sp,{fp,sp,lr};还原堆栈、帧指针和旧链接。
... ; 也许这里有更多的东西。
bx-lr;返回。
这就是foo()
的样子。如果不调用bar()
,那么编译器将执行叶优化,并且不需要保存帧;只需要bx lr
。很可能这就是为什么你会被网络示例弄糊涂的原因。它并不总是一样的
外卖应该是,
pc
和lr
是相关的code寄存器。一个是“你在哪里”,另一个是“你在哪里”sp
和fp
是相关的本地数据寄存器。一个是“本地数据在哪里”,另一个是“最后一个本地数据在哪里”
基本框架布局是
- fp[-0]保存了
,我们将此帧存储在此处pc
- fp[-1]保存了此函数的返回地址
李>lr
- fp[-2]在该函数吃掉堆栈之前,上一个
sp
- fp[-3]上一个
,最后一个堆栈帧fp
- 许多可选寄存器
附录:这不是汇编程序中的错误;这是正常的。问题中有一个解释。免责声明:我认为这大致正确;请根据需要更正 如本文件其他部分所述