2014-02-18 19 views
1

我使用的是在intel i7處理器上編譯的Opensuse 13.1上的程序。我在qemu(虛擬)環境中編譯了相同的程序,以模擬帶有ARM處理器的OpenSuse 13.1。這行代碼:mmap intel(i7)和arm上的不同行爲?

rvp = mmap(rvp, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fildes, 0); 

給我一個指向Ram內存的指針。但是這個內存的大小在intel和arm之間是不一樣的:在intel上,這個內存的大小是「長度」,與fildes所指向的文件的大小無關,不同的是intel和arm之間的內存大小不同:

在ARM上,大小(大約)是由fildes指向的文件的大小,並且忽略了大小大於fildes的事實。

我想擁有的不僅僅是文件分配更多的內存...

編輯:我試圖解決這個問題有兩個連續調用......沒有成功:

rvp = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 
    unsigned int i; 
    for (i = 0; i < length; i += 5000) 
      printf("acces buffer at %i --> %u\n", i, rvp[i]); 
    rvp = mmap(rvp, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fildes, 0); 
    for (i = 0; i < length; i += 5000) 
      printf("acces buffer at %i --> %u\n", i, rvp[i]); 

爲輸出I得到:

access buffer at 0 --> 0 
... 
access buffer at 90000 -> 0 
access buffer at 0 --> 0 
... 
access buffer at 85000 --> 0 
Segmentation fault... 

回答

1

official specification of mmap是不是在這一點上非常清楚,但請注意句子:

[存儲器]參考文獻[,]起始於pa並持續len字節[,]到物體的端部以下整頁的地址範圍內應導致遞送SIGBUS的信號。

我停留在一些逗號,並添加着重說明一點更清楚:如果你mmap區域比備份它的文件越大,OS是應該如果您嘗試訪問火信號如果超過頁面邊界(此許可證只是因爲硬件不允許操作系統在可訪問和不可訪問的內存之間設置不落在頁面邊界之間的邊界)(SIGBUS和現在許多操作系統都認爲它們是可以互換的)。

您的「兩次連續呼叫」方式正處於正確的軌道,但它不起作用,因爲您在兩次呼叫中使用了相同的長度。如果您在第二次調用中指定了文件的大小,它將會起作用。您可以通過系統調用fstat來檢索文件的實際大小。如果文件是大於您想要的分配長度的,則需要小心謹慎。這是我會怎麼寫:

char *map_file(int fd, size_t len) 
{ 
    struct stat st; 
    char *rv; 

    if (fstat(fd, &st)) 
     return report_error("fstat"); 

    if (st.st_size >= (off_t) len) { 
     /* If the file is at least as big as expected, just map the 
      chunk we want. */ 
     rv = mmap(0, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 
     if (rv == MAP_FAILED) 
      return report_error("mmap"); 

    } else { 
     /* Otherwise, we must allocate anonymous memory to fill in the gap. */ 
     char *anon; 
     anon = mmap(0, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); 
     if (anon == MAP_FAILED) 
      return report_error("mmap (anon)"); 

     rv = mmap(anon, (size_t) st.st_size, PROT_READ|PROT_WRITE, 
        MAP_PRIVATE|MAP_FIXED, fd, 0); 
     if (rv == MAP_FAILED) { 
      int save_errno = errno; 
      (void) munmap(anon, len); 
      errno = save_errno; 
      return report_error("mmap"); 
     } 
    } 
    return rv; 
} 

根據您的更大的目標,但也可以代替有意義放大文件,如果它不是像預期的那樣大,使用ftruncate

char *map_file(int fd, size_t len) 
{ 
    struct stat st; 
    char *rv; 

    if (fstat(fd, &st)) 
     return report_error("fstat"); 
    /* if the file isn't as big as expected, make it bigger */ 
    if (st.st_size < (off_t) len) 
     if (ftruncate(fd, (off_t) len)) 
      return report_error("ftruncate"); 

    rv = mmap(0, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 
    if (rv == MAP_FAILED) 
     return report_error("mmap"); 
    return rv; 
} 

,不過也許,如果這是你想要的內容,你將使用MAP_SHARED而不是MAP_PRIVATE

(注:該功能report_error,未顯示,記錄錯誤信息,然後返回NULL)。

+0

正如我在我的問題的編輯(1小時前)注意;我試過你的第二個建議:兩個連續的mmap調用......但第二個再次將可訪問內存截斷爲我正在閱讀的文件的大小... –

+0

感謝您的幫助,但我已經得到了我想要的替代方案方法: rvp = malloc(length); \t unsigned int nread = read(fildes,rvp,length); –

+1

@ChrisMaes是的,發生這種情況是因爲在兩次調用mmap時使用了相同的「length」值。如果你在第二次調用中指定了文件*的大小(由'fstat'返回)作爲映射長度,它就會起作用。 – zwol

0

好亂搞了一段時間後,我有答案:

  • mmap應該用來遍歷一個文件,所以它不是分配更多的內存比我們想要訪問的文件的大小
  • 我偶然訪問的文件有不同的大小在我的英特爾i7系統上,所以這就是它似乎在intel上工作的原因。

- >解決方案:使用malloc分配大小的「長度」 momory,然後使用「Read」讀取文件...