1. Core程序的结构、加载和运行
1.1 Core程序的结构
Core程序包含初始化、代码段、数据段和公共例程段。
MBR也是core初始化代码的一部分
MBR创建了4个段描述符,分别是4G段、MBR代码段、栈段和显示段
然后加载core程序,创建了3个段描述符,分别是公共例程段、core代码段、数据段,并将控制权转移到core程序
Core程序随后加载了APP程序,创建了4个段描述符,APP头部段、APP代码段、APP数据段和APP栈段
APP程序将控制重新转移到Core。
1.2 Core程序中用到的过程
重复使用的功能可以定义成过程
在MBR、Core和APP程序执行的过程中用到的过程描述如下
read_hard_disk_0
;从硬盘读取一个逻辑扇区
;EAX=逻辑扇区号
;DS:EBX=目标缓冲区地址
;返回:EBX=EBX+512
make_gdt_descriptor
;构造描述符
;输入:EAX=线性基地址
; EBX=段界限
; ECX=属性(各属性位都在原始
; 位置,其它没用到的位置0)
;返回:EDX:EAX=完整的描述符
sys_routine_seg_sel:put_string
;显示0终止的字符串并移动光标
;输入:DS:EBX=串地址
load_relocate_program
;加载并重定位用户程序
;输入:ESI=起始逻辑扇区号
;返回:AX=指向用户程序头部的选择子
(1)将寄存器的值压栈
(2)将用户程序的第一个扇区读取到core_buf
(3)获取APP的大小,并为用户程序分配内存
(4)读取用户程序剩余部分到内存中
(5)在GDT中创建4个段描述符,分别是APP的头部段、APP代码段、APP数据段和APP栈段
(6)重定位SALT
sys_routine_seg_sel:allocate_memory
;分配内存
;输入:ECX=希望分配的字节数
;输出:ECX=起始线性地址
sys_routine_seg_sel:make_seg_descriptor
;构造存储器和系统的段描述符
;输入:EAX=线性基地址
; EBX=段界限
; ECX=属性。各属性位都在原始
; 位置,无关的位清零
;返回:EDX:EAX=描述符
sys_routine_seg_sel:set_up_gdt_descriptor
;在GDT内安装一个新的描述符
;输入:EDX:EAX=描述符
;输出:CX=描述符的选择子
1.3 程序内容
MBR
初始化栈段寄存器SS和栈指针SP
在GDT中新建4个段描述符,分别是4G段、MBR代码段、栈段和显示段
更新GDTR。GDTR中记录了GDT的大小和物理地址
进入保护模式。jmp 0x0010:flush
将Core程序加载到内存中指定位置。Core在罗辑扇区1上,要加载到内存中地址为0x00040000的位置。使用过程read_hard_disk_0实现程序的加载
加载完成后,在GDT中再创建3个段描述符,分别是公共例程段、内核数据段、内核代码段
更新GDTR。
将控制权转移到内核代码段执行。jmp far [edi+0x10],这里edi为内核代码加载位置的首地址
填充若干个0和0x55aa
Core
打印message_1。put_string
打印cpu_brand
打印message_5
加载用户程序。load_relocate_program
打印do_status
将控制权转移到用户程序。jmp far [0x08]
从APP转移回来之后,打印message_6
停机。hlt
APP
打印message_1
将逻辑扇区100的程序加载到内存buffer中
打印message_2
打印buffer
远转移到Core的代码段继续执行。jmp far [fs:TerminateProgram]
2 知识点
SALT重定位
SALT,symbol address lookup table,符号地址表
内核代码里会定义一些公共例程,这些公共例程可供全部的用户程序使用。
但是用户程序在编写的时候,并不能总是知道公共例程中各个公共例程的段选择子和偏移地址,并且即使是知道某个版本的内核的公共例程的具体位置,随着内核代码的更新换代,这个位置也会发生变化,因此需要在用户程序中动态的计算要用到的公共例程的具体位置。
在用户程序中有一个SALT,称为U-SALT,它位于用户程序的数据段中,记录着用户程序里用到的公共例程段。表项由标号和一个长度为256的字符串组成
在内核代码中也有一个SALT,称为C-SALT,它位于内核程序的数据段中,记录着内核代码中定义的全部公共例程。表项有标号、一个长度为256的字符串、该公共例程所在的段的段选择子和偏移地址组成。
SALT重定位指的是U-SALT的重定位,重定位的工作是将U-SALT每个表项的字符串和C-SALT中的进行比对,如果找到一样的字符串,则把C-SALT中该表项的选择子和偏移地址复制到U-SALT中,此时U-SALT中保存的就是标号、段选择子和偏移地址,而没有字符串了。