以下是该计划:
#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
答案 0 :(得分:1)
Mmap返回您可以访问的内存缓冲区的地址:因此,它是一个虚拟地址,也是因为用户空间不应该看到物理地址。实际上,当前的体系结构总是(但在引导过程的最初几秒)在启用内存虚拟化的情况下运行。您只能在内核中看到物理地址,并且只有在您明确使用物理内存时才会看到;但你永远无法直接访问它们,首先需要将它们映射到虚拟地址。
您在程序中看到的内容因此是一个虚拟地址,不时会有所不同。当您使用mmap时,Linux会在进程的虚拟内存中选择一个空闲的虚拟内存区域,该区域足以容纳您请求的映射,并将物理内存映射到该区域。 Linux选择哪个虚拟内存区域取决于可用性以及地址空间布局随机化(http://en.wikipedia.org/wiki/Address_space_layout_randomization)等其他因素。