1、編譯過(guò)程
預(yù)處理(預(yù)編譯 .i)—> 編譯(.s) —> 匯編(.o) —> 鏈接(可執(zhí)行文件 .a .so)
命令
預(yù)編譯
gcc -E hello.c -o hello.i
cpp hello.c > hello.i
編譯
gcc -S hello.c -o hello.s
gcc -S hello.i -o hello.s
匯編(獲取ELF文件)
as hello.s -o hello.o
gcc -c hello.s -o hello.o
gcc -c hello.c -o hello.o
鏈接
ld -static a.o b.o … # -static表示靜態(tài)鏈接,默認(rèn)ld使用動(dòng)態(tài)鏈接
靜態(tài)鏈接 動(dòng)態(tài)鏈接
2、編譯器 (需要學(xué)習(xí)編譯原理)
3、目標(biāo)文件
3.1、目標(biāo)文件 .o,目標(biāo)文件包括.o文件和庫(kù)文件(靜態(tài)庫(kù)、動(dòng)態(tài)庫(kù))
3.2、目標(biāo)文件格式,使用file命令可以看到目標(biāo)文件格式
file foobar.o
3.3、目標(biāo)文件 section
可執(zhí)行文件、可重定位文件(.o文件)、共享目標(biāo)文件(動(dòng)態(tài)庫(kù)、靜態(tài)庫(kù))、核心轉(zhuǎn)儲(chǔ)文件(core dump file)都是ELF文件
.text section
.data section
.bss section
命令
objdump -h SImpleSection.o # 查看SimpleSection.o目標(biāo)文件的結(jié)構(gòu),各個(gè)section的空間布局 -h header(查看section頭)
objdump -s -d SimpleSection.o # -s將所有section以16進(jìn)制形式打印出來(lái),-d反匯編
objdump -x SimpleSection.o # -x 打印詳細(xì)信息
readelf -h SimpleSection.o # -h 查看文件ELF header,ELF header里面是文件的基本信息
readelf -S SimpleSection.o # -S 查看ELF文件section信息,顯示的是各個(gè)段的布局以及基本信息
3.4、 section和section之間是有空隙的(字節(jié)對(duì)齊的緣故)
3.5、 ELF 文件的section只有在編譯和鏈接的時(shí)候才有意義,裝載的時(shí)候是不看section的,只看可執(zhí)行文件的訪問(wèn)權(quán)限(只讀頁(yè)面,可讀可寫頁(yè)面。。。)
3.6、重定位section
readelf -S 查看如果有 rel.text,說(shuō)明rel.text是一個(gè)section,同時(shí)是.text的重定位表,在鏈接之后重定位
rel.xxx都是可重定位表,鏈接的時(shí)候使用,比如在調(diào)用函數(shù)的地方需要重定位到函數(shù)的定義位置
3.7、符號(hào)表 弱符號(hào)強(qiáng)符號(hào)
3.8、調(diào)試信息
strip # strip命令可以去掉ELF中的調(diào)試信息,是不是strip可以把debug文件編程release文件?
3.9 鏈接
ld a.o b.o -e main -o ab # -e main表示將main作為程序入口;ld鏈接器默認(rèn)程序入口是_start
鏈接二步:
step1:空間與地址分配
step2:符號(hào)解析與重定位
重要??!目標(biāo)文件&可執(zhí)行文件&進(jìn)程空間 映射關(guān)系

3.10、靜態(tài)庫(kù)
ar -t libc.a # ar -t 命令查看 libc.a 靜態(tài)庫(kù)由哪些目標(biāo)文件(.o)文件組成
objdump -t libc.a # objdump -t 可以看到 libc.a 靜態(tài)庫(kù)中包含了哪些函數(shù)以及section
ar -x libc.a # ar -x 可以將 libc.a 靜態(tài)庫(kù)解壓縮成為多個(gè).o文件