日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

目标文件(.o)结构的简单了解

發布時間:2025/6/17 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 目标文件(.o)结构的简单了解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • SimpleSection.o 的結構
    • 代碼段 .text
    • 數據段 .data和只讀數據段 .rodata
    • .bss段
    • 其他段


??????今天來了解一下在編譯過程中所產生的的目標文件的具體結構。(Ubuntu-20.04 64位虛擬機)

??????采用的源文件 SimpleSection.c 為:

int printf(const char* format,...);int global_init_var = 84; int global_uninit_var;void func1(int i) {printf("%d\n",i); }int main(void) {static int static_var = 85;static int static_var2;int a=1;int b;func1(static_var + static_var2 + a + b);return a; }

??????采用命令: gcc -c SimpleSection.c 編譯之后得到目標文件 SimpleSection.o 。下面就在這個目標文件上來分析。

SimpleSection.o 的結構

?????? 使用 binutils 的工具 objdump 來查看目標文件的結構,運行命令:objdump -h SimpleSection.o 將目標文件各個段的基本信息打印出來:


?????? 關于段的幾個重要屬性:Size 表示段的長度,File off 表示段的位置,每個段的第2行中的 “CONTENTS” 表示該段在文件中存在。在 bss 段中沒有 “CONTENTS” ,表示該段在目標文件中不存在。.note.GNU-stack 堆棧段的長度為0,在這里忽略掉它,認為它也不存在。

?????? 用 size 命令可以查看 ELF 文件的代碼段、數據段和 bss 段的長度(dec 表示3個段長度的和的十進制,hex表示長度和的十六進制) 如下圖。

??????為什么 size 和 objdump 查看目標文件的 .text 段的大小不一樣呢?
??????因為size默認是運行在"Berkeley compatibility mode"下。在這種模式下,會將不可執行的擁有"ALLOC"屬性的只讀段歸到.text段下,很典型的就是.rodata段。而在我們這個例子中,使用 size 命令得到的 text 段長度 = .text + .rodata + .note.gnu.property + .eh_frame 。如果你使用"size -A obj.o",那么size會運行在"System V compatibility mode",此時,用objdump -h和size顯示的.text段大小就差不多了,如下圖。

代碼段 .text

??????程序源代碼編譯之后的機器指令經常被放在代碼段中。通過使用 -s -d 參數的 objdump 命令將所有段以十六進制的形式打印出來(-s),并將所有包含指令的段反匯編(-d)。如下:


??????以及反匯編之后的代碼段內容:


??????Contents of section .text 就是將 .text 的數據以十六進制方式打印出來,總共 0x5f 字節,與前面我們得到的 .text 段長度相符合,最左邊一列表示偏移量,中間四列為十六進制內容,最右邊一列是 .text 的ASDII 碼形式。對照下面的反匯編結果,可以得到,.text 段中包含的正是SimpleSection.c 中兩個函數 func1() 和 main() 的指令。其中 func1() 函數在前,main() 在后。

數據段 .data和只讀數據段 .rodata

??????.data 段保存的是那些已經初始化了的全局靜態變量和局部靜態變量。在我們這個例子 SimpleSection.c 中,global_init_var 和 static_var 是已經初始化過的,每個變量 4 個字節,一共 8 個字節被存儲到 .data 段中。在這里采用小端法來存儲,.data 段中前四個字節為 5400 0000 ,轉換為十進制為 84;后四個字節為 5500 0000 ,轉換為十進制為 85。分別與這兩個變量的值一一對應。

??????.rodata 段中存放的是只讀數據,一般是程序中的只讀變量(如 const 修飾的變量)和字符串常量。在 SimpleSection.c 中調用 printf 時,用到了一個字符串常量 “%d\n”,它是一種只讀數據,被存儲到 .rodata 段中。.rodata 段中的四個字節 2564 0a00 分別對應的是字符 ‘%’、‘d’、’\n’ 和 ‘\0’ 。

??????有時候編譯器也會將字符串常量放在 .data 段中。

.bss段

??????.bss 段中存放的是未初始化的全局變量和局部靜態變量,在上述代碼中,global_uninit_var 和 static_var2 是未被初始化過的,它們被存放在 .bss 段中,更準確的來講,是在 .bss 段為它們預留空間。可以認為未初始化過的變量值為0,而存儲 0 是沒有必要的。.bss 段沒有實際內容,所以它在可執行文件中也不占據空間。

??????上面得到的 .bss 段大小為 4 個字節,與變量 global_uninit_var 和 static_var2 的大小之和 8 個字節不符。實際上通過符號表(Symbol Table)能夠看到,只有 static_var2 被放在了 .bss 段中,而 global_uninit_var 未被放在任何段,只是一個未定義的 “COMMON 符號”。這和不同的語言不同的編譯器有關,有的編譯器會將 全局未初始化變量 存放在目標文件 .bss 段中,有些則不存放,只是預留一個 未定義的全局變量符號,等到最終鏈接為可執行文件時再在 .bss 段中分配空間。原則上來講,可以簡單的認為全局未初始化變量被存放在 .bss 段中。但是未初始化的靜態變量(編譯單元內部可見)的確是存放在 .bss 段中的。

其他段

??????.comment 段中存放的是編譯器版本信息。.其余兩個段 .note.gnu.property 和 .eh_frame 在此不做說明。

總結

以上是生活随笔為你收集整理的目标文件(.o)结构的简单了解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。