《深入Linux内核架构》第4章 进程虚拟内存(1)

目录

4.1 简介

4.2 进程虚拟地址空间

4.2.1 进程地址空间分布

4.2.2 建立布局


第3章讲了两点:物理内存的管理,内核虚拟地址管理。

本章讲:用户进程的虚拟地址空间管理。

4.1 简介

一个进程的整个虚拟地址空间(0-3G)中只有少部分映射到物理页。其余虚拟地址在访问时通过缺页异常处理,分配物理页,并建立页表项。

MMU作用:将虚拟地址转换为物理地址。

        内部包含TLB硬件,用于缓存页表,加快转换速度。

4.2 进程虚拟地址空间

32位系统中,一个进程的虚拟地址空间范围:0 - 4G

TASK_SIZE:

        含义:用户的虚拟地址空间的大小。

        典型值:TASK_SIZE=3G。

PAGE_OFFSET:

        作用:划分内核空间和用户空间。

        典型值:0xC0000000,即3G用户空间,1G内核空间。

无论当前运行哪个进程,进程虚拟地址空间中内核部分的内容都相同。

解释:A/B两个进程的内核空间0xC0001000处会映射到相同物理内存。

        而两个进程的用户空间0xA0001000映射到不同物理内存。

4.2.1 进程地址空间分布

struct mm_struct:管理一个进程的虚拟地址空间。

struct task_struct {

        struct mm_struct         *mm;

}

虚拟内存区域:简称VMA。

一个进程空间有很多VMA,如:

        代码段,数据段,堆,栈,mmap映射区。

内核用struct vm_area_struct表示一个VMA。

struct mm_struct {         //部分成员如下

        ...

        unsigned long (*get_unmapped_area) (struct file *filp, addr, len, pgoff, flags);

                //在进程地址空间中寻找合适的mmap映射位置

        unsigned long         mmap_base;

                //mmap映射的起始位置

        

        unsigned long         task_size;

                //进程的虚拟空间长度

                //current->mm->task_size = TASK_SIZE;

        unsigned long         start_code, end_code, start_data, end_data;

                //代码段和数据段:开始和结束地址。

                //可执行文件映射到地址空间后,这些区域长度不变(只读)。

        unsigned long         start_brk, brk, start_stack;

                //start_brk:堆的起始地址。

                //brk:堆的结束地址。该值可变。(因为堆长度可变)

        unsigned long         arg_start, arg_end, env_start, env_end;

                //参数列表和环境变量。位于栈中最高位置。

        pgd_t *pgd;

                //该进程页全局目录表的起始位置。

};

task_struct中flags成员的PF_RANDOMIZE标志:

        作用:每次启动一个进程时,虚拟地址空间中mmap映射起点和栈起点进行随机偏移。

        好处:防止攻击,防止通过缓冲溢出而获得栈访问权。

        1. mmap映射起点:

                mm->mmap_base = TASK_SIZE/3 + 随机值。

        2. 栈起点:

                mm->start_stack = STACK_STOP - 随机值。

get_unmapped_area函数指针:

        作用:mmap函数以mmap_base为起始地址查找合适映射位置。

        体系架构可各自实现该函数指针。如ARM中arch_get_unmapped_area

宏CONFIG_STACK_GROWSUP:

        作用:可定义栈向上增长(默认向下增长)。

mmap增长方向也可以设置。

如何查找一个进程的虚拟地址address对应的物理地址?

        1. current -> task_struct -> mm_struct

        2. struct vm_area_struct *vma = find_vma(mm, address);

        3. 根据vma的起始地址和address,计算在vma中的偏移量。

                offset = address - vma->vm_start;

        4. 根据mm_struct的pgd成员和address得到PTE。

                三级/四级页表转换。

        5. 计算页帧号。

                pfn = pte_pfn(*pte);

        6. 加上偏移。

                物理地址 = pfn << PAGE_SHIFT | offset;

内核Linux 5.x为增加查找vma的cache hit,缓存了最近访问的vma

struct task_struct {

        struct vmacache         vmacache;

}

struct vmacache {

        struct vm_area_struct *vmas[4];

                //缓存最近访问的四个VMA

};

内核不能显式的将一个变量放入CPU cache。

访问变量后,其被硬件自动放入CPU cache中。

把VMA按访问时间先后顺序放入数组中,所以可得到最近访问的VMA,而该VMA大概率在CPU cache中。

4.2.2 建立布局

exec()调用load_elf_binary():

        作用:装载ELF二进制可执行文件,以创建进程的地址空间。

