GCC编译器查看C语言编译过程

编译过程:

  1. 预处理:预处理器将对源文件中的宏进行展开。
  2. 编译:编译器gcc将c文件编译成汇编文件。
  3. 汇编:汇编器as将汇编文件编译成机器码。
  4. 链接:将目标文件和外部符号进行连接,得到一个可执行二进制文件。

以一个很简单的01_test.c来探讨这个过程。

#include <stdio.h>
#define NUMBER  (1 + 2)
int main(void)
{
	int x = NUMBER;
	printf("x:%d\n",x);
	return 0;
}
  1. 预处理
    [csy@local compile_test]$ gcc -E -o 01_test.i 01_test.c

用cat查看01_test.i的内容如下:

int main(void)
{
	 int x = (1 + 2);
	 printf("x:%d\n",x);
	 return 0;
}

可以看到,文件中宏定义NUMBER出现的位置被(1+2)替换掉了,其它的内容保持不变。
2. 编译成汇编代码
gcc -S -o 01_test.s 01_test.i
通过cat test.s查看01_test.s的内容为汇编代码。

[csy@local compile_test]$ cat 01_test.s 
	.file	"01_test.c"
	.section	.rodata
.LC0:
	.string	"x:%d\n"
	.text
.globl main
	.type	main, @function
main:
	pushl	%ebp
	movl	%esp, %ebp
	andl	$-16, %esp
	subl	$32, %esp
	movl	$3, 28(%esp)
	movl	$.LC0, %eax
	movl	28(%esp), %edx
	movl	%edx, 4(%esp)
	movl	%eax, (%esp)
	call	printf
	movl	$0, %eax
	leave
	ret
	.size	main, .-main
	.ident	"GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
	.section	.note.GNU-stack,"",@progbits

  1. 使用汇编器编译成机器码
  [csy@local compile_test]$ gcc -c -o 01_test.o 01_test.s 

生成的机器码:

ELF                      ?      4     (   U夊冧饍?荄$   ?   婽$塗$?$椟?   擅   x:%d
  GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)  .symtab .strtab .shstrtab .rel.text .data .bss .rodata .comment .note.GNU-stack                                                      4   -                     	           X     	            %             d                      +             d                      0             d                     8      0       j   -                 A              ?                                   ?  Q                                ?  ?  
            	              @                                                ?                                                                                           -                    01_test.c main printf       "   	  
  1. 使用链接器把目标文件链接成可执行文件
    将所有的 .o文件链接起来生成可执行程序。
    [root@zhifachen test]# gcc -o 01_test.exe 01_test.o

运行:

[csy@local compile_test]$ ./01_test.exe 
x:3

编译过程小结

预处理阶段:对包含的头文件(#include)和宏定义(#define、#ifdef等)进行处理
gcc -E-o 01_test.c 01_test.i
//-o表示输出为指定文件类型 -E将源文件(.c)转换为(.i)
编译阶段:检查代码规范性、语法错误等,在检查无误后把代码翻译成汇编语言
gcc -S -o 01_test.i 01_test.s
//-S将已预处理的C原始程序(.i)转换为(.s)
汇编阶段:
gcc -c -o 01_test.o 01_test.s
//将汇编代码编译成机器码
链接阶段:将目标文件整合起来链接为可执行程序
gcc -o 01_test.exe 01_test.o
//将机器码(.o)和一些库函数整合成(.exe)

gcc常用选项

快速编译示例:
预编译,生成已预编译过的C原始程序*.i

  gcc -E gcc_test.c -o gcc_test.i    

编译,生成汇编语言原始程序*.s

gcc -S gcc_test.i -o gcc_test.s

编译,生成目标文件*.o

 gcc -c -o 01_test.o 01_test.s

链接,生成可执行程序

  gcc -o 01_test.exe 01_test.o

方法二:
编译

 gcc -c gcc_test.c -o gcc_test.o

链接

gcc -o gcc_test.exe gcc_test.o

运行测试程序

./gcc_test.exe

方法三:
编译并链接

 gcc -o gcc_test.exe gcc_test.c

运行测试程序

[csy@local compile_gcc]# ./gcc_test.exe
MAX=100
max(3,4)=4

编译时候传递全局宏定义示例

在代码中可以直接使用#define 来定义一个宏,然后在代码中引用,有时候我们希望通过编译时候决定编译宏内容,以及宏是否定义,这时候可以通过编译时候 -D 选项来指定。
hello.c源码

#include <stdio.h>
int main(void)
{
#ifdef  CSY//表示如果定义了CSY,即命令行参数传了CSY,就执行下面的输出
	printf("CSY is defined!\n");
#else
	printf("CSY is not defined!\n");
#endif
	printf("main exit\n");
	return 0;
}

条件编译,用-D传递,如果没有传CSY则执行#else

[csy@local compile_gcc]#  gcc -o hello hello.c -DCSY
[csy@local compile_gcc]#  ./hello.exe 
CSY is defined!
main exit
发布了65 篇原创文章 · 获赞 36 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_40860986/article/details/100184203