2013-09-26 106 views
0

對不起,如果問題是愚蠢的,但他們真的讓我困惑! 根據elf標準,二進制文件被分割爲如文本段(包含代碼和RO數據)和數據段(包含RW B0)的數據段,當程序執行並創建進程時,該段被加載到內存中,段提供信息用於流程執行的環境準備。 現在的問題是,如何決定在進程創建期間我沒有提供堆棧大小時要分配多少堆棧來處理? 此外,使用數據段,我們可以確定進程需要多少內存(對於全局變量),但是一旦分配了這個內存,如何將變量映射到分配的內存中的地址空間? 最後,這與分散加載有任何關係嗎?我認爲情況並非如此,因爲要將圖像加載到內存中並且一旦將控制權傳遞給操作系統時,分散加載就完成了,要分配給可執行文件或應用程序的內存由操作系統本身決定! 我知道這些問題太多,但任何幫助將不勝感激。 如果你可以提供任何參考書或鏈接,我可以詳細研究這一點,這也是讚賞。 謝謝你! :)堆棧分配過程及其數據段的佔用情況

回答

0

The question is, how it is decided that how much stack to allocate to process, when i am not providing stack size during process creation?

當一個新的過程中產生的,execve()系統調用用於將新的節目作爲處理圖像從當前運行中的進程圖像加載到存儲器中。當加載新程序時,這意味着execve替換舊的.text,.data段,heap並重置stack。現在,ELF可執行文件被映射到內存地址空間中,使得使用環境數組和參數數組初始化堆棧空間爲main()

在根據子程序bprm_mm_init()do_execve_common()過程調用處理任務,比如,

  1. mm_struct新實例使用呼叫管理進程的地址空間mm_alloc()。
  2. init_new_context()初始化此實例。
  3. bprm_mm_init()初始化堆棧。
  4. search_binary_handler()爲合適的binary formatload_binaryload_shlib常規搜索,以分別加載程序或動態庫。隨後將內存映射到虛擬地址空間,並在調度程序識別進程時使進程準備好運行。

    因此,堆棧內存最終看起來像下圖,這在執行開始時會出現在main()例程中。現在,當調用發生時,函數調用子集中的每個環境(包括參數和局部變量)將被動態存儲或推入堆棧內存區域。

    ----------------- 
    |     | <--- Top of the Stack 
    | environmental | 
    | variables and | 
    | the other  | 
    | parameters to | 
    | main()   | 
    _________________ <--- Stack Pointer 
    |     |     
    | Stack Space | 
    |     | 
    

Also, using the data segment we can determine how much memory the process requires (for global variables) but once this memory is allocated how mapping of variables is done with the address space inside this allocated memory?

讓嘗試通過如下調試簡單C程序找出變量如何映射到存儲器段的不同部分,

/* File Name: elf.c : Demonstrating Global variables */ 
#include <stdio.h> 
int add_numbers(void);   
int value1 = 10;  // Global Initialized: .data section 
int value2;    // Global Initialized: .bss section 

int add_numbers(void) 
{ 
    int result;   // Local Uninitialized: Stack section 
    result = value1 + value2; 
    return result; 
} 

int main(void) 
{ 
    int final_result; // Local Uninitialized: Stack section 
    value2 = 20; 
    final_result = add_numbers(); 
    printf("The sum of %d + %d is %d\n", 
     value1, value2, final_result); 
} 

使用readelf顯示.data部分標題如下,

$readelf -a elf 
    ... 
    Section Headers: 
    [26] .data    PROGBITS   00000000006c2060 000c2060 
     00000000000016b0 0000000000000000 WA  0  0  32 
    [27] .bss    NOBITS   00000000006c3720 000c3710 
     0000000000002bc8 0000000000000000 WA  0  0  32 
    ... 
    $readelf -x 26 elf 
    Hex dump of section '.data': 
    0x006c2060 00000000 00000000 00000000 00000000 ................ 
    0x006c2070 0a000000 00000000 00000000 00000000 ................ 
    ... 

讓我們使用GDB來看看這些部分包括,

(gdb) disassemble 0x006c2060 
    Dump of assembler code for function `data_start`: 
    0x00000000006c2060 <+0>: add %al,(%rax) 
    0x00000000006c2062 <+2>: add %al,(%rax) 
    0x00000000006c2064 <+4>: add %al,(%rax) 
    0x00000000006c2066 <+6>: add %al,(%rax) 
    End of assembler dump. 

.data部分的上述第一個地址是指data_start子程序。

(gdb) disassemble 0x006c2070 
    Dump of assembler code for function `value1`: 
    0x00000000006c2070 <+0>: or  (%rax),%al 
    0x00000000006c2072 <+2>: add %al,(%rax) 
    End of assembler dump. 
    .... 

以上拆機轉儲初始化 10.全局變量value1的地址,但我們沒有看到全球未初始化的變量value2在明年地址。

讓我們來看看在印刷value2地址,

(gdb) p &value2 
    $1 = (int *) 0x6c5eb0 
    (gdb) info symbol 0x6c5eb0 
    value2 in section **.bss** 
    (gdb) disassemble 0x6c5eb0 
    Dump of assembler code for function `value2`: 
    0x00000000006c5eb0 <+0>: add %al,(%rax) 
    0x00000000006c5eb2 <+2>: add %al,(%rax) 
    End of assembler dump. 

田田!拆解變量存儲在.bss部分中的value2 revels的參考指針。這解釋了未初始化的全局變量如何映射到進程內存空間。

Lastly, is there any relation of this with scatter loading?