gpt4 book ai didi

linux - 可执行目标文件和虚拟内存

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:33:34 25 4
gpt4 key购买 nike

我是Linux和虚拟内存的初学者,仍然在努力理解虚拟内存和可执行对象文件之间的关系。
假设我们有一个可执行的对象文件a.out存储在硬盘上,假设a.out最初有一个带全局变量的.data节,值为2018。
当加载程序运行时,它分配一个连续的虚拟页块,将它们标记为无效(即未缓存),并将它们的页表条目指向a.out中的适当位置。加载程序实际上从未将任何数据从磁盘复制到内存中。在第一次引用每个页面时,虚拟内存系统会根据需要自动调出数据。
我的问题是:假设程序在运行时将全局变量的值从2018更改为2019,并且包含全局变量的虚拟页似乎最终会向外翻页到磁盘,这意味着.data section的全局变量现在是2019,所以我们更改了不应该更改的可执行对象文件被改变了?否则每次完成并再次运行程序时,我们会得到不同的值?

最佳答案

一般来说(不是专门针对Linux的)。
启动可执行文件时,操作系统(内核)创建一个虚拟地址空间和一个(最初为空)进程,并检查可执行文件的头。可执行文件的头描述了“部分”(例如.text.rodata.data.bss.bss等),其中每个部分都有不同的属性-如果该部分的内容是否应该放在虚拟地址空间中(例如是符号表或运行时不使用的东西),如果内容是否是文件的一部分(例如.bss),如果该区域应该是可执行的,则为只读或读/写。
通常,可执行文件的(使用部分)由虚拟文件系统缓存;已经在vfs缓存中的文件片段可以映射(作为“写入时复制”)到新进程的虚拟地址空间。对于不在vfs缓存中的部分,可以将这些文件片段映射为“需要获取”到新进程的虚拟地址空间。
然后启动进程(给定CPU时间)。
如果进程从尚未加载的页读取数据;操作系统(内核)暂停进程,将页从磁盘上的文件提取到vfs缓存中,然后将页映射为“写时复制”到进程中;然后允许进程继续(允许进程重试从未加载的页读取,这将在页面加载后生效)。
如果进程写入一个仍然是“写时复制”的页;操作系统(内核)暂停进程,分配一个新页并将原始页的数据复制到其中,然后用进程自己的副本替换原始页;然后允许进程继续(允许进程重试写操作,该操作将在进程拥有自己的副本后生效复制)。
如果进程从一个尚未加载的页面写入数据;操作系统(内核)将前面的两件事结合起来(将原始页面从磁盘提取到vfs缓存中,创建一个副本,将进程的“副本”映射到进程的虚拟地址空间)。
如果操作系统开始耗尽可用RAM,则:
vfs缓存中的文件数据页,但未与任何进程共享为“写时复制”,可以在vfs中释放,而无需执行任何其他操作。下次使用文件时,这些页面将从磁盘上的文件提取到vfs缓存中。
vfs缓存中的文件数据页,以及与任何进程共享为“写时复制”的文件数据页,可以在vfs中释放,并且在任何/所有标记为“尚未提取”的进程中释放副本。下次使用文件时(包括当进程访问“尚未获取”页时),这些页将从磁盘上的文件获取到vfs缓存,然后在进程中映射为“写时复制”。
已修改的数据页(可能是因为它们最初是“写时复制”但被复制的,或者是因为它们根本不是可执行文件的一部分(例如SIGSEGV节、可执行文件的堆空间等)可以被保存以交换空间,然后被释放。当进程再次访问页面时,它们将从交换空间中获取。
注意:如果可执行文件存储在不可靠的媒体上(例如可能被刮伤的CD),一个“比平均水平更聪明”的操作系统可能会在开始时将整个可执行文件加载到VFS缓存和/或交换空间;因为当进程正在使用文件时,除了使进程崩溃(例如2018)并使其看起来像可执行文件在未运行时出现错误之外,没有合理的方法来处理“从内存映射文件读取错误”,因为这提高了可靠性(因为您依赖于更可靠的交换,而不依赖于不太可靠的刮擦CD)。此外,如果操作系统防止文件损坏或恶意软件(例如,在可执行文件中内置CRC或数字签名),则操作系统可以(应该)将所有内容加载到内存(VFS缓存)中,以便在允许执行可执行文件之前检查CRC或数字签名,并且(对于安全系统,如果在可执行文件运行时修改了磁盘上的文件,则释放RAM时,可以将未修改的页存储在“更受信任”的交换空间中(与修改页时相同),以避免从原始“不太受信任”的文件中提取数据(部分原因是不希望每次页被修改时都执行整个数字签名检查从文件中加载)。
我的问题是:假设程序在运行时将全局变量的值从2018更改为2019,并且包含全局变量的虚拟页似乎最终会向外翻页到磁盘,这意味着.data section的全局变量现在是2019,所以我们更改了不应该更改的可执行对象文件被改变了?
包含2019的页面将以“not fetched”开头,然后(当其被访问时)加载到vfs缓存中并映射到进程中作为“copy on write”。在这两个点上,如果需要,操作系统可以释放内存并从磁盘上的可执行文件中获取数据(尚未更改)。
当进程修改全局变量(将其更改为包含 )时,操作系统将为进程创建全局变量的副本。在此之后,如果操作系统希望释放内存,则操作系统需要将页的数据保存在交换空间中,如果再次访问,则从交换空间加载页的数据。可执行文件未被修改并且(对于该页,对于该进程)可执行文件不再使用。

关于linux - 可执行目标文件和虚拟内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53492168/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com