关于使用ARMcc和gcc编译C文件的整个流程
c文件预处理生成.i文件.i文件编译生成.s文件.s文件汇编生成.o文件.o文件链接生成 .axf文件最后使用fromelf或类似工具生成 .bin文件(纯二进制文件)这个流程适用于嵌入式开发环境,特别是使用 Keil 的 ARM 开发板。
使用 Keil 编译 C 语言文件时,从 .c 文件到最终的 .bin 文件的生成过程是这样的:
1. 预处理阶段 (Preprocessing)
-
输入:
.c(源文件),.h(头文件) -
动作:纯文本替换(Copy-Paste)。
-
细节:
-
宏展开:把所有的
#define替换成实际的数字或代码片段。 -
文件包含:遇到
#include "A.h",就找到A.h文件,把它里面的所有内容递归地复制粘贴到当前.c文件里。 -
extern 的处理:预处理器不关心
extern,它只是把头文件里的extern int status;这行字原封不动地搬进.c文件的文本流里。
-
-
输出:
.i文件(体积很大的纯 C 代码,无任何#指令)。
2. 编译阶段 (Compilation) —— "承诺与占位"
-
输入:
.i文件 -
动作:语法翻译(C $\rightarrow$ 汇编)。
-
extern 的作用(占位):
-
当编译器遇到
extern void FunctionB();或extern int g_Var;时,它会检查语法是否正确。 -
关键点:编译器不会为
g_Var分配内存,也不会生成FunctionB的机器码。 -
它会在生成的汇编代码中留下一个 "未解决符号 (Unresolved Symbol)" 的标记。这就好比编译器开了一张 "欠条":“这里需要用到
g_Var的地址,但我现在不知道它在哪,先空着(占位),等链接器来填。”
-
-
输出:
.s文件(汇编代码,人类可读)。
3. 汇编阶段 (Assembly) —— "各路汇合"
-
输入:
.s文件(来自 main.c 等),以及启动文件 (.s)。 -
动作:机器码生成。
-
关键角色:启动文件 (Startup File, e.g.,
startup_stm32fxxx.s)-
它是什么:包含了复位中断服务函数
Reset_Handler(芯片上电执行的第一句指令)和中断向量表。 -
它从哪来:通常由芯片厂商 (ST/NXP) 提供的固件包 (SDK) 中自带。你在 Keil 工程左侧目录里手动添加的那个
.s文件就是它。 -
处理:汇编器会把你的
main.s和厂商的startup.s分别转换成机器码。
-
-
输出:
.o文件(目标文件)。-
此时,
.o文件里的代码地址都是从 0 开始的相对地址。 -
extern的地方依然是一个空洞(欠条)。
-
4. 链接阶段 (Linking) —— "分房与兑现"(这里gcc对应的链接脚本文件是.ld文件)
这是 IAP 开发最核心的步骤。
-
输入:多个
.o文件 +.lib(库文件) + 分散加载文件 (.sct)。 -
动作:地址重定位 (Relocation) 和 符号解析 (Symbol Resolution)。
-
关键角色:分散加载文件 (Scatter File, .sct / .ld)
-
它是什么:内存分配地图。它告诉链接器:“Flash 从
0x08000000到0x08080000是合法的,RAM 从0x20000000开始。请把代码段放在 Flash,变量放在 RAM。” -
它从哪来:
-
自动生成:Keil 默认根据
Options -> Target里的设置(Start/Size)自动生成。 -
手动编写:你可以取消
Use Memory Layout...勾选,自己写.sct文件(IAP 中常用于把特定函数强制放到 RAM 或 Flash 的特定扇区)。
-
-
-
extern 的最终归宿(兑现欠条):
-
链接器扫描所有
.o文件,发现main.o里有个extern int g_Var的欠条。 -
它在
other.o里找到了int g_Var的实体定义。 -
根据
.sct文件,链接器决定把g_Var放在 RAM 的0x20000004位置。 -
回填:链接器回到
main.o的机器码里,把之前那个“占位空洞”填上0x20000004这个实际地址。
-
-
输出:
.axf/.elf文件(包含绝对物理地址的完整程序,带调试信息)。
5. 格式转换阶段 (Format Conversion)(这里gcc对应.hex文件)
-
输入:
.axf文件 -
动作:提取与剥离。
-
输出:
.hex或.bin。 -
最后,如果需要生成纯二进制格式的文件,Keil 会使用 转换工具(例如
fromelf)将.axf文件转换成.bin文件。这个文件是纯粹的二进制代码,去除了所有调试和符号信息,只包含程序的机器码部分。 -
命令示例(在Keil中使用
fromelf):fromelf --bin program.axf --output program.bin
总结:
整个流程是:
-
.c文件 预处理生成.i文件 -
.i文件 编译生成.s文件 -
.s文件 汇编生成.o文件 -
.o文件 链接生成.axf文件 -
最后使用
fromelf或类似工具生成.bin文件(纯二进制文件)
这个流程适用于嵌入式开发环境,特别是使用 Keil 的 ARM 开发板。
更多推荐



所有评论(0)