先说下什么是寄存器。

寄存器是一种物理存储元件,只不过它是比一般的存储介质要快,能够跟上cpu的步伐,所以在cpu内部有好多这样的寄存器用来给cpu存取数据。

先简短说这一两句,暂时离开一下主题,咱们先看看相对熟悉一些的概念——缓存。

缓存也是一项非常伟大的发明,成功解决了速度不匹配设备之间的数据传输,并且在一般情况下,IO是整个系统的瓶颈,缓存的出现,有效减少了低速IO设备的访问频率,从而大幅度的提升了速度。

大家对缓存一定不会陌生,生活中处处都是缓存的应用。比如浏览器在请求一个域名的ip时:

  1. 1浏览器内部都有dns客户端,它先查询本地dns缓存中是否有该域名的ip,如果有就直接去访问该ip。如果没有,该dns客户端先要查找自己主机所设置的dns服务器,然后去该dns服务器去查询ip。
  2. 如果该dns服务器本地缓存中有该域名的A记录(域名与ip地址的对应记录),则直接返回给浏览器中的dns客户端。没有该域名的A记录,就通过递归的方式向上询问其它dns服务器,也许问到了根dns服务器才找到了答案。于是这路上所有被询问过的dns服务器,都将此域名对应的A记录缓存到自己的cache中,以备下次再有相同域名查询时好直接返回。
  3. 浏览器中的dns客户端得到此域名的ip地址后,也将该域名和ip放在自己的缓存中,以备下次用户再键入同一域名时,避免再查一次ip。
  4. 浏览器开始通过网络用http协议访问该ip地址的80端口(默认是80端口,除非特别指定)。
  5. 一般情况下该ip对应的设备不是最终的web服务器,很少有人把web服务器直接暴露在公网。假设该ip对应的设备是台网关(一般是硬件路由设备),该网关检查本地缓存中是否有相关web服务器的缓存,若有则直接将该http请求分配给缓存中的web服务器。否则从服务器列表中重新分配一台web服务器,将该http请求转发给该web服务器处理。随后将该web服务器的ip地址(一般是内网地址)和端口号缓存起来,以备下次该用户的请求到来时,依然给该web服务器。有的网关可以识别用户cookie信息,从而将可以请求再次落到上一个请求的web服务器上。
  6. web服务器拿到请求后,如果是静态请求,先检查自己的缓存中是否有该页面的记录,否则直接从硬盘上取出页面,将其返回后,再存入本地静态缓存中。如果动态请求,先交给自己的cgi去处理。
  7. cgi拿到请求后,先检查自己的缓存系统如memcache,如果缓存中没有,与数据库建立连接,向数据库发出请求。
  8. 数据库也是先检查自己的缓存,若没有结果集,则从表中检索到数据后返回,并将结果集缓存起来。
  9. cgi拿到数据后,返回给web服务器。并将数据缓存到memcache中。
  10. web服务器拿到了数据后,将数据返回给网关。由于是动态数据,不需要缓存。
  11. 网关拿到数据后,直接返回给浏览器。
  12. 如果浏览器发现其中有静态数据,如图片,也将静态数据缓存到用户的internet 临时目录。

您看,就这么一个不起眼的网页请求,就经过了12步,几乎每一步都要缓存结果,当然每一层的缓存都有一定的失效时间,超过多少秒后就将缓存中的记录置为无效。这其中还有另外一个术语,如果缓存中恰好有需要的内容,这就称为命中hit,否则称为缺失mis。

其实上面的缓存,我还没说全呢,硬件之间还有缓存呢,比如硬盘控制器和硬盘……得,您还是打住吧,我是来学操作系统的,您跟我说这干吗,还说了12个步骤,这与我何干?

兄弟稍安误燥,待小弟细细道来。前面所说的各种缓存,是为了引出cpu中的缓存。cpu中的一级缓存L1,二级缓存L2,它们都是SRAM,即静态随机访问存储器,它是最快的存储器啦。也许您又说:“是啊,这个我知道,那又怎么样?”

好啦不卖关子啦,也许您只听说L1、L2、SRAM,但您可能不知道的是,SRAM是用寄存器来存储数据的,这就是SRAM快的原因。而寄存器为什么快呢?原因是,寄存器是使用触发器实现的,这也是一种存储电路,工作速度极快,是纳秒级别的,您想寄存器能不快吗,这和cpu的速度是一个级别啦。硬件我也不是很了解,所以只能跟您说到这了,点到为止,对于硬件背后的原理,咱们蜻蜓点水即可。

