3.4.2.4 段描述符

在保护模式下,段寄存器有另一个名字,叫段选择子,因为它保存的信息主要是该段在段表里索引值,用这个索引值可以从段表中“选择”出相应的段描述符。

先看看ds选择子的内容,还是用“sreg”命令:

cs:s=0x000f, dl=0x00000002, dh=0x10c0fa00, valid=1

ds:s=0x0017, dl=0x00003fff, dh=0x10c0f300, valid=3

ss:s=0x0017, dl=0x00003fff, dh=0x10c0f300, valid=1

es:s=0x0017, dl=0x00003fff, dh=0x10c0f300, valid=1

fs:s=0x0017, dl=0x00003fff, dh=0x10c0f300, valid=1

gs:s=0x0017, dl=0x00003fff, dh=0x10c0f300, valid=1

ldtr:s=0x0068, dl=0x52d00068, dh=0x000082fd, valid=1

tr:s=0x0060, dl=0x52e80068, dh=0x00008bfd, valid=1

gdtr:base=0x00005cc8, limit=0x7ff

idtr:base=0x000054c8, limit=0x7ff

可以看到,ds的值是0x0017。段选择子是一个16位寄存器,它各位的含义如下图:

其中RPL是请求特权级,当访问一个段时,处理器要检查RPL和CPL(放在cs的位0和位1中,用来表示当前代码的特权级),即使程序有足够的特权级(CPL)来访问一个段,但如果RPL(如放在ds中,表示请求数据段)的特权级不足,则仍然不能访问,即如果RPL的数值大于CPL(数值越大,权限越小),则用RPL的值覆盖CPL的值。而段选择子中的TI是表指示标记,如果TI=0,则表示段描述符(段的详细信息)在GDT(全局描述符表)中,即去GDT中去查;而TI=1,则去LDT(局部描述符表)中去查。

看看上面的ds,0x0017=0000000000010111(二进制),所以RPL=11,可见是在最低的特权级(因为在应用程序中执行),TI=1,表示查找LDT表,索引值为10(二进制)= 2(十进制),表示找LDT表中的第3个段描述符(从0开始编号)。

LDT和GDT的结构一样,每项占8个字节。所以第3项“0x00003fff 0x10c0f300”就是搜寻好久的ds的段描述符了。用“sreg”输出中ds所在行的dl和dh值可以验证找到的描述符是否正确。

接下来看看段描述符里面放置的是什么内容:

可以看到,段描述符是一个64位二进制的数,存放了段基址和段限长等重要的数据。其中位P(Present)是段是否存在的标记;位S用来表示是系统段描述符(S=0)还是代码或数据段描述符(S=1);四位TYPE用来表示段的类型,如数据段、代码段、可读、可写等;DPL是段的权限,和CPL、RPL对应使用;位G是粒度,G=0表示段限长以位为单位,G=1表示段限长以4KB为单位;其他内容就不详细解释了。

3.4.2.4段基址和线性地址

费了很大的劲,实际上我们需要的只有段基址一项数据,即段描述符“0x00003fff 0x10c0f300”中加粗部分组合成的“0x10000000”。这就是ds段在线性地址空间中的起始地址(ds段的段基址)。用同样的方法也可以算算其它段的基址,都是这个数。

段基址+段内偏移,就是线性地址了。所以ds:0x3004的线性地址就是:

0x10000000 + 0x3004 = 0x10003004

用“calc ds:0x3004”命令可以验证这个结果。

3.4.2.5 页表

从线性地址计算物理地址,需要查找页表。线性地址变成物理地址的过程如下:

首先需要算出线性地址中的页目录号、页表号和页内偏移,它们分别对应了32位线性地址的10位+10位+12位,所以0x10003004的页目录号是64,页号3,页内偏移是4。

IA-32下,页目录表的位置由CR3寄存器指引。“creg”命令可以看到:

CR0=0x8000001b: PG cd nw ac wp ne ET TS em MP PE

CR2=page fault laddr=0x10002f68

CR3=0x00000000

PCD=page-level cache disable=0

PWT=page-level writes transparent=0

CR4=0x00000000: osxmmexcpt osfxsr pce pge mce pae pse de tsd pvi vme

说明页目录表的基址为0。看看其内容,“xp /68w 0”:

0x00000000 : 0x00001027 0x00002007 0x00003007 0x00004027

0x00000010 : 0x00000000 0x00024764 0x00000000 0x00000000

0x00000020 : 0x00000000 0x00000000 0x00000000 0x00000000

0x00000030 : 0x00000000 0x00000000 0x00000000 0x00000000

0x00000040 : 0x00ffe027 0x00000000 0x00000000 0x00000000

0x00000050 : 0x00000000 0x00000000 0x00000000 0x00000000

0x00000060 : 0x00000000 0x00000000 0x00000000 0x00000000

0x00000070 : 0x00000000 0x00000000 0x00000000 0x00000000

