1. 程式人生 > 其它 >2.3.1測試

2.3.1測試

一、任務詳情

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

二、任務解決過程

本次任務在openeuler系統下實現

1、2.3.1程式碼修改

只用修改g的值,程式碼如下:

執行結果:

2、objdump命令學習

我找了6條比較不錯的連結:
部落格連結1
部落格連結2
部落格連結3
部落格連結4
微信讀書:嵌入式c語言自我修養-第4.8動態連結
微信讀書:linux裝置驅動開發詳解-3.6工具鏈
其中,我認為最好的是部落格連結3。該篇部落格寫得很詳細,並且用大量例項來演示objdump命令的引數、功能。

3、objdump命令例項

編譯
整個編譯過程分為預編譯、編譯和彙編,最終生成可執行檔案,其中在windows下生成 .obj檔案,在linux下生成 .o檔案,學名叫做二進位制可重定位檔案。

連結
(1)合併所有obj檔案的段,並調整段偏移和段長度,合併符號表,進行符號解析,分配記憶體地址(虛擬地址)。
(2)連結的核心:符號的重定位。

readelf -h 20191223t1.o輸出obj檔案頭部,可以檢視到obj檔案一些重要資訊。

可以看見入口地址是0x0
obj是一個二進位制可重定位檔案,不能執行,並不是一個executable的檔案。

下面分析.obj檔案的組成格式

objdump -s 20191223t1.o

readelf -S 20191223t1.o產看當前二進位制可重定位檔案中所有的段。

我們可以分析得出,obj檔案中都沒有儲存.bss段的資訊。

那麼問題來了,連結的第二步具體做了哪些事情,什麼是符號重定位?

連結器只對所有.obj檔案的global符號進行處理,對local的符號不做任何處理。如static生成的符號就是local的符號。

分別檢視20191223t1.o和t2.o所生成的符號表:

符號解析:所有obj檔案符號表中對符號引用的地方都要找到符號定義的地方,否則就會出現連結錯誤。由於原始檔是單獨編譯的,所以對外部的符號處理為UND即undefine。

objdump -d 20191223t1.o

可以看到編譯過程並不給資料和函式入口分配記憶體地址,都是以0地址作為替代。
下面詳細看連結過程:
簡單的合併策略,將每個obj檔案的段拿來即可,像下邊這樣:

我們總結一下obj檔案與exe檔案的區別:

  • 1.首先obj和exe組成格式開始都是ELF Header,但是exe的ELF Header中的程式入口地址不再是0,而且一個main函式的地址。
    2.exe的ELF Header也是52個位元組,和obj一樣,但是exe中.text起始地址不再是0x34了,exe比obj多了一塊空間,在ELF和.text中間,叫做program headers.
    3.exe本身還是按照段進行儲存的,不過兩個LOAD項指明瞭哪些段要放在一個頁面上。
    這些區別也說明了為什麼exe檔案可以執行,而obj檔案不能執行。
    ELF檔案頭包括程式入口地址,obj的入口地址是0,0地址不能訪問,而且obj檔案是可重定位檔案,他在編譯後生成,而編譯的時候是不給符號分配地址的,記憶體地址是在連結的時候分配,符號解析完以後就分配虛擬記憶體地址。其實說到底就是因為obj檔案沒有program headers,就沒有兩個LOAD頁面,LOAD頁面就指示了載入器,把當前程式的哪些東西載入到記憶體上。