本文是书籍《x86 汇编语言:从实模式到保护模式》的读书笔记
将编译好的程序提交给处理器
对于绝大多数编译好的程序来说,要想得到处理器的光顾,让它执行一下,必须借助于操作系统。
操作系统也是一个需要在处理器上运行的软件,只不过比起一般的程序而言,体积更为庞大,功能更为复杂。
每种操作系统都对它所管理的程序提出了种种格式上的要求。
以 windows 系统为例,例如:
- 编译好的程序必须在文件的开始部分包含编译日期
- 是针对哪种操作系统编译的
- 程序的版本
- 第一条指令从哪里开始
- 数据段从哪里开始及数据段长度
- 代码段从哪里开始及代码段长度
基本输入输出系统
每当处理器加电,或者 RESET 引脚的电平由低变高时,处理器都会执行一个硬件初始化,以及一个可选的内部自测试(Build-in Self-Test,BIST),然后将内部所有寄存器的内容初始到一个预置的状态。
Intel 8086 可以访问 1MB 的内存空间,地址范围为 0x00000 到 0xFFFFF。
在以 Intel 8086 为处理器的系统中,内存空间分配如下:
- 0xF0000~0xFFFFF 被 ROM 占据,大小 64KB,里面固化了开机时要执行的指令
- 0xA0000~0xEFFFF 其他外围设备
- 0x00000~0x9FFFF 被 DRAM 占据,大小 640KB
处理器取指令执行的自然顺序是从内存的低地址往高低地址推进,所以 ROM 中位于物理地址 0xFFFF0 的地方,通常是一个跳转指令。
占据高位地址空间的 ROM 又叫做基本输入输出系统(Base Input & Output System,BIOS)ROM。ROM-BIOS 的容量是有限的,当它完成自己的使命后,最后所要做的,就是从辅助存储设备读取指令数据,然后转到那里开始执行。基本上,这相当于接力赛中的交接棒。
硬盘及其工作原理
历史上,有多种辅助存储设备,比如软盘、光盘、硬盘、U 盘等,相对于内存,它们就是人们常说的「外存」,即外存储器。
硬盘有一或多个盘片,它们串在同一个轴上,有电动机带动者一起高速旋转,这个旋转参数就是我们通常说的「转/分钟」(Round Per Minute,RPM)。
每个盘片有两个磁头 Head
,上下各一个,磁头有编号,编号为 3 磁头和盘片接触那面称第 3 面。磁头编号从 0 开始。
磁头每步进一次,都会从它所在的位置开始,绕着圆心画出一个看不见的圆圈,这就是磁道 Track
。因为所有磁头都是联动的,故每个盘面上的同一条磁道又可以形成一个虚拟的圆柱,称为柱面 Cylinder
。
柱面编号是从盘面最边缘的那条柱面开始,向着圆心的方向,从 0 开始编号。
当 0 面的磁道不足以容纳要写入的数据时,应当把剩余的部分写在 1 面的同一磁道上。如果还写不下,那就继续把剩余的部分写在 2 面的同一磁道上。在硬盘上,数据的访问是以柱面来组织的。
磁道很窄,也看不见,但在想象中,它仍呈带状,占有一定的宽度。将它划分许多分段之后,每一部分都呈扇形,这称为扇区 Sector
。
每条磁道能够划分为几个扇区,取决于磁盘的制造者,但通常为 63 个。而且,每个扇区都有一个编号,扇区的编号是从 1 开始的。
扇区与扇区之间以间隙(空白)间隔开来。
每个扇区包含:
- 扇区头,扇区的开始
- 数据区,容量 512 个字节
扇区头包含了每个扇区自己的信息,用来供硬盘定位机构使用。主要有本扇区三个信息:
- 磁头号 Head
- 柱面号(磁道号) Cylinder
- 扇区号 Sector
采用磁头、磁道和扇区这种模式来访问硬盘的方法称为 CHS 模式,但不是很方便。如果有一大堆数据要写,还得注意磁头号、磁道号和扇区号不要超过界限。
后来引入了逻辑块地址(Logical Block Address,LBA)的概念。LBA 模式是由硬盘控制器在硬件一级上提供支持,所以效率很高,兼容性很好。
LBA 模式不考虑扇区的物理位置(磁头号、磁道号、扇区号),而是把它们全部组织起来统一编号。在这种编址方式下,原先的物理扇区被组织成逻辑扇区,且都有唯一的逻辑扇区号。
比如,某硬盘有 6 个磁头,每面有 1000 个磁道,每磁道有 17 个扇区。那么:
- 逻辑 0 扇区对应着 0 面 0 道 1 扇区;
- 逻辑 1 扇区对应着 0 面 0 道 2 扇区;
- 逻辑 16 扇区对应着 0 面 0 道 17 扇区;
- 逻辑 17 扇区对应着 1 面 0 道 1 扇区;
采用 LBA 模式的好处是简化了程序的操作,使得程序员不用关心数据在硬盘上的具体位置。
主引导扇区
硬盘的第一个扇区是 0 头 0 柱 1 扇区,或者说是 0 面 0 道 1 扇区,这个扇区称为主引导扇区(Main Boot Sector,MBR)。如果计算机的设置是从硬盘启动,ROM-BIOS 将读取硬盘主引导扇区的内容,将它加载到内存地址 0x0000:0x7c00 处(也就是物理地址 0x07C00),然后用一个 jmp 指令跳到那里接着执行。