gcc/g++命令使用GNU推出的基於C/C++的編譯器,是開放源代碼領域應用最廣泛的編譯器,具有功能強大,編譯代碼支持性能優化等特點。現在很多程序員都應用GCC,怎樣才能更好的應用GCC。目前,GCC可以用來編譯C/C++、FORTRAN、JAVA、OBJC、ADA等語言的程序,可根據需要選擇安裝支持的語言。
0x1.什麼是編譯器?
簡單講,編譯器就是將“一種語言(通常爲高級語言)”翻譯爲“另一種語言(通常爲低級語言)”的程序。舉個例子:當我們使用C語言寫了一段程序,想被運算機器執行(電腦或其它嵌入式設備等等),編譯器就是負責把這一段程序轉換成可以指定機器上執行的指令。
0x2.工作流程
gcc編譯主要工作流程有四個部分:預處理(preprocessing),編譯(compilation),彙編(assembly),鏈接(linking),當前網絡上還有其它的表現形式,如:源代碼 (source code) → 預處理器 (preprocessor) → 編譯器 (compiler) → 目標代碼 (object code) → 鏈接器 (Linker) → 可執行程序 (executables),其實原理都一樣,只是後面的更方便理解。關於編譯原理有詳情說明。
0x3.gcc常用命令
語法:gcc (選項)(參數:文件)
寫一個hello.c的程序
#include<stdio.h>
int main(){
printf("hello world!");
return 0;
}
1、無選項編譯鏈接
$ gcc hello.c
hello.c預處理、編譯、彙編並鏈接形成可執行文件。這裏未指定輸出文件,在Linux上默認輸出爲a.out,在window環境中編譯默認爲a.exe。
$ ls
a.exe hello.c
查看生成a.exe執行文件
$ ./a.exe
hello world!
執行a.exe,輸出結果
2、選項 -o(理解成output),對生成的目標進行重命名,linux下爲hello.out,windows下爲hello.exe
$ gcc -o hello hello.c
$ ls
a.exe hello.c hello.exe
3、選項 -E,把源代碼預處理輸出爲hello.i文件,詳見下一篇
$ gcc -E hello.c -o hello.i
$ ls
a.exe hello.c hello.exe hello.i
與cpp hello.c > hello.i命令功能一致。
4、選項 -S,把預處理輸出的文件hello.i彙編成hello.s文件
$ gcc -S hello.i
$ ls
a.exe hello.c hello.exe hello.i hello.s
查看彙編後hello.s的內容
.file "hello.c"
.text
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC0:
.ascii "hello world!\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
call __main
leaq .LC0(%rip), %rcx
call printf
movl $0, %eax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (GNU) 7.3.0"
.def printf; .scl 2; .type 32; .endef
5、選項 -c,把彙編成hello.s文件編譯輸出爲hello.o文件,輸出文件爲二進制目標文件。
$ gcc -c hello.s
$ ls
a.exe hello.c hello.exe hello.i hello.o hello.s
與as hello.s -o hello.o命令功能一致。
在IDA工具中查看hello.o文件
6、無選項鍊接,把hello.o目標文件鏈接成最終可執行文件hello1.exe,其實是調用ld命令進行鏈接。
$ gcc hello.o -o hello1
$ ls -l
總用量 394
-rwxrwxr-x+ 1 Administrator None 155707 八月 3 15:31 a.exe
-rwxrwx---+ 1 Administrators None 68 八月 3 15:21 hello.c
-rwxrwxr-x+ 1 Administrator None 34373 八月 3 16:48 hello.exe
-rw-rw-r--+ 1 Administrator None 34373 八月 3 16:48 hello.i
-rw-rw-r--+ 1 Administrator None 866 八月 3 17:18 hello.o
-rw-rw-r--+ 1 Administrator None 496 八月 3 17:05 hello.s
-rwxrwxr-x+ 1 Administrator None 155707 八月 3 17:26 hello11.exe
$ ./hello1.exe
hello world!
7、選項 -O(大寫的字母O),使用編譯優化級別,1~3,級別越大優化效果越好,但編譯的時候會長。
$ gcc -O3 hello.c -o hello2
8、選項 -M,查看生成文件關聯信息,包含目標文件所依賴的所有源代碼,該命令會在預處理階段中執行。
$ gcc -M hello.c
hello.o: hello.c /usr/include/stdio.h /usr/include/_ansi.h \
/usr/include/newlib.h /usr/include/_newlib_version.h \
/usr/include/sys/config.h /usr/include/machine/ieeefp.h \
/usr/include/sys/features.h /usr/include/cygwin/config.h \
/usr/include/sys/cdefs.h /usr/include/machine/_default_types.h \
/usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/stddef.h \
/usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/stdarg.h \
/usr/include/sys/reent.h /usr/include/_ansi.h /usr/include/sys/_types.h \
/usr/include/machine/_types.h /usr/include/sys/lock.h \
/usr/include/sys/types.h /usr/include/sys/_stdint.h \
/usr/include/machine/endian.h /usr/include/machine/_endian.h \
/usr/include/bits/endian.h /usr/include/sys/select.h \
/usr/include/sys/_sigset.h /usr/include/sys/_timeval.h \
/usr/include/sys/timespec.h /usr/include/sys/_timespec.h \
/usr/include/sys/_pthreadtypes.h /usr/include/machine/types.h \
/usr/include/endian.h /usr/include/bits/byteswap.h \
/usr/include/bits/wordsize.h /usr/include/sys/sysmacros.h \
/usr/include/sys/stdio.h
9、選項 -MM,與-M相比,會忽略#include文件的依賴關係
$ gcc -MM hello.c
hello.o: hello.c
10、多個文件一起編譯,hello.c、multi.c分別編譯後鏈接成multi.out或multi.exe的可執行文件。
$ gcc hello.c multi.c -o multi
11、多個.o二進制目標文件編譯後鏈接成一個可執行文件
$ gcc multi.o hello.o -o multi1
12、選項 -include file :包含某個代碼。相當於在文件中加入#include
$ gcc hello.c -include multi.c -o include
生成include.out可執行文件
13、選項 -Idir:當你使用#include”file”的時候,會先到你定製的目錄裏面查找。
14、選項 -L(library):定製編譯的時候使用的庫,/home/hello/lib作爲第一個尋找庫文件的目錄。
$ gcc -o hello hello.c -L/home/hello/lib
15、選項 -l:定製編譯的時候使用的庫,尋找動態鏈接庫文件libtest.so,如果加上-static,表示尋找libtest.a靜態鏈接庫。
$ gcc -o hello hello.c -ltest
16、選項 -w,表示不生成任何警告的信息。
$ gcc -w multi.c hello.c -o multi
17、選項 -Wall:生成所有警告信息。
$ gcc -Wall multi.c hello.c -o multi
18、選項 -g:在編譯的時候加入debug調試信息,用於gdb調試,文件會比一般大一點。
$ gcc -g hello.c -o hello5
19、選項 -share:此選項儘量的使用動態庫,所以生成文件比較小,但是必須是系統有動態庫。
20、選項 -shared:生成共享目標文件,通常用在建立共享庫。