不同可执行文件有各自实现的struct linux_binfmt,如a.out。

struct linux_binfmt         elf_format = {

        .load_binary         = load_elf_binary,         //加载ELF格式的二进制文件

        .load_shlib           = load_elf_library,         //加载ELF格式的共享库

};

ELF文件启动过程:

        应用层:fork->exec,执行对应do_execve系统调用。

        内核:do_execve->do_execve_common -> search_binary_handler

                遍历所有struct linux_binfmt实例,执行load_binary函数指针,即ELF的load_elf_library。

/proc/sys/kernel/randomize_va_space:

        作用:设置地址空间随机化。默认开启,随机偏移量最大1M

load_elf_binary实现:

load_elf_binary -> setup_new_exec - > arch_pick_mmap_layout

void arch_pick_mmap_layout(struct mm_struct *mm)

{

        if ((current->flags & PF_RANDOMIZE)

                random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;

        mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;

                //设置mmap区域起始位置

        mm->get_unmapped_area = arch_get_unmapped_area;

                //arch_get_unmapped_area为ARM中的实现

        mm->unmap_area = arch_unmap_area;

}

setup_arg_pages:

        设置mm->arg_start。

        设置mm->stack栈起始位置(加上随机偏移)。

get_unmapped_area什么时候调用?

        后续访问地址时,调用mmap来创建不同VMA,此时调用get_unmapped_area为新VMA选择合适位置。

        最终调用mm->get_unmapped_area或file->f_op->get_unmapped_area;

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JKTECH柔性振动盘柔性上料机

柔性供料器&#xff1a;用途广泛与好处显著 在现代工业生产中&#xff0c;随着技术的不断进步和市场的多样化需求&#xff0c;对物料供应系统的要求也日益提高。柔性供料器&#xff0c;作为一种新型的物料供应装置&#xff0c;其用途广泛且好处显著&#xff0c;正逐渐受到各行…

苍穹外卖亮点再梳理 ||

一、项目整体亮点&#xff1a; 【注&#xff1a;基于每个亮点&#xff0c;均有整理的相关知识&#xff0c;可在博客中查看】 1.数据库的设计采用RBAC&#xff08;基于角色访问控制&#xff09;的权限设计。 RBAC将权限授予角色&#xff0c;然后将用户分配给角色&#xff0c;…

算法——倍增

. - 力扣&#xff08;LeetCode&#xff09; 给你一棵树&#xff0c;树上有 n 个节点&#xff0c;按从 0 到 n-1 编号。树以父节点数组的形式给出&#xff0c;其中 parent[i] 是节点 i 的父节点。树的根节点是编号为 0 的节点。 树节点的第 k 个祖先节点是从该节点到根节点路径…

JavaScript中创建对象的方式

在JavaScript中&#xff0c;有多种方式可以创建对象&#xff1a; 对象字面量&#xff1a; 这是创建对象最简单的方式&#xff0c;直接使用大括号 {} 包含键值对。var obj { key1: "value1", key2: "value2" };new 关键字&#xff1a; 使用 new 关键字和构…

指针 基础知识

本笔记为观看56 指针-指针的定义和使用_哔哩哔哩_bilibili后的学习笔记 指针的定义和使用 1、定义指针 int main () {//1、定义指针int a 10;//指针定义的语法&#xff1a; 数据类型 * 指针变量名&#xff1b;int * p;//让指针记录变量a的地址p &a; //& 为取址符cou…

电商技术揭秘十六:电商中的实时分析与决策支持系统

相关系列文章 电商技术揭秘一&#xff1a;电商架构设计与核心技术 电商技术揭秘二&#xff1a;电商平台推荐系统的实现与优化 电商技术揭秘三&#xff1a;电商平台的支付与结算系统 电商技术揭秘四&#xff1a;电商平台的物流管理系统 电商技术揭秘五&#xff1a;电商平台…

数据结构_链表基本操作代码

链表是线性表的一种&#xff0c;是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 和顺序表差不多&#xff0c;用结构体定义一个节点&#xff0c;包括存储的数据和下一个节点的地址。 这里我们写几个接口&…

如何部署上线项目

❤️ Author&#xff1a; 老九 ☕️ 个人博客&#xff1a;老九的CSDN博客 &#x1f64f; 个人名言&#xff1a;不可控之事 乐观面对 &#x1f60d; 系列专栏&#xff1a; 文章目录 多环境多环境分类前端多环境实战请求地址启动方式项目配置 后端多环境实战 项目部署原始部署前端…

【项目】棋海争锋

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 项目介绍 WebSocket介绍 使用 项目创建 数据库设计 用户模块 登录接口 注册接口 获取用户信息接口 匹配模块 …

cartographer代码学习-概率栅格地图(ActiveSubmaps2D与Submaps2D)

概率栅格地图是二维激光SLAM的特点&#xff0c;能够将环境通过地图的形式表达出来。 ActiveSubmaps2D作为概率栅格地图中的重要成分&#xff0c;这个对象主要在LocalTrajectoryBuilder2D这里被使用 第一次调用&#xff1a; active_submaps_(options.submaps_options())传入一…

P1598 垂直柱状图

链接 ​​​​​​题目链接&#xff1a;P1598 垂直柱状图 题目 题目描述 写一个程序从输入文件中去读取四行大写字母&#xff08;全都是大写的&#xff0c;每行不超过 $100$ 个字符&#xff09;&#xff0c;然后用柱状图输出每个字符在输入文件中出现的次数。严格地按照输出…

为什么要学习SpringBoot呢?

学习SpringBoot的原因众多&#xff0c;以下是其中的一些主要理由&#xff1a; 简化Spring应用开发&#xff1a;SpringBoot极大地简化了Spring应用的开发过程。它提供了许多默认的配置&#xff0c;使开发者能够更快速地构建和运行Spring应用&#xff0c;而无需花费大量时间在繁…

【Bing】开启代理后使用 Bing 搜索引擎总是: 没有与此相关的结果

【Bing】开启代理后使用 Bing 搜索引擎总是: 没有与此相关的结果 1 问题描述2 解决方法2.1 修改代理规则2.1.1 Clash Verge2.1.2 Clash Verge Rev2.1.3 V2RayN 1 问题描述 当我开了代理访问 Bing 时&#xff0c;经常会出现下面的页面: 2 解决方法 我所知的有三种方法: 手动关…

关于JVM-三色标记算法剖析

相关系列 深入理解JVM垃圾收集器-CSDN博客 深入理解JVM垃圾收集算法-CSDN博客 深入理解jvm执行引擎-CSDN博客 jvm优化原则-CSDN博客 jvm流程图-CSDN博客 三色标记产生的原因&#xff1f; 在并发标记的过程中&#xff0c;因为标记期间应用线程还在继续跑&#xff0c;对象间的引…

使用Matplotlib绘制打断图Broken Axis

使用Matplotlib绘制打断坐标轴Broken Axis 对于一批存在离群点的或者两极分化的数据&#xff0c;为了突出其值域差异&#xff0c;时常需要用到打断坐标轴效果。 使用Matplotlib绘制的效果如下&#xff1a; 对于同样的数据&#xff0c;使用brokenaxes库的绘制效果如下&#x…

Ubuntu20.04安装和编译运行lidar_align来联合标定lidar与imu的外参

硬件&#xff1a;树霉派4b 1、下载并安装lidar_align mkdir -p lidar_align/src cd lidar_align/src git clone https://github.com/ethz-asl/lidar_align.git 将 lidar_align/src/lidar_align/NLOPTConfig.cmake 文件移动到 lidar_align/src/ 下(与lidar_align同级) NLOP…

ShardingSphere-ShardingSphere读写分离和数据脱敏

文章目录 一、读写分离1.1 读写分离1.2 读写分离应用方案1.3 分表+读写分离1.4 分库分表+读写分离二、ShardingSphere-JDBC读写分离2.1 创建SpringBoot并添加依赖2.2 创建实体类2.3 创建mapper2.4 配置读写分离2.5 测试测试插入数据测试读测试事务一致性测试负载均衡一、读写分…

免费泛域名SSL证书申请

二级域名使用较多时&#xff0c;一个个申请证书有点麻烦。泛域名证书一次性解决。 申请SSL免费证书 生成SSL最佳配置 https://ssl-config.mozilla.org/ Install curl https://get.acme.sh | sh -s emailzengsmosong.cc alias acme.sh~/.acme.sh/acme.sh# 证书机构二选一&am…

C语言每日一题(66)三数之和

题目链接 力扣15.三数之和 题目描述 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答…

KMP算法的实现示例(伪代码)

KMP算法&#xff0c;即Knuth-Morris-Pratt算法&#xff0c;是一个线性时间复杂度的字符串匹配算法。它能在O(nm)的时间复杂度内完成一个长度为n的文本串S和一个长度为m的模式串T的匹配工作&#xff0c;其中n和m分别代表文本串和模式串的长度。相比于朴素字符串匹配算法&#xf…