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

简介: 操作系统实验七 地址映射与共享(哈工大李治军)(二)

跟踪地址翻译过程


1.准备

./dbg-asm
c


在Bochs中编译运行 test.c



只要test.c不变,0x00003004这个值在任何人的机器上都是一样的。即使在同一个机器上多次运行test.c,也是一样的。


test.c是一个死循环,只会不停占用CPU,不会退出。


2.暂停

在命令行窗口按 Ctrl+c,Bochs 会暂停运行,进入调试状态


其中的 000f 如果是 0008,则说明中断在了内核里。那么就要 c,然后再 ctrl+c,直到变为 000f 为止。


如果显示的下一条指令不是 cmp ...(这里指语句以 cmp 开头),就用 n 命令单步运行几步,直到停在 cmp ...。


使用命令 u /8,显示从当前位置开始 8 条指令的反汇编代码,结构如下:



这就是 test.c 中从 while 开始一直到 return 的汇编代码。变量 i 保存在 ds:0x3004 这个地址,并不停地和 0 进行比较,直到它为 0,才会跳出循环。


现在,开始寻找 ds:0x3004 对应的物理地址。


3.段表

ds:0x3004 是虚拟地址,ds 表明这个地址属于 ds 段。首先要找到段表,然后通过 ds 的值在段表中找到 ds 段的具体信息,才能继续进行地址翻译。


每个在 IA-32 上运行的应用程序都有一个段表,叫 LDT,段的信息叫段描述符。


LDT 在哪里呢?ldtr 寄存器是线索的起点,通过它可以在 GDT(全局描述符表)中找到 LDT 的物理地址。


用 sreg 命令(是在调试窗口输入):



可以看到 ldtr 的值是 0x0068=0000000001101000(二进制),表示 LDT 表存放在 GDT 表的 1101(二进制)=13(十进制)号位置(每位数据的意义参考后文叙述的段选择子)。


而 GDT 的位置已经由 gdtr 明确给出,在物理地址的 0x00005cb8。


用 xp /32w 0x00005cb8 查看从该地址开始,32 个字的内容,及 GDT 表的前 16 项,如下:



GDT 表中的每一项占 64 位(8 个字节),所以我们要查找的项的地址是 0x00005cb8+13*8。


输入 xp /2w 0x00005cb8+13*8,得到:



“0x52d00068 0x000082fd” 将其中的加粗数字组合为“0x00faa2d0”,这就是 LDT 表的物理地址(为什么这么组合,参考后文介绍的段描述符)。


xp /8w 0x00fd52d0,得到:



4.段描述符

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


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



可以看到,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 为单位;其他内容就不详细解释了。


5.段基址和线性地址

组合规则见段描述符结构:其实就是将基地址进行组合



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


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

0x10000000 + 0x3004 = 0x10003004

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



6.页表

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



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


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



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



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



这就是我们要找的页目录表


里面的内容是 0x00fa6027


具体分析一下里面的结构



页表所在的物理页框号为0x00fa6,即页表在物理内存为0x00fa6000处,从该位置开始查找3号页表项(每个页表项4个字节),用命令:xp /w 0x00fa6000 + 3*4



7.物理地址

页表里所显示的即线性地址 0x10003004 对应的物理页框号为 0x00fa5,和页内偏移 0x004 连接在一起,得到 0x00fa5004,这就是变量 i 的物理地址。


可以用两种方法验证:


第一种方法是用命令 page 0x10003004



第二种方法是用命令 xp /w 0x00fa5004



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



添加系统调用号


目录 oslab/linux-0.11/include



在 unistd.h 中添加下面代码



然后增加两个系统调用号



添加系统调用的定义


文件位置oslab/linux0.11/include/linux/sys.h



增加函数声明



改写系统调用数


文件位置:oslab/linux0.11/kernel/system_call.s




编写 shm.c


文件位置:oslab/linux0.11/kernel/shm.s


#define __LIBRARY__
#include <unistd.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <errno.h>
static shm_ds shm_list[SHM_SIZE] = {{0, 0, 0}};
int sys_shmget(unsigned int key, size_t size)
{
    int i;
    unsigned long page;
    /* If the size exceeds the size of one page of memory */
    if (size > PAGE_SIZE)
    {
        printk("shmget: size %u cannot be greater than the page size %ud. \n", size, PAGE_SIZE);
        return -ENOMEM;
    }
    if (key == 0)
    {
        printk("shmget: key cannot be 0.\n");
        return -EINVAL;
    }
    for (i = 0; i < SHM_SIZE; i++)
    {
        if (shm_list[i].key == key)
        {
            return i;
        }
    }
    page = get_free_page();
    if (!page)
    {
        return -ENOMEM;
    }
    printk("shmget get memory's address is 0x%08x\n", page);
    for (i = 0; i < SHM_SIZE; i++)
    {
        if (shm_list[i].key == 0)
        {
            shm_list[i].key = key;
            shm_list[i].size = size;
            shm_list[i].page = page;
            return i;
        }
    }
    return -1;
}
void *sys_shmat(int shmid)
{
    unsigned long data_base, brk;
    if (shmid < 0 || SHM_SIZE <= shmid || shm_list[shmid].page == 0 || shm_list[shmid].key <= 0)
    {
        return (void *)-EINVAL;
    }
    data_base = get_base(current->ldt[2]);
    printk("current's data_base = 0x%08x,new page = 0x%08x\n", data_base, shm_list[shmid].page);
    brk = current->brk + data_base;
    current->brk += PAGE_SIZE;
    if (put_page(shm_list[shmid].page, brk) == 0)
    {
        return (void *)-ENOMEM;
    }
    return (void *)(current->brk - PAGE_SIZE);
}


