自定义OS内核加载失败问题求助
自定义内核加载失败,触发SIGSEGV段错误
开发自定义操作系统内核时,内核无法正常加载,无预期输出,使用gdb调试时出现以下错误:
During startup program terminated with signal SIGSEGV, Segmentation fault.
当前代码暂未规范整理,先聚焦解决加载问题,相关代码如下:
kernel/main.cpp
extern "C" void kernelMain() { const char* welcome = "Welcome to the kernel!"; char* videoMemory = (char*) 0xb8000; for (int i = 0; i < 80*25; i++) { videoMemory[i*2] = ' '; videoMemory[i*2+1] = 0x0f; } for (int i = 0; welcome[i] != '\0'; i++) { videoMemory[i*2] = welcome[i]; } } extern "C" void _start() { kernelMain(); while (1) {} }
kernel/linker.ld
ENTRY(_start) SECTIONS { . = 0x1000; .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } }
boot/boot.asm
[org 0x7c00] start: mov si, msg call print mov ah, 0x02 mov al, 0x06 mov ch, 0x00 mov cl, 0x02 mov dh, 0x00 mov dl, 0x80 mov bx, 0x1000 int 0x13 jmp 0x1000 print: mov ah, 0x0e mov bh, 0x00 mov bl, 0x07 mov al, [si] cmp al, 0 je .done int 0x10 inc si jmp print .done: ret msg db "Loading Bootloader...", 0 times 510-($-$$) db 0 dw 0xaa55
Makefile
NASM=nasm QEMU=qemu-system-x86_64 CC=gcc LD=ld all: boot.bin kernel.bin boot.bin: boot/boot.asm $(NASM) -f bin $< -o $@ kernel.bin: kernel/main.cpp kernel/linker.ld $(CC) -ffreestanding -c $< -o kernel.o $(LD) -o $@ -T kernel/linker.ld kernel.o run: boot.bin kernel.bin $(QEMU) -drive format=raw,file=boot.bin clean: rm -f boot.bin kernel.bin kernel.o
问题分析与修复步骤
1. 核心问题:内核未写入磁盘镜像
原Makefile的run命令仅加载boot.bin,内核kernel.bin并未合并到QEMU使用的磁盘镜像中。引导扇区执行读盘操作时,实际读取的是无效数据,跳转到0x1000后执行垃圾代码触发段错误。
修复Makefile:生成包含引导扇区和内核的完整磁盘镜像:
run: boot.bin kernel.bin # 创建100扇区的空镜像 dd if=/dev/zero of=os.img bs=512 count=100 # 写入引导扇区到第一个扇区 dd if=boot.bin of=os.img conv=notrunc # 从第2个扇区开始写入内核(对应引导扇区cl=0x02的设置) dd if=kernel.bin of=os.img bs=512 seek=1 conv=notrunc # 运行完整镜像 $(QEMU) -drive format=raw,file=os.img
2. 编译参数错误:默认生成64位代码
GCC默认编译64位代码,但引导扇区运行在16位实模式,跳转到0x1000后执行64位指令会导致错误。需指定32位编译和链接参数。
修复编译与链接命令:
kernel.bin: kernel/main.cpp kernel/linker.ld # 32位独立环境编译,禁用标准库、异常、RTTI $(CC) -ffreestanding -m32 -nostdlib -fno-exceptions -fno-rtti -c $< -o kernel.o # 32位ELF链接 $(LD) -m elf_i386 -o $@ -T kernel/linker.ld kernel.o
3. 缺失读盘错误检查
引导扇区的int 0x13读盘操作未检查错误标志,读盘失败时会直接跳转,导致后续执行无效代码。
修复引导扇区:添加读盘错误处理:
[org 0x7c00] start: mov si, msg call print mov ah, 0x02 mov al, 0x06 mov ch, 0x00 mov cl, 0x02 mov dh, 0x00 mov dl, 0x80 mov bx, 0x1000 int 0x13 jc disk_error ; CF置位表示读盘失败,跳转错误处理 jmp 0x1000 disk_error: mov si, disk_err_msg call print hlt ; 暂停系统,避免继续执行错误代码 print: mov ah, 0x0e mov bh, 0x00 mov bl, 0x07 mov al, [si] cmp al, 0 je .done int 0x10 inc si jmp print .done: ret msg db "Loading Bootloader...", 0 disk_err_msg db "Disk read error!", 0 times 510-($-$$) db 0 dw 0xaa55
内容的提问来源于stack exchange,提问作者Pigioty
相关产品推荐
相关产品推荐