巧妇难为无米之炊,不管是指令还是数据,cpu内部总该有个地方存放它们,否则cpu这位巧妇连锅都没有,还怎么给大家烧一桌好菜呢。所以,寄存器是给cpu处理数据的场所。

到这里,大家心里应该对寄存器有个感性认识了,这样学起来,似乎看得见摸得着了。

cpu中的寄存器大致上分为两大类:

  • λ一类是其内部使用的,对程序员不可见。“是否可见”不是说寄存器是否能看得见,是指程序员是否能使用。cpu内部有其自己的运行机制,是按照某个预定框架进行的,为了cpu能够运行下去,必然会有一些寄存器来做数据的支撑,给cpu内部的数据提供存储空间。这一部分对外是不可见的,我们无法使用它们。比如全局描述符表寄存器GDTR,中断描述符表寄存器IDTR,局部描述符表寄存器LDTR,任务寄存器TR,控制寄存器CR0~3,指令指针寄存器IP,标志寄存器flags,调试寄存器DR0~7。
  • λ另一类是对程序员可见的寄存器。我们进行汇编语言程序设计时,能够直接操作的就是这些寄存器。如段寄存器,通用寄存器。

虽说第一类的程序是不可见寄存器,我们没办法直接使用,但它们中的一部分还得由咱们给初始化呢。比如全局描述符表寄存器GDTR,以后咱们还要通过lgdt指令为其指定全局描述符表的地址及偏移量。对于中断描述符表寄存器IDTR,咱们也是要通过lidt指令为其指定中断描述符表的地址。而局部描述符表寄存器LDTR,可以用lldt指令为其指定局部描述符表ldt(但我们效仿了现代操作系统,未用局部描述符表ldt)。对于任务寄存器TR,我们也要用ltr指令为其在指定一个任务状态段tss。对于flags寄存器,我们也有办法设置它,系统提供了pushf和popf指令,分别用于将flags寄存器的内容压入栈,将栈中内容弹到flags寄存器。额外说一句,ldt和tss都位于gdt中。这些方面的内容咱们在学习保护模式后都会讲到。

在实模式下,默认用到的寄存器都是16位宽,咱们说说具体的寄存器吧。段寄存器是做啥的呢。说到段寄存器存在的理由,得先说到内存访问机制。cpu是用“段基址:段内偏移地址”的形式来访问内存的,如果您对此访存形式不了解,前面第0章中有解释过分段,而且在下一节中也是讲内存分段的理由。您合理安排阅读。

现在假设您已经了解分段机制啦,上面提到的“段基址:段内偏移地址”中的段基址,就是用段寄存器来存储的,段寄存器的作用就是指定一片内存的起始地址,故也称为段基址寄存器。尽管段基址在实模式下要乘以16,在保护模式下只是个选择子(保护模式中会讲),但其作用就是指定一片内存的起始地址。而段内偏移地址,顾名思义,仅仅相对于此起始地址的偏移量。

访问内存,是要通过地址总线,给地址总线一个数字(也就是地址),地址总线就能找到以该数字为地址的内存。可是这个数字是哪来的呢?对于首次访问内存之前,其内存地址肯定是要放在与内存不同的存储介质中更合适也更容易。如果用内存来存储内存地址,首先访问该内存就是个问题,该内存的地址是什么?这就跟先有鸡还是先有蛋的本源问题一样了。您可能会有疑问,地址也只是个数字,把数字存放在内存中有什么不行的。我这里所说的并不是内存寻址,您说的这个数字只是该内存单元中的内容,这是内存寻址,前提是您已经给地址总线提交了保存该数字的内存地址。我说的是,提交给地址总线的地址,是从哪里获得的。不知道我说清楚了没有,再举个例子,我想用木材做一个船模,我不可能还用木质工具去加工它,只能用铁器等比木更硬的材料通过削、磨等方式将它加工出来。换在计算机中也一样,访问内存就要提供地址,初次访问内存时,该地址要么用立即数,要么存储在某个存储器中能让cpu取出来再访问内存,肯定不能用内存本身来存。由于寄存器比内存更高级,cpu更能接受,所以就用寄存器来存储内存地址。由于要指定的是内存中的一段区域的起始地址,所以称之为段基址寄存器,也称段寄存器,无论是在实模式下还是保护模式下,它们都是16位宽。

