Linux Kernel程式碼藝術——陣列初始化

發表於2016-11-15

前幾天看核心中系統呼叫程式碼,在系統呼叫向量表初始化中,有下面這段程式碼寫的讓我有點摸不著頭腦:

我們先不管上面程式碼的意思,先來回顧一下 C 語言中陣列初始化的相關知識,然後再回頭來理解上面這段程式碼。

陣列初始化

C 語言中陣列的初始化,可以在定義時就給出其初始值,以逗號隔開,用花括號括起來,例如:

當然你可以不用顯示地去初始化所有的元素,例如,下面的程式碼就是顯示初始化了陣列的前三項,後面兩項預設為0:

在 C89 標準中,要求按照陣列中元素固定的順序對陣列的元素進行初始化;然而在 ISO C99 中,你可以以任意的順序對陣列元素初始化,只是需要給出陣列元素所在的索引號;當然 GNU 編譯器 GCC 對 C89 進行了擴充套件,也允許這麼做。為了指明初始特殊的陣列元素,需要在元素值前加上 [index] =,如:

GNU 還有一個擴充套件:在需要將一個範圍內的元素初始化為同一值時,可以使用 [first ... last] = value 這樣的語法:

這是將my_array陣列的第0~9個元素初始化為1, 第10~98個元素初始化為2, 第99個元素初始化為3(你也可以顯示地寫成[99] = 3)。** 注意 **:在語法中... 兩邊必須要留有空格符。

回到上面

對陣列特定元素進行初始化我之前還真沒遇到過,但也是 C 標準所支援的。核心中系統呼叫表是指根據系統呼叫號來找到系統呼叫的函式入口地址,結合上面陣列初始化這個語法點,再回頭看看上面系統呼叫表的定義:

先對錶中所有 __NR_syscall_max+1 項初始化為指向 sys_ni_syscall 的函式,該函式只返回 -ENOSYS,表示該系統呼叫未實現。接下來包含一個標頭檔案#include ,該檔案是在編譯時生成的,內容為:

__SYSCALL_I386 是一個巨集定義:

這樣上面的系統呼叫表定義就展開為:

當使用者程式發生系統呼叫,通過軟中斷 int 0x80 或者 sysenter 指令陷入到核心態,首先儲存暫存器,然後檢查系統呼叫號是否合法,最後跳轉到相應的核心系統呼叫函式中執行:

上面就是系統呼叫的進入過程,比較簡單,這裡只是說明了我們之前定義的系統呼叫表 sys_call_table 的用處。

再舉一例

核心中還有其他地方應用到此種初始化陣列的方法:

這是對系統啟動時對全域性符號表GDT的初始化。

參考資料:

相關文章