1. 程式人生 > 其它 >2.3.1測試----objdump學習

2.3.1測試----objdump學習

2.3.1測試

20191331 lyx

測試要求

0 推薦在OpenEuler系統中實現
1 編輯並執行2.3.1中的程式碼,要求在不修改t2.c 和 t1.c中main函式中的程式碼的情況下,程式執行結果是你的後四位學號。提交程式碼和執行結果截圖。
2 網上學習objdump命令,提交不少於5篇部落格連結和微信讀書上的圖書連結,並給出你認為最好的講解資源的連結或圖書名及章節
3 用objdump分析第1步中的可執行檔案和目標檔案,提交你的分析截圖以及如何和教材講解內容對應的,比如obj檔案的檔案頭,程式碼段,資料段等,可執行檔案如何連結mysum的。

0.實驗準備

  • 實驗環境

本次實驗使用 OpenEuler 20.03LTS

作業系統。

1.編輯並執行

  • 實驗程式碼
********************t1.c*******************
#include <stdio.h>


int g = 100;
int h;
static int s;

main(int argc,char *argv[]){
        int a = 1; int b ;
        static int c = 3;
        b =2;
        c = mysum(a,b);
        printf("sum = %d\n",c);
}
********************t2.c*******************
extern int g;
int mysum(int x,int y){
return 1229*x + y + g;
}

實驗截圖:

2.objdump學習

objdump命令是用檢視目標檔案或者可執行的目標檔案的構成的gcc工具。

--archive-headers 
-a 
顯示檔案庫的成員資訊,類似ls -l將lib*.a的資訊列出。 

-b bfdname 
--target=bfdname 
指定目標碼格式。這不是必須的,objdump能自動識別許多格式,比如: 

objdump -b oasys -m vax -h fu.o 
顯示fu.o的頭部摘要資訊,明確指出該檔案是Vax系統下用Oasys編譯器生成的目標檔案。objdump -i將給出這裡可以指定的目標碼格式列表。 

-C 
--demangle 
將底層的符號名解碼成使用者級名字,除了去掉所開頭的下劃線之外,還使得C++函式名以可理解的方式顯示出來。 

--debugging 
-g 
顯示除錯資訊。企圖解析儲存在檔案中的除錯資訊並以C語言的語法顯示出來。僅僅支援某些型別的除錯資訊。有些其他的格式被readelf -w支援。 

-e 
--debugging-tags 
類似-g選項,但是生成的資訊是和ctags工具相相容的格式。 

--disassemble 
-d 
從objfile中反彙編那些特定指令機器碼的section。 

-D 
--disassemble-all 
與 -d 類似,但反彙編所有section. 

--prefix-addresses 
反彙編的時候,顯示每一行的完整地址。這是一種比較老的反彙編格式。 

-EB 
-EL 
--endian={big|little} 
指定目標檔案的小端。這個項將影響反彙編出來的指令。在反彙編的檔案沒描述小端資訊的時候用。例如S-records. 

-f 
--file-headers 
顯示objfile中每個檔案的整體頭部摘要資訊。 

-h 
--section-headers 
--headers 
顯示目標檔案各個section的頭部摘要資訊。 

-H 
--help 
簡短的幫助資訊。 

-i 
--info 
顯示對於 -b 或者 -m 選項可用的架構和目標格式列表。 

-j name
--section=name 
僅僅顯示指定名稱為name的section的資訊 

-l
--line-numbers 
用檔名和行號標註相應的目的碼,僅僅和-d、-D或者-r一起使用使用-ld和使用-d的區別不是很大,在原始碼級除錯的時候有用,要求編譯時使用了-g之類的除錯編譯選項。 

-m machine 
--architecture=machine 
指定反彙編目標檔案時使用的架構,當待反彙編檔案本身沒描述架構資訊的時候(比如S-records),這個選項很有用。可以用-i選項列出這裡能夠指定的架構. 

--reloc 
-r 
顯示檔案的重定位入口。如果和-d或者-D一起使用,重定位部分以反彙編後的格式顯示出來。 

--dynamic-reloc 
-R 
顯示檔案的動態重定位入口,僅僅對於動態目標檔案意義,比如某些共享庫。 

-s 
--full-contents 
顯示指定section的完整內容。預設所有的非空section都會被顯示。 

-S 
--source 
儘可能反彙編出原始碼,尤其當編譯的時候指定了-g這種除錯引數時,效果比較明顯。隱含了-d引數。 

--show-raw-insn 
反彙編的時候,顯示每條彙編指令對應的機器碼,如不指定--prefix-addresses,這將是預設選項。 

--no-show-raw-insn 
反彙編時,不顯示彙編指令的機器碼,如不指定--prefix-addresses,這將是預設選項。 

--start-address=address 
從指定地址開始顯示資料,該選項影響-d、-r和-s選項的輸出。 

--stop-address=address 
顯示資料直到指定地址為止,該項影響-d、-r和-s選項的輸出。 

-t 
--syms 
顯示檔案的符號表入口。類似於nm -s提供的資訊 

-T 
--dynamic-syms 
顯示檔案的動態符號表入口,僅僅對動態目標檔案意義,比如某些共享庫。它顯示的資訊類似於 nm -D|--dynamic 顯示的資訊。 

-V 
--version 
版本資訊 

--all-headers 
-x 
顯示所可用的頭資訊,包括符號表、重定位入口。-x 等價於-a -f -h -r -t 同時指定。 

-z 
--disassemble-zeroes 
一般反彙編輸出將省略大塊的零,該選項使得這些零塊也被反彙編。

對目標檔案.o的反彙編:

gcc -c -o main.o main.c
objdump -s -d main.o > main.o.txt

對可執行檔案.exe.elf的反彙編:

gcc -o main main.c
objdump -s -d main > main.txt

我認為學習objdump最好的兩篇部落格:

知識補充

每個.0檔案都包含:

  • 一個檔案頭,包含程式碼段、資料段和BSS段的大小
  • 一個程式碼段,包含機器指令
  • 一個數據段,包含初始化全域性變數和初始化靜態區域性變數
  • 一個BSS段,包含未初始化全域性變數和未初始化靜態區域性變數
  • 程式碼中的指標以及資料和BSS中的偏移量的重定位資訊
  • 一個符號表,包含非靜態全域性變數、函式名稱及其屬性

可執行檔案包含以下部分:

  • 檔案頭:檔案頭包含可執行檔案的載入資訊和大小,其中
    • tsize=程式碼段大小
    • dsize=包含初始化全域性變數和初始化靜態區域性變數的資料段大小
    • bsize=包含未初始化全域性變數和未初始化靜態區域性變數的bss段大小
    • total_size=載入的可執行檔案的總大小
  • 程式碼段:也稱為正文段,其包含程式的可執行程式碼。程式碼段從標準C啟動程式碼zrt0.o開始,該程式碼呼叫main()函式。
  • 資料段:資料段包含初始化全域性變數和初始化靜態資料
  • 符號表:可選,僅位執行除錯所需。

參考資料:

3.使用objdump分析可執行檔案和目標檔案

使用objdump分析目標檔案:

使用objdump分析可執行檔案:

由於我在t1.c中引用了stdio.h標準庫 這就導致我的可執行程式反彙編後會包含所呼叫的stdio.h庫中的內容,使反編譯檔案分析難度加大。

資料段:初始化的全域性變數和初始化的靜態區域性變數

main函式:

mysum函式引用:

顯示所可用的頭資訊,包括符號表、重定位入口:

可執行程式和目標檔案的聯絡: