简单理解程序地址空间:Linux 中的内存映射与页表解析

ps: Linux操作系统对于程序地址,物理地址的处理,对于源码,我也看不大懂,只是截取当我们进程发生正常缺页中断的时候的调用情况。本文中所有的源码都是进行截取过的,如果大家感兴趣可以去下载源码。

在Linux 操作系统 进程(1)-CSDN博客 我们在最后简单介绍了我们所写的C语言程序的地址都是虚拟地址,通过页表映射到物理地址,那么这篇文章,我们就深入一点,通过观察Linux源码中对于页面内容的填充,或者是当发生缺页中断的时候,如何获取到物理地址。

进程的起点 (task_struct)

当说到一个进程所有的属性的时候,必不可少的一个结构体就是task_struct结构体,那么当我们说到程序地址空间的时候,该结构体里一定会包含描述这个属性的相关字段。

struct task_struct {volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped *///就在这里struct mm_struct *mm, *active_mm;
}

通过这个结构体,让我们仔细看看Linux对于程序地址空间描述(截取)

struct mm_struct {struct vm_area_struct *mmap;        /* list of VMAs */struct rb_root mm_rb;               /* 红黑树,用于管理 VMA */struct vm_area_struct *mmap_cache;   /* 上一个查找的 VMA */unsigned long start_code, end_code, start_data, end_data;unsigned long start_brk, brk, start_stack;unsigned long arg_start, arg_end, env_start, env_end;unsigned long rss, anon_rss, total_vm, locked_vm, shared_vm;unsigned long exec_vm, stack_vm, reserved_vm, def_flags, nr_ptes;//虚拟地址空间的定义  stack ...
};

对于程序地址空间的定义有了,那么相对应的页表的描述不就在第一行 struct vm_area_struct *mmap;

vm_area_struct

struct vm_area_struct {struct mm_struct * vm_mm;	/* 所属的mm_struct. */unsigned long vm_start;		/* Our start address within vm_mm. */unsigned long vm_end;		/* The first byte after our end addresswithin vm_mm. *//* linked list of VM areas per task, sorted by address */struct vm_area_struct *vm_next; /*链接下一个进程的VMA空间*/unsigned long vm_flags;		/* 保存的数据的权限 -> 只读 读写... */struct rb_node vm_rb;  /*栈空间,堆空间... 的范围 */

页表的填充

mm_struct的初始化

mm_struct 结构体的初始化是由一个 init_mm的宏完成的

struct mm_struct init_mm = INIT_MM (init_mm);
#define INIT_MM(name) \
{			 					\.mm_rb		= RB_ROOT,				\.pgd		= swapper_pg_dir, 			\.mm_users	= ATOMIC_INIT(2), 			\.mm_count	= ATOMIC_INIT(1), 			\.mmap_sem	= __RWSEM_INITIALIZER(name.mmap_sem),	\.page_table_lock =  SPIN_LOCK_UNLOCKED, 		\.mmlist		= LIST_HEAD_INIT(name.mmlist),		\.cpu_vm_mask	= CPU_MASK_ALL,				\.default_kioctx = INIT_KIOCTX(name.default_kioctx, name),	\
}

但这也只是对于虚拟地址空间的初始化,页表并没有填充任何内容,当我们进行读取程序内容的时候,一定会发生缺页中断,既然初始化并没有对于页表初始化,那也就是说,在缺页中断的过程中,会有对该情况的判断。那么让我们跳转到缺页中断时,系统执行的函数吧!

