进程地址空间
每个进程所看到的的线性地址集合是不同的,一个进程所使用的地址与另外一个进程所使用的地址之间没有什么关系。
当用户最终控制台输入一个命令时,shell进程创建一个新的进程去执行这个命令。一个全新的地址空间分配给了新进程。
与进程地址空间有关的全部信息都包含这种一个叫做内存描述符的数据结构中mm_struct,进程描述符的mm字段就指向这个结构。
段描述符与段寄存器
对任何程序的执行而言,至少要将CS,DS,SS赋予有效的段选择符,处理器还提供了ES、FS、GS供进程使用;
当一个进程要访问某个段时候,需使用段寄存器进行加载。这也是系统定义了数千个段,但是只有6个段时可以直接被使用的原因。
加载ELF格式内核
loader不是操作系统内核,也不能当做操作系统内核。最终我们希望自己的操作系统内核可以在Linux下用GCC编译链接,要不然就只能用汇编一点一点编写。
之前的内核编译均为原始格式
nasm boot.asm -o boot.bin
后续的内核编译需要为ELF格式,
nasm -f elf -o kernel.o kernel.asm
ld -s -o kernel.bin kernel.o
Loader要做的事情至少有两件:
(1)加载内核入内存;
(2)跳入保护模式。
在Linux下编译链接出的内核是ELF格式的文件,直接放入内存无法运行,需要研究将ELF格式拆解的方法。
加载内核到内存这一步和引导扇区的工作非常相似,只是处理内核时需要根据Program header table中的值把内核中相应的段放到正确的位置。
在由Loader进入保护模式之后,不打算做太多工作,所以1kB栈就足够了,等到进入内核后,可以重新设置堆栈。
nasm的代码包含也一定要区分是在16位代码中的包含还是在32位代码中的包含。
asm和C同步使用
关键字是extern和global,有了这两个关键字,就可以方便在asm和C代码之间自由来去。
向内核跳转
jmp SelectorFlatC:KernelEntryPoint
KernelEntryPoint定义在load.inc中,其值必须跟ld的参数-Ttext指定的值是一致的。
如果需要将内核放在另外的位置(如1MB以上的内存),只需改动这两个地方就可以。
NASM
org
ORG指令的功能是指定将程序加载到内存时NASM会假定其开始的原始地址。
ORG定向符的功能是在NASM将程序装入内存中时,指定的一个起始位置。
org指令并不改变cs的值,org在链接时期的重定位阶段起作用,改变符号引用的位置。
你也许已经震惊的发现,第一行代码尽然不是代码里的第一行:ORG 0100H,而是第二行MOV AX,0B800H。其实事情的原因是这样的:
那个ORG,其实不是汇编指令来的那个是一个标识,告诉编译器,这篇代码将来有可能被加载到内存的什么地方(请注意DeBug里面的MOV指令的偏移地址,没错,是0100H!)
注意:这个0100H可不是ORG伪指令设定的!(实际上CPU根本就没有,专门给编译器的指令称作伪指令)ORG只是告诉NASM,这篇代码会被加载到0100H好让NASM做好准备而已。