搜索
首页运维NginxLinux 保护模式下的内存管理

Linux 保护模式下的内存管理

Jul 06, 2023 pm 03:20 PM
linux模式保护

我们知道,内存可以看做一个非常大的数组,我们想要查找内存中某个元素的话,会通过数组的下标来指定,内存也是如此,不过这有一个前提是这个数组是由一组有序的字节组成的,在这个有序的字节数组中,每个字节都有一个唯一的地址,这个地址也叫做内存地址。

内存中存储着很多对象,每个对象是由不同字节组成的,比如一个 char 对象,一个 byte 对象,一个 int 对象等等,它们都分部在内存的各个位置中,CPU 对内存中这些对象的地址进行定位的操作就叫做内存寻址。内存总线宽度决定了可以寻址多少位的内存地址,从地址0开始计算。由于 80X86 是 32 位的,所以总线宽度也是 32 位,因此一共有 2 ^ 32 个内存地址,所以总共可以存放 4GB 的内存地址。可以通过连续的内存地址来提取多个字节的数据类型,比如 int、long、double。

虽然能够寻址到对象,但是这些对象存放的字节顺序是不同的,这里分为两种存放方式,即大端法和小端法。

比如现在有一个 int 类型的对象,位于地址 0x100 处,它的十六进制数值是 0x01234567,我给你画一幅图你就明白这两个存放顺序的区别了。

Linux 保护模式下的内存管理

这个其实很好理解,0x01234567 的 int 数据类型可以拆分为 01 23 45 67 个字节,并且 01 是高位,67 是低位,于是可以解释小端法和大端法的存储顺序:即小端法是低位在前,而大端法是高位在前。大端法和小端法只是存储顺序的区别,和对象的位数、数值无关。大多数 Intel 机器都采用的是小端模式,所以 80X86 也是小端存储,而一些 IBM 和 Oracle 的大多数机器都是使用的大端存储方式。

由于计算机是无法直接将内存中的数据一次性全部寻址完毕,因为它相对实在太过庞大,所以内存一般会进行分段,这里就涉及一个疑问:即内存为什么要分段。我上面只是笼统的介绍了下。

内存为什么要分段?

https://www.php.cn/link/d005ce7aeef46bd18515f783fb8e87fa

使用分段机制,内存空间被划分为线性区域,每个线性区域可以通过段基址加上段内偏移来定位。段基址部分由 16 位的段选择符来指定,其中 14 位是可以选择 2 ^ 14 次方即 16384 个段,段内偏移地址部分使用 32 位的值来指定,因此段内地址可以是 0 - 4G ,一个段的最大长度是 4 GB,这也就和上面所说的 4 GB 的内存地址相呼应。由 16 位段和 32 位段内偏移构成的 48 位地址或长指针称为一个逻辑地址,逻辑地址就是虚拟地址。

X86架构中有六个特殊的寄存器用于存放段基址,它们分别是CS、DS、ES、SS、FS和GS。其中 CS 用于寻址代码段,SS 用于寻址堆栈段,其他寄存器用于寻址数据段。在任何指定时刻由 CS 寻址的段称为当前代码段。当前代码段内下一条需要执行的指令的偏移地址已经存在于EIP寄存器中。此时的段基址:偏移地址就可以表示为 CS:EIP 了。

由段寄存器 SS 寻址的段称为当前堆栈段,栈顶由 ESP 寄存器给出,在任何时刻 SS:ESP 都指向栈顶,并且没有例外情况,其他四个是通用数据段寄存器,当指令中默认没有数据段时,由 DS 给出。

地址转换

通常,一个完整的内存管理系统由两个组成部分组成:访问保护和地址转换。访问保护是为了防止一个应用程序访问的内存地址是另一块程序所使用的;地址转换就是给不同的应用程序提供一个动态的地址分配方式。访问保护和地址转换是相辅相成的。

地址转换通常以内存块作为基本单位,这里解释下什么是块,大家知道在 Linux 中,一切都是文件,而文件就是由一个个的块构成的,块(block)是用于描述文件系统的组成单位,也是数据处理的基本单位。常见的块有不同大小,如 512B、1KB、4KB 等,虽然块是基本单位,但它实质上是由一个个扇区构成的。

