2

我已经开始阅读 Miro Samek 的“使用 GNU 构建裸机 ARM 系统”,发现自己陷入了困境。在 PDF 第 10 页上的注释之一中可以找到导致我困惑的原因:

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

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

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

4

1 回答 1

5

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

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

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

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

但是一个程序如果不放弃位置独立性就不能正常运行(例如调用和使用函数指针),所以他们选择在low_level_init.

例如,reset代码很长地使用非标准调用来调用low_level_init- 为它提供一个lr值而不使用BLor mov lr,pc(这将捕获 的预重映射(ROM)地址cstartup。)lr提供的值是地址的(搬迁)cstartuplow_level_init“返回”!

    (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:

B与 the 相结合的是MOV lr,r1调用。

于 2020-03-30T22:31:25.360 回答