0x00000080 : 0x00ff3027 0x00000000 0x00000000 0x00000000

0x00000090 : 0x00000000 0x00000000 0x00000000 0x00000000

0x000000a0 : 0x00000000 0x00000000 0x00000000 0x00000000

0x000000b0 : 0x00000000 0x00000000 0x00000000 0x00ffb027

0x000000c0 : 0x00ff6027 0x00000000 0x00000000 0x00000000

0x000000d0 : 0x00000000 0x00000000 0x00000000 0x00000000

0x000000e0 : 0x00000000 0x00000000 0x00000000 0x00000000

0x000000f0 : 0x00000000 0x00000000 0x00000000 0x00ffa027

0x00000100 : 0x00faa027 0x00000000 0x00000000 0x00000000

页目录表和页表中的内容很简单,是1024个32位(正好是4K)数。这32位中前20位是物理页框号,后面是一些属性信息(其中最重要的是最后一位P)。其中第65个页目录项就是我们要找的内容,用“xp /w 0+64*4”查看:

0x00000100 : 0x00faa027

其中的027是属性,显然P=1,其他属性实验者自己分析吧。页表所在物理页框号为0x00faa,即页表在物理内存的0x00faa000位置。从该位置开始查找3号页表项,得到(xp /w 0x00faa000+3*4):

0x00faa00c : 0x00fa7067

其中067是属性,显然P=1,应该是这样。

3.4.2.6 物理地址

最终结果马上就要出现了!

线性地址0x10003004对应的物理页框号为0x00fa7,和页内偏移0x004接到一起,得到0x00fa7004,这就是变量i的物理地址。可以通过两种方法验证。

第一种方法是用命令“page 0x10003004”,可以得到信息:“linear page 0x10003000 maps to physical page 0x00fa7000”。

第二种方法是用命令“xp /w 0x00fa7004”,可以看到:

0x00fa7004 : 0x12345678

这个数值确实是test.c中i的初值。

现在,通过直接修改内存来改变i的值为0,命令是: setpmem 0x00fa7004 4 0,表示从0x00fa7004地址开始的4个字节都设为0。然后再用“c”命令继续Bochs的运行,可以看到test退出了,说明i的修改成功了,此项实验结束。

附录:

调试汇编代码

用Bochs在汇编级调试操作系统很简单,只需要运行“dbg-asm”,然后就得到了如下图所示的调试界面。

图1 Bochs调试操作系统的界面

此时是暂停在BIOS中。而我们的代码是从0x7C00位置开始的,所以先要在那里设一个断点,然后继续运行到断点:

break 0x7c00

continue

(0) Breakpoint 1, 0x00007c00 in ?? ()

Next at t=4967728

(0) [0x00007c00] 0000:7c00 (unk. ctxt): mov ax, 0x07c0       ; b8c007

接下来可以用命令help来查看调试系统的各种基本命令,这里给出了一些常用的命令

1 执行控制指令

c/cont/continue 连续执行

s/step/stepi [count] 执行count条指令,默认为1条,会跟进到函数和中断调用的内部

p/n/next [count] 执行count条指令,默认为1条,但跳过函数和中断调用

Ctrl+C 停止执行,并回到命令行提示符下

q/quit/exit 退出调试和执行

2 断点设置命令

vb/vbreak seg:offset 在虚拟地址上设置指令断点,其中seg和offset可以是以0x开始的十六进制数,或十进制,或者是以0开头的八进制数

lb/lbreak addr 在线性地址上设置断点,addr同上面的seg和offset

b/break/pb/pbreak addr 在物理地址上设置断点

info break 显示当前所有断点的信息

d/del/delete n 删除一个断点

3 内存操作指令

x /nuf addr 检查位于线性地址addr处的内存内容

xp /nuf addr 检查位于物理地址addr处的内存内容

其中参数n、u、f分别表示:

n为要显示内存单元的计数值,默认为1

u表示单元大小,默认值为w

b(bytes) 1字节

h(halfwords) 2字节

w(words) 4字节

g(giantwords) 8字节

f为显示格式,默认为x

x(hex) 显示为十六进制数

d(decimal) 显示为十进制数

u(unsigned) 显示为无符号十进制数

o(octal) 显示为八进制数

t(binary) 显示为二进制数

c(char)   显示为对应的字符

4 信息显示和CPU寄存器操作命令

r/reg/regs/registers 列表显示CPU寄存器及其内容

set $reg=val 修改某寄存器的内容。除段寄存器和标志寄存器以外的寄存器都可以

修改,如set $eax=0x01234567

creg 列出所有的CR0-CR4寄存器

sreg 列出CPU全部状态信息,包括各个段选择子(cs,ds等)以及ldtr

和gdtr等。

print-stack        打印堆栈情况。

info tab 显示页表

