大城小魔

天下难事,必作于易;天下大事,必作于细

  C++博客 ::  :: 联系 :: 聚合  :: 管理

公告


最新评论

C/C++ 内存管理算法与实现--第一章:地址线和总线 (翻译连载)

第四节:Intel奔腾CPU构架   

你已经了解处理器如何从内存读入和写入数据。然而,大多数的处理器同样支持两种高级内存管理机制:分段和分页。所谓分段是指将计算机的地址空间划分为特定的区域。使用分段技术可以将内存划分为独立的区域,这样应用程序之间彼此独立不会产生冲突。分段提供了内存保护的机能。可以创建不带内存保护的内存段,但是这样做并不会带来什么好处。

分段结构带来的内存保护使得每个应用程序都至少分配到一个内存段。大型的应用程序通常具有好几个内存段。此外操作系统同样具有一系列属于自己的特定内存 段。这些系统的内存段设置了读写的权限明细,以便创建关于谁可以获得读写权限的策略。一般说来,操作系统的代码段以最高权限执行,应用程序装载到较低权限 的内存段中。


图1.5

分页是实现虚拟内存的方法之一。由DRAM提供的物理内存和从硬盘分配用于模拟DRAM的内存一起合并为一个更大的集合内存空间。如果启动了分页机制,处理器的可寻址的最大字节数称之为虚拟内存地址空间。要弄明白这一切的关键是:虚拟内存地址空间中的字节的地址不再跟之前处理器放置在地址总线上的地址一样了。这意味着,必须创建转换数据结构和转换代码,以便将虚拟地址空间里的字节映射到物理内存的一个字节上。(不必关心数据是保存在DRAM还是硬盘上)
当必须的分页构造完毕,虚拟内存空间便划分为了称为页面(pages)的小区域。操作系统会判定物理内存中运行使用机率低的数据,将这些物理内存中的数据 以分页的形式写入到硬盘中。如果分段机制被启用,薄记(bookkeeping)还要执行给定内存页与该内存页所属的分段的关联记录工作。所有的计算 工作都紧密与处理器相关,所以性能损耗跟硬盘的I/O有直接联系,可能会持续甚至1分钟。
图1.6

    注释:当内存页保存在物理内存(例如,DRAM)中时,这些内存页放置在被称为页帧(Page frame)用于记录页面大小的结构中。除了对所有内存页的使用情况进行监控外,大多数操作系统同样也对页帧的使用情况进行监控。通常页帧的数量大大少于内存页的数量,所以操作系统非常看重小心的对这些宝贵的资源进行管理。
    注释:可以使用不用硬盘的分页机制。但是在这种情况下,分页被转变为4KB内存大小的分段。

因为很容易得到Intel Pentium的处理器所以我决定以Pentium处理器来讲解分段和分页机制我 喜欢用MIPS64处理器来阐述理论,但是我买不起SGI的服务器(唉)。廉价是Intel系列产品常胜不衰的主要原因之一。像我这样的在1980年时候 买不起Apple IIe电脑的计算机痴迷者,都转而去寻觅二手的Intel机箱。成千上万的人不得不因为资金的考虑做出这样的选择。所以某种意义上来说,Intel产品广 泛使用跟基层使用者的推动不无关系。

Pentium系列处理器一直以来都是流行处理器

CPU             发布日期          物理地址空间

8086                1978                  1MB
8088                1979                  1MB
80286              1982                  16MB
80386              1985                  4GB
80486              1989                  4GB
Pentium           1993                  4GB
Pentium Pro     1995                  64GB
Pentium II       1997                  64GB
Pentium III      1999                  64GB
Pentium 4        2000                  64GB

    注释:
