热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

x86从实际模式到保护模式(3):强大的分页机制

x86从实模式到保护模式虚拟内存和用户程序结构物理内存的分页原因开启分页机制自我综述验证分页机制,强大如斯,理论和物理,分离让你脑子停熄虚

x86从实模式到保护模式

          • 虚拟内存和用户程序结构
          • 物理内存的分页原因
          • 开启分页机制
          • 自我综述
          • 验证


分页机制,强大如斯,理论和物理,分离让你脑子停熄


虚拟内存和用户程序结构

虚拟内存在理论上可以看作是一个用户程序拥有自己的一块4G内存,即该用户程序认为自己独占所有内存,而物理上则是高速缓存存储器(cache)根据局部性原理进行数据交换,加上流水线技术等等的一种假象,虚拟内存的地址是一种逻辑地址,是根据段式存储而分配的一种逻辑上的线性内存空间,如果不进行分页,则就是物理地址,否则还是要通过页部件转换成物理地址,在此不做过多叙述。

用户程序分为:全局部分(GDT,PCB,MBR,HMA,Stack segment,Kernel…)+ 任务的私有部分(LDT,TSS,Code segment,Data segment,Stack segment)。所有的用户程序的全局部分几乎是一样的。

物理内存的分页原因

物理内存分页的原因:

把虚拟内存对应于物理内存进行分页,页的大小为4K,物理内存一共有1024 * 1024个页(内存为4G),由物理地址00000000开始,每次加上4K即00001000,以此类推。

在这里插入图片描述
段地址转化成页地址的过程:取段地址的前20位*4找到页表中对应的索引的值(该值是物理地址的前20位)+ 线性地址的后12位 = 32位物理地址,将内容写入页中即可

为了让用户程序的两部分在页中也泾渭分明,因此在内存中必须先定义全局部分的页,因此产生了页目录表和页表

页表有1024个页表的物理地址,每个页表有1024个物理页,因此可以表示1024 * 1024个页

CR3(页目录基址寄存器)存放着当前任务的页目录地址,因此相应的页部件也得调整:

线性地址的前10位用来指明页目录的索引(CR3指向页目录),根据索引的值取得页表的地址,中间10位取得页表的索引的值,加上最后的12位合成32位物理页。

;创建系统内核的页目录表PDT;页目录表清零 mov ecx,1024 ;1024个目录项mov ebx,0x00020000 ;页目录的物理地址xor esi,esi.b1:mov dword [es:ebx+esi],0x00000000 ;页目录表项清零 add esi,4loop .b1

此处要搞清楚,是先有内核才有页表的,但是内核后期也要页表,因此内核的页表在映射的过程中是直接把线性地址转化成物理地址即可。

页表和页目录表结构

  • 21~31:页表物理基地址
  • 0:P,页表和页目录表是否在内存中
  • 1:RW,页表和页目录表是否可读写
  • 2:US,用户或管理位,特权级位
  • 3:PWT,页级通写位,是否写入高速缓存
  • 4:PCD,页级高速缓存位
  • 5:A,是否被访问
  • 6:D,是否写过数据
  • 7:O(页目录表);PAT(页表项):页属性表支持位
  • 8:G,全局位,该表是否为全局位
  • 9~11:程序是否可使用

;在页目录内创建指向页目录自己的目录项mov dword [es:ebx+4092],0x00020003 ;在页目录内创建与线性地址0x00000000对应的目录项mov dword [es:ebx+0],0x00021003 ;写入目录项(页表的物理地址和属性) ;创建与上面那个目录项相对应的页表,初始化页表项 mov ebx,0x00021000 ;页表的物理地址xor eax,eax ;起始页的物理地址 xor esi,esi.b2: mov edx,eaxor edx,0x00000003 mov [es:ebx+esi*4],edx ;登记页的物理地址add eax,0x1000 ;下一个相邻页的物理地址 inc esicmp esi,256 ;仅低端1MB内存对应的页才是有效的 jl .b2.b3: ;其余的页表项置为无效mov dword [es:ebx+esi*4],0x00000000 inc esicmp esi,1024jl .b3

开启分页机制

CR3:指向页目录,CR0的PG位表示开启分页机制

;令CR3寄存器指向页目录,并正式开启页功能 mov eax,0x00020000 ;PCD=PWT=0mov cr3,eaxmov eax,cr0or eax,0x80000000mov cr0,eax ;开启分页机制

页表建立的先后是,先把用户程序放入虚拟内存,然后搜寻物理内存的空闲页将其地址放入建立的页表


