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

开发64位教育类OS时.rodata段字符串无法显示的问题

64位自制OS中.rodata段字符串无法读取的问题排查与解决

问题背景

自制一款教学用64位OS,已完成模式切换并跳转至C函数kmain运行,交叉编译器、磁盘加载逻辑等环境配置完毕。栈上字符串的代码能正常显示内容,但使用.rodata段字符串时无法显示,系统未崩溃。

正常运行的代码(栈上字符串)

#define VIDEO_MEMORY_LOCATION 0xb8000

void kmain() {
    char msg[] = "Hello world!";
    int i =0;
    char *video_memory = (char *)VIDEO_MEMORY_LOCATION;

    while (msg[i]) {
        *video_memory = msg[i];
        i++;
        video_memory += 2;
    }
}

无法运行的代码(.rodata段字符串)

#define VIDEO_MEMORY_LOCATION 0xb8000

void kmain() {
    char *msg = "Hello world!";
    char *video_memory = (char *)VIDEO_MEMORY_LOCATION;

    while (*msg) {
        *video_memory = *msg;
        msg++;
        video_memory += 2;
    }
}

现象与调试信息

  • 仅.rodata字符串无法显示,栈上字符串正常(如测试代码中仅显示AZE)
  • 反汇编显示字符串存在于链接地址0xfe45:
00000200  55                push rbp
00000201  4889E5            mov rbp,rsp
00000204  48C745F845FE0000  mov qword [rbp-0x8],0xfe45  ; 字符串链接地址
0000020C  48C745F000800B00  mov qword [rbp-0x10],0xb8000
...
00000245  48                rex.w                           ; 字符串'H'
00000246  656C              gs insb                         ; 'e' 'l'
00000248  6C                insb                           ; 'l'
00000249  6F                outsd                          ; 'o'
...
  • QEMU中查看实际内存,字符串位于0x7e45(内核加载到0x7e00,偏移0x45):
(qemu) x/8c 0x7e45
000000000007e45: 'H' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' '!' '\0x00'
  • Bochs调试显示:代码尝试读取0xfe45,但该地址内存内容为0,导致循环直接退出。

编译脚本

os.bin: bootloader/bootloader.bin kernel/kernel.bin # must be in correct order !
    cat $^ > $@

kernel/kernel.bin: kernel/kmain.o bootloader/kernel_entry.o
    ${LD} --oformat binary -Ttext 0xFe00 $^ -o $@

kernel/kmain.o: kernel/kmain.c
    ${CC} -m64 -ffreestanding -nostdlib -nostdinc -fno-builtin -fno-stack-protector -Wall -g -c $^ -o $@

问题原因

链接时指定的代码起始地址-Ttext 0xfe00与实际加载地址0x7e00不匹配:

  • 栈上字符串是运行时在栈中生成,使用相对栈指针的地址,不受链接地址影响
  • .rodata段字符串的地址是编译链接时确定的绝对地址(0xfe45),但实际运行时字符串位于0x7e45,代码访问错误地址导致读取到0,循环直接退出。

解决方案

修改链接命令,将-Ttext设置为内核实际加载地址0x7e00,让链接器生成与实际运行地址一致的绝对地址:

kernel/kernel.bin: kernel/kmain.o bootloader/kernel_entry.o
    ${LD} --oformat binary -Ttext 0x7e00 $^ -o $@

重新编译后,.rodata段字符串的链接地址将与实际运行地址一致,代码就能正确读取并显示字符串。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:48:10