C源程序到可执行文件的步骤
2016-07-13 14:38
204 查看
大家都知道,计算机只认识0 1 二进制数,我们编写程序也是为了让计算机按照人的思维完成相应的操作,我们编写的程序代码计算机并不认识,所以需要翻译成计算机能够认识的机器语言,不同的计算机机器代码不一样,所以就需要编译器来实现中间的步骤,那从我们的.c文件到计算机可执行的文件中间到底经过了哪些步骤呢?
c源文件—->编译预处理—->编译程序—->优化程序—->汇编—->链接程序—->可执行文件
1.编译预处理阶段
加载头文件、宏替换、条件编译的作用。一般处理“伪指令”(带“#”的语句)和一些特殊符号,主要分为以下几类:
(1)宏定义指令,如#define,#undef等,进行宏替换和取消宏定义。
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif,等,让程序可以选择性的编译。
(3)头文件包含指令,如#include “”或者#include <>等。预编译程序将把头文件中的定义加入到产生的输出文件中,以供编译程序处理。
(4)特殊符号,预编译程序可以识别一些特殊的标识。
我们可以通过指令来查看,(hello.c)
[root@localhost c]# gcc -E hello.c
2.编译阶段
编译程序工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码,生成(.o)文件
我们可以通过指令来查看,(hello.c)
[root@localhost c]# gcc -c hello.c
3.优化阶段
优化一方面是对中间代码的优化,另一种则针对目标代码的生成而进行的。对代码的检查,主要是删除公共表达式、循环优化、复写传播,以及无用赋值的删除,后一种优化同机器的硬件结构密切相关,考虑如何充分利用机器的各个硬件寄存器存放的有关变量的值,以减少对于内存的访问次数,提高效率。
4.汇编阶段
把汇编代码翻译成目标机器指令的过程。目标文件由段组成。通常一个目标文件中至少有两个段:
代码段 :该段中所包含的主要是程序的指令。一般是可读和可执行不可写。
数据段:存放程序用到的各种全局变量或静态的数据。一般是可读可写可执行。
我们可以通过指令来查看生成(.s)汇编文件
[root@localhost c]# gcc -S hello.c
5.链接
将有关的目标文件彼此相连接,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体,这个文件可被加载或拷贝到存储器执行,在我的上一遍博文中也有讲过链接就是将各种目标文件根据他们之间调用关系联系到一起,才能成为整个工程的机器代码,开发人员指定同库函数的链接方式的不同,链接处理可分为两种:
(1)静态链接—函数的代码将从静态链接库(实际是一个目标文件的集合,其中每个文件含有库中相关函数的代码)拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中
(2)动态链接—函数的代码被放到动态链接库或共享对象的某个目标文件中。链接程序所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。执行时,动态链接库的全部内容将被映射到进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码,使最终可执行文件较短小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份共享对象的代码。
我们可以通过指令来查看,(hello.c)
[root@localhost c]# gcc hello.o -o hello
生成hello执行文件,如下
[root@localhost c]# gcc hello.c -o hello
[root@localhost c]# ./hello
hello world
经过这5个步骤,就可以生成可执行文件了,Windows下默认为a.exe,Linux下默认为a.out,在该目录下执行就可以了
补充
目标文件有三种形式:
1> 可重定位的目标文件:含二进制代码和数据,其形式可以在编译时与其它可定位目标文件合并起来,创建一个可执行目标文件。
2> 可执行目标文件:包含二进制代码和数据,其形式可以被直接拷贝到存储器并执行,也就是最后形成的文件。
3> 共享目标文件:一种特殊的可重定位目标文件,可以在加载或运行时,被动态加到存储器并执行。
编译器和汇编器生成可重定位目标文件(包括共享目标文件),链接器生成可执行目标文件。
c源文件—->编译预处理—->编译程序—->优化程序—->汇编—->链接程序—->可执行文件
1.编译预处理阶段
加载头文件、宏替换、条件编译的作用。一般处理“伪指令”(带“#”的语句)和一些特殊符号,主要分为以下几类:
(1)宏定义指令,如#define,#undef等,进行宏替换和取消宏定义。
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif,等,让程序可以选择性的编译。
(3)头文件包含指令,如#include “”或者#include <>等。预编译程序将把头文件中的定义加入到产生的输出文件中,以供编译程序处理。
(4)特殊符号,预编译程序可以识别一些特殊的标识。
我们可以通过指令来查看,(hello.c)
[root@localhost c]# gcc -E hello.c
2.编译阶段
编译程序工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码,生成(.o)文件
我们可以通过指令来查看,(hello.c)
[root@localhost c]# gcc -c hello.c
3.优化阶段
优化一方面是对中间代码的优化,另一种则针对目标代码的生成而进行的。对代码的检查,主要是删除公共表达式、循环优化、复写传播,以及无用赋值的删除,后一种优化同机器的硬件结构密切相关,考虑如何充分利用机器的各个硬件寄存器存放的有关变量的值,以减少对于内存的访问次数,提高效率。
4.汇编阶段
把汇编代码翻译成目标机器指令的过程。目标文件由段组成。通常一个目标文件中至少有两个段:
代码段 :该段中所包含的主要是程序的指令。一般是可读和可执行不可写。
数据段:存放程序用到的各种全局变量或静态的数据。一般是可读可写可执行。
我们可以通过指令来查看生成(.s)汇编文件
[root@localhost c]# gcc -S hello.c
5.链接
将有关的目标文件彼此相连接,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体,这个文件可被加载或拷贝到存储器执行,在我的上一遍博文中也有讲过链接就是将各种目标文件根据他们之间调用关系联系到一起,才能成为整个工程的机器代码,开发人员指定同库函数的链接方式的不同,链接处理可分为两种:
(1)静态链接—函数的代码将从静态链接库(实际是一个目标文件的集合,其中每个文件含有库中相关函数的代码)拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中
(2)动态链接—函数的代码被放到动态链接库或共享对象的某个目标文件中。链接程序所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。执行时,动态链接库的全部内容将被映射到进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码,使最终可执行文件较短小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份共享对象的代码。
我们可以通过指令来查看,(hello.c)
[root@localhost c]# gcc hello.o -o hello
生成hello执行文件,如下
[root@localhost c]# gcc hello.c -o hello
[root@localhost c]# ./hello
hello world
经过这5个步骤,就可以生成可执行文件了,Windows下默认为a.exe,Linux下默认为a.out,在该目录下执行就可以了
补充
目标文件有三种形式:
1> 可重定位的目标文件:含二进制代码和数据,其形式可以在编译时与其它可定位目标文件合并起来,创建一个可执行目标文件。
2> 可执行目标文件:包含二进制代码和数据,其形式可以被直接拷贝到存储器并执行,也就是最后形成的文件。
3> 共享目标文件:一种特殊的可重定位目标文件,可以在加载或运行时,被动态加到存储器并执行。
编译器和汇编器生成可重定位目标文件(包括共享目标文件),链接器生成可执行目标文件。
相关文章推荐
- 同一个textview设置不同文字样式
- LayoutAnimation
- iOS开发支付集成之支付宝支付
- css选择器大全
- 各大组织大马默认密码
- Google 的开源技术protobuf 简介与例子
- HDU 1045 Fire Net【DFS深搜】
- 排序算法的复习和总结[PHP实现]
- Unity3D 摄像机的Transform通过摇杆输出的方向
- 30分钟做一个二维码名片应用,有源码!
- 菜单 CSS3自定义图标悬浮菜单
- 用户登录过滤器
- JavaWeb-Spring框架-IOC-Bean
- C和C++混合编程
- 如何把一个qmake的Ubuntu手机应用打包为一个snap应用
- NYOJ 1063 生活的烦恼 (二叉树递归建立)
- 自我介绍和决心书
- Linux内存管理之mmap详解&&nginx子进程间通信
- Rgraph js 实时刷新canvas,并解决重绘问题
- iOS日常工作之常用宏定义大全