物联网软件开发资讯 Linux从新学:x86 处理器如何进行-层层的内存保护?

[[420226]] 实步地:bootloader 为方法打算段的基地址 保护步地:bootloader 为我方创建段神色符 详情 GDT 的地址 创建代码段的神色符 创建数据段的神色符 创建栈段的神色符 段神色符是如何确保段的安全的? 段寄存器高速缓存 对段寄存器自己的保护 对段界限的查验

在上一篇著作中物联网软件开发资讯,咱们一经凯旋的从实步地,过渡到了保护步地。

保护步地与实步地最本色的分裂即是:保护步地使用了全局神色符表,用来保存每一个方法(bootloader,操作系统,应用方法)使用到的每个段信息:启动地址,长度,以偏抓他一些保护参数。

这篇著作,咱们来看一下 bootloader 是如何来进行自我进化到保护步地的,然后深切看一下保护步地是如何对内存进行安全保护的。

作为配景学问,咱们先来看一下 x86 中的地址变换经由:

上期龙头开出奇数号码05,近10期龙头奇偶比7:3,本期龙头预测关注偶数号码,独胆参考08。

x86 处理器中的分页机制是不错被关闭的,此时线性地址就等于物理地址,这亦然咱们一直推断的情况。

下一篇著作,咱们就把 x86 中的分页机制绽放,并与 Linux 中的分段和分页机制进行对比。

实步地:bootloader 为方法打算段的基地址

在之前的著作:Linux从新学06:16张结构图,澈底相识【代码重定位】的底层道理中,咱们推断了 bootloader 是如何把应用方法读取到内存中,终末跳入到方法的进口地址的。

这里所说的方法,不错是操作系统,也不错是应用方法。

底下这张图,是方法被加载到内存中之后,header 中的信息:

因为方法是被 bootloader 动态读取到内存中的,它是不知谈我方被放在内存中的什么位置,因此它也不知谈我方代码段、数据段、栈的启动地址。

然而,方法要想大约平常引申,就必须要知谈这些信息,那怎么办?

只须 bootloader 才能处理问题,因为是它来把方法从硬盘加载到内存中的。

因此,bootloader 在跳入方法的进口地址之前,必须把其中的代码段、数据段、栈段的基地址打算出来,然后写入到方法的 header 中,如下图所示:

这么的话,方法启动引申时,就不错从我方的 header 中获得到这 3 个段基地址,而况赋值给相应的寄存器,从而凯旋的引申方法。

也即是说:方法的 header 空间,充任了 bootloader 与它进行信圮绝互的弁言,用来传递 3 个段寄存器的基地址。

以上的这个经由,一直责任在实步地,因此就莫得段神色符什么事情。

在以后著作中,咱们还会看到在保护步地下,bootloader 仍然会运用 OS 的 header 空间,来传递段的索引号。然后 OS 运用这个段索引号,去查找 GDT 表,从而找到每一个段的基地址以偏抓他一些保护信息。

保护步地:bootloader 为我方创建段神色符

bootloader 从 BIOS 接受系统之后,刚启动是运行在实步地下的。

当它完成一些准备责任之后,就不错参预保护步地了,也即是把 CR0 寄存器的 bit0 配置为 1。

这个准备责任中,最伏击的即是:成立 GDT 这个表,而况把 GDT 的启动地址,存储到寄存器 GDTR 中。

底下这张图,是 bootloader 被加载到内存中的布局图:

bootloader 被加载到 0x0000_7C00 地址处。

它最少需要创建 3 个段神色符:代码段、数据段和栈段。

详情 GDT 的地址

在创建段神色符之前,需要先详情: 把 GDT 表放在内存中的什么位置?

暂且就把它放在 0x0001_0000 这个地址吧,距离零地址 64K 的位置。

按照处理器的条目,在第 1 个表项(称之为 item 或者 entry,每本书上王人不相通)必须为空神色符(index = 0)。

创建代码段神色符

bootloader 的代码放在 0x0000_7C00 启动的地址,长度是 512B。

字据这些信息,就不错构造出代码段的神色符了:

创建数据段神色符

bootloader 待会需要把操作系统或其他应用方法,从硬盘读取到内存中,举例:读取到 0x0002_0000 的位置。

那么 bootloader 就必须大约拜谒到这个位置,而况是以数据段的读写样貌。

