You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何mmap虚拟地址转物理地址始终为0?0x670有何特殊?

关于虚拟地址转物理地址的两个问题解答

让我来逐一分析你遇到的两个问题:

一、mmap映射文件后页面未找到的原因

你用mmap映射文件后调用vtop返回页面未找到,核心原因和Linux内存管理的特性相关,主要有以下几点:

  • 按需分页的懒加载机制:mmap创建映射时,内核并不会立刻把文件内容加载到物理内存,也不会生成对应的页表项——只有当你实际读写该映射内存的某个页面时,内核才会触发缺页中断,完成文件内容加载、物理页分配和页表更新。你的代码在mmap后直接调用vtop,此时虚拟地址对应的页表项还未建立,pagemap中的present位(第63位)为0,所以vtop判定页面未找到。

  • 权限配置的潜在冲突:你用O_RDONLY打开文件,但mmap的mprot设置了PROT_WRITE。虽然MAP_PRIVATE模式下写操作会触发写时复制(创建私有内存副本),但原文件只读的属性会让内核进一步延迟页表的建立,甚至在未实际访问时完全不分配物理页。

  • 验证方法:你可以在调用vtop前,尝试访问映射的内存(比如执行*(char*)addr = 'x';,MAP_PRIVATE模式下这个修改不会影响原文件),之后再调用vtop,此时应该能获取到有效的物理地址。

二、malloc分配内存得到物理地址0x670的特殊之处

首先要明确:物理地址由页帧号(PFN)和页内偏移组成,假设你的系统页面大小是4KB(最常见的配置),页内偏移占低12位(范围0~0xFFF)。

  • 0x670是低页帧号+页内偏移的组合:0x670的数值小于4096,说明它的低12位就是完整的页内偏移,而高地址部分(页帧号)为0——意味着这个物理地址属于系统的第0号物理页。

  • 第0号物理页的特殊性:在绝大多数Linux系统中,物理页0是内核保留的特殊页,通常用于存储BIOS/UEFI启动信息、内核初始数据结构等。你的malloc分配的内存映射到这个页,大概率是因为:

    • 你分配的是极小的内存块,malloc使用了进程初始堆的预留页,而该页恰好被内核映射到物理页0;
    • 如果是嵌入式或定制化系统,可能存在物理页0允许分配给用户进程的特殊配置(这种情况比较少见)。

你可以通过sysconf(_SC_PAGESIZE)确认系统页面大小,这会直接影响物理地址的拆分逻辑。


附上你的格式化代码供参考:

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h> // O_RDONLY
#include <string.h> // NULL is also defined in string.h, stdlib.h
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include "inttypes.h"

uint64_t vtop(uint64_t vaddr) {
    FILE *pagemap;
    uint64_t paddr = 0;
    unsigned long long int offset = (vaddr / sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
    uint64_t e;
    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));
                    printf(" paddr %lu \n", paddr);
                } else {
                    printf("page not found\n");
                }
            }
        }
        fclose(pagemap);
    }
    return paddr;
}

int main() {
    int oflag = O_RDONLY;
    const char *path = "file.json";
    const int fd = open(path, oflag);
    // use stat to find the file size
    struct stat stat;
    int ret = fstat(fd, &stat);
    int mflags = MAP_PRIVATE; // information about handling the mapped data
    int mprot = PROT_READ|PROT_WRITE; // access permissions to the data being mapped
    size_t size = stat.st_size;
    void *addr = mmap(NULL, size, mprot, mflags, fd, 0);
    printf("virtual addres is %p\n", addr);
    printf("physical addres is %ld\n", vtop((uint64_t)addr));
    return 0;
}

内容的提问来源于stack exchange,提问作者BODDU MANOHAR REDDY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:54:58