从源码到可执行程序的步骤:预编译、编译、链接、strip

预编译:预编译器执行。譬如C中的宏定义就是由预编译器处理,注释等也是由预编译器处理 。

编译:编译器来执行。把源码.c  .S 编成机器码.o文件。编译的过程是真正在干活,.o的文件其实已经是机器码,已经是二进制了,只不过它现在还没有组织起来,还是零散的,一个函数编译出来是一段.o,是好多个函数编译出来的代码段。

链接:链接器来执行。 把.o文件的各函数(段)按照一定规则(链接脚本来指定)累积(打包)在一起,形成可执行文件。这个可执行程序在操作系统底下是可以直接执行的。

strip(可选): strip是把可执行程序中的符号信息给拿到,以节省空间。其实你在编译链接生成的可执行程序中是有很多符号信息的,什么叫符号信息,譬如说你的函数名,函数在链接的过程中,可执行程序里面是有专门的一个符号表来记录各个函数名的信息的,所以我们在反汇编的时候才能找到每个函数的名字,符号表存在的意义就是为了能够反向调试。例如在Linux内核启动失败,就会打印出来一个OOPS, 打印出来的这个信息里面就会有符号,通过这个符号就能知道哪个函数失败了。如果你的程序调试完了没有任何的bug了,就可以不要符号信息了,我们就可以strip掉,这样就可以节省一些空间。就像你有一个3M的可执行程序,你把符号去掉好,可能就只剩下2M了,这些符号信息在我们正式运行的时候是不起作用的。这就是我们windows里面讲的debug版本和release版本。release版本用户拿去反编译的时候得到的是只是一些数字,得不到任何符号。

objcopy(可选) :编译链接得到的可执行程序是不能用来烧录的, 烧录需要用bin文件来烧录,这就要用到objcopy了,由可执行程序生成可烧录的镜像bin文件,通过objcopy工具来实现的,

strip 和 objcopy是可选的

注意: 假如源文件中有两个.c (1.c 2.c),1个.c(3.s)文件,每个文件中又有多个函数f1,f2...,编译的时候是每一个.c/.s是各自编译自己的,得到的目标文件是1.o  2.o,  3.o,但是1.o里面又按照函数分成好几段,f1段,f2段等等,这个f1段的名字就是f1,里面有许多二进制代码,f2也一样,每一坨二进制代码就是这个函数f生成的,2.c 3.c也是一样的,这就是我们编程的时候是以函数为单位的,因为编译的时候也是以函数为单位的,这些编译好的.o文件我们叫目标文件,然后再由目标文件去链接。链接的过程就是把上面编译得到的零散的函数给他结合起来。这就好比做菜,原料有葱姜蒜,葱姜蒜就是.c文件里面的一个一个函数,把葱姜蒜一个个拿出来,切好,分开成一个一个的,这里对每一个原材料进行加工后放好的过程就是相当于编译,链接的过程就相当于炒菜的过程,把切好的葱姜蒜按照一定的顺序下锅翻炒,先放什么后放什么,这是有个顺序和过程的,链接的时候也是有个顺序和过程的,这些函数是不能杂乱的堆在一起的,需要按照一些顺序来堆,这些顺序就是我们链接时候的一些规则,这些规则就是链接脚本,链接之后就按顺序排成一坨了,最终形成可执行文件,

 

 

你可能感兴趣的:(从源码到可执行程序的步骤:预编译、编译、链接、strip)