關於程序的編譯鏈接與裝載,有一些問題一直沒有弄得很清楚。這次花了不少精力,把這些問題,好好研究了一番。在學習的過程中,熟讀了<<程序員的自我修養-鏈接、裝載與庫>>這本書,收穫良多。強烈推薦這本書。
此次系列文章,是針對靜態編譯,動態編譯太多複雜,目前仍有很多問題,沒有解決。
在開始之前,帶有如下的一些問題:
-
程序是如何編譯成可執行程序?
-
跨模塊之間,如何知道其他模塊的函數以及變量地址?
-
linux下,可執行程序elf,長什麼樣?
-
對於任意一個elf,如何查看該elf的信息?
-
反彙編中,程序的地址,以及符號,是如何得到的?
-
爲什麼程序,以section爲單位進行組織?
-
section與segment的區別是什麼?
-
ELF中的VMA與LMA的區別是什麼?鏈接視圖與執行視圖區別是什麼?
-
在EDA仿真中,elf,是如何裝載到環境中去運行的?
-
在linux中,elf程序,是如何裝載到內存中運行的?
-
鏈接腳本的AT,MEMORY關鍵字,到底有什麼用?
通過查看資料,以及自己做實驗,對這些問題,有了清晰的答案。希望通過本系列博文,也能讓大家,對這些問題,也有清晰的答案。
一、工具介紹
首先介紹下,之後會用到的一些工具:
- aarch64工具鏈,包括如下:
- -S參數: 將源程序轉換成.S
- -c參數: 將源程序轉換成.o
- aarch64-none-elf-gcc:arm-gcc編譯器
- aarch64-none-elf-as: 彙編器,將.s轉換成.o
- aarch64-none-elf-ld: 鏈接器,將 .o 鏈接成elf
- aarch64-none-elf-objdump: 反彙編,將elf反彙編
- readelf工具,用於查看elf文件內容
- -a: 查看elf文件的所有信息
- -h: 查看elf文件的頭信息
- -l: 查看program段信息
- -S: 查看section段信息
- -s: 查看符號表信息
- -r: 查看可重定位表信息
- gvim工具,-b參數,表示查看的文件是二進制文件
- :%!xxd,該命令,在gvim中查看二進制數據
- hexdump工具,直接查看二進制文件
藉助以上的一些工具,就便於之後分析.o文件,.elf文件。
藉助以上的一些工具,就便於之後分析.o文件,.elf文件。
二、示例程序
首先,先介紹使用的示例程序。
兩個程序:
- a.c
- 2個全局變來那個,一個有賦初值,一個沒有賦初值
- 2個局部靜態變量,一個有賦初值,一個沒有賦初值
- 調用了b.c中的swap函數
- b.c
- 引用a.c中的一個全局變量
- 定義了一個全局變量
- 定義了swap函數,供a.c調用
- 在swap函數中,更改了a.c中定義的全局變量
程序如下圖所示:
之後,便以編譯這兩個c文件,成最終的可執行程序out.elf爲例,來進行詳細的分析。
Makefile腳本如下:
後面的 .o和.elf文件的分析,就是基於這個示例程序進行分析的。