纯汇编实现OS的IDT模块遇编译错误,求技术支持
纯汇编实现裸机OS的IDT解决方法
问题根源
objconv转换的代码是针对用户态EXE的,生成的isg/ieg/idg/imake属于工具专属伪指令,裸机汇编器(如NASM、GAS)不支持,必须手动重写符合裸机规范的IDT代码。
手动实现IDT核心步骤(以NASM为例)
1. 定义IDT描述符结构
IDT每个描述符为8字节,对应处理器要求的格式:
; 32位中断门描述符结构 struc IDT_Descriptor .offset_low resw 1 ; 中断处理函数地址低16位 .selector resw 1 ; 内核代码段选择子(通常为0x08) .zero resb 1 ; 保留位,固定为0 .flags resb 1 ; 标志位:0x8E表示32位中断门、特权级0、存在 .offset_high resw 1 ; 中断处理函数地址高16位 endstruc
2. 声明IDT表与IDTR寄存器结构
; 256项的IDT表,初始化为0 idt_table: times 256 db 0 ; IDTR结构,用于加载IDT到处理器 idtr: dw idt_table - $$ + 256*IDT_Descriptor_size - 1 ; IDT长度(字节数-1) dd idt_table ; IDT基地址
3. 编写中断处理存根并填充IDT
先实现通用中断处理模板,再将其地址写入IDT对应项:
; 中断0(除零错误)处理存根 isr0: cli ; 关闭中断 pusha ; 保存所有通用寄存器 ; 此处添加中断逻辑,比如打印错误信息 mov ax, 0x13 mov gs, ax mov esi, msg_div_zero call print_string ; 自行实现的VGA字符串打印函数 popa ; 恢复寄存器 sti ; 开启中断 iret ; 中断返回 ; 填充IDT的中断0描述符 mov word [idt_table + 0*IDT_Descriptor_size], isr0 & 0xFFFF mov word [idt_table + 0*IDT_Descriptor_size + 2], 0x08 mov byte [idt_table + 0*IDT_Descriptor_size + 4], 0 mov byte [idt_table + 0*IDT_Descriptor_size + 5], 0x8E mov word [idt_table + 0*IDT_Descriptor_size + 6], isr0 >> 16
4. 加载IDT并开启全局中断
; 加载IDT到处理器寄存器 lidt [idtr] sti ; 开启全局中断
修正构建命令(NASM+LD为例)
放弃EXE相关构建流程,改用裸机编译链接命令:
# 编译汇编代码为32位ELF目标文件 nasm -f elf32 kernel.asm -o kernel.o # 用链接脚本指定裸机加载地址 ld -m elf_i386 -T link.ld kernel.o -o kernel.bin # 写入软盘镜像用于BOCHS调试 dd if=kernel.bin of=os.img bs=512 count=1 conv=notrunc
配套的link.ld链接脚本示例:
ENTRY(_start) SECTIONS { . = 0x100000; ; 内核加载到1MB内存地址 .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } }
关键注意事项
- 所有中断处理函数必须用
iret返回,不能用普通ret - 代码段选择子必须与GDT中定义的内核代码段匹配
- 异常中断部分会自动压入错误码,对应存根需额外处理栈帧
- 调试时确保BOCHS配置指向生成的
os.img镜像
内容的提问来源于stack exchange,提问作者Bob Dude
相关产品推荐
相关产品推荐

