2015-12-31 120 views
2

我最近試圖想象如何在Linux內核中處理堆棧內存,但無法提供任何可靠的東西。我知道內核使用自己的函數進行動態內存管理,但是我不知道它是如何管理普通的C堆棧內存的,因爲畢竟,這可以用普通的C實現並且用普通的GCC編譯。就我而言,堆棧內存分配通常在處理操作系統時甚至在處理AVR時通過libc的形式處理。據我所知,儘管Linux內核不依賴於libc?Linux內核中的堆棧內存

我不能完全肯定的內存管理是如何棧委託擺在首位到libc雖然它似乎是一個語言功能構建的。我可以想像的是,它以某種方式編譯(或實現),以便提供者可以在之後或可能作爲編譯過程的一部分被分配。有人可以幫我解釋一下嗎?

+0

當一個新進程啓動時,它有一個映射到進程地址空間的用戶空間堆棧和一個用於進行系統調用的內核堆棧。堆棧指針開始指向堆棧。 libc並沒有參與這個* *。發佈的答案有點令人困惑,但它似乎是正確的關於ELF二進制文件能夠控制他們得到什麼樣的堆棧設置:http://stackoverflow.com/questions/18278803/how-does-elf-file-format - 定義最堆棧。缺省情況是不具有這樣的部分,然後在內核默認的virt地址選擇處獲得默認堆棧。 –

回答

0

至於我擁有它,堆內存分配由 libc中的一種形式,通常處理...

這個程序說明從libc中沒有用於棧內存分配:

// compile with: gcc -nostdlib nolibc.c -o nolibc 
_start() 
{ 
    int a[9999]; 
    *a = 0; 
    asm(" mov %0,%%ebx\n\ 
      mov $1,%%eax\n\ 
      int $128" : : "r" (*a)); // _exit(*a); 
} 

如果超過了分配的堆棧空間,則會發生故障並且內核的故障處理程序可以分配更多空間,除非達到了限制或使用了固定大小。

0

堆內存被分配在鏈接步驟(整個堆疊)。

堆棧存儲器(通常)放置在.STACK段(其只不過是一個偏移量和長度更大,沒有內容)。

.startup代碼(通常是某個庫中的彙編函數,我不確定哪個庫)會在加載的代碼中找到.stack節的名稱,並添加長度值以獲取堆棧的頂部地址(堆棧向下增長)和(在其他幾個操作中)設置寄存器spbp。當操作系統運行時(I.E.不處於'用戶'模式),它(通常)具有其自己的堆棧空間,並使用其自己的值作爲spbp寄存器的值。

「用戶」模式和「特權」模式和寄存器值的交換之間的切換是在轉變之間的你寫什麼,在內核代碼進行處理。

大部分此類切換都在libc庫中的包裝函數中進行處理,並且生成的控件會通過跳轉到內核例程的表格進行轉換。

注:其它的CPU和操作系統有關於事物是如何實現的細節別共,但結果非常相似。

+0

我在現代linux中找不到.stack段。 '%objdump -h/bin/cat' –

+0

也許你可以閱讀這個stackoverflow問題來找到你正在尋找的答案: user3629249

+1

保存/恢復寄存器,並交換到內核堆棧,*不*由libc處理。內核不能信任libc,因爲libc只是非特權進程運行的用戶空間代碼!而且,當你直接進行系統調用時(例如在64位模式下使用「syscall」指令),即使對於不鏈接任何庫的玩具可執行文件,它也必須發生並且工作相同。 –

0

堆棧可以是任何讀/寫存儲器塊。堆棧沒有特別之處。操作系統創建一個堆棧,即分配內存並將其位置分配給堆棧指針寄存器 - 因爲需要啓動一個進程,但不管理堆棧。

在UNIX的土地,運行的程序是一個兩個步驟的過程。首先,你克隆一個父進程。因此,新進程與父進程具有相同的堆棧設置。

最後,你執行程序。程序負載從可執行文件中獲得所需的堆棧大小,然後從可執行文件中獲取鏈接器的信息(例如,請參閱ld命令的「堆棧」選項)。

啓動後,應用程序可以調用系統服務來分配內存頁面,並具有堆棧指針寄存器引用。然後,這成爲程序堆棧。

請記住,這一切都指的是用戶堆棧。操作系統爲每個進程使用它自己的目的維護一個KERNEL堆棧。