在使用gcc编译程序时,编译过程可以细分为4个阶段:
1.预处理(Pre-Processing)
2.编译(Compiling)
3.汇编(Assembling)
4.链接(Linking)
gcc -o main -v main.c
-v:vebose
//显示整个编译过程
//gcc -v xx(可执行)就会显示其编译过程中不同阶段的信息
1.预处理(Pre-Processing)
gcc -E main.c -o main.i
//-E:macro expansion 宏展开,.i:intermediate 中间产物
//没有-o main.i,则默认打印到标准输出
cpp main.c
//是gcc -E main.c的底层真正执行的命令
//cpp : C Preprocessor的缩写
命令
/usr/bin/x86_64-linux-gnu-cpp-9 main.c -o main.i
详细过程
[root@Orz 23:40 /mnt/d/linux/c]# whereis cpp
cpp: /usr/bin/cpp /usr/lib/cpp /usr/share/man/man1/cpp.1.gz
[root@Orz 23:40 /mnt/d/linux/c]# ll /usr/bin/cpp
lrwxrwxrwx 1 root root 5 Mar 20 2020 /usr/bin/cpp -> /usr/bin/cpp-9
[root@Orz 23:40 /mnt/d/linux/c]# ll /usr/lib/cpp
lrwxrwxrwx 1 root root 21 Nov 16 03:00 /usr/lib/cpp -> /etc/alternatives/cpp*
[root@Orz 23:42 /mnt/d/linux/c]# ll /etc/alternatives/cpp
lrwxrwxrwx 1 root root 12 Nov 16 03:00 /etc/alternatives/cpp -> /usr/bin/cpp*
[root@Orz 23:43 /mnt/d/linux/c]# ll /usr/bin/cpp-9
lrwxrwxrwx 1 root root 22 Aug 8 2020 /usr/bin/cpp-9 -> x86_64-linux-gnu-cpp-9*
[root@Orz 23:44 /mnt/d/linux/c]# ll /usr/bin/x86_64-linux-gnu-cpp-9
-rwxr-xr-x 1 root root 1158288 Aug 8 2020 /usr/bin/x86_64-linux-gnu-cpp-9*
[root@Orz 23:49 /usr/bin]# ll /usr/bin | grep "gcc"
-rwxr-xr-x 1 root root 428 May 7 2006 c89-gcc*
-rwxr-xr-x 1 root root 454 Apr 11 2011 c99-gcc*
lrwxrwxrwx 1 root root 5 Mar 20 2020 gcc -> gcc-9*
lrwxrwxrwx 1 root root 22 Aug 8 2020 gcc-9 -> x86_64-linux-gnu-gcc-9*
lrwxrwxrwx 1 root root 8 Mar 20 2020 gcc-ar -> gcc-ar-9*
lrwxrwxrwx 1 root root 25 Aug 8 2020 gcc-ar-9 -> x86_64-linux-gnu-gcc-ar-9*
lrwxrwxrwx 1 root root 8 Mar 20 2020 gcc-nm -> gcc-nm-9*
lrwxrwxrwx 1 root root 25 Aug 8 2020 gcc-nm-9 -> x86_64-linux-gnu-gcc-nm-9*
lrwxrwxrwx 1 root root 12 Mar 20 2020 gcc-ranlib -> gcc-ranlib-9*
lrwxrwxrwx 1 root root 29 Aug 8 2020 gcc-ranlib-9 -> x86_64-linux-gnu-gcc-ranlib-9*
lrwxrwxrwx 1 root root 5 Mar 20 2020 x86_64-linux-gnu-gcc -> gcc-9*
-rwxr-xr-x 1 root root 1154192 Aug 8 2020 x86_64-linux-gnu-gcc-9*
lrwxrwxrwx 1 root root 8 Mar 20 2020 x86_64-linux-gnu-gcc-ar -> gcc-ar-9*
-rwxr-xr-x 1 root root 35464 Aug 8 2020 x86_64-linux-gnu-gcc-ar-9*
lrwxrwxrwx 1 root root 8 Mar 20 2020 x86_64-linux-gnu-gcc-nm -> gcc-nm-9*
-rwxr-xr-x 1 root root 35464 Aug 8 2020 x86_64-linux-gnu-gcc-nm-9*
lrwxrwxrwx 1 root root 12 Mar 20 2020 x86_64-linux-gnu-gcc-ranlib -> gcc-ranlib-9*
-rwxr-xr-x 1 root root 35464 Aug 8 2020 x86_64-linux-gnu-gcc-ranlib-9*
使用-E参数可以让gcc在预处理结束后停止编译过程,
工作内容:
1.处理#include预编译指令:递归地引入要include的文件,insert到预编译指令所在的位置
2.处理条件预编译指令:比如#if、#ifdef、#elif、#else、#endif,分析逻辑关系,然后删除这些预编译指令,只留下想要的代码
3.对#define预处理命令,进行宏展开,也就是字面值替换
4.把所有的注释全部删除
5.添加行号和文件名标识,以便于在编译过程中产生编译错误或者调试时都能够生成行号信息。
预处理器(cpp)根据以字符#开头的命令,修改原始的C程序,把宏定义进行替换。
另外可以使用gcc main.c -I 头文件的路径 -o main
2.编译(Compiling)
gcc -S main.i -o main.s
命令
/usr/lib/gcc/x86_64-linux-gnu/9/cc1 -quiet -v -imultiarch x86_64-linux-gnu main.c -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase main -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o main.s
详细过程
[root@Orz 00:09 /mnt/d/linux/c]# ll /usr/lib/gcc/x86_64-linux-gnu/9/cc1
-rwxr-xr-x 1 root root 25654616 Aug 8 2020 /usr/lib/gcc/x86_64-linux-gnu/9/cc1
编译器(cc1)将文本文件main.i文件看成是预处理后的C语言源代码,再翻译成文本文件main.s,它包含一个汇编语言程序。
3.汇编(Assembling)
gcc -c main.s -o main.o
as -v --64 -o main.o main.s
命令
/usr/bin/x86_64-linux-gnu-as -v --64 -o main.o main.s
详细过程
[root@Orz 00:03 /mnt/d/linux/c]# whereis as
as: /usr/bin/as /usr/share/man/man1/as.1.gz
[root@Orz 00:04 /mnt/d/linux/c]# ll /usr/bin/as
lrwxrwxrwx 1 root root 19 Oct 20 19:09 /usr/bin/as -> x86_64-linux-gnu-as*
[root@Orz 00:05 /mnt/d/linux/c]# ll /usr/bin/x86_64-linux-gnu-as
-rwxr-xr-x 1 root root 696624 Oct 20 19:09 /usr/bin/x86_64-linux-gnu-as*
汇编器(as)将main.s翻译成机器语言指令,把这些指令打包成一种可重定位目标程序的格式,并将结果保存在目标文件main.o中。main.o文件是一个二进制文件,它的字节编码是机器语言指令而不是字符,如果我们在文本文件中打开main.o文件,看到的将是一堆乱码。
4.链接(Linking)
gcc -v main.o -o main 可以看见详细过程
命令
/usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccZ7lCdk.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o main /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. main.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
1779 whereis ld
1780 ll /usr/bin/ld
1781 ll /usr/bin/x86_64-linux-gnu-ld
1782 ll /usr/bin/x86_64-linux-gnu-ld.bfd
链接器(ld)负责处理合并目标代码,生成一个可执行目标文件,可以被加载到内存中,由系统执行
GCC基本使用方法、常用指令
gcc [options] [filenames] -o [outputfilename]
/*其中options就是编译器所需要的参数;filenames给出相关的文件名称,可同时给出多个文件;
outputfilename为生成文件名称。*/
[options]
-c:通知gcc取消连接步骤,即编译源码并在最后生成目标文件
-Dmacro:定义指定的宏,使它能够通过源码中的#ifdef进行检验
-E:不经过编译预处理程序的输出而输送至标准输出
-g3:获得有关调试程序的详细信息,它不能与-o选项联合使用
-Idirectory:在包含文件搜索路径的起点处添加指定目录
-llibrary:提示连接程序在创建最终可执行文件时包含指定的库
-O、-O2、-O3:将优化状态打开,该选项不能与-g选项联合使用
-S:要求编译程序生成来自源代码的汇编程序输出
-v:启动所有警报
.h:预处理文件(标头文件)
-Wall:在发生警报时取消编译操作,即将警报看作是错误
-w:禁止所有的报警