![进程中变量的物理地址](https://linux22.com/image/133818/%E8%BF%9B%E7%A8%8B%E4%B8%AD%E5%8F%98%E9%87%8F%E7%9A%84%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80.png)
当我们使用系统调用创建子进程时fork()
,父进程的地址空间被复制到子进程。下面的代码清楚地演示了这一点。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void){
int *mem = (int*)malloc( sizeof(int) * 1 );
pid_t pid = fork();
if( pid == 0 ){ // child process
printf("Child address = %ld\n", mem);
}
else{ // parent process
printf("Parent address = %ld\n", mem);
}
return 0;
}
然而,这是虚拟地址空间。也就是说,这段代码打印的地址是虚拟地址。
我想知道是否有机会通过虚拟地址获得物理地址?
我认为有一个基址寄存器存储正在运行的进程的起始物理地址。如果我将此虚拟地址与基址寄存器的值相加,我可以找到该变量的物理地址。这是真的 ?
答案1
是的,进程本身直接看到的只是虚拟地址。
在通常的分页系统上,没有“基址寄存器”,因为虚拟到物理地址的映射是按页进行的,不需要按顺序排列。 (例如,您可以在物理页 4563 处设置虚拟页 1,但在物理页 2413 处设置虚拟页 2。)请参见例如上的图像页表上的维基百科页面。
我不认为进程可以直接访问它的页表,但 Linux 似乎通过.内核文档位于
/proc/<pid>/pagemap
Documentation/vm/pagemap.txt
。阅读页面地图时还有另一个问题:查看进程的页表。
答案2
无法保证特定的虚拟地址映射到唯一的物理地址。不保证特定的虚拟地址映射到任何实际地址。无法保证虚拟地址和某个物理地址之间的任何映射在任何有趣的时间长度内都保持一致。
所以,你的问题确实没有反映虚拟内存的工作方式。您确实在虚拟地址方面进行工作。然而,内核可以随意修改 MMU 之类的东西,只要它想改变什么点在哪里,所以即使你知道一些物理地址,你也永远不能用它来做任何事情。即使您从控制进程的可见内核中获得了足够的信息来推断某些内容可能在哪里,您也无法确定您不在某个虚拟机中,并且在您所掌握的内容之上还有一个完整的其他间接层看——这样你认为的物理地址实际上只是某些虚拟机主机软件内的虚拟地址。
您的虚拟地址被分组为页面。 MMU 使用一些页表进行编程,因此它具有一些映射。如果 MMU 内有一个带有偏移量的简单寄存器,则无法将其从 MMU 中取出,因为它不是属于 ISA 一部分的 CPU 寄存器。 (在较旧的机器上,MMU 是与 CPU 完全独立的物理芯片。)您唯一能做的就是阅读适合您的架构的一堆 MMU 文档,并访问内核的页表配置并逐步完成这些内容“模拟”MMU 对某些输入的行为。 CPU 本身甚至(明显/直接)不知道间接寻址。
那么,你真正想做的是什么?