【问题标题】:What determines position-independence following a memory remap operation?什么决定了内存重映射操作后的位置无关性?
【发布时间】:2020-03-30 18:45:28
【问题描述】:

我已经开始阅读 Miro Samek 的 "Building Bare-Metal ARM Systems with GNU" 并发现自己被困在某个点上。在 PDF 第 10 页上的注释之一中可以找到导致我困惑的原因:

注意:函数 low_level_init() 可以用 C/C++ 编写,但有以下限制。该函数必须在 ARM 状态下执行,并且不能依赖于 .data 部分的初始化或 .bss 部分的清除。另外,如果要执行内存重映射,则必须在 low_level_init() 函数内部进行,因为该函数返回后代码不再与位置无关

代码“不再与位置无关”究竟如何?从low_level_init/_cstartup 标签返回后,引用的代码(可在 PDF 中的第 7-9 页查看)似乎仍然与位置无关。 _cstartup 标签之后的指令似乎唯一不同的是它们引用了链接描述文件中定义的标签(指南的第 3 节)。

那么重映射究竟如何影响它后面的指令是否与位置无关?

【问题讨论】:

  • 你问的时候作者说了什么?
  • @old_timer 对不起,恐怕我听不懂。我从来没有问过作者。
  • 这是您在提出问题时要开始的地方,我们应该如何知道作者想说什么。那么如果答案没有意义,那么拥有比您这里更多的信息的 SO 可能是一个问题的地方。
  • @old_timer 很好。我会联系作者并直接询问他们。如果我的问题得到解答,我一定会更新这篇文章。

标签: assembly arm gnu remap position-independent-code


【解决方案1】:

位置无关是加载时的概念,而不是运行时的概念。位置无关是一种代码质量,它允许将其加载到内存中的任何地址并且仍然可以工作,但位置无关不是正在运行的程序的质量。

一旦我们有了引用代码的调用堆栈和/或(重新定位的)数据,我们就不再具有代码或数据的位置独立性,并且无法移动它们。实际上,当程序开始执行时,位置独立性就消失了(尽管有位置独立的代码)。

两个返回地址——通过调用动态生成(例如BL)——以及指向代码的数据指针(代码指针向量(如在vtables中)和初始化的全局函数指针)都会破坏正在运行的程序的位置独立性。

作者的警示节点是描述位置独立性消失的一种方式。更令人困惑的是,通过非常小心的操作,即使代码已经开始执行,它们也允许实际移动代码,所以这里我们的位置独立性实际上在执行开始后持续了一小段时间。

但是一个程序在不放弃位置独立性的情况下无法正常运行(例如调用和使用函数指针),所以他们选择在low_level_init末尾的沙地上画线。

例如,reset 代码使用非标准调用来调用 low_level_init — 为它提供 lr 值而不使用 BLmov lr,pc(这将捕获cstartup 的预重映射(ROM)地址。)提供的lr 值是low_level_init 将“返回”到的(重新定位的)cstartup 的地址!

    (10) LDR r0,=_reset /* pass the reset address as the 1st argument */
    (11) LDR r1,=_cstartup /* pass the return address as the 2nd argument */
    (12) MOV lr,r1 /* set the return address after the remap */
    (13) LDR sp,=__stack_end__ /* set the temporary stack pointer */
    (14) B low_level_init /* relative branch enables remap */
_cstartup:

BMOV lr,r1 结合是调用。

【讨论】:

  • 我明白了。因此,注释的目的是强调位置无关代码在执行期间固有的不适用性。非常感谢您的解释!不过,具体来说,当您说“位置独立性实际上在执行开始后持续了一些时间”时,您指的是在low_level_init 中设置主要和次要向量表,对吗?
  • 是的,执行该设置的代码小心地避免了重定位的危险,但这是不可持续的,一旦捕获到代码的指针,因此只能持续很短的时间——尽管只要它们当然,因为他们可以控制这一点,所以想要在极端限制的情况下进行编码。
  • 看起来_cstartup 在重映射后在技术上并未重新定位。根据Atmel AT91SAM7S64 Datasheet 的第 18.3.3 节,此特定 MCU 的重新映射操作“导致通过内部存储器区域 0 访问内部 SRAM”,即 ROM 地址空间。所以看起来启动代码实际上并没有在内存中“移动”,唯一被“移动”的是向量表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-04
  • 2020-08-16
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
  • 2012-04-02
相关资源
最近更新 更多