 do_page_fault

/*datammu : 错误类型
* esr0 : 错误信息
* ear0 ; 错误的虚拟地址
*/asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear0)
{struct vm_area_struct *vma;struct mm_struct *mm;unsigned long _pme, lrai, lrad, fixup;siginfo_t info;pgd_t *pge;pud_t *pue;pte_t *pte;int write;mm = current->mm;  //获取错误页的 mm_struct//...vma = find_vma(mm, ear0);switch (handle_mm_fault(mm, vma, ear0, write))// ...}

在这个函数的前面数据的定义中,我们发现了几个之前并未出现的参数  pgd_t *pge;  pud_t *pue;   pte_t *pte;  这几个参数是操作系统对自己页表访问的具体描述,等下再说。当这个函数正常执行时,我们会发现他调用了这个函数 vma = find_vma(mm, ear0);  获取到发生缺页终端的虚拟地址所在的vma

/* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
{struct vm_area_struct *vma = NULL;if (mm) {/* Check the cache first. *//* (Cache hit rate is typically around 35%.) */vma = mm->mmap_cache;if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {struct rb_node * rb_node;rb_node = mm->mm_rb.rb_node;vma = NULL;while (rb_node) {struct vm_area_struct * vma_tmp;vma_tmp = rb_entry(rb_node,struct vm_area_struct, vm_rb);if (vma_tmp->vm_end > addr) {vma = vma_tmp;if (vma_tmp->vm_start <= addr)break;rb_node = rb_node->rb_left;} elserb_node = rb_node->rb_right;}if (vma)mm->mmap_cache = vma;}}return vma;
}

在这个函数中,我们可以很清楚的看到,查找vma的时候,先去查找上一次使用过的vma(我们所写的程序的都具有局部性),然后在使用红黑树结构查找。那么有同学就有疑问了,为什么我们已经得到了出现错误的虚拟地址,为什么还要去查找他所在的vma范围呢?

unsigned long vm_flags;		/* 保存的数据的权限 -> 只读 读写... */

在我们所写的程序中,有只读的变量,可以读写的变量,或者是需要申请内存的堆空间的变量,如果我们只有虚拟地址,什么不知道,那么这个数据是需要重新申请内存呢,或者说是不可更改呢,vm_flags保存的权限,和vma结构体中的其他字段就起到了作用。 

页表填充

找到我们地址的其他属性后,就应该去找到页表了,handle_mm_fault(mm, vma, ear0, write),为什么说是找页表呢? 在do_page_fault 函数中,我们没有见过的那几个变量其实就是Linux系统的三级页表结构,通过一级一级的转变才得到最后的页表,分别就是 页目录 , 页中间目录 ,页表,最后通过偏移量才得到虚拟地址所在的页框。

int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,unsigned long address, int write_access)
{pgd_t *pgd;pud_t *pud;pmd_t *pmd;pte_t *pte;__set_current_state(TASK_RUNNING); //更改进程为运行态inc_page_state(pgfault);//通过页目录去获得页表pgd = pgd_offset(mm, address);  spin_lock(&mm->page_table_lock);pud = pud_alloc(mm, pgd, address);if (!pud)goto oom;pmd = pmd_alloc(mm, pud, address);if (!pmd)goto oom;pte = pte_alloc_map(mm, pmd, address);if (!pte)goto oom;return handle_pte_fault(mm, vma, address, write_access, pte, pmd);oom:spin_unlock(&mm->page_table_lock);return VM_FAULT_OOM;
}

我们终于获得进程的页表,进入到了最后一个函数,页表第一次映射的处理就出现了,以及后续对于正常缺页中断的处理。

static inline int handle_pte_fault(struct mm_struct *mm,struct vm_area_struct * vma, unsigned long address,int write_access, pte_t *pte, pmd_t *pmd)
{pte_t entry;entry = *pte;// 判断页框存在不存在  不存在就是第一次映射 if (!pte_present(entry)) {/** If it truly wasn't present, we know that kswapd* and the PTE updates will not touch it later. So* drop the lock.*/if (pte_none(entry))return do_no_page(mm, vma, address, write_access, pte, pmd);if (pte_file(entry))return do_file_page(mm, vma, address, write_access, pte, pmd);return do_swap_page(mm, vma, address, pte, pmd, entry, write_access);}if (write_access) {if (!pte_write(entry))return do_wp_page(mm, vma, address, pte, pmd, entry);entry = pte_mkdirty(entry);}entry = pte_mkyoung(entry);ptep_set_access_flags(vma, address, pte, entry, write_access);update_mmu_cache(vma, address, entry);pte_unmap(pte);spin_unlock(&mm->page_table_lock);return VM_FAULT_MINOR;
}

 当然,为了加快这个过程,cpu中汇集成一个MMU(内存管理单元)用来处理这些事情

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1553038.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【Burp入门第三十三篇】IP Rotate 插件实现IP轮换爆破

