Linux 存储管理3——地址映射全过程

假定一条程序已经运行,整个映射机制都已建立好,并且cpu正在执行main()中的:call 08048368 这条指令,要转移到虚拟地址0x08048368去。接下来我们分析整个地址映射的过程:

首先是段式映射阶段。由于地址0x08048368是一个程序的入口,更重要的是在执行的过程中是由cpu中的“指令指针寄存器(用于存储下次将要执行的指令在代码段中的偏移量)”EIP所指向的代码段中。因此i386 CPU使用代码段寄存器CS的当前值来作为段式映射的“选择码”,也就是用它作为在段描述表中的下标。

什么是段描述表呢?什么是全局段描述表GDT?什么是局部段描述表LDT?

我们先回顾一下保护模式下段寄存器的格式:


也就是说,bit2(TI=Table Indicator:指示器)为0时表示用GDT,为1时表示用LDT。intel的设计意图是内核用GDT而各个进程都用其自己的LDT,最后两位RPL为所要求的特权级别,分为4个级别,0为最高级。(一般内核为0级,用户未3级)

现在可以来看看CS的内容了,内核在建立一个进程时都要将其段寄存器设置好,有关代码如下:


这里reg->xds 是段寄存器DS的映像,一次类推,这里可以看到一个有趣的事,就是除了CS被置成USER_CS之外,其他所有的段寄存器都设置成USER_DS,你看,比如堆栈寄存器SS,也被设置成了USER_DS,这说明了什么呢?这说明:虽然Intel的意图是将一个进程映像分成代码段、数据段、和堆栈段,但是,linux内核却并不买这个帐,在linux中堆栈段和数据段式不分的。

上面说寄存器的映像,被设置成了USER_CS和USER_DS到底是什么:


也就是说,Linux内核中只使用四种不同的段寄存器数值,两种用于内核本身,两种用于所有的进程。现在我们讲这四种数值用二进制展开并与段寄存器的格式相对照:


首先TI都是0,也就是说全部使用GDT。这就与Intel的设计意图不一致了。实际上,在Linux内核中基本上不使用局部段描述表LDT。LDT只是在VM86模式中运行wine以及其它在Linux上模拟Windows软件或DOS软件的程序中才使用。

再看RPL,只用了0和3两级,内核为0级而用户(进程)为3级。

回到我们的程序中。我们的程序显然不是内核程序,所以在进程的用户空间运行,内核在调度该进程进入运行时,把CS设置成_USER_CS即0x23。所以,CPU以4为下标,从全局扫描表GDT中找对应的段描述项








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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值