自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C語言與操作系統(tǒng)的內(nèi)存布局

開發(fā) 前端
C語言適合寫操作系統(tǒng),我覺得跟丹尼斯-里奇發(fā)明它的目的就是為了寫Unix有關(guān):不好用的地方已經(jīng)被優(yōu)化過了。

?C語言之所以適合寫操作系統(tǒng),就在于它的內(nèi)存布局簡單:

1,所有的全局變量都被常量初始化,

2,不需要運行時的狀態(tài),

3,也不需要在main()函數(shù)之前運行額外的初始化代碼。

操作系統(tǒng)的初始化是很復(fù)雜的。

在C語言寫成的內(nèi)核main()函數(shù)運行之前,操作系統(tǒng)要運行一段很復(fù)雜的匯編代碼,以完成內(nèi)核的內(nèi)存初始化。

這段匯編代碼包含著很多重要的內(nèi)核全局數(shù)據(jù),它是由內(nèi)核作者精心定制的,沒法由編譯器自動生成。

對于內(nèi)核程序員來說,編譯器做的事越少越好,但是又不能像匯編器那么少?

C語言適合寫操作系統(tǒng),我覺得跟丹尼斯-里奇發(fā)明它的目的就是為了寫Unix有關(guān):不好用的地方已經(jīng)被優(yōu)化過了。

1970年,丹尼斯-里奇怎么一邊改unix系統(tǒng)的代碼、一邊改cc編譯器的代碼的咱就不回憶了。

這里說說C語言和操作系統(tǒng)的內(nèi)存布局。

1.C語言的內(nèi)存布局。

C語言編譯連接之后的可執(zhí)行文件,分為:

1) 代碼段(.text),

2) 只讀數(shù)據(jù)段(.rodata),

3) 數(shù)據(jù)段(.data),

4) 堆 (heap),

5) 棧 (stack),

其中需要存儲在文件里的只有前3個,

后2個在進程運行期間是動態(tài)變化的臨時數(shù)據(jù),并不需要存儲在文件里。

代碼段的權(quán)限是只讀+可執(zhí)行,

只讀數(shù)據(jù)段的權(quán)限是只讀,

數(shù)據(jù)段、堆、棧的權(quán)限都是可讀可寫的,但不能運行。

如果系統(tǒng)內(nèi)核發(fā)現(xiàn)了進程的內(nèi)存權(quán)限是錯誤的,那么就是段錯誤:信號是SIGSEGV。

*("hello") = 1;

這種代碼肯定是“段錯誤”的,因為常量字符串位于只讀數(shù)據(jù)段,它的內(nèi)容是不可寫的。

通過緩沖區(qū)溢出來覆蓋棧的返回地址的黑客代碼,也會被系統(tǒng)內(nèi)核發(fā)現(xiàn)運行地址不在代碼段,所以也是段錯誤。

2.內(nèi)核的內(nèi)存布局。

內(nèi)核的內(nèi)存布局,包含這幾個重要的全局數(shù)據(jù):

1)內(nèi)核頁表

它是內(nèi)核的虛擬內(nèi)存與物理內(nèi)存的映射。

在開啟分頁機制之前,就要設(shè)置好內(nèi)核頁表的前幾頁:

至少要把內(nèi)核代碼所在的內(nèi)存空間映射到頁表里,否則開啟分頁機制時就直接出錯了。

在32位機上,它是由頁目錄-頁表構(gòu)成的2級數(shù)組:

頁目錄里的每一項記錄每個頁表的物理地址,頁表里的每一項記錄每個內(nèi)存頁的物理地址。

在64位機上頁表的結(jié)構(gòu)更為復(fù)雜,intel手冊上有:我沒仔細看過,有興趣的可以看看。

1個內(nèi)存頁是4096字節(jié),所以物理地址的最低12位全是0,用來記錄每個頁的讀寫權(quán)限。

頁目錄里每項的最低12位,用于記錄它對應(yīng)的整個頁表的讀寫權(quán)限。

1個頁表記錄1024個頁,每個頁4096字節(jié),所以1個頁表管理4M的物理內(nèi)存。

2)中斷向量表

它存放各種硬件中斷、以及int 0x80軟件中斷的處理函數(shù),也叫中斷服務(wù)例程(irq)。

int 0x80軟件中斷,就是Linux系統(tǒng)調(diào)用的中斷號。

當(dāng)然,在64位機上,直接使用syscall匯編指令就行。

syscall的軟件中斷機制,是intel在64位上又新造的一種進入CPU ring0特權(quán)級的指令,使用方式跟之前的int指令不大一樣。

我懷疑intel的CPU研發(fā)也是有KPI的,怪不得Linus大牛也經(jīng)常吐槽intel的CPU設(shè)計。

一個版本加一個新的指令,純屬給系統(tǒng)軟件的開發(fā)者找難題?

中斷向量表,也是個256項的數(shù)組,每項都是某個中斷的函數(shù)指針。

在中斷被觸發(fā)之后,CPU就是靠這個數(shù)組去查找對應(yīng)的中斷處理函數(shù)的。

3)全局描述符表

它描述的是內(nèi)核的內(nèi)存布局,每項8個字節(jié),共256項。

但實際上,只需要使用前5項就行:

0x0,不使用,

0x8,內(nèi)核代碼段,

0x10,內(nèi)核數(shù)據(jù)段,內(nèi)核堆棧段,它們2個的權(quán)限一樣,可以共用一項。