Burp Suite是一款功能强大的渗透测试工具,被广泛应用于Web应用程序的安全测试和漏洞挖掘中。 本专栏将结合实操及具体案例,带领读者入门、掌握这款漏洞挖掘利器 读者可订阅专栏:【Burp由入门到精通 |CSDN秋说】 文章目录 正文安装步骤使用步骤应用场景实战文章正文 在 Burp…

留存率的定义与SQL实现

1.什么是留存率 留存率是指在特定时间段内&#xff0c;仍然继续使用某项产品或服务的用户占用户总数的百分比。 通常&#xff0c;留存率会以日&#xff0c;周&#xff0c;或月为单位进行统计和分析。 2.SQL留存率常见问题 1.计算新用户登录的日期的次日留存率以及3日留存率 …

假期惊喜,收到公司款项86167.14元

假期惊喜 近日&#xff0c;有网友爆料称&#xff0c;比亚迪在未提前通知员工的情况下&#xff0c;突然发放了利润奖金。 有人获得了七八万元&#xff0c;也有人拿到了十多万元。 一位比亚迪员工的帖子显示&#xff0c;在9月26日下午&#xff0c;他的银行卡突然收到一笔 86167.1…

知识图谱入门——4:Protégé 5.6.4安装和主要功能介绍、常用插件(2024年10月2日):知识图谱构建的利器

Protg 是斯坦福大学开发的一款开放源代码的本体编辑工具。它为构建、共享和管理本体&#xff08;Ontologies&#xff09;提供了一个强大的平台&#xff0c;广泛应用于语义网、知识管理、自然语言处理等领域&#xff0c;特别是知识图谱的开发和管理。Protg 支持 OWL&#xff08;…

解决问题AttributeError: “safe_load“ has been removed, use

解决问题AttributeError: "safe_load" has been removed, use~ 1. 问题描述2. 解决方法 1. 问题描述 在复现cdvae代码时&#xff0c;运行 python scripts/compute_metrics.py --root_path MODEL_PATH --tasks recon gen opt评估模型时&#xff0c;出现以下问题。 …

【优选算法】(第十六篇)

目录 连续数组&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 矩阵区域和&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 连续数组&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&#xff08;LeetCode&a…

Java--IO基本流

IO流 概述 生活中&#xff0c;你肯定经历过这样的场景。当你编辑一个文本文件&#xff0c;忘记了ctrls &#xff0c;可能文件就白白编辑了。当你电脑上插入一个U盘&#xff0c;可以把一个视频&#xff0c;拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢&#xff1f;键盘…

汇总binder相关一些常见面试题-安卓系统常见面试题

背景&#xff1a; 国庆前有几个学员朋友在群里讨论了几个binder相关的面试题&#xff0c;讨论较为激烈&#xff0c;这里马哥统一整理一下列出来了&#xff0c;并且也补充了几个&#xff0c;大家有兴趣的可以尝试做一下&#xff0c;后续方便每个学员进行查缺补漏。后续会进行整…

JSP(Java Server Pages)基础使用三(表单传参)

表单传参 1.这次学习的是我们在网络上使用次数相对来说很多的jsp的使用方式&#xff0c;表单传参是运用了form表单的post方法来讲表单中的数据传递给action页面,action的作用是跳转就类似a标签&#xff0c;当然action不只可以是页面&#xff0c;还可以是后端类&#xff0c;用来…

如何解决 Photoshop 中的“暂存盘已满”错误

