开发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
相关产品推荐
相关产品推荐

