Chip123 科技應用創新平台

標題: Linux 下的 mmap() [打印本頁]

作者: gogojesse    時間: 2008-8-4 03:17 PM
標題: Linux 下的 mmap()
以下希望藉由一個實際可以在user mode運作的API, mmap()
) ]8 O/ v  y1 V& b. y6 [& j# a讓programmer能夠感受到MMU這個硬體在系統中所扮演的角色
' r- L3 K; _3 R
. h( A. T2 Z7 C  M4 b, R寫linux底下driver的人常常會看到這個東西 mmap()$ [4 i* _: M. K6 w& n. G$ ]7 {% Y
在user mode program裡面假如你用open( "/dev/xxx", ... )
/ {8 D1 W: u4 a+ U- ^去打開一個檔案系統的節點4 x& ~4 t  N# D
就可以用這個file descriptor的handler對他做mmap()的動作6 M2 T" u0 h. s
那這個mmap究竟背後藏了哪些意義?
, a9 Z, L& Q9 n8 [; a# T又有哪些硬體在工作才能達成?% F7 m; f# K: c, @) i2 K6 U, t
" I- ~) O" M8 o, D+ n( ^8 N
mmap的字面意義是memory map7 |' y+ D; P0 T: h; x
顧名思義就是『記憶體映對』1 j! w  u8 g- \5 a, G0 {4 W7 A$ a
簡單來看,就是用mmap()幫你做對映
4 F2 g" [3 i' k; F, q/ C5 E6 h對映好了,對著傳回的address作存取
* E* w- k( {' E; h3 Z就等於對檔案作存取
. j& V; k2 O1 P  d, \* Y  u. j' Z, s8 Z$ W  D
1. 首先來看mmap()一般是怎麼被使用的 (這邊可以先不用管要傳什麼參數)' I, @4 U+ ^6 H
int fd, mapSize, offset, start;* u! D! c$ a1 l: q) s- O! ~: h( k
char* ptr;
9 N* g# `) F1 t/ {2 Y8 s( X" U2 h( o6 h% [1 s/ x) ^  \- w' G* |
mapSize = 0x1000; /* 希望映對多大的區塊 */+ q! d$ c% d$ N- D& t* T7 @7 X
offset = 0;' `: [! e, m; ?+ G3 Y3 z
start = 0;4 f( T) [; U7 {; R
/* 打開檔案 */
. s' O* K# d5 \, e' Kfd = open( "/home/tester/a.txt", O_RDWR | O_SYNC );  $ T( j0 Q3 Y' E
/* 作mmap動作,取得一個對應好的address */6 a4 V: o6 x9 z5 U6 ]
ptr = mmap( 0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset );6 A: x7 L: b2 c, I9 d+ P

- h5 a: V$ L% s, e4 R假如一切順利的話 ptr 就會接到一個address,這個address會對應到a.txt這個檔案所在的起始位置,# _3 q/ f: {+ X' h4 p
如果這時候我們用 strcpy( ptr, "hello!!" );
) Q7 C+ I$ }0 d/ b9 e. p6 ^
. a* m3 O1 m( }& w$ fa.txt裡面就會被寫入"hello!!"的字串$ K/ n; F4 Y9 w5 s( ]! I3 ?2 `

5 s# _( e! r: Z( i! c2. 假如我寫了兩個程式,都是用mmap()到同一個a.txt,程式會不會出問題? 如果不會,那我既然對同一個檔案作mmap(),那我拿到的ptr不是應該是相同的address?
, k. v- ]8 R4 W$ r0 U
3 v5 t4 c4 @4 [5 T7 m. A7 N答案是:兩個程式可以正常執行,但是這兩個回傳的address不一定相同。
" D/ \0 r/ t4 [0 h7 H* zwhy?  為什麼對同一個檔案寫入,也都做同樣的mmap()動作,甚至傳的參數值都相同。
- ^% f  V' c5 u* ?/ O. L, J. w為什麼拿到的address可以是不同的? 更奇怪的是,位址不同,還是同樣寫到同一個檔案上頭。* Y% o4 Y+ q' k$ x  Y2 l9 P% j- i
' L( m. G  y! n7 C  O
假如這一切都是合理的,那表示雖然這兩個位址不一定相同,其實都是對映同一個地方,表示有某種東西記錄著這個對應關係。而且,兩個program的ptr有時候會一樣,可是有時候又不一樣。唯一個可能是表示兩個process各自保有這些映對的方式。; H. ?+ a4 J+ V% h( [$ E7 I

% V8 r9 `4 J! F2 g; s) r2 t! e! E3. 假設我只寫一個程式,但是mmap()兩次到同一個檔案上呢? 得到的兩個ptr會一樣嗎?) m) t- J, q4 B2 `  X2 Q/ V4 V

0 R' t2 q; f* u答案是:這個兩ptr還是不一樣的,兩個不同program 跑出來的mmap()結果不同也就算了,同一個program呼叫兩次mmap()跑出來的ptr也不一樣,但又都對映著相同的檔案a.txt。因此我們又可以猜測這一個mmap()是動態的,動態去產生一種應對的方式,將傳回的ptr對應到真正的檔案a.txt去,所以同一個process可以對應好幾次,好幾次都用不同的address去對映到相同的檔案上去。2 p$ {  B7 F: a9 r

6 I! V7 P6 b/ o# _綜合上面三種現象,我們合理的懷疑系統裡面存在了一個東西,它讓每一個process可以動態地記錄address的對應關係。並且,每個process各自擁有這個table,而這些對映的關係會動態的反應在這個table當中。
6 G3 y, A$ ~7 Q+ S  m3 k# \3 h9 p. ]( l5 c1 e! @3 W& x# F+ t
回想一下一個系統有誰會做這種工作,不就是MMU所擔任的重要角色嗎?# E& H0 R3 E  j4 A& h4 ^
每個process各自擁有自己的 page table 當他呼叫mmap()的時候,系統就動態地幫她在這個table上寫上紀錄著" R8 D. l1 P* e5 X4 Y! v% p# d$ ^
+ `5 J+ |5 }. ]) l* Q, K3 L3 z3 e
[processA-pgtable]/ ?+ i+ c" J2 p" g$ ~# u
0x00008000 ptr1 --> a.txt
) t( h8 e; w* [) J0xa0008000 ptr2 --> a.txt3 Q, R  l0 i" R7 b9 s, E

4 s% h: l* C+ y. n. m[processB-pgtable]
( {8 f' |/ v; _% [6 F0x00008000 ptr1 --> a.txt
% @! R/ T' w8 a& g% l+ |& e# S. g+ N3 r# V0xb0008000 ptr2 --> a.txt) T6 N; `% G1 B' q( i7 l3 w! V
: A5 G5 L# W/ j1 `" x
這樣ptr1, ptr2都可以對應到相同的地方,又因為各個process又有不同table,所以有時候ptr1有可能會相同。
8 f& n4 v. v% q% t如此一來,我們終於可以合理的解釋我們觀察mmap()為何對映出來的address會有如此的表現。原來就是MMU被加入,而且OS又被設計成每個process都會各自擁有一個page table來記錄他對記憶體如何解讀。
作者: gogojesse    時間: 2008-8-4 03:20 PM
略寫下兩個延伸的想像問題( H. t( }- |$ e2 h% ?" s$ B
或許有人有興趣可以回答或是深入研究
3 F+ `) W& L8 J7 e% ^; x+ P
# `+ ?9 v; `) b  }2 [- D[延伸想像]
6 W* y. P/ c9 c! A( e* ?我們又可以仔細想想假如每個process都有各自的table8 t( p( u* _* X' [) s8 ]
那麼從一個process做context switch到另外一個process的時候
, e7 {1 E. q, x' W! l+ E# h. X代表所用的table是不同的
+ _. S3 O3 T0 F' q4 K8 Bwow!!!可想而知系統是很忙碌的,1秒鐘context switch 10次就要替mmu切換10次page table的mmap方式
# a' I" Y& Z$ j% G) e8 ~不然process用錯page table可能就會指到錯誤的位址
" y, d" e- h# B: ]9 j& w- Y5 p& g那OS到底怎麼切換這些page table?' Y- l& [; Q3 W, a$ T
kernel和user program的page table有什麼不同??
. X* f/ ~* U0 g* I4 R/ d! q( @% A% r% q1 J
[延伸想像]
$ \5 ]7 p# ~( x假如我們可以修改page table的權利,是不是就可以寫出一個可以偷取別的process data的東西?因為我可以偷偷的map過去他的address space讀取它的資料??    有辦法嗎? 還是根本沒機會?




歡迎光臨 Chip123 科技應用創新平台 (http://chip123.com/) Powered by Discuz! X3.2