簡體   English   中英

mmap 和指令/數據緩存一致性:為什么我們可以復制和運行共享庫?

[英]mmap and instruction / data cache coherency: Why can we copy and run shared libraries?

在 ARM 上,在向 memory 寫入指令后,在執行指令之前需要一個 memory 屏障 具體清理數據緩存,使指令緩存無效,然后在將執行代碼的 CPU 上執行指令同步屏障 ( ISB )。

可以使用cp復制可執行文件或共享庫,然后在沒有顯式 memory 障礙的情況下執行。 這相當於:

  1. 打開文件。
  2. 使用write文件。
  3. 關閉文件。
  4. 打開文件。
  5. Map 帶 PROT_READ 的mmap文件PROT_READ | PROT_EXEC PROT_READ | PROT_EXEC
  6. 執行代碼。

同樣,大概可以使用mmap寫入文件:

  1. 打開文件。
  2. Map 帶 PROT_READ 的mmap文件PROT_READ | PROT_WRITE PROT_READ | PROT_WRITE一個MAP_SHARED
  3. 使用正常的 memory 寫入寫入。
  4. 使用munmap文件。
  5. 關閉文件。
  6. 打開文件。
  7. Map 帶 PROT_READ 的mmap文件PROT_READ | PROT_EXEC PROT_READ | PROT_EXEC
  8. 執行代碼。

那么在上述步驟中,必要的緩存操作隱藏在哪里? 它是在munmap還是在mmap中? 假設沒有磁盤訪問。

據推測,如果在寫入和執行之間既沒有調用munmap也沒有調用mmap ,則需要通過調用__clear_cache顯式緩存同步,但這可以通過任一映射來完成嗎?

它是由mmap系統調用完成的。 當您 map 個頁面可執行時,kernel 必須確保當系統調用返回時,這些頁面已准備好執行。

為了完成它的工作, mmap必須更新頁表。 在 function __set_pte_at中,我從它的名字推測它在頁表條目更新時被調用,我們有一個對__sync_icache_dcache的調用,如果你追蹤它,它最終應該執行相關的icdc指令。

這就isb了。 它的目的是成為一個“上下文同步事件”(請參閱“體系結構參考手冊”下的“數據和指令訪問之間的同步和一致性問題”),這是刷新任何預取指令所需要的。 但是從 kernel 返回到用戶空間的eret指令已經算作這樣一個事件,所以它會自動處理。

如果您將第二個序列的步驟 4-7 替換為對mprotect的調用,以簡單地對已經存在的 memory 設置執行權限,則會發生同樣的事情。

munmap的情況下,實際上不需要緩存刷新。 它將取消映射這些頁面並刷新 TLB,並且它像以前一樣從eret獲得一個免費的上下文同步事件。 這意味着任何未來在該地址執行的嘗試都將發生頁面錯誤,因此 icache 行中實際有哪些位並不重要。

據我所知,唯一需要在用戶空間中進行緩存刷新和isb的情況是,如果您想將代碼寫入 memory 的某個塊,然后立即分支到那里,就像 JIT 編譯器可能做的那樣,沒有mmap/mprotect 之間的調用。 這可以通過PROT_WRITE | PROT_EXEC來完成。 PROT_WRITE | PROT_EXEC映射(雖然我不確定這些天是否所有內核都允許這樣做); 或者通過“別名化”——將相同的物理地址 memory 映射到兩個不同的虛擬地址,具有不同的權限。 請參閱AArch64 memory 多重映射地址上的同步操作和 ARM 上的 JIT/自修改代碼的同步緩存

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM