2026/08/20 程序的编译
一般在编写出程序之后,并不能直接运行,而是需要把程序通过编译器进行编译,生成可执行文件才能运行。而对于嵌入式学习,一般都是在Linux系统下使用GCC编译器对程序进行编译。

GCC编译器是Linux系统默认的C/C++编译器,大部分Linux发行版本中都是默认安装的。GCC编译器主要以Linux命令的形式在shell终端中使用,所以需要掌握关于GCC编译器的相关参数。


C语言程序编译过程:源程序---预处理---编译---汇编---链接---可执行文件
预处理:
对源码进行简单的加工,GCC编译器会调用预处理器cpp对程序进行预处理,其实就是解释源程序中所有的预处理指令,如#include(文件包含)、#define(宏定义)、#if(条件编译)等以#号开头的预处理语句。
这些预处理指令将会在预处理阶段被解释掉,如会把被包含的文件拷贝进来,覆盖掉原来的#include语句,把所有的宏定义展开,所有的条件编译语句被执行,GCC还会把所有的注释删掉,添加必要的调试信息。
预处理指令: gcc -E xxx.c -o xxx.i 会生成预处理文件 xxx.i
编译:
就是对经过预处理之后的.i文件进行进一步翻译,也就是对语法、词法的分析,最终生成对应硬件平台的汇编文件,具体生成什么平台的汇编文件取决于编译器,比如X86平台使用gcc编译器,而ARM平台使用交叉编译工具arm-linux-gcc。
编译指令:gcc -S xxx.i -o xxx.s 会生成对应汇编文件 xxx.s
汇编:
GCC编译器会调用汇编器as将汇编文件翻译成可重定位文件,其实就是把.s文件的汇编代码翻译为相应的指令。
编译指令:gcc -c xxx.s -o xxx.o 会生成汇编后的文件 xxx.o
链接:
经过汇编步骤后生成的.o文件其实是ELF格式的可重定位文件,虽然已经生成了指令流,但是需要重定位函数地址等,所以需要链接系统提供的标准C库和其他的gcc基本库文件等,并且还要把其他的.o文件一起进行链接。
-lc -lgcc 是默认的,可以省略
编译指令:gcc hello.o -o hello -lc -lgcc 会得到可执行文件 xxx // l是lib的缩写
程序的格式
一般对源文件进行编译和汇编之后,就会得到对应的目标文件xxx.o,目标文件也被称为可重定位文件,就是指还未完成链接的中间文件,用户可以把这些目标文件制作成在Linux系统下使用的静态库libxxx.a或者动态库libxxx.so。
其实目标文件和可执行文件的内容和结构非常相似,所以Linux系统下把目标文件xxx.o和可执行文件都称为ELF文件,ELF指的是Executable Linkable Format的缩写,中文翻译为可执行可链接格式。
注意:可以在linux系统中利用查看文件格式的指令: file 查阅目标文件和可执行文件的区别:


目标文件中的内容至少有编译后的机器指令代码、数据。除了这些内容以外,目标文件中还包括了链接时所需要的一些信息,比如符号表、调试信息、字符串等。一般目标文件将这些信息按不同的属性,以“节”(Section)的形式存储,有时候也叫“段”(Segment),一般情况下,它们都表示一个一定长度的区域,基本上不加以区别。
程序源代码编译后的机器指令经常被放在代码段(Code Section)里,代码段常见的名字有“.code”或“.text”。全局变量和局部静态变量数据经常放在数据段(Data Section),数据段一般名字都叫“.data”。
注意:linux系统的GCC编译套件有一款工具叫做objdump,可以查看目标文件内部的数据!

数据段中有一个叫做.bss段, bss以前其实是汇编伪指令,作用是为某些数据预留一块空间,bss其实是Block Started by Symbol,也就是用于存储未被初始化的全局变量和静态局部变量,但是在程序编译阶段是没有分配空间的,在程序运行时会得到空间。

| 常用的段名 | 说 明 |
|---|---|
| .rodatal | 这种段里存放的是只读数据,比如字符串常量、全局const变量。跟".rodata"一样 |
| .comment | 存放的是编译器版本信息,比如字符串:“GCC:(GNU)4.2.0” |
| .debug | 调试信息 |
| .dynamic | 动态链接信息 |
| .hash | 符号哈希表 |
| .line | 调试时的行号表,即源代码行号与编译后指令的对应表 |
| .note | 额外的编译器信息。比如程序的公司名、发布版本号等 |
| .strtab | String Table.字符串表,用于存储ELF文件中用到的各种字符串 |
| .symtab | Symbol Table.符号表 |
| .shstrtab | Section String Table.段名表 |
| .plt | 动态链接的跳转表和全局入口表 |
| .init | 程序初始化与终结代码段。 |
另外,objdump工具也可以实现把可执行文件进行反汇编,可以把得到的反汇编代码重定向到某个文本中进行查看 “objdump -D demo > > xxx.txt”
作者:bbzhu04@gmail.com ,多有不妥之处,望批评指正
本文原创,欢迎转载;转载请在文章显著位置标明原文链接: href="https://www.cnblogs.com/zhubb/p/22604751"
保留所有权限,未经许可禁止篡改、商用发布。

浙公网安备 33010602011771号