用户程序的页表是怎么来的?是先复制内核的页目录,将高端映射为内核部分,低端映射为用户任务部分

空闲页的搜索
页映射位串:操作系统会在获得内存信息的时候会获得所有页的相关信息,当有程序要分配内存时,就在位串中来指定每个页的分配情况,共1024 * 1024个b

搜索位串是否空闲

bts r, r

刷新TLB:传统情况下,程序要使用内存,必须经过页目录表和页表转化成物理地址,因此把页表项预先装在处理器中,可以加快速度,这个叫做TLB(转换速查缓存器,快表)

mov cr3, ebx
mov ebx, cr3

在这里插入图片描述

tlb较小,当tlb满的时候,替换掉那些用的少的行


自我综述

一篇文章想讲全分页机制肯定是不可能的,想完全弄懂只能去看源码和理论和物理上的实现,这点很绕,但是不可避免。
虚拟内存说白了其实就是个虚拟的玩意,是程序自己想的,你可以想象程序的所有段其实都在硬盘上。打个比方,一个.c文件生成.out文件里面的地址其实都是虚拟地址,而这个地址是他自封的,他认为他在运行的时候也是这个地址
当程序变成一个进程的时候他会将线性地址(虚拟地址)通过页目录表和页表映射到内存中,当发生切换进程的时候,旧的进程会将页目录表的信息存放在CR3寄存器,这个新的进程也会通过页目录表和页表得到物理页,如果物理页都被占用了,则将暂时不用的物理页先换出内存(cache或者其他技术)。

验证

// 01.c
#include int main() {printf("Hello World! \n");return 0;
}

gcc 01.c # 编译源代码
readelf -a a.out

# 查看该用户程序头
lh@lh-virtual-machine:~$ readelf -a a.out
ELF 头:# 魔数,其中45 4c 46对应的是ASCII表值是ELF,表明这个文件是一个elf文件Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 ....入口点地址: 0x1060程序头起点: 64 (bytes into file)Start of section headers: 14712 (bytes into file)标志: 0x0Size of this header: 64 (bytes)Size of program headers: 56 (bytes)# 标号的数量Number of program headers: 13Size of section headers: 64 (bytes)# 段的数量Number of section headers: 31

好了,x86从实模式到保护模式到此结束啦,下一阶段我要走业务了,所以先学一学protobuf和libevent空间吧!


推荐阅读
  • 查找给定字符串的所有不同回文子字符串原文:https://www ... [详细]
  • 《2017年3月全国计算机等级考试二级C语言上机题库完全版》由会员分享,可在线阅读,更多相关《2017年3月全国计算机等级考试二级C语言上机题库完全版( ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 解决Sharepoint 2013运行状况分析出现的“一个或多个服务器未响应”问题的方法
    本文介绍了解决Sharepoint 2013运行状况分析中出现的“一个或多个服务器未响应”问题的方法。对于有高要求的客户来说,系统检测问题的存在是不可接受的。文章详细描述了解决该问题的步骤,包括删除服务器、处理分布式缓存留下的记录以及使用代码等方法。同时还提供了相关关键词和错误提示信息,以帮助读者更好地理解和解决该问题。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 本文整理了Java中com.evernote.android.job.JobRequest.getTransientExtras()方法的一些代码示例,展示了 ... [详细]
  • 如何使用PLEX播放组播、抓取信号源以及设置路由器
    本文介绍了如何使用PLEX播放组播、抓取信号源以及设置路由器。通过使用xTeve软件和M3U源,用户可以在PLEX上实现直播功能,并且可以自动匹配EPG信息和定时录制节目。同时,本文还提供了从华为itv盒子提取组播地址的方法以及如何在ASUS固件路由器上设置IPTV。在使用PLEX之前,建议先使用VLC测试是否可以正常播放UDPXY转发的iptv流。最后,本文还介绍了docker版xTeve的设置方法。 ... [详细]
  • 深入理解计算机系统之链接(一)
    程序是怎样运行的写好的c程序怎样运行的呢?答案是一个写好的程序要先经过语言预处理器,编译器,汇编器和链接器生成最后的可执行文件,然后加载器将可执行文件加载到内存中才能运行。这里以一 ... [详细]
  • c语言 怎么访问64位地址_C语言调动硬件的原理是什么?
    大家都知道我们可以使用C语言写一段程序来控制硬件工作,但你知道其工作原理吗?1c语言在实际运行中,都是以汇编指令的方式运行的,由编译器把C ... [详细]
author-avatar
0519bobo_724
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有