brk指针在哪里?可以参考下图。我们可以发现 brk 指针正好指向堆区顶部,我们可以利用这个指针帮我们定位需要申请的空间首地址。



在进程PCB当中记录了brk指针的 逻辑地址,然后加上进程开始处的虚拟地址就可以得到brk指针的虚拟地址或者叫线性地址(虚拟地址=段基址+逻辑地址)

目录
相关文章
|
5月前
|
弹性计算 运维
阿里云操作系统智能助手OS Copilot实验测评报告
**OS Copilot 产品体验与功能反馈摘要** 运维人员发现OS Copilot易上手,文档清晰,助其高效排查故障(8/10分)。愿意推荐并参与开源开发。亮点在于知识问答,能快速筛选答案。相较于竞品,优点是新手友好、文档清晰,但功能扩展性待增强。期望增加系统错误排查与解决方案,并集成ECS等,以优化系统安装流程。
阿里云操作系统智能助手OS Copilot实验测评报告
|
5月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot实验测评报告
OS Copilot是针对Linux的智能助手,助力学习、运维及编程。用户界面直观,自然语言交互方便新手。官方文档详尽,但初次配置略复杂,适合学生和开发者。在提高代码编写和调试效率、系统学习上得分高,功能亮点包括代码生成、问答和命令执行。用户期待更多操作系统支持、自动错误分析和系统排查功能。
184 3
|
5月前
|
弹性计算 人工智能 运维
阿里云操作系统智能助手OS Copilot实验测评报告
阿里云操作系统智能助手OS Copilot实验测评报告
112 2
|
5月前
|
弹性计算 运维
阿里云操作系统智能助手OS Copilot的实验测评报告
OS Copilot 产品体验摘要 用户角色与场景:一位计算机学生使用辅助学习和解决问题,特别是通过代码解释功能加深理解。 易用性与文档:初者可能会觉得有些细节不明确。 帮助程度:用户给予极高评价,对学习帮助大,评分10分,快速定位和解决代码问题,提升学习效率。 推荐与参与:用户愿意推荐给他人。 功能体验:用户尝试了所有功能,对知识问答、辅助编程和命令执行特别感兴趣,尤其是命令执行帮助大。 对比其他产品:OS Copilot优点是便捷、准确。 期望功能:用户希望增加自动报错分析和系统错误排查。 联动体验:用户期待,以实现更全面的工具集。 总结:整体体验积极,用户看好其潜力,期待改进和未来联动。
|
5月前
|
弹性计算 运维 Python
阿里云操作系统智能助手OS Copilot实验测评报告
**OS Copilot 产品测评摘要** - 学生使用,用于学习和编码,发现上手难度较高,指引文档不清晰,特别是Access ID设置和代码复制流程。 - 功能上,评分9分,辅助编程和知识问答功能显著提升了学习效率,减少了错误。 - 愿意推荐,并有兴趣参与开源开发以提升自我。 - 希望增强错误排查,提供具体错误原因和位置。 - 联动ACK智能助手可增强学习效果。 [链接]: https://developer.aliyun.com/topic/instructions-for-os-copilot
|
5月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot的实验测评报告
阿里云OS Copilot是AI驱动的Linux操作系统助手,助于系统管理和运维。学生反馈它在代码解释和编写上有很大帮助,给予8-9分的评价。功能亮点包括自然语言问答、辅助编程和命令解释,简化操作,提升效率。尽管易用,但需基础Linux知识。用户期待更多功能如系统优化建议和代码优化。与ACK智能助手配合,实现故障排查和运维。适合寻求效率提升的个人和团队。
71 0
|
5月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot实验测评报告
阿里云OS Copilot是面向Linux的智能助手,助运维工程师提升效率。易上手,文档清晰,对新人友好。提供自然语言问答、编程辅助,尤善理解与响应。评分10/10,推荐给同行。目前侧重辅助编程,期望支持更多OS、并发命令执行及错误分析。适合集成于ECS等,打造自动化工作流。期待开源版本与社区合作。
97 0
|
22天前
|
安全 Linux 数据安全/隐私保护
Vanilla OS:下一代安全 Linux 发行版
【10月更文挑战第30天】
42 0
Vanilla OS:下一代安全 Linux 发行版
|
25天前
|
人工智能 安全 Linux
|
2月前
|
Unix 物联网 大数据
操作系统的演化与比较:从Unix到Linux
本文将探讨操作系统的历史发展,重点关注Unix和Linux两个主要的操作系统分支。通过分析它们的起源、设计哲学、技术特点以及在现代计算中的影响,我们可以更好地理解操作系统在计算机科学中的核心地位及其未来发展趋势。
下一篇
无影云桌面