You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x86-64裸机内核:GCC -fPIC下常量未用RIP相对寻址的问题与解决

问题核心原因

你遇到的是const全局符号重定位项缺失的问题:

  • GCC对extern "C" const全局变量,默认会将其标记为非重定位符号(const被视为编译期固定值),即便开启了-fPIE/-fPIC也不会生成重定位项。
  • 链接为ET_EXEC格式时,链接器会直接将该符号的地址绑定到链接时的固定地址(如0x4072D0),不会生成R_X86_64_RELATIVE或R_X86_64_PC32这类重定位项。
  • 而普通全局变量(非const)和函数符号,编译器默认会生成RIP相对寻址代码,链接器也会生成对应重定位项,因此加载器重定位后地址正确。
强制生成重定位项的方法

1. 给常量添加重定位属性

修改Memory.cc中的定义,将常量放入可重定位的只读数据段,强制链接器生成重定位项:

extern "C" const unsigned long kMemHighAddrDirectMappingBase __attribute__((section(".data.rel.ro"))) = 0xFFFF880000000000;

.data.rel.ro是专为可重定位只读数据设计的段,链接器会为该段内的符号生成R_X86_64_RELATIVE重定位项,加载器重定位时会自动修正符号地址。

2. 用包装函数获取地址

编写一个extern "C"的包装函数,返回常量的地址——编译器会为函数生成RIP相对寻址的代码:

extern "C" const unsigned long* get_kMemHighAddrBase() {
    return &kMemHighAddrDirectMappingBase;
}

汇编代码中调用这个函数,就能得到重定位后的正确地址:

call get_kMemHighAddrBase
; rax寄存器中存储的就是重定位后的&kMemHighAddrDirectMappingBase

3. 切换为ET_DYN格式链接

将编译链接选项调整为生成位置无关的ET_DYN格式ELF:

  • 在CFLAGS中保留-fPIE,链接时添加-pie参数:LDFLAGS += -pie
  • 调整UEFI加载器支持加载ET_DYN文件,这类文件本身就是位置无关的,链接器会为所有符号生成重定位项,重定位后地址自然正确。

4. 自定义链接脚本强制重定位

编写链接脚本,明确标记.rodata段需要参与重定位:

SECTIONS {
    . = 0x400000; /* 链接基地址 */
    .text : { *(.text) }
    .rodata : {
        *(.rodata)
        KEEP(*(.rodata.kMemHighAddrDirectMappingBase))
    } :reloc /* 标记该段需要重定位 */
    .data : { *(.data) }
    .bss : { *(.bss) }
}

链接时指定该脚本:LDFLAGS += -T your_kernel.ld,链接器会为.rodata段内的符号生成重定位项。

其他可行解决方案

1. 改为非const变量放入只读段

去掉const修饰,用属性强制放入.rodata段保证只读特性:

extern "C" unsigned long kMemHighAddrDirectMappingBase __attribute__((section(".rodata"))) = 0xFFFF880000000000;

这样编译器会将其当作普通全局变量处理,生成RIP相对寻址代码,链接器也会生成重定位项,同时.rodata的只读属性保证变量无法被修改。

2. 汇编中直接使用RIP相对寻址

如果汇编代码需要访问该常量的地址,直接用lea指令的RIP相对形式:

lea rax, [rip + kMemHighAddrDirectMappingBase]
; rax寄存器中存储的就是重定位后的常量地址

链接器会自动为该指令生成R_X86_64_PC32重定位项,加载器重定位后即可得到正确地址。

内容的提问来源于stack exchange,提问作者Jack Zhao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 01:37:52