地址映射与共享———2相关推荐

  1. 操作系统实验七 地址映射与共享(哈工大李治军)

    实验七 地址映射与共享 实验目的 深入理解操作系统的段.页式内存管理,深入理解段表.页表.逻辑地址.线性地址.物理地址等概念: 实践段.页式内存管理的地址映射过程: 编程实现段.页式内存管理上的内存共 ...

  2. 操作系统实验一到实验九合集(哈工大李治军)

    操作系统实验 作者寄语 操作系统实验的学习是一个循序渐进的过程,初次看linux-0.11中的代码,看着满屏的汇编语言,确实头疼.但通过学习赵炯博士的Linux内核0.11完全注释,结合着王爽老师的汇 ...

  3. C | 进程间通信的方式

    C | 进程间通信的方式 1.无名管道 无名管道是实现亲缘间进程通信的一种方式,属于半双工通信. 无名管道的实现是队列,不能使用lseek对读写指针偏移. 无名管道有两个端:数据流入端和数据流出端,也 ...

  4. 哈工大操作系统实验总结

    实验地址, https://www.lanqiao.cn/courses/115/learning/?id=374, 在现做实验, 好处是环境提前都配好了, 不足之处是敲代码有网络延迟, 环境无法保存 ...

  5. RocketMQ源码级别面试题板块

    目录 事务消息篇 消费者端 Broker端 面试题版块 Kafka版块 Kafka生产消息为什么快之PageCache kafka的生产者和消费者如何借助Pagecache实现快速读和快速写 Kafk ...

  6. 1. 定义、功能和目标

    1. 计算机系统 计算机系统的层次结构: 硬件:处理器.寄存器.内存储器(内存).外存储器(外存)及各种I/O设备 操作系统: 负责协调硬件.软件等计算机资源工作 为上层提供接口和服务 封装硬件的复杂 ...

  7. 最快69秒逆向DRAM地址映射,百度设计的这款逆向工具如何做到快速可靠?

    来源 | 百度安全实验室 出品 | AI科技大本营(ID:rgznai100) 导读:近日,国际顶级设计自动化大会DAC大会公布DAC 2020会议议程和论文名单,由百度安全发表的<DRAMDi ...

  8. linux进程间通讯-共享内存

    文章目录 共享内存概述 共享内存的特点 共享内存操作 在ubuntu 12.04中共享内存限制值如下 获得一个共享存储标识符 创建共享内存 共享内存映射(attach) 解除共享内存映射(detach ...

  9. cuda合并访问的要求_在 CUDA C / C ++ 中使用共享内存

    在 上一篇文章 中,我研究了如何将一组线程访问的全局内存合并到一个事务中,以及对齐和跨步如何影响 CUDA 各代硬件的合并.对于最新版本的 CUDA 硬件,未对齐的数据访问不是一个大问题.然而,不管 ...

最新文章

  1. 网络营销外包专员浅析尽管快照不见了网络营销外包仍在继续
  2. 学好python工资一般多少钱-Python工资一般是多少 看完吓你一跳
  3. 反射的基本知识(详解)
  4. 使用PowerShell和Windows任务计划程序备份Linux SQL Server数据库
  5. gitlab 项目分支管理的一种策略
  6. 编程练习赛11B 物品价值(装压dp)
  7. ZOJ ACM 1314(JAVA)
  8. 理想的低通滤波器、巴特沃斯滤波器、高斯滤波器
  9. python笔记26-命令行传参sys.argv实际运用
  10. 一位全减器逻辑电路图_全减器(全减器逻辑电路图)
  11. 云计算如何从计算机发展而来,云计算是由什么发展而成的产物?
  12. python 循环高级用法 [expression for x in X [if condition] for y in Y [if condition] ... for n in N [if con
  13. 微店关键词取商品列表API接口(item_search-根据关键词取商品列表API接口),微店API接口
  14. Android大话设计模式 第二章----单一职责原则 乔峰VS慕容复
  15. ubuntu16.0.4bug无法解析域名
  16. Android OTA升级后更新APN参数的实现
  17. SE、ECA、CA、SA、CBAM、ShuffleAttention、SimAM、CrissCrossAttention、SK、NAM、GAM、SOCA注意力模块、程序
  18. IPv6下DHCPv6协议(RFC3315)详细介绍
  19. ENVI5.3 安装教程,新手入门(超详细)附安装包和常见问题
  20. html页面滚动条设置

热门文章

  1. BZOJ 3620 似乎在梦中见过的样子 KMP+暴力
  2. php框架大批量 数据,codeigniter框架批量插入数据
  3. 桃花庵歌——风流才子不“风流”
  4. The smallest free number
  5. python输出星号等腰三角形_python打印直角三角形与等腰三角形实例代码
  6. Glibc编译过程总结
  7. linux 查看glibc,Linux平台查看glibc版本
  8. IOS常用的系统文件目录介绍
  9. Unity3D射击游戏《全民飞机大战》截图
  10. 嘀嗒出行能识别手机卡吗_面具竟然能替代人脸解锁手机!人脸识别还安全吗?|人脸识别|手机|面具|人脸识别系统...