好久没有用Photoshop了&#xff0c;今天想自己修个图&#xff0c;就启动了一下PS&#xff0c;结果出现一个对话框“不能初始化Photoshop&#xff0c;因为暂存盘已经满”。我一直存在C盘焦虑&#xff0c;常年C盘显示都是红色的。上网一查&#xff0c;发现PS启动时暂存盘的空间是…

最新BurpSuite2024.9专业中英文开箱即用版下载

1、工具介绍 本版本更新介绍 此版本对 Burp Intruder 进行了重大改进&#xff0c;包括自定义 Bambda HTTP 匹配和替换规则以及对扫描 SOAP 端点的支持。我们还进行了其他改进和错误修复。 Burp Intruder 的精简布局我们对 Burp Intruder 进行了重大升级。现在&#xff0c;您可…

原文翻译:Make Skeleton-based Action Recognition Model Smaller, Faster and Better

全网没找到一个完整的翻译&#xff0c;用chatgpt翻译如下&#xff0c;可能有的地方不够准确&#xff0c;推荐结合原文对照着看更。 摘要 尽管基于骨架的动作识别在近年来取得了巨大的成功&#xff0c;但大多数现有方法可能面临模型规模庞大和执行速度缓慢的问题。为了解决这个…

国庆节快乐前端(HTML+CSS+JavaScript+BootStrap.min.css)

一、效果展示 二、制作缘由 最近&#xff0c;到了国庆节&#xff0c;自己呆在学校当守校人&#xff0c;太无聊了&#xff0c;顺便做一个小demo帮祖国目前庆生&#xff01;&#xff01;&#xff01; 三、项目目录结构 四、准备工作 (1)新建好对应的文件目录 为了方便&#xff…

【MyBatis 源码拆解系列】JVM 级别缓存能力设计:MyBatis 的一、二级缓存如何设计?

欢迎关注公众号 【11来了】 &#xff0c;持续 MyBatis 源码系列内容&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址&#xff1a;点击查看文章导读&#xff01; 感谢你的关注&#xff…

Linux内核对连接的组织和全连接队列

一、Linux内核的组织形式 1.1 描述“连接”的结构 TCP协议的特点是面向连接&#xff0c;一个服务端可能会被多个客户端连接&#xff0c;那这些连接也一定会被操作系统组织起来&#xff0c;接下来我们谈一谈在Linux内核中是如何管理这些连接的。 既然要管理这些连接&#xff0c…

vue3中el-input在form表单按下回车刷新页面

摘要&#xff1a; 在input框中点击回车之后不是调用我写的回车事件&#xff0c;而是刷新页面&#xff01; 如果表单中只有一个input 框则按下回车会直接关闭表单 所以导致刷新页面 再写一个input 表单 &#xff0c;并设置style“display:none” <ElInput style"display…

SkyWalking 高可用

生产环境中,后端应用需要支持高吞吐量并且支持高可用来保证服务的稳定,因此需要高可用集群管理。 集群方案 Skywalking集群是将 skywalking oap 作为一个服务注册到nacos上,只要skywalking oap服务没有全部宕机,保证有一个skywalking oap在运行,就可以提供服务。 高可用…

鸿蒙应用开发前置学习-TypeScript

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…

数据安全新攻略!4大神技在手,固态硬盘数据恢复秒变Easy Mode

现在咱们都离不开电脑和手机了&#xff0c;里面存了好多重要的东西&#xff0c;比如学习资料、工作文件&#xff0c;还有照片、视频这些宝贵的记忆。但是有时候数据可能会不小心弄丢或者删掉&#xff0c;特别是在固态硬盘上的数据&#xff0c;要是没了&#xff0c;想找回来比老…

Sui主网升级至V1.34.2

Sui主网现已升级至V1.34.2版本&#xff0c;同时协议升级至60版本。其他升级要点如下所示&#xff1a; 协议 #19014: 在验证Groth16 zk-proof时对无效公共输入进行快速判断。添加了一个新的Move函数flatten&#xff0c;可将向量中的向量展平成单个向量&#xff0c;这在新协议…