1. 程式人生 > >深入理解程序的結構

深入理解程序的結構

程序結構 數據段 代碼段

深入理解程序的結構

1靜態可執行程序中的段

程序由不同的段構成(代碼段、數據段),程序的靜態特征就是指令和數據,動態特征就是執行指令處理數據。
源程序代碼到可執行程序的對應關系:
技術分享圖片

代碼段

  • 源代碼的可執行語句編譯後進入代碼段,編譯完成後大小固定
  • 代碼段在內存管理單元的系統中具有只讀屬性(是一種保護,防止被改寫)
  • 代碼段中可以包括常量數據(如字符串常量)

    數據段(.data .bss .rodata)

    .bss段(Block Started by Symbol segment)
    存儲未初始化的全局數據,不占用可執行文件的大小。
    .data段:存儲具有非0初始值的變量
    .rodata段:存儲const修飾的和其他只讀數據

    問題:.bss和.data段同樣存儲的是全局數據,為什麽初始化的和不初始化的保存在不同的段中?
    .bss段中的變量不用在再程序文件中保存初始值,從而減小可執程序的大小,提高程序加載的效率。(對於.bss段中的變量,在可執行文件中只需要保存其變量名和變量類型,在加載時統一將其初始化為0;而對於存儲於.data段中的數據,需要保存其變量名,類型、和值,在加載其需要將變量值拷貝得到變量對應的空間)
    編程實驗:可以編寫簡單測試程序,通過objdump -h命令查看各個段的信息,使用nm命令查看可執行文件中的符號和地址,使用objdump -s -j .data ./a.ou查看某個段中的具體信息,並將上述信息對應起來。

    6.2動態加載後生成的段

    棧(stack)

    棧時在程序被加載到內存之後才生成的,其本質時片連續的存儲空間
    SP寄存器作為棧頂“指針”實現入棧操作和出棧操作
    技術分享圖片
    棧通常作為以下用途
    中斷發生時,棧用於保存寄存器的值(現場保護)
    函數調用時,棧用於保存函數的活動記錄(棧幀信息)
    並發編程時,每個線程擁有自己獨立的棧

    堆(Heap)

    堆和棧一樣,時程序被加載到內存後才生成的。是一片“空閑的空間”,用於提供動態內存分配。
    需要函數的支持(malloc、free)
    內存映射段(memory mapping segment)
    內核將硬盤中的文件內容直接映射到內存映射段(mmap)
    動態鏈接庫在可執行程序加載時映射到內存映射段

    程序執行時能夠創建匿名映射區存放程序數據
    內存映射文件的原理:
    將硬盤上的文件數據邏輯映射到內存中(零耗時),通過缺頁中斷進行文件數據的實際載入(一次數據拷貝),映射後對內存的讀寫就是對文件的讀寫(極大的提高了文件的讀寫效率)。
    技術分享圖片
    使用傳統的方式通過read函數來讀取文件,首先內核程序接到應用程的請求,然後內核程序去讀取硬盤中的文件內核空間,然後再講內核空間中的數據拷貝到應用空間(使用了兩次數據拷貝)。
    最終各個段在內存中的布局:
    技術分享圖片
    這裏我們看到棧、堆的起始地址都是隨機的,這樣做的目的是為了安全,當其實地址隨機後,惡意代碼修改程序的暗度變大(難以直接通過固定地址獲取到程度的返回地址)。

深入理解程序的結構