正常
很好,这一步你做得非常对 👍 你现在其实已经积累了一整套**“真实踩坑经验”,我帮你整理成一份可以直接写进项目 README / 面试讲解的笔记**(我按“问题 → 本质 → 解决”结构给你梳理,保证你以后不再踩)。
🚀 Cinux Bootloader 踩坑总结(Real Mode 阶段)
🧨 坑1:段寄存器不匹配(最早那个)
❓现象
print_string不输出- 单字符
int 0x10正常
🧠 本质
text
物理地址 = segment << 4 + offset但你当时:
text
CS ≠ DS👉 字符串地址按 CS 计算 👉 访问用 DS:SI
👉 💥 读错地址
✅ 解决
asm
mov %cs, %ax
mov %ax, %ds
mov %ax, %es🧨 坑2:Stage2 地址模型错误
❓现象
- 能执行代码
- 访问数据就炸
🧠 本质
你用了:
makefile
. = 0x8000同时:
asm
DS = 0x0800👉 地址变成:
text
0x8000 + 0x80xx → 💥 双重偏移✅ 正确模型(二选一)
✔ 推荐(Stage2)
makefile
. = 0asm
DS = CS✔ MBR(特殊情况)
makefile
. = 0x7C00
DS = 0🧨 坑3:栈踩内存(超级隐蔽)
❓现象
- print 后飞
- BIOS 调用后崩
🧠 本质
你把栈放在:
text
0x7B00(MBR 附近)但:
- BIOS 会用栈
- 你的函数也在 push
👉 💥 覆盖关键内存
✅ 解决
asm
mov $0x9000, %sp🧨 坑4:BIOS 会污染寄存器(重点)
❓现象
- print 之后正常
- 下一个函数炸
🧠 本质
text
BIOS int ≠ 函数调用👉 会改:
- DS / ES
- FLAGS
- BX / SI 等
✅ 解决(必须)
asm
pushf
push 所有寄存器
...
int 0x10
...
pop 全部🧨 坑5:跨文件 + 16位重定位(你中期怀疑的)
❓现象
.data引用炸- relocation truncated
🧠 本质
text
ELF + 16-bit + 多文件
→ R_386_16 限制👉 symbol 地址可能不再是“段内偏移”
✅ 解决
👉 关键原则:
text
数据放调用者,函数放 common🧨 坑6:MBR 超 512B(你最后这个大坑)
❓现象
text
放在 mbr.S 正常
放到 common.S → call 直接飞🧠 本质(最关键)
text
BIOS 只加载 512B但你:
text
mbr.S + serial.S 一起 link👉 .text > 512B
👉 后半部分(common.S)根本没加载
👉 call 跳到:
text
未加载内存 → 💥✅ 解决(标准架构)
✔ MBR:
text
极简(<512B)
不要链接 common.S✔ Stage2:
text
所有功能都放这里🧨 坑7:函数调用约定(你刚刚意识到的)
❓现象
- 有时候能跑,有时候炸
- 多调用就不稳定
🧠 本质
你从:
text
写代码变成:
text
写“模块”👉 必须定义:
- 哪些寄存器能改
- 哪些必须保存
✅ 当前阶段建议
👉 最简单策略:
text
所有函数:
保存全部寄存器🚀 最终正确架构(你现在应该这样)
🔹 MBR(512B)
text
- 初始化段寄存器
- 设置栈
- 读 Stage2
- 跳转👉 可选:
- tiny print(无 push)
🔹 Stage2
text
- print_string(完整版)
- A20
- VESA
- GDT / PM🔹 common.S
text
只放:
- 函数
不放:
- 关键数据(尤其给 MBR 用的)🧠 最重要的三条认知(必须记住)
🧩 1️⃣ 地址模型
text
链接地址 ≠ 运行地址🧩 2️⃣ BIOS 不是函数
text
会破坏寄存器🧩 3️⃣ MBR 不是程序
text
MBR = 512B 跳板