开始:
电脑开机后,cpu会指向主板上的BIOS程序,BIOS会将硬盘上0盘0道1扇区的那512字节的数据复制到内存中0x7c00这个位置。
硬盘的一个扇区的大小就为512字节。这512字节的数据是预先写在硬盘中的程序。
从0x7c00开始,共512字节,也就是说,要一直到0x7dff结束。0x100是256,0xff是255,再加上0x7c00这个地址,就是256,两个256加起来就是512。
硬盘上的这第一扇区的512字节的空间,是启动区。只要这512字节的最后两个字节分别是0x55和0xaa,BIOS就会认为这个区域是启动区,从而读取这个区域到内存中。
复制之后,会跳转到0x7c00这个地址开始执行程序。当然,是cpu跳转到的这个地址,并执行的程序。
Linux0.11最开始的代码,是用汇编写的bootsect.s,boot是引导,sect是sector的缩写,所以bootsect是引导扇区的意思。此文件编译后会被存在第一扇区,然后就是由BIOS搬运,cpu执行。
汇编指令mov:
mov是move的缩写,所以,mov指令的作用就是将数据从一个地址,移动到另一个地址;或者是一个寄存器移动到另一个寄存器中;或者从一个寄存器移动到一个内存地址中;或者从一个内存地址移动到一个寄存器中。反正意思都是从一个存储空间中移动到另一个存储空间中。寄存器是cpu中用于存储和处理数据的组件,主打一个快。
ax寄存器和ds寄存器:
accumulate:积累,accumulator:累加器。ax中的x似乎没有具体含义,只是命名是这样命名的。但默认还有一个register:寄存器。
所以,ax是累加器寄存器,用于存储算术和逻辑运算的结果。反正寄存器基本都是用来存储和处理数据的。
ds中的d是data的意思,s是segment的意思,所以它叫数据段寄存器。用来存储数据段的基址,也就是起始地址。数据段是程序存储数据的段,而访问一段数据,自然要从起始地址开始。
bootsect.s开始的几句:
一开始,定义了一些常量和段什么的。具体如下:
SYSSIZE = 0x3000
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text
SETUPLEN = 4
BOOTSEG = 0x07c0
INITSEG = 0x9000
SETUPSEG = 0x9020
SYSSEG = 0x1000
ENDSEG = SYSSEG + SYSSIZE
当然,还有一些注释,代码写于1991年,作者是Linux Torvalds。他说,SYS_SIZE是以clicks为单位的,这个滴答数或点击数具体想表达啥,不清楚,反正一个clicks是16bytes,也就是16字节。
那么16字节就是0x10字节,0x3000个clicks就是0x30000字节,0x30000转成二进制的话,是11后面还有16个0,也就是:,而:
个字节,叫做1kb,那么剩下的:
,结果是192。最后,也就是说,0x3000个clicks有多大呢?欸!就是192kb。这个系统大小,是完全够用滴。
.globl指令可以标记符号为全局符号,这意味着符号可以被程序中的其他文件访问,也就是说,
begtext, begdata, begbss, endtext, enddata, endbss
这些符号是可以在其他文件里访问到的。
.text是指定代码段,.data是指定数据段,.bss是指定未初始化的数据段。使用这些指令的逻辑是这样的:
.text
begtext:
//一些代码
也就是说,先用.text指定下面的指令为代码段中的内容,而begtext:则是一个入口,代表了代码段的开始。也就是说,在接下来的代码中,可以写begtext:,然后在它的下面写的代码,就会被指定为代码段中的内容。
后面的.data和.bss也是这个逻辑。
那么现在所知的就是:SYSSIZE(system size)的值是0x3000,SETUPLEN(number of setup sectors 设置扇区数量)的值是4,BOOTSEG(boot segment)的值是0x07c0,INITSEG(initial segment)的值是0x9000,SETUPSEG(setup segmen)的值是0x9020,SYSSEG(system segment)的值是0x1000,ENDSEG(end segment)的值是SYSSEG+SYSSIZE,也就是0x1000+0x3000=0x4000。至于为什么都是十六进制的四位数,大概是因为系统是16位的吧。
程序的正式开始:
mov ax,#BOOTSEG
mov ds,ax
#代表后面的变量是个立即数。BOOTSEG的值是0x07c0,mov指令的作用是移动数据,手段就是复制地址,所以说第一句的意思就是把ax中的值变成0x07c0,第二句就是把ds中的值变成0x07c0。
ds寄存器用于指定许多数据传输指令的默认数据段地址。也就是说,之后要把某个地址传给某个寄存器,都要默认加上ds中的地址,这个寻址方式是汇编中特意规定的。比如:
mov ax, [0x0001]
0x0001只是偏移地址,还要加上ds中的值,才是真正复制到ax中的地址。注意,#BOOTSEG是个立即数,[0x0001]是个地址,二者是不一样的。
而在复制时,ds中的值会默认左移四位,也就是十六进制的一位,那么0x07c0就会变成0x7c00,也就是最开始的那512字节数据被移动到内存中的起始地址。那么,以这个地址为基本点,加上不同的值,就可以访问后面的不同的地址了,在后面的代码中就可以看到,不同的代码是放在不同的区域的。
总之就是方便了寻址。