Linux进程的页表

3
Intel core i5, Ubunu 16.04

我正在阅读有关内存分页的内容这里,现在正在尝试进行实验。我编写了一个简单的汇编程序来获取段错误并在gdb中运行。以下是程序代码:

 section .text
     global _start

 _start:
     mov rax, 0xFFFFFFFFFFFF0A31
     mov [val], eax
     mov eax, 4
     mov ebx, 1
     mov ecx, val
     mov edx, 2

     int 0x80

     mov eax, 1
     int 0x80

 segment .bss
     dummy resb 0xFFA
     val resb 1

我将其汇编并链接成一个64位ELF静态可执行文件。

据我所知,每个进程都有自己的页表,cr3寄存器指向它。现在我想要查看这个页表,是否可能在Linux中找到有关进程页表的信息?


3
应用程序无法访问页表,它只对内核可访问。 - Barmar
1
Unix.stackexchange.com可能是一个更好的地方来询问这个问题。 - Barmar
1
同时请注意,它一直在变化。除非您将页面锁定到内存中,否则这些信息可能没有什么用处。 - Jester
@MichaelPetch非常好的观点。谢谢。看起来我可以以人类可读的格式获取分段和页面的人类可读内存布局。你能否把它发布为答案? - St.Antario
@St.Antario /proc/$pid/map 包含进程 $pid 的内存映射。页面表本身并不是很有趣,因为它经常被内核修改,并不能真正指示您可以访问哪些页面。 - fuz
显示剩余7条评论
3个回答

3
您需要将程序编译为内核模块才能读取页表。我相信有一些项目可以做到这一点。
请看这里:https://github.com/jethrogb/ptdump
似乎描述了您想要的内容。

如果您无法提供更具体的细节,那么这似乎更适合作为注释。 - Barmar

1
你可以在/proc/PID/smaps中查看进程的所有映射。这将告诉你在不获取SIGSEGV的情况下可以访问哪些内容。
这与你的cr3页表不同,因为内核并不总是“固定”你的所有映射。也就是说,硬件页面故障并不总是SIGSEGV:内核页面故障处理程序会检查你的进程是否逻辑上具有该内存映射,并纠正情况,或者你确实违反了内存保护。
在调用mmap()系统调用之后,或者在进程启动时将文本/数据/BSS段映射到内存中,逻辑上你已经完成了内存映射,但是Linux可能会决定懒惰一些,并且暂时不提供任何物理页面。(例如,也许页面还没有在页面缓存中,所以没有必要阻塞直到你真正触摸那个内存并得到一个页面错误)。
对于BSS内存,多个逻辑页面可能最初被复制写入同一个零值的物理页面。尽管根据Unix语义,您的内存是可读写的,但页表实际上具有只读映射。写入页面将导致页面错误,并且内核将在返回到故障指令的过程中,将该条目指向一个新的零值物理页面(然后将再次运行并成功)。
总之,这并不能直接回答你的问题,但可能是你实际想要的一部分。如果你想深入了解,那么可以查看实际的页表,但通常情况下你不需要这样做。smaps可以告诉您映射在内存中的大小。
请参见 /proc/pid/smaps中的pss是什么意思 以了解字段含义的详细信息。

顺便提一下,查看为什么64位虚拟地址比物理地址短4位(48位长)?以获取漂亮的四级页表格式图(以及2M / 1G大页面的适配方式)。


1
我写了一个简单的汇编程序来获取分段错误并在gdb中运行...据我所知,每个进程都有自己的页表,cr3寄存器指向该页表。现在我想亲自查看页表?在Linux中是否可能找到有关进程页表的信息?
操作系统维护页表。它们受到用户模式访问的保护(正如您试图做的那样)。
为了理解保护的工作原理,您需要了解处理器模式之间的区别(例如,内核和用户模式),以及处理器如何在这些模式之间转换。
然而,简而言之,尝试编写代码来检查页表就像你正在做的那样是一条死路。您最好从书籍中学习有关页表结构的知识,而不是尝试编写代码。我建议查看Intel手册。

https://software.intel.com/en-us/articles/intel-sdm

遗憾的是,这篇文章相当枯燥,而英特尔编写的处理器手册是我见过最糟糕的。我建议仅查看64位模式。英特尔的32位模式过于复杂。如果有关段的讨论,则正在阅读32位模式,可以忽略它。英特尔的文档从未指定地址是物理还是逻辑的。因此,您可能需要查看在线讲座以进行澄清。
为了补充这篇文章,您可以查看Linux源代码。https://github.com/torvalds/linux 总之,似乎您需要两个前提才能达到目标:(1)处理器模式;和(2)页表结构。

没有任何阻止你编写一个Linux内核模块,该模块可以为调用进程拍摄页面表的快照,并通过类似于IOCTL(或其他机制)的方式将其提供给用户进程。 - Michael Petch
但显然,这个人不具备那种能力或使用内核模式调试器的技能。 - user3344003

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接