C 在Linux中,如何从用户空间查找变量的物理地址?

C 在Linux中,如何从用户空间查找变量的物理地址?,c,linux,C,Linux,我想找到在用户空间进程中定义的变量的物理地址?有没有办法使用root权限执行此操作?首先,为什么要执行此操作?现代虚拟机系统的目的是使应用程序程序员从复杂的物理内存布局中解脱出来。让他们各自拥有统一的地址空间,让他们的生活更轻松 如果您确实想这样做,您几乎肯定需要使用内核模块。以正常方式获取变量的虚拟地址,使用该地址索引到进程页表中,并读取找到的值(帧的物理地址)。然后添加页偏移量以获得完整的物理地址。注意:启用分页时,您将无法使用此地址 (如果幸运的话,您可以从/proc文件系统中获得VM区域

我想找到在用户空间进程中定义的变量的物理地址?有没有办法使用root权限执行此操作?

首先,为什么要执行此操作?现代虚拟机系统的目的是使应用程序程序员从复杂的物理内存布局中解脱出来。让他们各自拥有统一的地址空间,让他们的生活更轻松

如果您确实想这样做,您几乎肯定需要使用内核模块。以正常方式获取变量的虚拟地址,使用该地址索引到进程页表中,并读取找到的值(帧的物理地址)。然后添加页偏移量以获得完整的物理地址。注意:启用分页时,您将无法使用此地址


(如果幸运的话,您可以从/proc文件系统中获得VM区域的帧地址,因此不需要编写内核模块。)

正如前面部分回答的那样,普通程序不需要担心物理地址,因为它们在虚拟地址空间中运行非常方便。此外,并非每个虚拟地址都有物理地址,这些地址可能属于映射文件或交换的页面。然而,有时看到这种映射可能会很有趣,即使是在userland中

为此,Linux内核通过
/proc
中的一组文件公开其到userland的映射。可以找到文档。小结:

  • /proc/$pid/maps
    提供虚拟地址映射列表以及其他信息,例如映射文件的对应文件
  • /proc/$pid/pagemap
    提供有关每个映射页面的更多信息,包括物理地址(如果存在)
  • 提供一个C程序,该程序使用此接口转储所有正在运行的进程的映射,并解释其作用。

    #包括“stdio.h”
    
    #include "stdio.h"
    #include "unistd.h"
    #include "inttypes.h"
    
    uintptr_t vtop(uintptr_t vaddr) {
        FILE *pagemap;
        intptr_t paddr = 0;
        int offset = (vaddr / sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
        uint64_t e;
    
        // https://www.kernel.org/doc/Documentation/vm/pagemap.txt
        if ((pagemap = fopen("/proc/self/pagemap", "r"))) {
            if (lseek(fileno(pagemap), offset, SEEK_SET) == offset) {
                if (fread(&e, sizeof(uint64_t), 1, pagemap)) {
                    if (e & (1ULL << 63)) { // page present ?
                        paddr = e & ((1ULL << 54) - 1); // pfn mask
                        paddr = paddr * sysconf(_SC_PAGESIZE);
                        // add offset within page
                        paddr = paddr | (vaddr & (sysconf(_SC_PAGESIZE) - 1));
                    }   
                }   
            }   
            fclose(pagemap);
        }   
    
        return paddr;
    }   
    
    #包括“unistd.h” #包括“inttypes.h” uintptr\u t vtop(uintptr\u t vaddr){ 文件*页面地图; intptr_t paddr=0; int offset=(vaddr/sysconf(_SC_PAGESIZE))*sizeof(uint64_t); uint64_t e; // https://www.kernel.org/doc/Documentation/vm/pagemap.txt if((pagemap=fopen(“/proc/self/pagemap”,“r”)){ if(lseek(fileno(pagemap)、offset、SEEK\u SET)=offset){ if(fread&e,sizeof(uint64_t),1页地图)){
    如果(e&(1ULL…),除非将页锁定到内存中,否则该物理地址可能随时更改。您不需要编写内核模块:正如其他示例所解释的,这已经通过
    /proc/$pid/pagemap
    公开了。在NUMA体系结构中,了解变量的物理地址可能会很有趣“您为什么要这样做?”这不是/dev/mem的答案吗?下面是一些测试示例中的相关信息: