保护模式下的段寄存器值转化为线性地址过程
2013-07-23 14:55
375 查看
关键字:
段寄存器、段选择子、全局描述符表、局部描述符表、段描述符、线性地址;
保护模式下使用段机制的CS,SS,DS,ESt,FS,GS保存的并不是实模式下的段地址,而是一个包含了段选择子和偏移地址的组合值。CPU在读取内存的时候,需要将段寄存器的值解析成为段地址,才能定位找到相应的段。下面我们一步一步解析这个过程。
知识点:
段寄存器值=段选择子,简单来说,段选择子就是用来指定段描述符的位置的一个值。
段选择子格式:
低0-1位表示特权级,为减少复杂度,目前不关注。低第2位表示指定的是描述符表是GDT(0)还是LDT(1),第3-15位指示段描述符在段描述表中的序号,很关键。
全局描述符表,一个系统只有一个全局描述符表,用来存放一些全局的段描述符(下面有讲述这个术语)。全局描述符表第一个项值规定是空值。全局描述符表的首地址由GDTR寄存器给出,这个值是线性地址,不需要解析。
GDTR的是一个48位的值,16-47位范围共32位(Base Address)的GDT基地址,0-15位范围共16位(Limit)表示GDT表的大小(以字节计算)。
在windbg内核模式,可以用r gdtr命令列出32位的基地址,用rgdtl列出16位的GDT大小值。
r gdtr列出base address 指出段描述符表的基地址,是以平坦线性模式的地址显示,这个是其他段地址使用段选择子的基础。
r gdtl列出limit以字节为单位,如果limit是1023,则包含1024个字节,GDT包含共有1024/8=128项段描述符。
段描述符:共64位值,下图中的下部分是低32位,上部分是高32位。此段描述符中指出的段地址为:(32:24)(23:16)(15:00)这个值(共32位),就是我们所求的线性段地址了。
局部描述符表寄存器LDTR表示当前任务的LDT表在GDTR中的索引,其格式是典型的段选择子。(结合全局描述符表理解)
段机制和页机制一起工作原理示意图,页基制需要另一篇文章详细介绍。
使用windbg来做上述过程的实验:
1. 使用r命令列出寄存器值
kd> r
eax=00000001 ebx=00000000 ecx=8080a188 edx=8292eadc esi=8080a188 edi=00000029
eip=82868bc0 esp=8292eaf8 ebp=8292eca4 iopl=0 nv up ei pl nz na po nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00200202
2. 以cs为例,因为其值0008是段寄存器值=段选择子,我们使用.formats命令显示二进制数
kd> .formats 0008
Evaluate expression:
Hex: 00000008
Decimal: 8
Octal: 00000000010
Binary: 00000000 00000000 00000000 00001000
Chars: ....
Time: Thu Jan 01 08:00:08 1970
Float: low 1.12104e-044 high 0
Double: 3.95253e-323
第2位为0,表示使用的是全局描述符表,我们使用r gdtr命令查看全局描述符表的首地址。
kd> r gdtr
gdtr=80b95000
第3-15位值为1,表示使用的是全局描述符表的第1个项(从0开始,第0项一定为0);我们查看全局描述符表的内容:
kd> dd 80b95000
80b95000 00000000 00000000 0000ffff 00cf9b00
80b95010 0000ffff 00cf9300 0000ffff 00cffa00
80b95020 0000ffff 00cff300 600020ab 80008b1c
80b95030 1c003748 82409393 00000fff 0040f200
80b95040 0400ffff 0000f200 00000000 00000000
80b95050 f0000068 82008992 f0680068 82008992
80b95060 00000000 00000000 00000000 00000000
80b95070 500003ff 800092b9 00000000 00000000
可见第0项的确为0,第一项内容为0000ffff 00cf9b00。根据段描述符的格式,段描述符中指出的段地址为:(32:24)(23:16)(15:00)这个值(共32位)为线性地址。
kd> .formats 0000ffff
Evaluate expression:
Hex: 0000ffff
Decimal: 65535
Octal: 00000177777
Binary: 00000000 00000000 11111111 11111111
Chars: ....
Time: Fri Jan 02 02:12:15 1970
Float: low 9.18341e-041 high 0
Double: 3.23786e-319
kd> .formats 00cf9b00
Evaluate expression:
Hex: 00cf9b00
Decimal: 13605632
Octal: 00063715400
Binary: 00000000 11001111 10011011 00000000
Chars: ....
Time: Sun Jun 07 19:20:32 1970
Float: low 1.90656e-038 high 0
Double: 6.72208e-317
得出(32:24)(23:16)(15:00)这三个地方的值都为0,所以找到的线性段地址为0。也就是cs=0008指定的线性段地址为0.
我们为验证结果,使用dg命令查看段选择子所指定的段描述符的内容
kd> dg 0008
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0008 00000000 ffffffff Code RE Ac 0 Bg Pg P Nl 00000c9b
结果正确。
3. 再以fs=0030为例验证。
kd> .formats 0030
Evaluate expression:
Hex: 00000030
Decimal: 48
Octal: 00000000060
Binary: 00000000 00000000 00000000 00110000
Chars: ...0
Time: Thu Jan 01 08:00:48 1970
Float: low 6.72623e-044 high 0
Double: 2.37152e-322
可见低第2位为0,指定的是全局描述符表。同样使用r gdtr找全局描述符基地址,然后定位第110b的段描述符:
kd> r gdtr
gdtr=80b95000
kd> dd 80b95000+6*8 l2
80b95030 1c003748 82409393
kd> .formats 1c003748
Evaluate expression:
Hex: 1c003748
Decimal: 469776200
Octal: 03400033510
Binary: 00011100 00000000 00110111 01001000
Chars: ..7H
Time: Tue Nov 20 13:23:20 1984
Float: low 4.24231e-022 high 0
Double: 2.321e-315
kd> .formats 82409393
Evaluate expression:
Hex: 82409393
Decimal: -2109697133
Octal: 20220111623
Binary: 10000010 01000000 10010011 10010011
Chars: .@..
Time: ***** Invalid
Float: low -1.41483e-037 high -1.#QNAN
Double: -1.#QNAN
得出的线性段地址二进制值为: 10000010 10010011 00011100
00000000 B
转变为16进制为:82931c00;
使用dg来验证线性段地址:
kd> dg 30
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0030 82931c00 00003748 Data RW Ac 0 Bg By P Nl 00000493
结果正确。
参考资料:
Intel64 and IA-32 Architectures Software Developer's Manual.pdf
张银奎《软件调试》
段寄存器、段选择子、全局描述符表、局部描述符表、段描述符、线性地址;
保护模式下使用段机制的CS,SS,DS,ESt,FS,GS保存的并不是实模式下的段地址,而是一个包含了段选择子和偏移地址的组合值。CPU在读取内存的时候,需要将段寄存器的值解析成为段地址,才能定位找到相应的段。下面我们一步一步解析这个过程。
知识点:
段寄存器值=段选择子,简单来说,段选择子就是用来指定段描述符的位置的一个值。
段选择子格式:
低0-1位表示特权级,为减少复杂度,目前不关注。低第2位表示指定的是描述符表是GDT(0)还是LDT(1),第3-15位指示段描述符在段描述表中的序号,很关键。
全局描述符表,一个系统只有一个全局描述符表,用来存放一些全局的段描述符(下面有讲述这个术语)。全局描述符表第一个项值规定是空值。全局描述符表的首地址由GDTR寄存器给出,这个值是线性地址,不需要解析。
GDTR的是一个48位的值,16-47位范围共32位(Base Address)的GDT基地址,0-15位范围共16位(Limit)表示GDT表的大小(以字节计算)。
在windbg内核模式,可以用r gdtr命令列出32位的基地址,用rgdtl列出16位的GDT大小值。
r gdtr列出base address 指出段描述符表的基地址,是以平坦线性模式的地址显示,这个是其他段地址使用段选择子的基础。
r gdtl列出limit以字节为单位,如果limit是1023,则包含1024个字节,GDT包含共有1024/8=128项段描述符。
段描述符:共64位值,下图中的下部分是低32位,上部分是高32位。此段描述符中指出的段地址为:(32:24)(23:16)(15:00)这个值(共32位),就是我们所求的线性段地址了。
局部描述符表寄存器LDTR表示当前任务的LDT表在GDTR中的索引,其格式是典型的段选择子。(结合全局描述符表理解)
段机制和页机制一起工作原理示意图,页基制需要另一篇文章详细介绍。
使用windbg来做上述过程的实验:
1. 使用r命令列出寄存器值
kd> r
eax=00000001 ebx=00000000 ecx=8080a188 edx=8292eadc esi=8080a188 edi=00000029
eip=82868bc0 esp=8292eaf8 ebp=8292eca4 iopl=0 nv up ei pl nz na po nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00200202
2. 以cs为例,因为其值0008是段寄存器值=段选择子,我们使用.formats命令显示二进制数
kd> .formats 0008
Evaluate expression:
Hex: 00000008
Decimal: 8
Octal: 00000000010
Binary: 00000000 00000000 00000000 00001000
Chars: ....
Time: Thu Jan 01 08:00:08 1970
Float: low 1.12104e-044 high 0
Double: 3.95253e-323
第2位为0,表示使用的是全局描述符表,我们使用r gdtr命令查看全局描述符表的首地址。
kd> r gdtr
gdtr=80b95000
第3-15位值为1,表示使用的是全局描述符表的第1个项(从0开始,第0项一定为0);我们查看全局描述符表的内容:
kd> dd 80b95000
80b95000 00000000 00000000 0000ffff 00cf9b00
80b95010 0000ffff 00cf9300 0000ffff 00cffa00
80b95020 0000ffff 00cff300 600020ab 80008b1c
80b95030 1c003748 82409393 00000fff 0040f200
80b95040 0400ffff 0000f200 00000000 00000000
80b95050 f0000068 82008992 f0680068 82008992
80b95060 00000000 00000000 00000000 00000000
80b95070 500003ff 800092b9 00000000 00000000
可见第0项的确为0,第一项内容为0000ffff 00cf9b00。根据段描述符的格式,段描述符中指出的段地址为:(32:24)(23:16)(15:00)这个值(共32位)为线性地址。
kd> .formats 0000ffff
Evaluate expression:
Hex: 0000ffff
Decimal: 65535
Octal: 00000177777
Binary: 00000000 00000000 11111111 11111111
Chars: ....
Time: Fri Jan 02 02:12:15 1970
Float: low 9.18341e-041 high 0
Double: 3.23786e-319
kd> .formats 00cf9b00
Evaluate expression:
Hex: 00cf9b00
Decimal: 13605632
Octal: 00063715400
Binary: 00000000 11001111 10011011 00000000
Chars: ....
Time: Sun Jun 07 19:20:32 1970
Float: low 1.90656e-038 high 0
Double: 6.72208e-317
得出(32:24)(23:16)(15:00)这三个地方的值都为0,所以找到的线性段地址为0。也就是cs=0008指定的线性段地址为0.
我们为验证结果,使用dg命令查看段选择子所指定的段描述符的内容
kd> dg 0008
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0008 00000000 ffffffff Code RE Ac 0 Bg Pg P Nl 00000c9b
结果正确。
3. 再以fs=0030为例验证。
kd> .formats 0030
Evaluate expression:
Hex: 00000030
Decimal: 48
Octal: 00000000060
Binary: 00000000 00000000 00000000 00110000
Chars: ...0
Time: Thu Jan 01 08:00:48 1970
Float: low 6.72623e-044 high 0
Double: 2.37152e-322
可见低第2位为0,指定的是全局描述符表。同样使用r gdtr找全局描述符基地址,然后定位第110b的段描述符:
kd> r gdtr
gdtr=80b95000
kd> dd 80b95000+6*8 l2
80b95030 1c003748 82409393
kd> .formats 1c003748
Evaluate expression:
Hex: 1c003748
Decimal: 469776200
Octal: 03400033510
Binary: 00011100 00000000 00110111 01001000
Chars: ..7H
Time: Tue Nov 20 13:23:20 1984
Float: low 4.24231e-022 high 0
Double: 2.321e-315
kd> .formats 82409393
Evaluate expression:
Hex: 82409393
Decimal: -2109697133
Octal: 20220111623
Binary: 10000010 01000000 10010011 10010011
Chars: .@..
Time: ***** Invalid
Float: low -1.41483e-037 high -1.#QNAN
Double: -1.#QNAN
得出的线性段地址二进制值为: 10000010 10010011 00011100
00000000 B
转变为16进制为:82931c00;
使用dg来验证线性段地址:
kd> dg 30
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0030 82931c00 00003748 Data RW Ac 0 Bg By P Nl 00000493
结果正确。
参考资料:
Intel64 and IA-32 Architectures Software Developer's Manual.pdf
张银奎《软件调试》
相关文章推荐
- x86 cpu 32位,保护模式下,EIP寄存器存放的是线性地址还是物理地址
- [Intel汇编-NASM]进入保护模式全过程
- 实模式和保护模式虚拟地址映射
- 实地址模式与保护模式下的中断与异常处理
- 保护模式进阶--读取1MB地址之外的数据
- 80X86的物理地址形成(实模式+保护模式)——段式寻址
- 保护模式之大观--查找物理地址
- 保护模式下Intel 80x86 CPU 硬件中断过程
- 保护模式的 A20地址线问题
- 80x86保护模式系列教程(3)控制寄存器和系统地址寄存器
- (转)保护模式下Intel 80x86 CPU 硬件中断过程
- 读书笔记--第三章--“实模式--保护模式--实模式”转换过程
- (实模式+保护模式)模式切换的过程步骤(代码+文字解析)
- 保护模式下,读写大地址内存 & 从32位保护模式跳回16位实模式
- 实地址模式与保护模式之间的切换
- 实模式和保护模式下的地址计算方式
- (实模式+保护模式)模式切换的过程步骤(代码+文字解析)
- [Intel汇编-NASM]进入保护模式全过程
- 保护模式下,读写大地址内存 & 从32位保护模式跳回16位实模式
- 实模式及保护模式下的地址转换