Linux中的分段,GDT,LDT

Linux中的分段:

        微处理器的分段鼓励程序员将程序划分成逻辑上的实体,如子程序或者全局与局部数据区,然而Linux以非常有限的方式分段,实际上,分段和分页在某种程度上有点多余,因为他们可以划分进程的物理地址空间:分段可以给每个进程分配不同的线性地址空间,而分页可以把同一个线性地址空间映射到不同的物理空间。Linux更喜欢使用分页的方式,因为:

        ①当所有进程使用相同的段寄存器值时,内存管理变得更简单,也就是说它们能共享同样的一组线性地址。

        ②Linux设计目标之一是可以把它一直到绝大多数流行的处理器平台上,但是RISC体系结构对分段的支持有限。

        运行在用户态的所有Linux进程都是用一对相同的段来对指令和数据寻址(用户代码段和用户数据段),运行在内核态的Linux进程都使用一对相同的段来对指令和数据寻址,它们分别叫做内核代码段和内核数据段。

四个主要的Linux段的段描述符字段的值:

        相应的段选择符由宏__USER_CS, __USER_DS,__KERNEL_CS,  __KERNEL_DS,为了对内核代码段寻址,内核只需要把__KERNEL_CS宏产生的值装进cs段寄存器。

        与段相关的线性地址从0开始,达到2^31-1寻址限长,用户态或内核态下的所有进程可以使用相同的逻辑地址。所有的段都从0x00开始,得到的结论是,Linux下逻辑地址与线性地址是一致的,即逻辑地址的偏移量字段的值与相应的线性地址的值总是一致的。

CPL

        CPL反应进程是在用户态还是内核态,并存放在cs寄存器中的段选择符的RPL字段指定,当特权级被改变时,一些寄存器必须相应地更新,例如当CPL=3时,ds寄存器必须含有用户数据段的段选择符,当CPL=0时,ds寄存器必须含有内核数据段的段选择符。ss寄存器也是如此,CPL=0,ss必须指向内核数据段中的一个内核栈,CPL=3,必须指向用户数据段的一个用户栈。当从用户态切换到内核态时,要确保ss寄存器里有内核数据。

       对于指向指令(code)或数据结构(data)指针,不需要设置逻辑地址的段选择符,因为cs寄存器包含了,如内核调用一个函数时,他执行一条call汇编语言指令制定了逻辑地址偏移量,你用指定段选择符,因为在内核状态的段只有一种,代码段,由宏__KERNEL_CS定义,同样的也适用于内核数据结构指针及用户数据结构指针。

Linux GDT       

        操作系统的内存关系:

​        

         虚拟内存,这个概念是面向软件程序而言,他们希望程序是连续的地址,一段一段的,注意,在32位系统里,一个program仅有3G,(还有1G OS程序占据)

        因为程序中一般将一个程序所使用的部分分为程序段,数据段,堆段和栈段等,这里面每一个段也就会有相应的Base,执行中也会Offset(即Linear Address),段通过段描述(Segment Descriptor)保存段的信息,每一个 Segment Descriptor 作为一个 entry 保存到 GDT(全局段表)中;

        每个cpu对应一个GDT,所有GDT,它的地址和大小都存放在arch/架构名/kernel/head.S中被定义,(如x86:arch/i386/kernel/head.S,cpu_gdt_table和cpu_gdt_descr)(section?)

        每个GDT包含18个段描述符和14个空的,未使用的项目的是为了使经常一起访问的描述符能处于同一个32字节高速缓存中。

                

 18个段:

        ①用户态和内核态的代码段和数据段共四个

        ②任务状态段(TSS),每个处理器一个,每个TSS的线性地址空间都是内核数据段相应一个线性空间的一个子集,所有的任务状态段都顺序的存放在init_tss数组,第n个cpu的TSS描述符的Base字段指向init_tss数组,G=0,Limit=0xeb(236字节),Type=9或11,(进程能否在CPU下运行),DPL=0,不允许用户态下的进程访问TSS段。

        ③一个包括缺省的局部描述符表的段,这个段通常是被所有进程共享的段

        ④3个局部线程存储(TLS):允许多线程应用程序使用最多3个局部于线程的数据段。系统调用set_thread_area和get_thread_area分别创建和撤销一个TLS段

        ⑤高级电源管理:BIOS代码使用段,当Linux APM驱动程序调用BIOS函数来获取或者设置APM设备的状态,就可以自定义的代码段和数据段

        ⑥支持即插即用功能的BIOS服务程序 :由于BIOS例程使用段,当Linux的PnP设备驱动调用BIOS函数来检测PnP设备使用的资源时,可以使用它自定义代码段和数据段。

        ⑦被内核用来处理“双重错误(处理一个异常时可能引发另一个异常)”异常的特殊TSS段

Linux LDT

        LDT内部存储的是进程相关的段的基址内容,GDT存储的是内核代码的段的基址。

        大多数用户态的Linux程序都不使用局部描述表,所以定义一个缺省的LDT供大多数进程共享,一般放在default_ldt数组中,他有5个项,内核只使用2个,用于iBCS执行文件的调用门和Solaris/x86可执行文件的调用门。

        (调用门是80x86微处理器提供的一种机制,用于在调用预定义函数时改变CPU的特权级)

        在某些情况下,进程需要创建自己的局部描述符表,像Wine那样的程序,它们执行面向段的微软Windows应用程序。modify_ldt系统调用允许进程创建自己的局部描述符表,它需要自己的段,当处理器开始执行自定义局部描述符表的进程时,CPU的GDT副本中的LDT对应的就被修改了。

        用户态下的程序同样也利用modify_ldt来分段,但是内核不会使用这些段,也不用了解相应的段描述符,这些段描述符被包含在进程自定义的局部描述符表中了

*************************

 总结:

        系统会给程序自动分配程序段,代码段等,这些段以及偏移组成了逻辑地址,而逻辑地址通过GDTR/LDTR,找到位于虚拟内存的段基址,最后得到虚拟地址.

***************************************************************************

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值