【问题标题】:Absolute addresses in position-independent code (PIC)位置无关代码 (PIC) 中的绝对地址
【发布时间】:2020-06-08 04:01:28
【问题描述】:

我正在尝试构建和链接单个图像以作为 OS 内核(即在 QEMU 中)加载,目标是 aarch64-unknown-none-softfloat。我使用了一个自定义的 linker.ld 文件,它为内核 ENTRY(_reset) 设置入口点并定位图像

. = 0x40080000

程序计数器 (PC) 处于复位状态的位置。

在我将 0x40080000 处的页面映射到内核将驻留的高内存并启用虚拟内存转换之前,它工作正常。为了保证切换后调试信息网格化,我将标称图像位置改为

. = 0xffffff8200000000

然后重建。

我发现了访问权限:

  • 到一些(pub extern)静态,和
  • 某些核心库函数

是通过从.rodata 中的某处读取绝对地址。这在映射之前运行时会破坏代码。如果我把它改回来,它会在我映射后运行它时破坏代码。

它生成的代码在 O1 看起来有点像这样(间接通过 PC 相关页面):

adrp  x0, 0x10000 // page offset from PC up to rodata
add   x0, 0x120   // byte offset from page in rodata
ldr   x0, [x0]    // use as address

我需要的是跨代码和数据真正定位独立代码,以便它在内存中的两个位置工作,而不参考任何存储的绝对地址,即使这些地址相对于 PC 可用。

我尝试了其他重定位模型,包括 Pic 和 RopiRwpi,但我看不到它生成不同的代码。

谢谢!

编辑:非常感谢临时映射的建议。我见过用的。我更感兴趣的编译器选项将使 -no-dynamic-linker 工作,避免生成需要 R_AARCH64_ABS64 重定位的代码,以保证代码和数据将相隔一定距离..

【问题讨论】:

    标签: rust linker arm64 bare-metal position-independent-code


    【解决方案1】:

    根据我的经验,大多数想要驻留在高内存中的操作系统内核只是链接到它们的目标高内存地址,内核在启动时做的第一件事就是构建页表以映射自身进入高内存。这样,操作系统内核设计者只需要确保入口点的某些块是位置独立的(或者实际上,只需将启动代码放在其真正的低内存位置,方法是将其放置在一个特殊的部分并更改链接器脚本)。

    参见示例 entrypointlinker script(不是 Rust 内核/aarch64)。

    一个足够复杂的内核可以控制其内存分配器,然后可以考虑释放包含入口点代码的页面,由入口点部分的开始和结束标识(实际上扩展它以处理所有以同样的方式初始化代码)。

    如果你能负担得起在启动时使用额外的内存,一个不错的 rust 选项也可以是为加载程序编写一个单独的 crate,将所有内容与链接描述文件绑定在一起,然后在启动后释放它的内存。

    【讨论】:

    • 非常感谢临时映射的链接和建议。我见过用的。我对使 -no-dynamic-linker 能够工作的编译器选项更感兴趣,避免生成需要 R_AARCH64_ABS64 重定位的代码,以保证代码和数据相隔一定距离..
    【解决方案2】:

    您不能在执行过程中对任意代码进行变基并期望它继续运行。从字面上看,在变基点使用的每个地址都将变得无效。即使你摆脱了所有的静态引用,你将如何处理动态分配的内存?

    您要么必须在高地址映射后加载二进制文件的干净副本,要么必须使用高加载地址编译并在运行任何其他代码之前将自己映射到那里。

    如果您觉得您的映射逻辑太长/太复杂而无法在这样的阶段完成,您可以先使用将所有内容映射为 RWX 的琐碎页表,然后您可以切换、调出您的库和其他代码,然后继续构建最终页表。这种“平凡”的页表可以在编译时构建,最多可以容纳 4 页内存(每个 TTBR 两个),并且使用它们切换到高地址最多需要 20 条指令。

    【讨论】:

    • 非常感谢临时映射的建议。我见过用的。我对使 -no-dynamic-linker 能够工作的编译器选项更感兴趣,避免生成需要 R_AARCH64_ABS64 重定位的代码,以保证代码和数据相隔一定距离..
    猜你喜欢
    • 2020-10-13
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多