https://www.cnblogs.com/zhangpengshou/p/3587751.html
http://m.elecfans.com/article/663750.html
https://www.cnblogs.com/LiuYanYGZ/p/5548855.html
https://blog.csdn.net/qq_33160790/article/details/78887349

c語言編譯分為4個過程:
1:預編譯:預編譯做的事情為:把偽指令轉換為實際指令 命令 gcc -E
a:#define a b
b:#條件編譯指令,如#ifdef,#ifndef,#else,#elif,#endif等
c:#include 頭文件加入到編譯的文件中
d:一些符號處理如file local 等等;
# 1 "/usr/lib/gcc/x86_64-redhat-linux/4.4.7/include/stddef.h" 1 3 4 # 211 "/usr/lib/gcc/x86_64-redhat-linux/4.4.7/include/stddef.h" 3 4 typedef long unsigned int size_t; # 35 "/usr/include/stdio.h" 2 3 4 # 1 "/usr/include/bits/types.h" 1 3 4 # 28 "/usr/include/bits/types.h" 3 4 # 1 "/usr/include/bits/wordsize.h" 1 3 4 # 29 "/usr/include/bits/types.h" 2 3 4 typedef unsigned char __u_char; typedef unsigned short int __u_short; typedef unsigned int __u_int; typedef unsigned long int __u_long; typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef signed short int __int16_t; typedef unsigned short int __uint16_t; typedef signed int __int32_t; typedef unsigned int __uint32_t; typedef signed long int __int64_t; typedef unsigned long int __uint64_t;
可以看出一個很小的程序經過編譯以后把所有的頭文件包含進來都是很大的
2:編譯 命令是 gcc -S
把預編譯好的文件逐條轉化為匯編語言
優化階段,經過預編譯得到的輸出文件中,只有常量;如數字、字符串、變量的定義,
以及c語言的關鍵字,如main,if,else,for,while,{,}, +,-,*,\等等。
編譯程序所要作得工作就是通過詞法分析和語法分析,在確認所有的指令都符合語法規則之后,
將其翻譯成等價的中間代碼表示或匯編代碼。如下都是匯編代碼;操作寄存器
.file "test7.c" .text .globl power .type power, @function power: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -20(%rbp) movl %esi, -24(%rbp) movl $1, -8(%rbp) movl -20(%rbp), %eax movl %eax, -4(%rbp) jmp .L2 .L3: movl -4(%rbp), %eax movl -20(%rbp), %edx imull %edx, %eax movl %eax, -20(%rbp) addl $1, -8(%rbp)
3:匯編 命令gcc -c
將.c文件直接編譯成.o的二進制文件:

4:鏈接 命令是 gcc *.c 鏈接命令是ld 鏈接的時候要考慮代碼和數據所要放的內存位置,可以通過鏈接腳本來設置(這里下次課再說)
鏈接程序的主要工作就是將有關的目標文件彼此相連接,也即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來,使得所有的這些目標文件成為一個能夠誒操作系統裝入執行的統一整體。
根據開發人員指定的同庫函數的鏈接方式的不同,鏈接處理可分為兩種:
(1)靜態鏈接
在這種鏈接方式下,函數的代碼將從其所在地靜態鏈接庫中被拷貝到最終的可執行程序中。這樣該程序在被執行時這些代碼將被裝入到該進程的虛擬地址空間中。靜態鏈接庫實際上是一個目標文件的集合,其中的每個文件含有庫中的一個或者一組相關函數的代碼。
(2) 動態鏈接
在此種方式下,函數的代碼被放到稱作是動態鏈接庫或共享對象的某個目標文件中。鏈接程序此時所作的只是在最終的可執行程序中記錄下共享對象的名字以及其它少量的登記信息。在此可執行文件被執行時,動態鏈接庫的全部內容將被映射到運行時相應進程的虛地址空間。動態鏈接程序將根據可執行程序中記錄的信息找到相應的函數代碼。
對於可執行文件中的函數調用,可分別采用動態鏈接或靜態鏈接的方法。使用動態鏈接能夠使最終的可執行文件比較短小,並且當共享對象被多個進程使用時能節約一些內存,因為在內存中只需要保存一份此共享對象的代碼。但並不是使用動態鏈接就一定比使用靜態鏈接要優越。在某些情況下動態鏈接可能帶來一些性能上損害。
=====================
gcc -o 指定文件名 如 gcc -c hello.c -o hello.a
gcc -M 只輸出編譯信息不編譯
gcc -MM 只輸出編譯信息不編譯