为了运用一起的 4G 内存空间,bootloader 不错把这 4G 空间,物联网软件开发价格作为一个数据段来界说它的神色符,如下:

创建栈段神色符

表面上,bootloader 不错使用内存中的轻易一块适意空间,来作为我方的栈。

因为栈在 push 操作的技艺,是向低地址标的增长的。

因此许多书本王人会把栈顶基地址配置为 bootloader 的启动地址,也即是 0x0000_7C00 地址处,而况把栈的空间大小斥逐在 4K 的界限。

字据以上这些信息,就不错创建出栈的段神色符,如下:

小程序开发

当以上这几个段的神色符王人创建好之后,就不错把 GDT 的地址(0x0001_0000),配置到 GDTR 寄存器中了。

终末,再把 CR0 寄存器的 bit0 配置为 1,就致密的参预保护步地来引申 bootloader 中背面的代码了。

段神色符是如何确保段的安全拜谒的? 段寄存器高速缓存

参预保护步地之后,固然对段寄存器中内容的施展转换了,然而引申每一条提示,如故需要使用到这些段寄存器的: cs, ds, ss等等。

设想一下:每引申一条提示,王人会从逻辑地址中,获得到段索引号,然后去查找 GDT 表,从而定位到段的基地址。

全球王人知谈方法有个“局部性”道理,也即是伙同引申的代码,王人是聚会在一段伙同的方法空间中的。

这个伙同的方法空间,它们王人是在合并个代码段中,因此段的基地址王人是调换的,那么它们王人属于 GDT 中合并个代码段神色符所代表的段空间。

淌若每一条提示王人去查表,就会影响到方法的引申效果。

是以,处理器里面就为每一个段寄存器,安排了一个高速缓存。

拿代码段寄存器 cs 来说:当引申一条提示的技艺,淌若它与上一条提示中的段索引号不同,才会字据新的段索引号到 GDT 中查找相应的段神色符表项。

查找到之后,就把这个表项的内容复制到 cs 寄存器的高速缓存中。

当延续引申背面的提示时,淌若逻辑地址中的段索引号莫得变化,处理器就顺利从高速缓存中读取段神色,从而幸免了查表操作,提高了系统效果。

对段寄存器自己的保护

当逻辑地址中段寄存器的索引号转换时,就会字据新的索引号,到 GDT 中去查表。

天然了,这个索引号不行朝上 GDT 的界限。

当定位到某一个神色符表项之后,就启动进行一系列查验。

再来看一下每一个段神色符中 8 个字节的内容:

bit8 ~ bit11 界说了刻下这个段的类型。

假如: 咱们在切换代码段空间的技艺,不留神犯错,定位到了 GDT 中的一个数据段神色符表项,那么处理器就大约实时发现:

“刻下这个段神色符的类型是数据段,你却把它作为念代码段来使用,不容,杀无赦!”

因此,处理器就会隔绝把这个段神色符复制到代码段的高速缓存中,从而对代码段寄存器进行了保护。

对段界限的查验

在通过了第一层的段类型保护之后,还会延续对段的界限进行查验,这就要使用到逻辑地址中的偏移地址( EIP )了。

淌若偏移地址朝上了神色符中规矩的界限,那么就阐发发生诞妄了。

举例:在 bootloader 的代码段神色符中,最大的界限是 512B,淌若把 EIP 配置为 0x0000_1000,那就折服诞妄了。

因为这个地址根底就不属于代码段的空间界限。

关于数据段来说相比异常念念,因为咱们把数据段神色符的基地址配置为 0x0000_0000,段的界限是统共 4G 的空间,是以它不错对统共内存进行操作。

多想一步:

代码段亦然属于这 4G 空间,因此不错通过数据段,来改写代码段空间中的提示内容。

也即是说:淌若你想修改代码段的提示,顺利通过代码段来操作是不不错的。

因为代码段神色符中规矩了:代码段的内容只可被读取、引申,然而不行被写入。

此时,就不错匠心独具:代码段也放在 4G 的空间,那么就不错通过数据段的可写特质,来改写代码段中的提示。

 物联网软件开发资讯

想一想 gdb 的调试经由,是不是就运用了这个道理?

 



Powered by 物联网软件定制开发 @2013-2022 RSS地图 HTML地图

Copyright Powered by站群系统 © 2013-2024 云迈科技 版权所有