下面就是实模式下的段寄存器

代码段简而言之就是把所有指令都连续排放在一起,形成了一个全部都是指令的区域,里面存储的是指令的操作码及寻址方式等。该区域可以在硬盘上的文件中,也可以是被加载后的内存中。总之是一段指令区域,它们内部都是紧凑挨着的,内容形式完全一样,只是存放的介质不一样而已。代码段寄存器CS就是用来指向内存中这段指令区域的起始地址。具体程序分段的解释,可见第0章。

数据段和代码段类似,只是这段区域中的内容不是指令而是纯粹的数据,也就是说里面存储的是程序运行所需要的数据,属于指令的操作数。数据段寄存器DS便是用来指向此数据区域的起始地址。

栈段是在内存中,硬盘文件中可真没有。一般的栈段是由操作系统分配指定的,所以是属于被加载到内存后才有的。本章后面还会讲栈,这里大家就先当它是一段内存区域就好。栈段寄存器SS就是用来指向此区域的起始地址。

代码段、数据段、栈段寄存器从名字上就较容易理解,那三个附加段寄存器是干吗的?其实就是多给大家提供几个段寄存器用而已,多几个寄存器用不是更好吗,省得紧巴巴的,纯粹是为了方便大家。

值得说明的是,在16位cpu中,只有一个附加段寄存器——ES。而FS和GS附加段寄存器是在32位cpu中增加的。我们使用的是32位cpu,并不是说32位cpu在实模式下的16位环境中就不能用FS和GS寄存器。32位的cpu是兼容16位cpu的特性,就像一个小学生也可以穿中学生的衣服一样,无非是多用了个可用的资源。

IP寄存器是不可见寄存器,CS寄存器是可见寄存器。这两个配合在一起后就是cpu的罗盘,它们是给cpu导航用的。cpu执行到何处,完成要听这两个寄存器的安排。为什么要用两个寄存器?因为指令是在内存中,访问内存就要用“段:段内偏移”的形式,所以CS寄存器用来存代码段段基址,IP寄存器用来存储代码段段内偏移地址,同CS寄存器一样都是16位宽。

其实这两个寄存器没什么神奇的,并不是它们真的决定了cpu的航向,只是cpu的航向被存入了这两个寄存器之中。之前说过啦,指令在逻辑上是紧凑的,这样cpu便能连续不断的执行下去,天荒地老,直到断电。cpu执行完一条指令后,顺便就把下一条指令的内存地址读进来。注意看,读入的是下一条指令的内存地址,这有两个关键字,一个是内存,一个是地址。刚刚说过啦,是内存就应该用“段基址:段内偏移地址”的机制来访问。是地址就该有地方存放。您想,即使是洗菜,菜也得先找个盘子或盆之类的器具盛着再拿到水笼头下冲洗。在x86体系架构中,本着先满足“段基址:段内偏移”的形式,这个地址就分开存到了代码段CS寄存器和指令指针IP寄存器。在执行当前指令的同时,在不跨段的情况下,cpu以“当前IP寄存器中的值+当前执行指令的机器码长度”的和做为新的代码段内偏移地址,将其存入IP寄存器,再到该新地址处读取指令并执行。如果下一条指令需要跨段访问,还要加载新的段基址到CS寄存器。此后,继续重复以上“取址、执行”的循环。

好啦,客官以后常来玩儿哦。

本节内容摘自操作系统真象还原,请大家支持正版。

【再续】

