按照 Day1 完成了 Linux0.11 的运行之后,可以在 ~/oslab/linux-0.11 找到 linux0.11 的源码
根据闪客的文章第一回:https://mp.weixin.qq.com/s/LIsqRX51W7d_yw-HN-s2DA
Linux0.11 的启动代码程序入点在 bootsect.s 里,总共 512 个字节
这个 bootsect.s 会被编译成二进制文件,存放在启动区的第一扇区。
skip掉前面那些宏,bootsect.s 最开始的两行汇编代码如下:
mov ax, 0x07c0
mov ds, ax
含义是把 0x07c0 这个值复制到 ax 寄存器里,再将 ax 寄存器里的值复制到 ds 寄存器里。
ds 是一个 16 位的段寄存器,具体表示数据段寄存器,在内存寻址时充当段基址的作用。啥意思呢?就是当我们之后用汇编语言写一个内存地址时,实际上仅仅是写了偏移地址,比如:
mov ax, [0x0001]
实际上相当于
mov ax, [ds:0x0001]
ds 是默认加上的,表示在 ds 这个段基址处,往后再偏移 0x0001 单位,将这个位置的内存数据,复制到 ax 寄存器中。
形象地比喻一下就是,你和朋友商量去哪玩比较好,你说天安门、南锣鼓巷、颐和园等等,实际上都是偏移地址,省略了北京市这个基址。
当然你完全可以说北京天安门、北京南锣鼓巷这样,每次都加上北京这个前缀。不过如果你事先和朋友说好,以下我说的地方都是北京市里的哈,之后你就不用每次都带着北京市这个词了,是不是很方便?
那 ds 这个数据段寄存器的作用就是如此,方便了描述一个内存地址时,可以省略一个基址,没什么神奇之处。
ds : 0x0001
北京市 : 南锣鼓巷
再看,这个 ds 被赋值为了 0x07c0,由于 x86 为了让自己在 16 位这个实模式下能访问到 20 位的地址线这个历史因素(不了解这个的就先别纠结为啥了),所以段基址要先左移四位。那 0x07c0 左移四位就是 0x7c00,那这就刚好和这段代码被 BIOS 加载到的内存地址 0x7c00 一样了。
把 ds 赋值为 0x07c0 最核心的原因是,我们在链接 这段代码的时候是使用 0x7c00 作为代码段起始地址的,所以为了汇编代码能够顺利执行,必须把 ds 赋值为 0x07c0。
也就是说,之后再写的代码,里面访问的数据的内存地址,都先默认加上 0x7c00,再去内存中寻址。
为啥统一加上 0x7c00 这个数呢?这很好解释,BIOS 规定死了把操作系统代码加载到内存 0x7c00,那么里面的各种数据自然就全都被偏移了这么多,所以把数据段寄存器 ds 设置为这个值,方便了以后通过这种基址的方式访问内存里的数据。