linux的内存寻址(段)

  前一段时间看linux的起始代码时,对linux的内存寻址总是似懂非懂。最近认真看了下《深入理解linux内核》,觉得里面对内存寻址讲述的比较清晰,稍微总结一下。

   在linux系统中,应用程序使用的是逻辑地址,逻辑地址到物理地址的转换如下:

逻辑地址-----|分段单元|--->线性地址----|分页单元|--->物理地址

   即我们应用程序的地址需要经过分段和分页两个转换才能得到实际的物理地址。

分段和分页有什么作用呢,最重要的一个功能是实现保护。因为我们可以人为的给某个段规定一个权限值,只有特定权限的进程才能访问该段。这样,我们可以将存储系统代码和数据的段规定为特权级0,只有操作系统的代码(0特权级)才有权限对它进行修改,防止用户程序对系统造成破坏。还有另外一个作用是便于内存管理和申请,具体就不详细展开了。

   假设我们现在的系统对内存是分段管理的,那么我们需要知道什么才能知道这个地址段是干什么的,并且找到对应的物理地址呢?显然,我们需要一个段描述符知道这个段的一些信息,段选择符知道这个段的位置。

每一个段由一个8字节的描述符来表示,描述符放在全局描述符表(GDT)或局部描述符表(LDT)

描述符的格式如下:


    描述符规定了特定段的特性,如特权级,段限长,基地址等。可以看出段描述符内容比较多,而且系统可能有比较多的段,因此GDT或LDT的数据是比较大的。显然这些数据不可能直接存储在寄存器上,那么cpu是如何得知这些设定的呢?答案是通过GDT和LDT的地址。GDT和LDT的地址分别存在gdtr和ldtr。除了GDT的线性地址以外,gdtr寄存器还存储了16位的表长度。

    段选择符:由cs,ss,ds等寄存器指定。注意,在没开启保护模式之前段寄存器只是存着段的基地址,打开保护模式后段寄存器不仅保存有基地址,还有一些段信息,以cs为例

   15~3位为index(索引),起着在GDT或LDT查找相应段描述符的作用,找到相应的段描述符也就知道了该段的属性和起始地址了。2位为TI位,决定是查找GDT还是LDT,1~0位为权限位,00为系统权限,11为用户权限。

直接举个例子:

   比如此时我们的段选择符CS=8=0b0000 1000,cpu首先检查到TI=0,于是使用gdtr寄存器找到GDT的基地址(TI=1则使用ldtr找到LDT地址),然后利用CS中Index=1,求得对应的段描述符的地址=GDT基地址+8*1。

   为什么要乘以8呢?因为一个段的段描述符需要64位,即8字节,如前面figure2-3所示。同时因为CS的RPL权限位为00,即为系统权限,普通用户的进程(3权限)是无法访问该段的,起到了保护作用。

   通过以上的操作,我们通过CS顺利找到了段描述符,得到了段的基地址。只需再加上一个offset偏移值就能找到对应的线性地址了(如果没有分页,该地址也是物理地址),而这个偏移值offset就是我们在程序中经常使用的地址。如

...一些代码...

proc:

....一些代码...

proc标号指代的不是一个绝对地址,而是这个地址相对于程序所在源文件起始地址的偏移值。比如说这个偏移值为10,而这个源文件的代码在内存0x1000 0000处,则proc对应的绝对地址为0x1000 0000+10,偏移地址仍然为10。所以在处理地址时要十分小心CS,DS等段选择符是不是指向了正确的地方。

  在cpu中有专门的指令lgdt lldt处理加载gdtr和ldtr的操作。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值