正常
很好,这一版代码基本已经“正轨了”。我帮你把我们这一路踩过的坑 + 你当前这版为什么是对的系统性梳理一下,这对你后面面试讲项目非常加分。
🧠 一、核心踩坑总结(按严重程度)
🚨 1. GDB 符号错位(最关键)
❌ 现象
plaintext
p/x pm_entry = 0x66❌ 根因
你之前:
- ELF 被 objcopy / 重新构建
- 或者 add-symbol-file 地址错误
- 或 linker layout ≠ 实际加载地址
👉 导致:
❗GDB 把代码当数据解释了
✅ 正确做法
plaintext
file build/boot/stage2👉 只用 ELF,不要用 bin
🚨 2. ELF vs BIN 混用(非常经典坑)
你工程里:
makefile
objcopy -O binary → stage2.bin❗误区
| 文件 | 用途 |
|---|---|
| stage2(ELF) | 调试 |
| stage2.bin | 启动加载 |
👉 不能互相替代
🚨 3. .code16 + .code32 混乱
你现在是:
asm
.code16
...
ljmp $0x08, $pm_entry
.code32
pm_entry:❗坑点
- 如果
ljmp不是 16-bit 编码 → 会直接炸 - 你之前踩过:
text
(bad) + rex + 错误反汇编👉 说明 CPU 根本没正确进入 32 位
🚨 4. GDT 加载地址错(经典 real mode 陷阱)
你这句:
asm
lgdt gdt_ptr但在 real mode:
text
物理地址 = DS * 16 + offset❗所以必须:
asm
movw $0, %ds👉 否则:
❗lgdt 读到错误内存 → 直接崩
🚨 5. stack 没对齐 / 切换错误
你做了:
asm
movw $0x900, %ax
movw %ax, %ss
movw $0xFFFE, %sp👉 这个是正确姿势
❗之前可能的问题:
- stack 在错误段
- ss:sp 未初始化
- 导致
call/push直接炸
🚨 6. A20 / VESA / BIOS 调用
你这条链:
asm
call enable_a20
call vesa_get_controller_info
call vesa_get_mode_info
call vesa_set_mode❗关键坑:
| 错误 | 后果 |
|---|---|
| A20 没开 | 地址回卷 |
| VBE buffer 地址错 | 数据被覆盖 |
| 未保护寄存器 | 调用链炸掉 |
🚨 7. GDT 放置位置错误(你之前问过)
你现在:
asm
.section .gdt,"a"👉 这是正确的!
❗之前的坑:
- 放在
.text - 或未对齐
👉 会导致:
❗lgdt 读取非法结构
🧠 二、你这版代码为什么是“正确版本”
✅ 1. 分段结构正确
asm
.section .text
.code16👉 real mode 正确
✅ 2. GDT 独立 section
asm
.section .gdt,"a"
.align 8👉 确保:
- 8字节对齐
- 结构稳定
✅ 3. GDT pointer 正确
asm
gdt_ptr:
.word (gdt_end - gdt - 1)
.long gdt👉 标准写法(完全正确)
✅ 4. 关键 real → protected 流程正确
asm
movw $0, %ds
lgdt gdt_ptr
movl %cr0, %eax
orb $0x1, %al
movl %eax, %cr0
ljmp $0x08, $pm_entry👉 这是教科书级别流程
⚠️ 5. 你唯一还可以优化的点
❗ljmp 注释写错了(非常关键)
你写:
asm
// 16-bit encoding: ea <offset16> <seg16>但实际:
👉 GAS 会根据 .code16 自动生成正确编码
👉 不需要手写 ea
🚨 建议(避免坑)
asm
ljmp $0x08, $pm_entry👉 OK,不要手动拼机器码
🧠 三、你整个 Boot 流程已经成熟
你现在已经具备:
🔥 Bootloader 能力
- MBR → Stage2
- 16-bit → 32-bit 切换
- A20 控制
- GDT 构建
- 保护模式进入
- VESA 初始化
- framebuffer 获取
- debug 输出(0xE9)
👉 这已经是:
💥 一个完整 mini OS boot pipeline
🚀 四、你这次真正进步的点(面试重点)
✅ 你已经掌握:
1️⃣ CPU 模式切换本质
- real mode
- protected mode
- segment descriptor
2️⃣ BIOS / VESA 调用机制
3️⃣ 地址计算本质
text
real mode: DS:SI
linear = DS * 16 + offset4️⃣ ELF vs BIN 分离
5️⃣ GDB + QEMU 调试链
🧨 五、最后帮你总结一句“可以写进简历”的话
你可以这样写:
实现了基于 x86 架构的自研 Bootloader,完成从 MBR 到 Stage2 的加载流程,支持 A20 开启、GDT 构建、保护模式切换、VESA 图形模式初始化以及帧缓冲获取,并通过 GDB/QEMU 完成底层指令级调试。