后进式无遮挡啪啪摇乳免费
秋霞国产午夜伦午夜福利片 你的位置:后进式无遮挡啪啪摇乳免费 > 秋霞国产午夜伦午夜福利片 > Linux从新学:x86 处理器怎样进行

Linux从新学:x86 处理器怎样进行

发布日期:2022-06-18 17:07    点击次数:201

Linux从新学:x86 处理器怎样进行

实花式:bootloader 为程序野心段的基地址 保护花式:bootloader 为我方创建段描写符 详情 GDT 的地址 创建代码段的描写符 创建数据段的描写符 创建栈段的描写符 段描写符是怎样确保段的安全的? 段寄存器高速缓存 对段寄存器自己的保护 对段界限的查验

在上一篇著述中,咱们仍是告成的从实花式,过渡到了保护花式。

保护花式与实花式最本色的诀别等于:保护花式使用了全局描写符表,用来保存每一个程序(bootloader,操作系统,应用程序)使用到的每个段信息:开动地址,长度,以偏激他一些保护参数。

这篇著述,咱们来看一下 bootloader 是怎样来进行自我进化到保护花式的,然后潜入看一下保护花式是怎样对内存进行安全保护的。

行为布景常识,咱们先来看一下 x86 中的地址变换进程:

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地图