地址转换有两种实现方式:分段机制和分页机制。x86 在内存管理的实现方式结合了分段和分页机制,下面是虚拟地址经过分段和分页后转换为物理地址的映射图

Linux 保护模式下的内存管理

针对这张图,有必要解释一下:

首先,这张图包含三个地址和这三个地址的转换过程,从大体上来看,逻辑地址会经过分段基址转换后变为线性地址,线性地址是保护模式下的段基址 + 段内偏移,因此这张图是保护模式下的地址转换图。线性地址会经过分页机制后转换为物理地址,前提是需要开启分页机制;如果没有开启分页机制,线性地址 = 物理地址。

需要再说一下逻辑地址,逻辑地址里面包含段选择子和段内偏移,段选择子这个概念我刚开始接触也比较模糊,简单一点来说可以把它理解为是保护模式下的段基址,大家知道段基址是 16 位的,而段内偏移是 32 位的。

很多书或者文章中都提到了段选择符,其实段选择子就是段选择符,这完全是翻译问题,英文都是 selector。

后面会提到段描述符,段描述符和段选择子不是一回事,但段选择子是一个 16 位的段描述符。

再和大家说一下这个图上没有写出来的内容,现在大家知道逻辑地址可以转换为线性地址,线性地址可以转换为物理地址,那么根源是如何转换的呢?实际上这里使用的方式是 MMU(内存管理单元)进行转换;而线性地址转换为物理地址使用的是分页单元的硬件电路。本文的重点不在于讨论具体的转换过程,而是将重点放在分段和分页这两个机制上。

下面来详细聊一聊分段和分页这两个机制。

分段机制

这里推荐大家先看一下我写的 "内存为什么要分段" 的那段描述。

https://www.php.cn/link/d005ce7aeef46bd18515f783fb8e87fa

多个程序在同一个内存空间中运行,不会相互干扰,这是因为分段提供了隔离代码、数据和堆栈区域的机制。如果 CPU 中有多个程序或者任务正在运行,那么每个程序都可以分配各自的一套段(包含程序代码、数据和堆栈),CPU 通过加强段之间的界限来达到防止应用程序相互干扰的目的。

一个系统中所有使用的段都包含在 CPU 的线性地址空间中。为了定位指定段中的字节,程序必须提供逻辑地址才能进行转换。逻辑地址包含段选择子和段内偏移,每个段都有一个段描述符,段描述符用于指出段的大小、访问权限和段的特权级、段类型以及段第一个字节在线性地址空间中的位置(段基址)。逻辑地址的偏移量部分加到段基址上就可以定位段中某个字节的位置,因此段基址 + 偏移量形成了 CPU 线性地址空间中的地址。

线性地址空间与物理地址空间具有相同的结构,但是它们所能容纳的段相差甚远,虚拟地址也就是逻辑地址空间可包含最多 16 K 的段,而每个段可容纳的大小为 4 GB ,所以虚拟地址总共能查找到 64TB(2 ^ 46) 的段,线性地址和物理地址的空间是 4GB (2 ^ 32)。所以,如果禁用了分页机制,那么线性地址空间就是物理地址空间。

Linux 保护模式下的内存管理

这幅图就是逻辑地址 -> 线性地址 -> 物理地址的映射图,GDT 表和 LDT 表各占一半的地址空间,各为 8192 个段,每个段最长为 4 G,从 GDT 表还是 LDT 表查询,具体从哪个表查还是要看段选择子的 TI 属性,段选择子的结构如下所示

Linux 保护模式下的内存管理

段选择子总共分为三个部分:

  • RPL(Request Privilege Level):请求特权级,表示进程应该以什么权限来访问段,数值越大权限越小。
  • TI(Table Indicator):表示应该查询哪个表,TI = 0 查 GDT 表;TI = 1 查 LDT 表。
  • Index:CPU 会自动将 Index * 8,在加上 GDT 和 LDT 中的段基址,就是要加载的段描述符。

