为什么mmap / dev / mem返回不同的地址?

时间:2014-02-18 04:41:36

标签: linux mmap

以下是该计划:

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/file.h>
#include <errno.h>

long* mapmem(off_t offset)
{
    int fd;
    long *ret;

    fd = open("/dev/mem", O_RDWR|O_SYNC);

    if (fd == -1) {
        perror("open");
        return NULL;
    }

    printf("offset (pageaddr) is: %ld\n", offset);

    ret = mmap(0, sizeof(long), PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
    if (ret == MAP_FAILED) {
        perror("mmap");
        ret = NULL;
    }

    printf("Return address is: %p\n", ret);

    if (close(fd) == -1)
        perror("close");

    return ret;
}

int main(int argc, char *argv[])
{
    long *mem = 0;
    volatile long *_mem = 0, dummy;
    long long int addr, offset, pageaddr;
    char *endpt;

    if (argc != 2) {
        fprintf(stderr, "Usage %s <addr>\n", argv[0]);
        return 1;
    }

    addr = strtoll(argv[1], &endpt, 16);
    offset = addr % sysconf(_SC_PAGE_SIZE);
    pageaddr = addr - offset;

    printf("addr is: %lld, offset: %lld, pageaddr: %lld\n", addr, offset, pageaddr);

    mem = mapmem(pageaddr);

    return 0;
}

为什么mmaped物理地址与我们传入的物理地址不同?或者地址是否返回映射到相应物理地址的虚拟地址?

我运行上述程序的输出:

 $ sudo ./test 0x12345
addr is: 74565, offset: 837, pageaddr: 73728
offset is: 73728
Return address is: 0x7f3081fc0000

1 个答案:

答案 0 :(得分:1)

Mmap返回您可以访问的内存缓冲区的地址:因此,它是一个虚拟地址,也是因为用户空间不应该看到物理地址。实际上,当前的体系结构总是(但在引导过程的最初几秒)在启用内存虚拟化的情况下运行。您只能在内核中看到物理地址,并且只有在您明确使用物理内存时才会看到;但你永远无法直接访问它们,首先需要将它们映射到虚拟地址。

您在程序中看到的内容因此是一个虚拟地址,不时会有所不同。当您使用mmap时,Linux会在进程的虚拟内存中选择一个空闲的虚拟内存区域,该区域足以容纳您请求的映射,并将物理内存映射到该区域。 Linux选择哪个虚拟内存区域取决于可用性以及地址空间布局随机化(http://en.wikipedia.org/wiki/Address_space_layout_randomization)等其他因素。