2014-02-18 76 views
0

下面是程序:爲什麼mmap/dev/mem返回不同的地址?

#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 
+2

'man mem:mem是一個字符設備文件,它是計算機主內存的一個映像。「我猜這意味着你的程序要求OS將主內存的物理地址映射到虛擬內存中的某個地址你的過程的空間。 –

+0

爲什麼你認爲虛擬地址應該與物理地址相同? –

+0

@BasileStarynkevitch我只想確認返回的地址是否在我當前正在運行的程序的虛擬地址空間中,即使從'/ dev/mem'映射。我認爲是這樣。對於普通地址,我知道它在虛擬地址空間中。 – Amumu

回答

1

MMAP返回一個內存緩衝區,你可以訪問的地址:正因爲如此,它是一個虛擬地址,也因爲物理地址應該不可見用戶空間。事實上,當前的體系結構始終(但在啓動過程的最初幾秒內)就會啓用內存虛擬化。你只能在內核中看到物理地址,並且只能在明確使用物理內存的情況下才能看到;但你永遠不能直接訪問它們,你首先需要將它們映射到虛擬地址。

因此,您在程序中看到的是一個虛擬地址,該虛擬地址隨時間而有所不同。當您使用mmap時,Linux會在您的進程虛擬內存中選擇一個足夠大的虛擬內存區域,以滿足您請求的映射,並將物理內存映射到該區域。 Linux選擇哪個虛擬內存區域取決於可用性和其他因素,如地址空間佈局隨機化(http://en.wikipedia.org/wiki/Address_space_layout_randomization)。

相關問題