Chip123 科技應用創新平台

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

作者: gogojesse    時間: 2008-8-4 03:17 PM
標題: Linux 下的 mmap()
以下希望藉由一個實際可以在user mode運作的API, mmap()
3 p9 v" V( S0 N! U讓programmer能夠感受到MMU這個硬體在系統中所扮演的角色
- G1 A* ^' C9 ^3 y: [! L  d) n9 ~8 E  ~
寫linux底下driver的人常常會看到這個東西 mmap()4 [9 C( f6 v) x$ @" h- g9 m) ~) q
在user mode program裡面假如你用open( "/dev/xxx", ... )7 B' q$ A$ W, s
去打開一個檔案系統的節點
' s8 W+ U1 x* q" |( ?就可以用這個file descriptor的handler對他做mmap()的動作
6 e/ {2 z( k; H8 U9 q1 F那這個mmap究竟背後藏了哪些意義?
& t+ ]( n8 Z* q. |8 h% k又有哪些硬體在工作才能達成?
+ H* `" M4 s2 ?; n. f; v0 t, B* H0 j% Q1 W
mmap的字面意義是memory map7 k( H' s0 s8 s& b
顧名思義就是『記憶體映對』2 ^6 d  @+ t! C) |/ n1 d
簡單來看,就是用mmap()幫你做對映
# m) N- g1 [6 A7 {! O5 c對映好了,對著傳回的address作存取3 a6 R' U, N% M7 {
就等於對檔案作存取1 y, I8 Z" M3 J2 m

! ~6 O" G* y! a4 ^' S* D" y1. 首先來看mmap()一般是怎麼被使用的 (這邊可以先不用管要傳什麼參數)
, _( F) p6 o8 q3 p$ _9 x6 Mint fd, mapSize, offset, start;
+ w* ^! l. r- _- jchar* ptr;
( W( X* i! S: N# K- G  B7 a$ m; a- K  g
mapSize = 0x1000; /* 希望映對多大的區塊 */
# J/ A6 F  Y- t  xoffset = 0;
; V; T0 E, H, x: [) wstart = 0;
' I5 ~3 \. d3 k- J" f$ E/* 打開檔案 */% \0 S( z) U$ j" J2 f) I  C$ }' U
fd = open( "/home/tester/a.txt", O_RDWR | O_SYNC );  # N; Y! f$ Z' `1 `5 W& E
/* 作mmap動作,取得一個對應好的address */; G& Z3 ~1 ]' _  n7 X% K
ptr = mmap( 0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset );& z# X* B' q5 f9 ?' A1 u( p5 i- J

4 p* l6 }+ E  h# w: I假如一切順利的話 ptr 就會接到一個address,這個address會對應到a.txt這個檔案所在的起始位置,5 u4 g5 X3 }) S: \
如果這時候我們用 strcpy( ptr, "hello!!" );
2 V2 y( K0 Q* O1 Y1 {- V: c7 W5 H+ s4 B7 c: d' X  f
a.txt裡面就會被寫入"hello!!"的字串
; T6 u2 ^3 }$ w8 \9 b. t5 a  B; r. V, ^/ V6 O/ v
2. 假如我寫了兩個程式,都是用mmap()到同一個a.txt,程式會不會出問題? 如果不會,那我既然對同一個檔案作mmap(),那我拿到的ptr不是應該是相同的address?
$ T0 J9 Q: j/ e! x
) m" u% z" t' m* O6 X答案是:兩個程式可以正常執行,但是這兩個回傳的address不一定相同。
! K8 E( s  z2 L8 [' Twhy?  為什麼對同一個檔案寫入,也都做同樣的mmap()動作,甚至傳的參數值都相同。) w/ H2 h" g9 @- ]& u
為什麼拿到的address可以是不同的? 更奇怪的是,位址不同,還是同樣寫到同一個檔案上頭。
3 _9 C7 [. Z/ |) h
) i# L, X' W9 N7 T. r. e假如這一切都是合理的,那表示雖然這兩個位址不一定相同,其實都是對映同一個地方,表示有某種東西記錄著這個對應關係。而且,兩個program的ptr有時候會一樣,可是有時候又不一樣。唯一個可能是表示兩個process各自保有這些映對的方式。
, R5 H- p# _6 _* t
# k0 F; U: f# [! a4 M7 I3. 假設我只寫一個程式,但是mmap()兩次到同一個檔案上呢? 得到的兩個ptr會一樣嗎?
0 H3 U* u/ ?- o8 g( i" b( C$ }8 D$ z
答案是:這個兩ptr還是不一樣的,兩個不同program 跑出來的mmap()結果不同也就算了,同一個program呼叫兩次mmap()跑出來的ptr也不一樣,但又都對映著相同的檔案a.txt。因此我們又可以猜測這一個mmap()是動態的,動態去產生一種應對的方式,將傳回的ptr對應到真正的檔案a.txt去,所以同一個process可以對應好幾次,好幾次都用不同的address去對映到相同的檔案上去。+ `% u+ I% M' B& f, }4 `( ]

/ E3 M# [' x7 P' U1 ?綜合上面三種現象,我們合理的懷疑系統裡面存在了一個東西,它讓每一個process可以動態地記錄address的對應關係。並且,每個process各自擁有這個table,而這些對映的關係會動態的反應在這個table當中。
4 N0 J2 H6 _5 o* |; l. K+ B8 a2 G5 J; y6 A. r; l& J
回想一下一個系統有誰會做這種工作,不就是MMU所擔任的重要角色嗎?6 i- ^% z5 J0 }
每個process各自擁有自己的 page table 當他呼叫mmap()的時候,系統就動態地幫她在這個table上寫上紀錄著: x" X: Z1 i5 p- r; ?

$ z# T* e7 c1 m[processA-pgtable]
, a2 _: t5 D- H0x00008000 ptr1 --> a.txt
# f1 H$ P7 a" R; v2 k0xa0008000 ptr2 --> a.txt! @+ M' X. U  V# [
) z" L3 U- r% s$ t1 {
[processB-pgtable], k& ^) \0 ~/ E' e# u
0x00008000 ptr1 --> a.txt4 \0 _; N, X8 A8 ?- j, [
0xb0008000 ptr2 --> a.txt1 |; m  m9 v! W8 M& H/ W
) j7 U: H4 Z  k8 D) I- O
這樣ptr1, ptr2都可以對應到相同的地方,又因為各個process又有不同table,所以有時候ptr1有可能會相同。
' r, Q" C6 x; g' c  p, X如此一來,我們終於可以合理的解釋我們觀察mmap()為何對映出來的address會有如此的表現。原來就是MMU被加入,而且OS又被設計成每個process都會各自擁有一個page table來記錄他對記憶體如何解讀。
作者: gogojesse    時間: 2008-8-4 03:20 PM
略寫下兩個延伸的想像問題; n) X2 ~' c: z
或許有人有興趣可以回答或是深入研究8 H9 f! a4 r" a' v
2 g1 E0 v1 c2 I  ]* b
[延伸想像]
. b' `. Q$ ^5 U% ?$ s6 F" g我們又可以仔細想想假如每個process都有各自的table% c8 J# C( V, b8 |8 v
那麼從一個process做context switch到另外一個process的時候8 a1 @  |' u8 S0 x3 f5 V
代表所用的table是不同的
  z) S  H$ b$ i6 cwow!!!可想而知系統是很忙碌的,1秒鐘context switch 10次就要替mmu切換10次page table的mmap方式& a) M! L4 B5 _1 l, X  D( S) ^- E0 x3 M
不然process用錯page table可能就會指到錯誤的位址. \1 n/ M( z, i! S  d2 r& Z! S9 A% Y
那OS到底怎麼切換這些page table?! v: m. D: X3 s7 i! L8 m) B" m
kernel和user program的page table有什麼不同??
" J) S0 P  x( f: _  ?7 N( z
! m, j# e7 a; l3 D* @* u[延伸想像]! P: ^4 E# Y8 ]* E0 I
假如我們可以修改page table的權利,是不是就可以寫出一個可以偷取別的process data的東西?因為我可以偷偷的map過去他的address space讀取它的資料??    有辦法嗎? 還是根本沒機會?




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