Segmentation(段),一个源于让程序运行在不同模式(80286: real mode and protected mode)和处理逻辑地址的概念。正如前面所提到的,一个逻辑地址由一个段ID和一个偏移量组成,段ID是一个16位的段选择器,而偏移量则是一个32位的数据。在x86体系里,分别由不同的寄存器表示代码段(cs),堆栈段(ss),数据段(ds),以加速处理器对这些段的读取。除此之外,还有别外一些通用的段寄存器,比如es,fs,gs等。其中cs有两位是用来表示CPU当前所处的特权等级的,0表示最高级,3表示最低级。Linux只使用的0和3两个等级,即内核模式和用户模式。
每个段都由一个8字节的段描述符表示,所有的段描述符都存储于全局描述符表(GDT)或局部描述符表(LDT)中。通常情况下,只有一个GDT,但每个处理器可以有属于自己的LDT。GDT和LDT在内存的地址和大小分别存放在寄存器gdtr和ldtr中。在Linux里,常用的段描述符有代码段描述符,数据段描述符,任务状态段描述符和局部段描述符。至于描述符的结构,还是来张图吧,这样比写上一千字也要清淅得多。里面每一项的意思就不细说的。
为了加快把逻辑地址转成线性地址,x86提供了一些非可编程的寄存器来存放段描述符。一旦一个段描述符从内存中读进来,就会被复制到相应的寄存器中,从这时起,CPU要访问这些段就不需要再去内存读段描述符,而是直接从这些寄存器中读出来就可以了。
在看逻辑地址是怎样转换成线性地址之前,先看看段选择器(segment selector)。图片真是好,简单明了。
由于每个段描述符都是8个字节,要取得它的地址也就很简单了。只要把段选择器的索引乘以8再加上段描述符的基地址就可以了。有了段描述符就可以根据逻辑地址与线性地址的关系求得线性地址了。
另外再提一下段错误是怎么产生的。因为段描述术的第一个描述符是0,所以如果段选择器里的index是0,乘以8后也会落入第一个段描述符,而这是一个非法的段描述符,于是内核就会报告一个段错误。
阅读(797) | 评论(0) | 转发(0) |