Linux从头学10:三级跳过程详解-从 bootloader 到 操作系统,再到应用程序
扫描二维码
随时随地手机看文章
目录
-
bootloader 跳转到操作系统
-
操作系统跳转到应用程序
-
应用程序调用操作系统中的函数
bootloader 跳转到操作系统
在上一篇文章中,讨论了bootloader在进入保护模式之后,在地址0x0001_0000处创建了全局描述符表(GDT),表中创建了3个段描述符:
注意:
- 在 GDT 中为操作系统程序中的三个段,建立相应的描述符;
- 把每一个段的描述符索引号,写回到操作系统程序的 header 中;
操作系统的 header 布局
既然header需要作为媒介,来接收bootloader往其中写入段索引号,所以bootloader与OS就要协商好,写在什么位置?
建立操作系统的三个段描述符
bootloader把OS加载到内存中之后,会解析OS的header中数据,得到每个段的基地址以及界限。
PS:这里的示例只为操作系统创建了 3 个段描述符,实际情况也许有更多的段。OS段描述符建立之后,bootloader再把这3个段描述符在GDT中的索引号,填写到OS的header中相应的位置:
因此,把入口地址和索引号放在一起,有助于bootloader直接使用跳转语句,进入到OS的start标记处开始执行。
- 代码段的索引号;
- 代码的入口地址;
操作系统跳转到应用程序
从现代操作系统来看,这个标题是有错误的:
以上这些信息,都以段描述符的形式,创建在GDT中。
- 代码段的基地址、界限、类型和权限等信息;
- 数据段的基地址、界限、类型和权限等信息;
- 栈段的基地址、界限、类型和权限等信息;
- 操作系统把应用程序读取到内存中的某个空闲位置;
- 操作系统分析应用程序 header 部分的信息;
- 操作系统为应用程序创建每一个段描述符,并且把索引号写回到 header 中;
- 跳转到应用程序的入口地址,应用程序从 header 中获取到每个段索引号,设置好自己的执行上下文(即:设置好各种寄存器);
应用程序调用操作系统中的函数
这里的函数可以理解成系统调用,也就是操作系统为所有的应用程序提供的公共函数。
对于第一个问题,所以Linux中通过中断,提供一个统一的调用入口地址,然后通过一个寄存器来区分是哪一个函数。
- 如果操作系统提供的系统函数很多,应用程序也很多,那么操作系统在加载每一个应用程序时,岂不是要忙死了?而且应用程序也不知道应该保留多大的空间来存放这些系统函数的跳转信息;
- 在执行系统函数时,此时代码段、数据段都是属于操作系统的势力范围,但是栈基址和栈顶指针使用的仍然是应用程序拥有的栈,这样合理吗?
这就涉及到 x86 中复杂的特权级的相关内容了,下一篇文章,我们就向这些细节问题继续探索。
- 应用程序虽然可以调用操作系统提供的函数了,但是操作系统如何对内核代码进行保护?;
- Linux 为应用程序建立内部栈的底层支撑是什么?