【问题标题】:Why do ARM saves return address in Link Register instead of the stack?为什么ARM将返回地址保存在链接寄存器而不是堆栈中?
【发布时间】:2019-05-20 03:56:00
【问题描述】:

我一直在寻找这个答案一个多星期,但没有运气。到目前为止,我已经了解到堆栈会在函数嵌套或中断发生时保存返回地址,但最近我了解到现代处理器使用链接寄存器来实现相同的目标。经过一番研究,我知道堆栈确实被用于在旧处理器中保存返回地址。但是,为什么现代处理器在旧实现工作时使用整个单独的寄存器( LR )来保存返回地址对我来说没有意义?与基于堆栈的实现相比,LR 有什么好处?

提前致谢!!!

【问题讨论】:

  • 这是一个寄存器,不是内存。使用起来要快得多。
  • 速度一,内存真的很慢。通常,更多的寄存器比使用更少的寄存器和更多的堆栈更快。传入参数的答案相同,如果架构有足够的寄存器,您将看到使用的寄存器与堆栈作为首选项。
  • 不限于arm。
  • 这是有道理的,寄存器访问速度更快。然而,如果函数超过 1 级深度嵌套,我们有 1 个 LR,它会迫使我们将 LR 存储到堆栈中,这反过来会降低处理器的速度。如果我错了,请纠正我!

标签: arm processor


【解决方案1】:

RISC 架构往往具有较少的特殊指令或行为 - 而是使用标准指令进行堆栈管理。这通常意味着程序更大,CPU 本身更简单,并且编译器预计会更难优化

考虑:

int bar(int a)
{
    return a * a;
}

void foo()
{
    bar(22);
}


foo();

这里,bar() 是一个叶函数——它不会继续进行进一步的函数调用。因此,LR 中的返回地址永远不会被覆盖。因此,根本不需要将它写入堆栈。这将保存和加载并从/存储到内存。

另一方面,foo() 会改变LR,因为它会进行函数调用,因此需要将调用者的返回地址存储在堆栈中。

将此与在其中进行函数调用自动将返回地址压入堆栈的架构进行对比——这种优化是不可能的。

ARM 过程调用标准的所有版本都为函数调用定义了一个被调用者保存寄存器 - 调用者可以期望在函数调用中维护这些寄存器。如果该函数是微不足道的,它再次导致没有内存访问。

在中断中,时间通常更为关键。 ARM CPU 有一组影子寄存器,只能在中断状态下访问。这意味着可以编写不需要内存访问的普通中断处理程序。

【讨论】:

  • 那么,您的意思是说如果函数嵌套仅向下一层,这是一种优化,因为我们从寄存器而不是内存访问返回地址?但是对于更深层次的函数调用,它将是相同的,因为它涉及将 LR 存储到堆栈。如果我错了,请纠正我。
  • 正确 - 然而,叶子函数根据定义很小,并且被频繁调用。由于它们的大小,加载/存储到内存将占其执行时间的很大一部分。
  • 您可能想看看 SPARC 架构 - 它有一个更大的寄存器文件和一个滑动窗口,可以在函数调用时移动,从而可能消除大量溢出到堆栈。在一定数量的函数调用之后,堆栈会发生巨大的溢出。
  • 谢谢,Marko,现在说得通了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-03
  • 2016-12-28
  • 1970-01-01
  • 2015-03-17
  • 2016-03-15
相关资源
最近更新 更多