0x20,任務(wù)門的描述項,

0x28,局部描述符表的描述項。

siska內(nèi)核demo的內(nèi)存布局

因為每項都是8字節(jié),所以地址都是8的倍數(shù)。

4)局部描述符表

它是用于進程的,進程因為跟內(nèi)核的權(quán)限不同,所以進程的段選擇符都在局部描述符表里:

內(nèi)核的段選擇符是0x8,進程的是0xf。

段寄存器CS、DS、SS,到了保護模式下都成了段選擇符,真正的內(nèi)存地址在GDT表里。

在16位的實模式下,它們才存儲真正的段的內(nèi)存地址。

5)任務(wù)門

CPU把每個進程看做一個任務(wù),所以要切換進程時需要任務(wù)門的描述結(jié)構(gòu)。

它是104個字節(jié)。

但是,Linux系統(tǒng)的進程切換是軟切換:任務(wù)門的描述結(jié)構(gòu)只在系統(tǒng)初始化時加載一次,具體的進程切換時只切換頁表和內(nèi)核棧,然后就可以騙過CPU了?

重新加載任務(wù)門的時間消耗比較大,而軟切換的時間消耗比較小。

intel的這個設(shè)計,也是不受Linus大牛待見的設(shè)計之一?

6)系統(tǒng)調(diào)用表

它也是一個大數(shù)組,它的每一項也是函數(shù)指針。

系統(tǒng)調(diào)用的入口是int 0x80軟件中斷(64位機上是syscall指令)。

進入內(nèi)核之后,每個號碼對應(yīng)一個系統(tǒng)調(diào)用。

open()、close()、write()、read(),這些系統(tǒng)調(diào)用都有各自的號碼,這些號碼就是系統(tǒng)調(diào)用表的數(shù)組索引。

如果open()的系統(tǒng)調(diào)用號碼是i,那么open()在內(nèi)核里實際運行的就是這行代碼:

syscall_table[i]();

7)物理內(nèi)存的管理數(shù)組

物理內(nèi)存的管理結(jié)構(gòu),是一個很大的一維數(shù)組。

假設(shè)物理內(nèi)存有4G,1個內(nèi)存頁是4K,那么這個數(shù)組的元素個數(shù)就是1024x1024,1M。

數(shù)組的每一項,記錄1個物理內(nèi)存頁的狀態(tài)。

如果每項是4個字節(jié)的話,那么管理效率就是:(4096-4) / 4096。

管理數(shù)據(jù)所占的字節(jié)數(shù)越多,對物理內(nèi)存的浪費越大。

get_free_pages()函數(shù),就是通過查看這個數(shù)組來分配物理內(nèi)存頁的。

因為內(nèi)核是一個高并發(fā)環(huán)境,這個管理結(jié)構(gòu)里必須要有自旋鎖,以控制多個CPU的并發(fā)訪問。

自旋鎖+引用計數(shù)就至少8字節(jié),所以這個數(shù)組也是非常浪費內(nèi)存的。

如果多個線程之間要共享內(nèi)存,那么只要把同一個物理內(nèi)存頁映射到這幾個線程的頁表里,然后增加物理內(nèi)存頁的引用計數(shù)就行:

這就是共享內(nèi)存在內(nèi)核里的本質(zhì)。

8)進程的頁表和內(nèi)核棧

進程的頁表和內(nèi)核棧,不屬于內(nèi)核的全局數(shù)據(jù),而是附屬于進程的局部數(shù)據(jù)。

內(nèi)核在調(diào)度某個進程的時候,就把頁目錄基地址寄存器cr3和棧寄存器rsp切換成這個進程的頁表和內(nèi)核棧。

不同的進程之間,之所以有各自的虛擬內(nèi)存空間,互相不干擾,就是因為每個進程的頁表不一樣。

要在進程之間共享內(nèi)存,也跟線程之間共享內(nèi)存一樣,把同一個物理內(nèi)存頁映射到它們各自的頁表就行。

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2022-11-01 11:22:38

2022-11-28 07:21:53

操作系統(tǒng)內(nèi)存管理

2021-06-11 07:26:16

操作系統(tǒng)內(nèi)存管理Cpu

2022-06-26 00:24:57

C語言操作系統(tǒng)語言

2025-01-06 08:28:45

C語言操作系統(tǒng)程序

2009-08-17 08:32:56

Linux操作系統(tǒng)內(nèi)存管理Linux

2021-06-22 09:09:34

V語言Vinix操作系統(tǒng)

2010-04-20 14:17:21

Unix操作系統(tǒng)

2023-11-06 08:47:52

操作系統(tǒng)物理內(nèi)存

2021-03-28 13:54:31

操作系統(tǒng)內(nèi)存管理

2012-08-13 10:19:03

IBMdW

2018-08-09 16:12:59

操作系統(tǒng)內(nèi)存分配

2014-07-29 10:12:38

LinuxC語言編程

2010-04-22 15:14:12

Aix操作系統(tǒng)

2012-05-04 09:49:34

進程

2010-04-15 14:40:26

Unix操作系統(tǒng)

2009-12-23 17:47:15

Linux操作系統(tǒng)

2010-04-19 18:13:48

Unix操作系統(tǒng)

2009-12-09 17:25:19

Linux操作系統(tǒng)

2010-04-20 17:34:25

Unix操作系統(tǒng)
點贊
收藏

51CTO技術(shù)棧公眾號