asponse.word 设置全局段前段后信息_一步步编写操作系统 12 代码段、数据段、栈和cpu寄存器的关系...相关推荐

  1. Word 为标题设置段前段后间距设置与异常

    Word 为标题设置段前段后间距设置与异常 参考文章: (1)Word 为标题设置段前段后间距设置与异常 (2)https://www.cnblogs.com/neillee/p/7001891.ht ...

  2. 【论文写作】利用word表格插入图片和公式,以及段落的段前段后间距设置

    公式:段前段后各6磅 图片和段落之间:12磅 小标题:段前6磅,段后12磅 图片标题:段前6磅,段后12磅 表格标题:段前12磅,段后6磅 图标(a)(b)-段前段后均为0 表格插入公式 可以看出,表 ...

  3. word2019技巧:段落的段前段后单位行设置为磅

    word2019技巧:段落的段前段后单位行设置为磅 当单位是行时我们怎么把单位设置为磅?一般搜到答案都是直接打字多少磅就行了,但是我的word不行,打字自动变成英文 我们可以从别的地方复制磅这个字儿黏 ...

  4. WPS 设置默认标题格式,段前段后间距

    打开WPS文件时,经常需要改动标题的段前段后距离.行间距.标题字体大小等信息,WPS常碰到的问题是:修改后有时候有效果有时候却没有(WPS这块设计的实在不太友好).琢磨了好一会,发现一个还算靠谱有效的 ...

  5. html 文字段后间距,css怎么设置段前段后的距离?

    在网页中文章段落一般我们用html 标签进行分段,可以在css样式表中设置 标签的段前后间距.下面本篇文章来给大家介绍一下使用css怎么设置段前段后的距离? 一.line-height行高 我们对li ...

  6. wps排版-一级标题设置段前段后两行,段前不显示格式和怎么删除下一页分节符,不改变格式

    1. 问题 正常显示 2. 解决方法 (1)先清除"第1章 绪论"的段落布局,鼠标放在在"第1章 绪论"开头,点击---插入---分页----下一页分节符--- ...

  7. WORD设置节起始页码后出现诡异隐藏页/跳页、节首页页面边框丢失

    原文URL:http://blog.csdn.net/kevinhg/article/details/6266170 向原文作者致敬:从下文可以看出作者对于问题的执着性,能够不厌其烦地把所想所做所有细 ...

  8. 设置 核心内存转储后无效_从内存转储的第1部分(共3部分)调查无效的程序异常

    设置 核心内存转储后无效 Datadog automated instrumentation for .NET works by rewriting the IL of interesting met ...

  9. 一步步编写操作系统 45 linux的elf可执行文件中的段和节

    接上文,为了描述清楚文件格式的本质,咱们先从最基本的"段"说起. 程序中最重要的部分就是段(segment)和节(section),它们是真正的程序体,是真真切切的程序资源,所以下 ...

  10. 【python-docx】文本操作(段落、run、标题、首行缩进、段前段后、多倍行距、对齐方式)

    1.概念 块级元素(block-level) 是指作为一个整体的元素,典型的是段落(paragraph). 行内元素(inline) ,你可以把它理解为一部分块级元素,即一个块级元素包含一个或多个行内 ...

最新文章

  1. Codeforces Round #331 (Div. 2) A. Wilbur and Swimming Pool 水题
  2. ubuntu12.04上安装flashcahce
  3. 可视化应用实战案例:绘制交互式+pdf+png等多格式桑基图
  4. Oracle的奇葩设置之非归档模式与RMAN备份
  5. HID报表描述符(目前最全的解析,也是USB最复杂的描述符)
  6. 无锁数据结构三:无锁数据结构的两大问题
  7. Spring MVC X-Frame-Options
  8. debian添加删除用户
  9. 高度平衡二叉树的构建_数据结构与算法系列(十六)平衡二叉树的构建实现过程演示...
  10. Mac JDK 卸载方法
  11. @ConfigurationProperties 在IDEA中出现红色波浪线问题
  12. java中的jackson_Java中的JSON数据绑定框架Jackson使用介绍
  13. oracle清空回收站指定表,清空Oracle 10g回收站中以BIN$开头的表
  14. 好用的局域网文件共享工具
  15. 关于内网使用Nginx正向代理发送极光推送
  16. Vmware中win7联网
  17. Replacing Elements (CodeForces - 1473A)
  18. 集智全球开源 聚合中国力量 Tungsten Fabric中文社区成立大会暨社区第一次全员大会成功举行
  19. 微信企业支付(一)注意
  20. Raptor入门练习

热门文章

  1. [2018.07.10 T1]叠盒子
  2. 小程序学习笔记(8)-导航组件
  3. micropython教程nucleo-f767zi开发板_micropython移植到正点原子F767的問題
  4. android混合编程 pdf,混合编程在A/D转换中的应用.pdf
  5. python好用的模块_Python中好用的模块们
  6. 韩顺平 jdbc 之 mysql,(韩顺平讲解)jdbc学习(四)---java连接mysql
  7. python创建线程_Python 创建线程的方法
  8. 卸载程序_Windows 7 如何卸载或删除应用和程序,我教你
  9. 8代cpu能装linux 系统吗,Intel支持八九代酷睿的B365芯片组将登场亮相
  10. centos安装cmake