这里没有太细致的详解一下段描述符,因为此篇还是偏向于内存管理,没有太执着于某个细节。

在GDTR中,段选择子和偏移量组成的逻辑地址可以合成段描述符,并直接保存。段选择子和段内偏移经过 MMU 后可以转换成为线性地址。

分页机制

上面我们说到,线性地址是由逻辑地址转换过来的,如果禁用了分页机制,线性地址就是物理地址,如果开启分页机制,线性地址和逻辑地址空间的数量还是不同的。一般程序都是多任务的,而多任务通常定义的线性地址空间要比物理内存容量大得多,为什么呢?地址转换映射图上画着明明线性地址和物理地址都是 4G 的大小啊。那是因为,线性地址被虚拟存储技术所虚拟化了。

虚拟存储是一种内存管理技术,使用这项技术可以让我们产生内存空间要比实际的物理内存容量大的多的错觉,其本质是把内存虚拟化了,就是说内存可能只有 4G,但是你以为内存有 64 G,所以我为什么能开那么多应用程序的原因。

分页机制其实就是虚拟化的一种实现,在虚拟化的环境中,大量的线性地址空间会映射到一小块物理内存(RAM 或者 ROM)中。当进行分页时,每个段被分割为页面(通常是4K),这些页面会被存储在物理内存或磁盘上。操作系统通过使用一个页目录和页表来维护这些页面。当程序试图访问线性地址空间中的某一个地址位置时,CPU 就会使用页目录和页表把这个线性地址转换成物理地址,再存储在物理内存上。

如果当前访问的页面不在物理内存中,CPU 就会执行中断,一般错误就是页面异常,然后操作系统会把这个页面从硬盘上读入物理内存中,然后继续从中断处执行程序。操作系统常常频繁进行页面换入和换出,这也成为一个性能瓶颈。

在分段中,每个段的长度是不固定的,最大长度为4G;而在分页中,每个页面的大小是固定的。不论在物理内存还是磁盘上,使用固定大小的页面更适合管理物理内存;而分段机制使用大小可变的块更适合处理复杂系统的逻辑分区。

尽管分段和分页是两种不同的地址转换机制,但它们在整个地址变换过程中被独立处理,每个过程都是独立的。这两种机制都使用了一种中间表来存储表项映射,但是这个中间表的结构是不同的。段表存在线性地址空间中,页表则存储在物理地址空间。

保护机制

80x86拥有两种保护机制,其中一种是通过为每个任务分配不同的虚拟地址空间来实现任务之间的完全隔离。这是通过给每个任务逻辑地址到物理地址的不同变换得到的,每个应用程序只能访问自己虚拟空间内的数据和指令,只能通过它自己的映射得到物理地址;第二种机制是保护任务,保护操作系统的内存段和一些特殊寄存器不会被应用程序所访问。下面我们就来具体探讨一下这两个任务。

任务之间的保护

每个任务会单独的放在自己的虚拟地址空间中,再经过硬件映射成为物理地址,不同的虚拟地址会变换成为不同的物理地址,不会存在 A 的虚拟地址会映射到 B 所在的物理地址的范围内,这样就会把所有的任务都隔绝开,且不同任务之间不会相互干扰。

每个任务都有各自的映射表、段表和页表,当 CPU 切换不同的应用程序或任务时,这些表也会进行切换。

虚拟地址是操作系统的抽象,也就是说虚拟地址完全是操作系统所抽象出来能够更好管理应用程序和任务的一个载体,每个任务都可以把逻辑地址映射成为虚拟地址,这也表明每个任务都可以访问操作系统,操作系统可以被所有的任务所共享。这个所有任务都具有相同虚拟地址空间的部分被称为全局地址空间(Global address space),Linux 就使用到了全局地址空间。

全局地址空间中每个任务都有自己的唯一的虚拟地址空间,这个虚拟地址空间叫做局部地址空间(Local address space)。

内存段和寄存器的特殊保护

如果将操作系统在不同任务之间的保护比喻为横向保护,那么对内存段和寄存器的保护可看作是纵向保护。为了限制对任务中各段的访问,操作系统设定了4个特权级别,以保护每个任务。

