C语言程序变为一个可执行程序需要经过四个步骤:预处理、编译、汇编、链接。vs2019不好演示这四个阶段,以下代码和指令都是在linux环境下执行,不需要理解指令是什么意思,可以后面学了linux在看。
代码
预处理
生成预处理完成后的代码。
gcc test.c -E -o test.i
gcc hello.c -E -o hello.i
将源文件执行完预处理后停止,将代码保存到test.i、hello.i文件中
ls查看当前文件夹的文件
vim是编辑文件的工具,先打开文件。
hello.i和test.i里面存放预处理后的代码。
预处理阶段,完成对头文件的包含(#include <stdio.h>变成上面八百多行的代码);对define定义的符号完成替换(N被替换成5);删除注释(对于编译器而言,注释是没有用的东西,直接删掉)。
编译
生成编译后的代码。
gcc hello.i -S
gcc test.i -S
指令执行完,会生成对应后缀为.s的文件hello.s、test.s。
编译结束,C语言代码变成汇编代码,pushq、movq等等是汇编指令。中间要经过词法分析、语法分析、语义分析、符号汇总。代码有编译错误的都在这个阶段就会找出来并报错。符号汇总:汇总全局的符号,hello.c中的hello函数、test.c中的main函数和hello函数。注:static修饰的全局变量和函数不会进符号汇总。
汇编
生成汇编后的代码
gcc hello.s -c
gcc test.s -c
执行完指令,生成对应后缀为.o的文件hello.o、test.o
执行完汇编后的代码,将汇编指令变成机器语言(二进制序列)。
查看符号表。
readelf hello.o -s
readelf test.o -s
查看hello.o和test.o的符号表
hello.o的符号表中hello的TYPE是FUNC(函数),test.o的符号表中的hello的TYPE是NOTYPE(未定义)。
链接
合并段表,符号表的合并和重定位。
readelf test -s
查看可执行程序的符号表
可以看到符号表中的hello合并了,没有了TYPE是NOTYPE的hello函数,只剩下TYPE为FUNC的hello函数。如果链接的时候有TYPE为NOTYPE的函数或者变量,程序报错,链接错误,出现未定义的符号。
可执行程序
生成可执行程序并运行。
gcc test.o hello.o -o test
编译生成可执行程序test
./test
运行可执行程序
文章评论