32位自制内核中相同指令在main与函数内执行结果异常求助
32位自制内核函数调用异常问题
问题现象
开发32位自制内核时,相同的内存写入指令在main函数中执行正常,但在自定义函数foo中执行时行为异常。排查确认是foo内部的指针解引用操作失效,写入0xb8000的是错误数据(表现为清屏,推测是写入了0),预期两者行为一致但实际不符。
相关代码
C代码
int foo(const char *str) { *(char*)0xb8000 = *str; // 执行后清屏,推测写入了0 } extern void main() { const char str[4] = {'A', 'B', 'C', '\0'}; *(char*)0xb8000 = *str; // 执行正常,写入'A' for(int i=0;i<1000000000;i++); // 延时 foo(str); for(;;); return; }
启动代码(boot.asm)
[org 0x7c00] KERNEL_LOCATION equ 0x1000 mov [boot_disk], dl ; 设置栈 xor ax, ax mov es, ax mov ds, ax mov bp, 0x8000 mov sp, bp ; GDT加载等操作 [bits 32] start_protected_mode: mov ax, DATA_SEG mov ds, ax mov ss, ax mov es, ax mov fs, ax mov gs, ax mov ebp, 0x90000 ; 32位栈基址 mov esp, ebp jmp KERNEL_LOCATION times 510-($-$$) db 0 dw 0xaa55
Makefile
all: x86_64-elf-gcc -Wall -nostdlib -ffreestanding -m64 -g -c "kernel.c" -o "kernel.o" x86_64-elf-gcc -Wall -nostdlib -ffreestanding -m64 -g -c "idt.c" -o "idt.o" x86_64-elf-gcc -Wall -nostdlib -ffreestanding -m64 -g -c "system.c" -o "system.o" nasm "kernel_enrty.asm" -f elf64 -o "kernel_entry.o" nasm "start.asm" -f elf64 -o "start.o" x86_64-elf-ld -nostdlib -o "full_kernel.bin" -Ttext 0x1000 "kernel_entry.o" "start.o" "idt.o" "system.o" "kernel.o" -j .text --oformat binary nasm "boot.asm" -f bin -o "boot.bin" cat "boot.bin" "full_kernel.bin" > "everything.bin" nasm "padding.asm" -f bin -o "padding.bin" cat "everything.bin" "padding.bin" > "OS.bin"
问题根源
核心矛盾是编译目标架构不匹配:
- 内核运行在32位保护模式下,但Makefile中使用
-m64参数编译64位代码,同时nasm生成elf64格式的目标文件。 - 64位系统的函数调用约定(System V AMD64)使用寄存器(如
rdi)传递第一个参数,而32位系统通常使用栈传参。在32位模式下执行64位编译的foo函数时,函数无法正确获取str参数,导致*str读取到错误值(大概率是0),写入0xb8000后出现清屏现象。
解决方案
修改编译和链接流程,统一为32位目标架构:
- 修改GCC编译参数:将所有
-m64替换为-m32,编译32位代码:x86_64-elf-gcc -Wall -nostdlib -ffreestanding -m32 -g -c "kernel.c" -o "kernel.o" - 修改NASM编译参数:将
-f elf64替换为-f elf32,生成32位ELF目标文件:nasm "kernel_enrty.asm" -f elf32 -o "kernel_entry.o" - 修改链接器参数:添加
-m elf_i386参数,指定链接32位目标文件:x86_64-elf-ld -m elf_i386 -nostdlib -o "full_kernel.bin" -Ttext 0x1000 "kernel_entry.o" "start.o" "idt.o" "system.o" "kernel.o" -j .text --oformat binary
内容的提问来源于stack exchange,提问作者BlockMagiX97
相关产品推荐
相关产品推荐

