使用者空間棧 & 系統空間棧
以下簡稱使用者棧、核心棧
1、使用者棧和核心棧的區別
核心在建立程序的時候,在建立task_struct的同時,會為程序建立相應的堆疊。每個程序會有兩個棧,乙個使用者棧,
存在於使用者空間,乙個核心棧,存在於核心空間。記住,程序對應的使用者棧和核心棧都是程序私有的。當程序在使用者空間
執行時,cpu堆疊指標暫存器裡面的內容是使用者堆疊位址,使用使用者棧;當程序在核心空間時,cpu堆疊指標暫存器裡面
的內容是核心棧空間位址,使用核心棧。
注:有些系統中專門為全域性中斷處理提供了中斷棧,但是x86中並沒有中斷棧,中斷在當前程序的核心棧中處理。
2、linux中有多少個核心棧
在/include/linux/sched.h中定義了如下乙個聯合結構:
union task_union ;
每個程序在建立的時候會在核心空間連續分配兩個page即8k的資料用來儲存程序結構(task_struct),這個程序結
構大概有1k左右,剩下的7k用作該程序的核心棧(寫中斷程式的時候不要用什麼遞迴,大的區域性變數)。 也就是說,
除了每個程序都有乙個使用者棧之外,同時都有乙個系統空間棧。
實際上,程序的task_struct結構所佔的記憶體是由核心動態分配的,更確切地說,核心根本不給task_struct分配內
存,而僅僅給核心棧分配8k的記憶體,並把其中的一部分給task_struct使用。
2.1、首先要搞清楚linux的排程機制,在核心態時是不會發生排程的;
2.2、進入核心態與返回使用者態對堆疊的使用是平衡的:
在程序從使用者態轉到核心態的時候,程序的核心棧總是空的。這是因為,當程序在使用者態執行時,使用的是使用者
棧,當程序陷入到核心態時,核心棧儲存程序在核心態執行的相關資訊,但是一旦程序返回到使用者態後,核心棧中儲存
的資訊無效,會全部恢復,因此每次程序從使用者態陷入核心的時候得到的核心棧都是空的。
2.3、linux把堆疊與task_struct放在一起,並用簡單操作得到current指標(esp & 8191ul),這在共享堆疊情況下
是不允許的,也無法區分是哪乙個程序;
2.4、程序的獨立性:如果乙個程序(中斷,呼叫)的時候由於某種原因(中斷處理程式寫的不對)使堆疊不平衡了,那就會影
響整個系統,而如果堆疊是獨立的,那只會影響此程序,大不了把它kill掉。這就像linux的設計:使用者與核心分的非常清楚,好
理解也更強壯,你死你的,不關別人的事。
3、程序使用者棧和核心棧的切換
當程序因為中斷或者系統呼叫而陷入核心態時,程序所使用的堆疊也要從使用者棧轉到核心棧。程序陷入核心態後,首先把
使用者態的堆疊位址儲存在核心堆疊中,然後設定堆疊指標暫存器的位址為核心棧位址(cpu從任務狀態段tss中裝入核心棧指
針esp),這樣就完成了使用者棧向核心棧的轉換; 當程序從核心態恢復到使用者態之行時,在核心態之行的最後將儲存在核心棧
裡面的使用者棧的位址恢復到堆疊指標暫存器即可。這樣就實現了核心棧和使用者棧的互轉。
那麼,我們知道從核心轉到使用者態時使用者棧的位址是在陷入核心的時候儲存在核心棧裡面的,但是在陷入核心的時候,我們
是如何知道核心棧的位址的呢?
關鍵在程序從使用者態轉到核心態的時候,程序的核心棧總是空的(理由見上面的2.2)。所以在程序陷入核心的時候,直接
把核心棧的棧頂位址給堆疊指標暫存器就可以了。
4、使用者態、核心態之間的共享
4.1、我們知道linux的虛擬位址空間是核心態使用3g以上的高位址空間,那麼所有的使用者程序是如何共享這乙個核心空間的呢?
linux系統中的init程序(pid=1)是除了idle程序(pid=0,也就是init_task)之外另乙個比較特殊的程序,它是linux核心開始
建立起程序概念時第乙個通過kernel_thread產生的程序,其開始在核心態執行,然後通過乙個系統呼叫,開始執行使用者空間的
/sbin/init程式,期間linux核心也經歷了從核心態到使用者態的特權級轉變,/sbin/init極有可能產生出了shell,然後所有的使用者
程序都有該程序派生出來。而linux採用2級頁表(1k x 1k x 4k),頁目錄的1/4(3g/4g)即256b是屬於核心的;所以建立用
戶程序時會複製init程序的這256b的頁目錄以及後面的一級、二級頁表,也即實現了核心空間的共享。
4.2、乙個程序在核心態 可以直接通過虛擬位址訪問其他程序核心態的資料,因為他們是乙個頁表。
乙個程序在核心態 不可以直接通過虛擬位址訪問其他程序的使用者態的資料,因為他們不使用同乙個頁表。
4.3、由於系統中只有乙個核心例項在執行,因此所有程序都對映到單一核心位址空間。核心中維護全域性資料結構和每個程序的
一些物件資訊,後者包括的資訊使得核心可以訪問任何程序的位址空間。通過位址轉換機制程序可以直接訪問當前程序的位址空
間(通過mmu),而通過一些特殊的方法也可以訪問到其它程序的位址空間。
4.4、核心態與使用者態的互動
舉個特例:當系統呼叫的引數超過6個時,將借助暫存器將所要傳遞給核心的引數包裝成乙個結構體,並將結構體指標放到
指定暫存器。
另請參考:linux 使用者態與核心態的互動 ——netlink 篇
參考:程序的使用者棧和核心棧
棧空間和堆空間
乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 又編譯器自動分配釋放,存放函式的引數值,區域性變數的值等,其操作方式類似於資料結構的棧。2 堆區 heap 一般是由程式設計師分配釋放,若程式設計師不釋放的話,程式結束時可能由os 值得注意的是他與資料結構的堆是兩回事,分配...
棧空間和堆空間
乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 又編譯器自動分配釋放,存放函式的引數值,區域性變數的值等,其操作方式類似於資料結構的棧。2 堆區 heap 一般是由程式設計師分配釋放,若程式設計師不釋放的話,程式結束時可能由os 值得注意的是他與資料結構的堆是兩回事,分配...
棧空間和堆空間
一直都把堆疊放一起,所以很多人會誤以為他們的組合是乙個詞語,就像 衣服 一樣簡單,其實不然,今天在下就將最近學習總結的一些與大家分享。乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 又編譯器自動分配釋放,存放函式的引數值,區域性變數的值等,其操作方式類似於資料結構的棧。2...