C语言 如何从Linux中的用户空间找到变量的物理地址?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2440385/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:51:18  来源:igfitidea点击:

How to find the physical address of a variable from user-space in Linux?

clinux

提问by Sandip

I want to find the physical address of a variable defined in a user-space process? Is there any way to do it using root privileges?

我想找到在用户空间进程中定义的变量的物理地址?有没有办法使用root权限来做到这一点?

采纳答案by PinkyNoBrain

First, why would you want to do this? The purpose of modern VM systems is to remove the application programmer from the complexity of physocal memory layout. Gving them each their own uniform address space to make their life easyer.

首先,你为什么要这样做?现代 VM 系统的目的是将应用程序程序员从物理内存布局的复杂性中移除。给他们每个人自己统一的地址空间,让他们的生活更轻松。

If you did want to do this you would almost certanly need to use a kernel module. Get the virtual address of the variable in the normal way, use this to index into the processes page tables and read the value you find(the physical address of the frame). Then add the page offset to get the complete physical address. Note you wont be able to use this address while paging is enabled.

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

(If your lucky you may be able to get the frame address of a VM region from the /proc file system and thus wouldnt require to write a kernel module.)

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

回答by ingomueller.net

As partially answered before, normal programs should not need to worry about physical addresses as they run in a virtual address space with all its conveniences. Furthermore, not every virtual address has a physical address, the may belong to mapped files or swapped pages. However, sometimes it may be interesting to see this mapping, even in userland.

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

For this purpose, the Linux kernel exposes its mapping to userland through a set of files in the /proc. The documentation can be found here. Short summary:

为此,Linux 内核通过/proc. 文档可以在这里找到。简短的摘要:

  1. /proc/$pid/mapsprovides a list of mappings of virtual addresses together with additional information, such as the corresponding file for mapped files.
  2. /proc/$pid/pagemapprovides more information about each mapped page, including the physical address if it exists.
  1. /proc/$pid/maps提供虚拟地址的映射列表以及附加信息,例如映射文件的相应文件。
  2. /proc/$pid/pagemap提供有关每个映射页面的更多信息,包括物理地址(如果存在)。

This websiteprovides a C program that dumps the mappings of all running processes using this interface and an explanation of what it does.

这个网站提供了一个 C 程序,它使用这个接口转储所有正在运行的进程的映射,并解释它的作用。

回答by auselen

#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;
}