以下討論的內容是以i386平台為基礎的 Linux將4G的地址劃分為用戶空間和內核空間兩部分。在Linux內核的低版本中(2。0。X),通常0-3G為用戶空間,3G-4G為內核空間。這個分界點是可以可以改動的。 正是這個分界點的存在,限制了Linux可用的最大內存為2G.而且要通過重編內核,調整這個分界點才能達到。 實際上還可以有更好的方法來解決這個問題。由於內核空間與用戶空間互不重合,所以可以用段機制提供的保護功能來保護內核級代碼。以下為2。0。X的部分代碼: /usr/src/linux/arch/i386/kernel/entry.S A: .quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 * B: .quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 * C: .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 * D: .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 * A,B為內核代碼段及數據段的描述符。C,D為用戶代碼及數據段的描述符從以上,我們可以清楚的看到A,B的特權級為0,而C,D的特權級為3。當內核存取用戶空間的內容時,他借助於fs寄存器,同過將FS寄存器的內容置為D來達到訪問用戶空間的目的。 2。2。X版的 內核對此進行了改動。這樣內核空間擴張到了4G,所以可以直接進行拷貝了 .quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 * .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 * .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 * .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 * 從表面上看內核的基地址變為了0,但實際上,內核通常仍在虛址3G以上。其中奧妙在與 不同的連接描述文件: 2。2。X: . = 0xC0000000 + 0x100000; _text = .; /* Text and read-only data */ .text : { *(.text) *(.fixup) *(.gnu.warning) } = 0x9090 .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) } .kstrtab : { *(.kstrtab) } 。。。。 2。0。X: faint,2。0內核被刪除了。 :( 不管怎莫說,請大家相信我,2。0。X的起址為0x100000。這樣一來,二者就相等了。都是0xC0000000 + 0x100000 用戶空間在2。2。X中從直觀上變為0-4G,讓人迷惑:其不是可以直接訪問內核了?其實不然, 同過使用頁機制提供的保護,阻止了用戶程序訪問內核空間。 這樣,存取用戶空間實際上已不需要FS,GS的支持。但在內核中仍保留set_fs(X)等宏上你設的值用來驗證隨後的操作是否合適。是否超過設定的X。此處X不再是一個段描述符,而是一個具體的值。 此處就有一個陷阱:如果你將Set_fs的值設置為Kernel_DS,而沒有將其該回去,當用戶通過系統調用將一個Buffer的地址(應該在用戶空間)設置為一個內核空間,而內核在訪問該地址前認為默認當前的閥值仍為User_DS,事情就大大?了。