当 1981年IBM PC诞生的时候,搭载了一颗主频为4.77MHz的8088CPU。毫无疑问,大型机上开发人员们欣喜若狂。因为PC给了他们一个属于自己的施展空间了。 在那个时候,标准的哑终端除了向大型机来回传输缓冲区里的数据什么也干不了。不仅如此,工程师也无法对他们的代码的运行时间和运行方式有丝毫的控制能力。 只能痛苦的等待。Tom Petty说得没错,偶尔用PIZZA贿赂下系统管理员,可以让程序运行得快一些,但是这种奉承很快让人感觉疲惫。有了IBM PC以后工程师终于用于了属于自己的机器,拥有一切权利,不再需要任何等待。

题外话
    我认识一个CDC的工程师,也正是因为PC带给程序员的诸多好处,他在1982年将FORTRAN '77移植到PC。他的头走到他身边问道:“你为什么想在小三轮车一样的机器上运行代码,而不是功能强大的大型机上”,他回答:“因为它是我的自己的这段话或许概括了个人电脑(PC)大获成功的原因所在。

为了留住老客户,Intel为此跨域了重重困难使他们32位处理器能够向后兼容16位的处理器构架。Intel成功的做到了这一点,我能够在我的电脑上
使用启动盘启动DOS 6.22系统,并且运行大多数老的DOS应用程序(包括Doom和Duke Nukem)。
Pentium处理器是一种
运行在几种不同的工作模式下实现后兼容需求的产品。各个运行模式指定各自不同的处理器如何解释运行机器指令如何访问内存的方式。Pentium具有四种运行模式。
  • Real mode           实模式
  • Protected mode      保护模式
  • System management mode(SMM) 系统管理模式
  • Virtual 8086 mode           虚拟8086模式


系统管理模式和虚拟8086模式都是特定目的运行模式,只在特定的环境下使用。我的焦点将主要集中在两个运行模式上:实模式和保护模式。此外,我会对它们如何支持分段和分页机制的部分进行深入。

具备不同的运行模式的特性的这种技术并不仅仅限于 Intel平台。例如,MIPS64处理器同样可以工作在四种运行模式下。
  • Kernel mode        内核模式
  • User mode           用户模式
  • Debug mode        调试模式
  • Supervisor mode 管理员模式

实模式

第一台IBM PC完全运行在实模式下。而且所有的32位Intel计算机同样在启动的时候运行于实模式下。这是实现向后兼容的必须要具备的最基本的特性。
运行在实模式下的操作系统都非常小(小于128KB)。因为它们都依靠BIOS提供的硬件接口。使得它们可以轻易的适应1.44MB的软盘。病毒保护的修复盘依据这个事实,系统修复盘也是同样道理。我也买过可运行在启动盘中那种分区软件。

在实模式中,我们在图1.2中所见到过的通用寄存器被截取为16位的寄存器,错误标志寄存器和指令指针寄存器也被截取为16位。实模式寄存器结构如图1.7所示。



图1.7

正 如你看到的,寄存器名字前面的'E'前缀被拿掉了。此外,每一个16位的通用寄存器,AX,CX,DX,和EX,可以作为两个8位寄存器来使用。例 如,AX寄存器可以可做是由AH和AL寄存组合而成的。AH寄存器是AX寄存器的高字节部分,AL寄存器是AX的低字节部分。

    注释:
在图1.2中的内存和模式寄存器在实模式中还是可见的。32位CPU在实模式中依然是32位的,但是它们对于实模式来说没有任何意义和用处。除非你切换到保护模式当中。


实模式中计算机可寻址1M的DRAM。这暗示实模式中只使用了20条地址线。对于运行在实模式中的处理器来说,内存中字节的地址由段地址加上一个偏移量地 址组成。其结果总是一个20位地址值(记住这个事实:这点非常重要)这就打消了是否真的使用20条地址线的疑问。由段地址和偏移地址的和组成的地址值,便 符合了处理器的地址线上的值。现在你可以得到了为什么叫它为“实模式”的更好解释。实模式中字节的地址直接映射到物理内存中一个“真实”的字节。

在Intel汇编语言中,地址由一个"段地址:偏移地址(segment:offset)" 的值对来表示。例如,如果一个字节位于段地址为0x8200,偏移地址为0x0100,该字节的地址值就表示为:

0x8200:0x0100

