che*_*ong 2 assembly arm gnu remap position-independent-code
我已经开始阅读 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 节)。
那么重映射究竟如何影响它后面的指令是否与位置无关呢?
位置无关是一个加载时的概念——而不是一个运行时的概念。位置无关是一种代码质量,它允许它被加载到内存中的任何地址并且仍然可以工作,但位置无关不是正在运行的程序的质量。
一旦我们有一个调用堆栈和/或(重定位)数据引用代码,我们就不再拥有代码或数据的位置独立性,也无法移动它们。实际上,当程序开始执行时,位置无关性就消失了(尽管有位置无关代码)。
返回地址——通过调用(例如BL)动态生成——以及指向代码的数据指针(代码指针向量(如在 vtables 中)和初始化的全局函数指针)破坏了正在运行的程序的位置独立性。
作者的警示节点是描述位置独立性消失的一种方式。更令人困惑的是,通过非常小心的操作,它们允许实际移动代码,即使它的执行已经开始,所以这里我们的位置独立性实际上在执行开始后持续了一些。
但是程序在不放弃位置独立性的情况下无法正常运行(例如进行调用和使用函数指针),因此他们选择在low_level_init.
例如,reset代码用了很长的篇幅来使用非标准调用来调用low_level_init——为它提供一个lr值而不使用BLor mov lr,pc(这将捕获 的预重新映射(ROM)地址cstartup。)lr提供的值是地址的(搬迁)cstartup,其low_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:
Run Code Online (Sandbox Code Playgroud)
这B结合MOV lr,r1是调用。