csdn地址:《程序員的自我修養(yǎng)》讀書筆記-編譯鏈接過程
準(zhǔn)備
對(duì)于入門的hello world程序, 如下所示:
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
在IDE中僅需點(diǎn)擊一下運(yùn)行既可看到程序的運(yùn)行結(jié)果沟饥,而如果使用GCC編譯锌仅,也非常簡(jiǎn)單贾费,只需gcc hello.c即可生成目標(biāo)文件a.out, 但其中隱藏了編譯鏈接的基本步驟吕世,分別為:預(yù)處理碑幅、編譯戴陡、匯編和鏈接。通過
gcc --verbose hello.c -o a.out
可看到各步驟的流程枕赵。
預(yù)處理
預(yù)處理過程主要處理源碼中以“#”開始的預(yù)編譯指令猜欺, 比如“#include"、“define"等拷窜。通過預(yù)處理后的輸出文件后綴為.i 或者.ii开皿, 具體實(shí)現(xiàn)預(yù)處理過程的為預(yù)編譯器cpp。若要查看預(yù)處理后的文件篮昧,可用:
gcc -E hello.c -o hello.i
或者:cpp hello.c > hello.i
- 主要處理規(guī)則:
1. 刪除所有的#define, 并展開所有的宏定義;
2. 處理所有的條件預(yù)編譯指令赋荆,如#if、#ifdef等懊昨;
3. 處理“#include"預(yù)編譯指令窄潭;
4. 刪除所有注釋;
5. 添加行數(shù)和文件名標(biāo)識(shí)酵颁;
- 舉例說明:
例如定義常量 CONST_TEST嫉你,如下:
#include <stdio.h>
#define CONST_TEST 5
int main()
{
printf("%d\n", CONST_TEST);
return 0;
}
在經(jīng)過預(yù)處理后main函數(shù)變成如下:
int main()
{
printf("%d\n", 5);
return 0;
}
編譯
編譯過程就是把預(yù)處理完的文件進(jìn)行一系列詞法分析月帝、語法分析、語義分析以及優(yōu)化后生成相應(yīng)的匯編代碼文件幽污。gcc命令如下:
gcc -S hello.i -o hello.s
或者:ccl hello.c
備注:對(duì)于c語言來說嚷辅, 預(yù)處理和編譯的實(shí)現(xiàn)程序?yàn)閏cl, c++對(duì)應(yīng)的程序?yàn)閏clplus距误。
生成的hello.s文件為:
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 12
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
subq $16, %rsp
leaq L_.str(%rip), %rdi
movl $0, -4(%rbp)
movb $0, %al
callq _printf
movl $1, %ecx
movl %eax, -8(%rbp) ## 4-byte Spill
movl %ecx, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "hello world\n"
.subsections_via_symbols
匯編
匯編過程主要是將匯編代碼轉(zhuǎn)變成機(jī)器可以執(zhí)行的指令, 生成目標(biāo)文件簸搞。gcc命令為:
gcc -c hello.s -o hello.o
或者:as hello.s -o hello.o
鏈接
通過匯編過程生成的目標(biāo)文件并不能直接執(zhí)行,其原因包括:某個(gè)源文件中的函數(shù)可能引用了另一個(gè)源文件中定義的某個(gè)符號(hào)(如變量或者函數(shù)調(diào)用等)准潭;在程序中可能調(diào)用了某個(gè)庫文件中的函數(shù)等趁俊, 而鏈接就是解決這些問題。鏈接程序的主要工作就是將有關(guān)的目標(biāo)文件彼此相連接刑然,也即將在一個(gè)文件中引用的符號(hào)同該符號(hào)在另外一個(gè)文件中的定義連接起來寺擂,使得所有的這些目標(biāo)文件成為一個(gè)能夠按操作系統(tǒng)裝入執(zhí)行的統(tǒng)一整體。鏈接命令為ld泼掠,對(duì)于上訴的hello wrold程序沽讹,可用:
ld -demangle -dynamic -arch x86_64 -macosx_version_min 10.12.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -o hello.out hello.o -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/lib/darwin/libclang_rt.osx.a
備注:測(cè)試環(huán)境為mac 10.12.3 (16D32)。