有时候,由于某些原因(一会给出解释),也可以写为:

0x8200[0]:0x100


实模式中内存地址解析过程如图1.8:

图1.8

段地址表示一个特定的内存段,并且总是保存在一个16位的段寄存器中。特别的,段地址指基地址,内存段的最低地址。各个段寄存器都各自具有特定用途:

寄存器    作用
CS         当前执行代码的段地址
SS         堆栈段地址
DS         数据段地址
ES          额外段地址(通常作为数据段地址)
FS          额外段地址(通常作为数据段地址)
GS         额外段地址(通常作为数据段地址)

     注释:
实际当中的具有6个寄存器的意思是:在任何时候,只能控制6个寄存一个程序可以获得大于6个以上的寄存器,但是在任何一刻只有6个寄存器可以访问。

偏移地址可以保存在16位的通用寄存器中。提供一个16位的偏移地址,这将每个内存段限制在64KB的大小以内。

    问题:1.如果段地址和偏移地址都存储在16位的寄存器中,为什么两个16位值的和却得到的是20位的值

    答案:原因是段地址的末尾被添加了一个隐含的0,处理器将段地址0x0c00被处理为0x0c000。这表示,在实际书写中,要将这个隐含0放置到方括号中。(例如,0x0c00[0])这就是为什么处理器得到20位的地址值。

    正如你所见,实模式的 段地址/偏移地址 提供了一种简单的分段机制。但是,它没有提供我说提到过的内存段边界保护的机制。糟糕的事实是在实模式中没有提供任何内存保护。
当你的程序运行在实模式中,它拥有了一切,甚至可以破坏一切。

    在实模式中运行应用程序就好象让一群童子军到你家,他们精力充沛,活力十足,随着你手中的糖果蹦上窜下。如果你不小心,他们会把房子毁掉。将一台运行在实模式中的机器崩溃非常容易,而且你没有太多办法防止它发生。(除了不断的备份你的工作)


如果你对上述内容疑惑,我肯定有一些人一定存在同样的疑惑,这里有个C程序代码的例子可以使运行在实模式下的机器崩溃:


/* --crashdos.c-- */


void main()
{
     unsigned char *ptr;
     int i;

     ptr = (unsigned char *)0x0;
     for(i=0;i<1024;i++)
     {
         ptr[i]=0x0;
     }
     return;
}


看是不是不费吹灰之力?这段攻击代码没有任何特别和秘密之处。我只是覆盖了位于内存底端的中断向量表而已。如果你想将这类代码隐藏在一个大的可执行程序中,你或许可以将这个代码简化不到五行的汇编。如果你真的想做坏事,你能让键盘无法响应然后开始格式化硬盘。这个时候能做的就是拔掉电源,不过即使那样,当明白过来发生什么的时候,或许已经太晚了。然而,我想要说明的并不是要告诉你如何去攻击DOS系统。没有人再去使用它,总之,我是证明是模式是一个不安全的运行环境。
更糟的是,实模式不支持分页机制。你只能使用1MB的DRAM内存。在实际情况下呢,竟然还不到1MB,因为BIOS和视频硬件消耗了相当大一部分的内存。还记得比尔盖茨的那番话吗?

注释:没有内存保护机制?没有分页机制?你现在明白第一个版本的PC-DOS系统是怎样少于5,000行汇编代码的了。或许“实”模式的称呼,正是因为它真的很小

Intel处理器如果仅仅依靠这种米老鼠玩具一样的内存管理,将毫无作为。为了力图支持更加健壮的操作系统和更大的内存地址空间,Intel推出了80386CPU,80386具备4GB的物理地址空间并且支持一个全新的运行模式:保护模式。


posted on 2008-12-06 00:07 momor 阅读(1171) 评论(1)  编辑 收藏 引用 所属分类: 翻译

Feedback

# re: C/C++ 内存管理算法与实现--第一章:Intel奔腾CPU构架--实模式 (翻译连载) 2008-12-09 23:43 region
不错,很受益。  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理