编译过程:预编译、编译、汇编与链接

原文地址:http://blog.csdn.net/u014120684/article/details/46352167

预编译的文件扩展名是ii 

gcc -E hello.c -o hello.i 
预编译过程主要处理源代码文件当中的以#开头的预编译指令,比如#include就是把头文件插入到这个位置 #define就是把所有的宏定义展开,还有就是删除所有的注释

编译就是把i文件编译成为汇编代码文件,汇编代码扩展名是.s 
gcc -S hello.i -o hello.s

但是现在版本的gcc把预编译和编译两个步骤合并成为一个步骤, 
gcc -S hello.c -o hello.s 
或者编译器ccl:ccl hello.c 
c++的编译器:cclplus hello.cpp

汇编就是将汇编语言的代码文件转变成机器语言,只是对照汇编语言的指令和机器语言一条一条翻译过来。 
使用汇编器as 
as hello.s -o hello.o 
或者 gcc -c hello.s -o hello.o 
或者最常用的预编译,编译,汇编三合一:gcc -c hello.c -o hello.o 或:gcc -c hello.c 
这么看来,最后生成的目标文件.o里面就是机器语言,其实它本身就是按照可执行文件格式存储的,只是和真正的可执行文件在结构上稍有不同。

链接:在一个程序被分为多个模块的时候,这些模块之间最后如何组合形成一个单一的程序是要解决的问题。模块之间如何组合的问题可以归结为模块之间如何通信的问题,最常见的属于静态语言的C/C++模块之间通信有两种方式,一种是模块之间的函数调用(可以看我的笔记:C++头文件与CPP的关系),另外一种是模块间的变量访问。 
函数访问需要知道目标函数的地址,变量访问也需要知道目标变量的地址。从原理上来讲,链接的过程工作无非就是把函数和变量的引用加以修正,让程序能找到函数和变量的地址。 
源代码文件.c编译成为目标文件.o,目标文件和库一起链接形成最终可执行文件。最常见的库就是运行时库(runtime library). 
在链接的时候,假设我们有个全局变量叫做var,他在目标文件A里面,我们在目标文件B里面要访问这个全局变量,比如在B里面: 
mov1 $0x2a,var 
相当与C语言里面的var=42 
在编译目标文件B的时候,编译器并不知道var的目标地址,所以u编译器在没法确定地址的情况下,将这条Mov指令的目标地址置为0,等待链接器在将目标文件A和B链接起来的时候再将其修正。

动态链接:解决空间浪费和更新困难的问题,不使用静态库而使用动态库,动态链接就是把程序按照模块拆分成各个相对独立的部分,在程序运行时才将他们链接在一起形成一个完整的程序,而不是像静态链接那样把所有的程序模块都链接成一个个单独的可执行文件。 
gcc -fPIC -shared 
-shared表示产生一个共享对象

比如一个静态库libtest.a和一个动态库libtest.so,在链接libtest.a和hello.o的时候,生成的hello可执行文件里面就包含了libtest.a。以后执行hello的时候就算删除了libtest.a也能执行出来。而在链接libtest.so和hello.o的时候,生成的hello可执行文件里面就没libtest.so,如果删除了libtest.so则不能执行。

猜你喜欢

转载自blog.csdn.net/alss1923/article/details/78971743
今日推荐