数据段描述符和代码段描述符(一)——《x86汇编语言:从实模式到保护模式》读书笔记10
一、段描述符的分类
在上一篇博文中已经说过,为了使用段,我们必须要创建段描述符。80X86中有各种各样的段描述符,下图展示了它们的分类。
看了上图,你也许会说:天啊,怎么这么多段描述符啊!我可怎么记住呢? 别担心,我会在以后的博文中,跟随原书的作者,为您逐步介绍。我们的学习是循序渐进的,所以不要求一下子掌握所有东西。我们的原则是:用到什么学什么。我们今天的重点是“存储段描述符”。
二、段描述符的通用格式[1]
段描述符是GDT和LDT中的一个数据结构项,用于向处理器提供有关一个段的位置、大小以及访问控制的状态信息。每个段描述符的长度是8个字节,含有3个主要字段:
- 段基地址
- 段限长
- 段属性
段描述符通常由编译器,链接器,加载器或者操作系统来创建,但绝不是应用程序。
下图给出了所有类型的段描述符的一般形式。
1.段限长字段Limit
用于指定段的长度。处理器会把段描述符中两个段限长字段组合成一个20位的值,并根据颗粒度标志G来指定段限长Limit值的实际含义。
如果G=0,则Limit值的单位是B,也就是说Limit的范围可以是1B到1MB;
如果G=1,则Limit值的单位是4KB,也就是说Limit的范围可以是4KB到4GB。
根据段类型字段TYPE中的段扩展方向标志E,处理器可以以两种不同的方式使用Limit。
E=0:表示向上扩展的段(简称上扩段),逻辑地址中的偏移值范围可以从0到Limit;
E=1:表示向下扩展的段(简称下扩段),逻辑地址中的偏移范围可以从Limit到0xFFFF(当B=0时)或者0xFFFF_FFFF(当B=1时)。关于B位,后面将解释。
2.基地址字段Base
该字段定义在4GB线性地址空间中一个段的字节0所处的位置。也许你觉得这句话不好理解,我们换一种说法:对于一个逻辑地址,如果段内偏移为0,那么这个逻辑地址对应的线性地址就是Base;如果段内偏移为X,那么这个逻辑地址对应的线性地址就是Base+X;
段基地址可以是0~4GB范围内的任意地址(这同实模式不同,实模式下段基地址要求16字节对齐),但是,为了让程序具有最佳性能,还是建议段基地址对齐16字节边界。
3.段类型字段TYPE
该字段用于指定段或者门(Gate)的类型、说明段的访问种类以及段的扩展方向。该字段的解释依赖于描述符类型标志S;TYPE字段的编码对代码段、数据段或者系统描述符都不同。
4.描述符类型标志S
S=0:表示存储段描述符。所谓“存储段”,就是存放可由程序直接进行访问的代码和数据的段。说白了,存储段就是代码段或者数据段。
S=1:表示系统描述符。
5.描述符特权级字段DPL
用于指明描述符的特权级。特权级范围从0(最高)到3(最低)。DPL字段用于控制对段的访问。
6.段存在标志P
用于指出一个段是在内存中(P=1)还是不在内存中(P=0).
7.D/B(默认操作数大小/默认栈指针大小和上界限)
对于代码段,此位称为“D”位;对于栈段,此位称为“B”位。我们在后文会说。
8.颗粒度标志G
该字段用于确定段限长字段Limit值的单位。
如果G=0,则Limit值的单位是B;
如果G=1,则Limit值的单位是4KB;
注意:这个字段不影响段基地址的颗粒度,基地址的颗粒度总是以字节为单位。
9.可用和保留位
L位(就是上图灰色的那个位):是64位代码段标志,保留此位给64位处理器使用。目前,我们将此位置“0”即可。
AVL:是软件可以使用的位,通常由操作系统来用,处理器并不使用它。
三、数据段描述符[1]
当S=1且TYPE字段的最高位(第2个双字的位11)为0时,表明是一个数据段描述符。
下图是数据段描述符的格式。
1.B位(默认栈指针大小和上界限)
对于栈段(由SS寄存器指向的数据段)来说,该位用来指明隐含堆栈操作(如PUSH、POP或CALL)时的栈指针大小。
B=0:使用SP寄存器
B=1:使用ESP寄存器
同时,B的值也决定了栈的上部边界。
B=0:栈段的上部边界(也就是SP寄存器的最大值)为0xFFFF;
B=1:栈段的上部边界(也就是ESP寄存器的最大值)为0xFFFF_FFFF.
2.A位(已访问)
用于表示一个段最近是否被访问过(准确地说是指明从上次操作系统清零该位后一个段是否被访问过)。
当创建描述符的时候,应该把这位清零。之后,每当该段被访问时(准确地说是处理器把这个段的段选择符加载进段寄存器时,也许你不懂这句话,没有关系,现在忽略就可以了。)它就会将该位置“1”;对该位的清零是由操作系统负责的,通过定期监视该位的状态,就可以统计出该段的使用频率。当内存空间紧张时,可以把不经常使用的段退避到硬盘上,从而实现虚拟内存管理。
3.W位(可写)
指示段的读写属性。
W=0:段不允许写入,否则会引发处理器异常中断;
W=1:允许写入。
4.E位(扩展方向)
E=0:表示向上扩展的段(简称上扩段),逻辑地址中的偏移值范围可以从0到Limit;
E=1:表示向下扩展的段(简称下扩段,通常是栈段),逻辑地址中的偏移范围可以从Limit到0xFFFF(当B=0时)或者0xFFFF_FFFF(当B=1时)。
四、代码段描述符[1]
当S=1且TYPE字段的最高位(第2个双字的位11)为1时,表明是一个代码段描述符。
下图是代码段描述符的格式。
1.D位(默认操作数大小)
用于指出该段中的指令引用有效地址和操作数的默认长度。
D=0:默认值是16位的地址和16位或者8位的操作数;
D=1:默认值是32位的地址和32位或者8位的操作数;
说明:指令前缀0x66可以用来选择非默认值的操作数大小,指令前缀0x67可以用来选择非默认值的地址大小。
2.A位(已访问)
与数据段描述符中的A位相同。
3.R位(可读)
R=0:代码段不可读,只能执行。
R=1:代码段可读,可执行。
也许有人会问,当R=0时,既然代码段不可读,那处理器怎么从里面取指令执行呢?事实上,这里的R属性并非针对处理器,而是用来限制程序的行为。当常数或者静态数据被放在了一个ROM中时,就可以使用一个可读可执行的代码段,然后通过使用带CS前缀的指令,就可以读取代码段中的数据。
注意:
- 在保护模式下,代码段是不可写的。
- 堆栈段必须是可读可写的数据段。
4.C位(一致性)
C=0:表示非一致性代码段。这样的代码段可以被同级代码段调用,或者通过门调用;
C=1:表示一致性代码段。可以从低特权级的程序转移到该段执行(但是低特权级的程序仍然保持自身的特权级)。
注意:所有的数据段都是非一致性的,即意味着它们不能被低特权级的程序或过程访问。然而与代码段不同,数据段可以被更高特权级的程序或过程访问,而无需使用特殊的访问门。
有关特权级和特权级检查我们以后再讨论,这里对上面的概念了解即可,不用深究。
最后,补充一张图表,也是引用自赵炯的《Linux内核完全剖析》。
参考资料:
[1]:赵炯,《Linux内核完全剖析》,机械工业出版社. 4.3.4节
数据段描述符和代码段描述符(一)——《x86汇编语言:从实模式到保护模式》读书笔记10的更多相关文章
- 数据段描述符和代码段描述符(二)——《x86汇编语言:从实模式到保护模式》读书笔记11
这篇博文,我们编写一个C语言的小程序,来解析数据段或者代码段描述符的各个字段.这样我们阅读原书的代码就会方便一点,只要运行这个小程序,就可以明白程序中定义的数据段或者代码段的描述符了. 这段代码,我用 ...
- 堆、栈、数据区、bss、代码段
一个程序的运行是需要内存的,那么我们平常写的程序的内存都是怎么分配的呢 (1)首先我们要知道,内存是真实存在的,内存是一个物理器件.它时由操作系统管理的,我们平常只要使用它就行了,为了方便管理.操作系 ...
- Linux从头学08:Linux 是如何保护内核代码的?【从实模式到保护模式】
作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...
- 内存布局:栈,堆,BSS段(静态区),代码段,数据段
简介 我们程序运行的时候都是放在内存里的.根据静态.成员函数.代码段.对象.等等.放在不同的内存分块里.大概分为5块 1 栈 2 堆 3 BSS段-全局区-(静态区) 4 代码段 5 数据段 栈 ...
- OCA读书笔记(10) - 管理UNDO数据
Undo自动管理与手动管理 undo段自动管理SQL> show parameter undo_management 将undo段改为手工管理SQL> alter system set u ...
- 静态库动态库的编译、链接, binutils工具集, 代码段\数据段\bss段解释
#1. 如何使用静态库 制作静态库 (1)gcc *.c -c -I../include得到o文件 (2) ar rcs libMyTest.a *.o 将所有.o文件打包为静态库,r将文件插入静态库 ...
- linux进程的堆栈空间_代码段(指令,只读)、数据段(静态变量,全局变量)、堆栈段(局部变量)、栈【转】
转自:http://blog.csdn.net/gongweijiao/article/details/8207333 原文参见:http://blog.163.com/xychenbaihu@yea ...
- 数据段、代码段、堆栈段、BSS段
在linux中,进程在内存中一般会分为5个段,用来存放从磁盘载入的程序代码,等. 这五个段分别是: BSS段: 通常用来存放程序中未初始化的全局变量的一块内存区域.属于静态内存分配. 问题:全局变量不 ...
- 不同特权级间代码段的跳转{ 门 + 跳转(jmp + call) + 返回(ret) }
[0]写在前面 0.1)我们讲 CPU的保护机制,它是可靠的多任务运行环境所必须的: 0.2) CPU保护机制:分为段级保护 + 页级保护: 0.2.1)段级保护分为:段限长 limit 检查.段类型 ...
随机推荐
- jQuery插件扩展extend的实现原理
相信每位前端的小伙伴对jQuery都不陌生吧,它最大的魅力之一就是有大量的插件,去帮助我们更轻松的实现各种功能. 前几天晚上,闲来无事,就自己动手写了个简单的jQuery插件,功能很简单,只是让选定的 ...
- 使用"*"通配符来选择文件
Include 方法和IncludeDirectory 方法中的搜索模式中指定的虚拟路径可以接受一个"*"通配符字符作为前缀或后缀,以在最后一个路径段.搜索字符串是大小写不敏感的. ...
- C# 中关于汉字与16进制转换的代码
/// <summary> /// 从汉字转换到16进制 /// </summary> /// <param name="s"></par ...
- 三、SpringBoot-application.properties配置文件和application.yml配置文件
其实SpringBoot的配置文件有.properties和.yml两种形式,两种配置文件的效果类似,只不过是格式不同而已,孩儿们可以根据下面这几种张截图,通过对比端口号的配置,以及连接SQLServ ...
- Kotlin if else判断
Kotlin的if相对与java,有着较为灵活的用法. if是用来判断. if在Kotlin里面可以作为表达式来使用. 如果熟悉C java C#等 A>B:A?B这个判断应该是很熟悉,而Kot ...
- CHNetRequest网络请求
Paste JSON as Code • quicktype 软件的使用 iOS开发:官方自带的JSON使用 JSON 数据解析 XML 数据解析 Plist 数据解析 NetRequest 网络数据 ...
- 转载智能家居 作者:热情的沙漠 出处:http://www.cnblogs.com/buptzym/
理工男打造帝都89平智能家庭 毕业后的2016年年初,搬入新家,总算不用在出租屋里鬼混了,于是就想把之前童年的梦想:智能家居+家庭影院好好实现一下~ 相比帝都高昂的房价,这些东东还凑合玩得起,不过 ...
- 自动备份数据库crond
#!/bin/bash # export and backup the abgent_web database.sql mysqldump -uuser -ppassword ltden_db --s ...
- [Swift]八大排序算法(二):快速排序
排序分为内部排序和外部排序. 内部排序:是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列. 外部排序:指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存 ...
- [jvm]垃圾回收与内存分配策略
一.垃圾回收算法 概述 JVM中,当创建的对象不再被使用的时候,此时我们认为他是无用的“垃圾”:在现代主流的商用jvm中,都是通过可达性分析来判断对象是否存活的.这个算法的基本思想是通过一系列“GCR ...