优先级分为 4 个等级,0 最高,3 最低。一般最敏感的数据会被赋予最高优先级,它们只能被任务中最受信任的部分访问,不太敏感的数据会赋予低优先级;内核操作系统访问一般是 0 级,应用程序数据一般是 3 级。每个内存段都与一个特权级相关联。

我们知道 CPU 通过 CS 从段中取得指令和数据执行,从段中取得的指令和数据是具有特权级的,一般用当前特权级(Current Privilege Level)来访问,CPL 就是当前活动代码的特权级。当应用程序尝试访问段时,将与该特权级进行比较,只有低于该段的特权级才能访问。

以上是Linux 保护模式下的内存管理的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:51CTO.COM。如有侵权,请联系admin@php.cn删除
在Nginx和Apache之间进行选择:适合您的需求在Nginx和Apache之间进行选择:适合您的需求Apr 15, 2025 am 12:04 AM

NGINX和Apache各有优劣,适合不同场景。1.NGINX适合高并发和低资源消耗场景。2.Apache适合需要复杂配置和丰富模块的场景。通过比较它们的核心特性、性能差异和最佳实践,可以帮助你选择最适合需求的服务器软件。

nginx怎么启动nginx怎么启动Apr 14, 2025 pm 01:06 PM

问题:如何启动 Nginx?答案:安装 Nginx启动 Nginx验证 Nginx 是否已启动探索其他启动选项自动启动 Nginx

怎么查看nginx是否启动怎么查看nginx是否启动Apr 14, 2025 pm 01:03 PM

确认 Nginx 是否启动的方法:1. 使用命令行:systemctl status nginx(Linux/Unix)、netstat -ano | findstr 80(Windows);2. 检查端口 80 是否开放;3. 查看系统日志中 Nginx 启动消息;4. 使用第三方工具,如 Nagios、Zabbix、Icinga。

nginx怎么关闭nginx怎么关闭Apr 14, 2025 pm 01:00 PM

要关闭 Nginx 服务,请按以下步骤操作:确定安装类型:Red Hat/CentOS(systemctl status nginx)或 Debian/Ubuntu(service nginx status)停止服务:Red Hat/CentOS(systemctl stop nginx)或 Debian/Ubuntu(service nginx stop)禁用自动启动(可选):Red Hat/CentOS(systemctl disable nginx)或 Debian/Ubuntu(syst

nginx在windows中怎么配置nginx在windows中怎么配置Apr 14, 2025 pm 12:57 PM

如何在 Windows 中配置 Nginx?安装 Nginx 并创建虚拟主机配置。修改主配置文件并包含虚拟主机配置。启动或重新加载 Nginx。测试配置并查看网站。选择性启用 SSL 并配置 SSL 证书。选择性设置防火墙允许 80 和 443 端口流量。

nginx403错误怎么解决nginx403错误怎么解决Apr 14, 2025 pm 12:54 PM

服务器无权访问所请求的资源,导致 nginx 403 错误。解决方法包括:检查文件权限。检查 .htaccess 配置。检查 nginx 配置。配置 SELinux 权限。检查防火墙规则。排除其他原因,如浏览器问题、服务器故障或其他可能的错误。

linux怎么启动nginxlinux怎么启动nginxApr 14, 2025 pm 12:51 PM

在 Linux 中启动 Nginx 的步骤:检查 Nginx 是否已安装。使用 systemctl start nginx 启动 Nginx 服务。使用 systemctl enable nginx 启用在系统启动时自动启动 Nginx。使用 systemctl status nginx 验证启动是否成功。在 Web 浏览器中访问 http://localhost 查看默认欢迎页面。

linux怎么查看nginx是否启动linux怎么查看nginx是否启动Apr 14, 2025 pm 12:48 PM

在 Linux 中,使用以下命令检查 Nginx 是否已启动:systemctl status nginx根据命令输出进行判断:如果显示 "Active: active (running)",则 Nginx 已启动。如果显示 "Active: inactive (dead)",则 Nginx 已停止。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。