(1) 编译,MDK 软件使用的编译器是 armcc 和 armasm,编译后生成 .o 类型的目标文件;
(2) 链接,链接器 armlink 把各个.o 文件及库文件链接成一个映像文件“.axf”或“.elf”;
(3) 格式转换,一般来说 Windows 或 Linux 系统使用链接器直接生成可执行映像文件 elf 后,内核
根据该文件的信息加载后,就可以运行程序了,但在单片机平台上把该文件的内容加载到芯片上,需要对链接器生成的 elf 映像文件利用格式转换器 fromelf 转换成“.bin”或“.hex” 文件,交给下载器下载到芯片的 FLASH 或 ROM 中。
/***********************************************************************************************************/
armcc编译器

armcc 用于把 c/c++ 文件编译成 ARM 指令代码,编译后会输出 ELF 格式的 .O 文件;
从该图中的命令可看到,它调用了-c、-cpu –D –g –O1 等编译选项,这些选项具体作用可以查看 MDK 的帮助手册,在 armcc 编译器说明章节,可详细了解
/***********************************************************************************************************/
armasm汇编器

armasm 是汇编器,它把汇编文件编译成 .O 文件.
/***********************************************************************************************************/
armlink 是链接器

armlink 是链接器,它把各个 O 文件链接组合在一起生成 ELF 格式的 AXF 文件,AXF 文件是可
执行的,下载器把该文件中的指令代码下载到芯片后,该芯片就能运行程序了;利用 armlink 还
可以控制程序存储到指定的 ROM 或 RAM 地址。
/***********************************************************************************************************/
armar 工具

armar 工具用于把工程打包成库文件(
把.o 文件打包成 lib 文件的)
,
fromelf 可根据 axf 文件生成 hex、bin 文件,hex 和 bin 文件是大多数下载器支持的下载文件格式。 在 MDK 中,针对 armar 和 fromelf 工具的选项几乎没有,仅集成了生成 HEX 或 Lib 的选项。

如果我们想利用 fromelf 生成 bin 文件,可以在 MDK 的“Option for Target->User”页中添加调用 fromelf 的指令.
在 User 配置页面中,提供了三种类型的用户指令输入框,在不同组的框输入指令,可控制指令
的执行时间,分别是编译前 (Before Compile c/c++ file)、构建前 (Before Build/Rebuild) 及构建后
(AfterBuild/Rebuild) 执行。这些指令并没有限制必须是 arm 的编译工具链,例如如果您自己编写
了 python 脚本,也可以在这里输入用户指令执行该脚本。
图中的生成 bin 文件指令调用了 fromelf 工具,紧跟后面的是工具的选项及输出文件名、输入文件
名。由于 fromelf 是根据 axf 文件生成 bin 的,而 axf 文件又是构建 (build) 工程后才生成,所以我
们把该指令放到“AfterBuild/Rebuild”一栏。
/***********************************************************************************************************/
MDK编译过程

(1)说明构建过程中使用的编译器,链接器,格式转换器,以及所在的目录.
其中armar 是用于把.o 文件打包成 lib 文件的
;
(2)使用 armasm 编译汇编文件,编译后每个汇编源文件都对应有一个独立的.o 文件;
(3)使用 armcc 编译 c/c++ 文件,编译后每个 c/c++ 源文件都对应有一个独立的.o 文件;
(4)使用 armlink 链接 .o 文件,根据程序的调用把各个.o 文件内容链接起来,最后生成axf 映像文件,并附带程序各个域大小的说明,包括 Code、RO-data、RW-data 及 ZI-data 的大小;
(5)使用 fromelf 格式转换器生成下载格式文件,它根据 axf 映像文件转成 hex 文件,并列出编译过程出现的错误和警告;
(6)最后一段提示给出了整个构建过程消耗的时间;
构建完成后,可在工程的“Output”及“Listing”目录下找到由以上过程生成的各种文件
/***********************************************************************************************************/
程序的内存分布
Code
:即代码域,它指的是编译器生成的机器指令,这些内容被存储到
ROM 区
RO-data:即只读数据域它指程序中用到的只读数据,这些数据被
存储在ROM区,因而程序不能修改其内容。例如 C 语言中 const 关键字定义的变量就是典型的RO-data。在运行过程中不需要加载到SRAM,内核可以直接取ROM中读取。
RW-data:
即可读写数据域,它指初始化为“非
0
值”的可读写数据,
在存储状态下在ROM区,运行的时候它们会被复制到 RAM 区
,因而应用程序可以修改其内容,但是掉电需要保存初值数据(这就是为什么和ZI-data都是全局变量要分开存储的原因)
。例如 C
语言中定义的初始值非0的全局变量。
ZI-data:
即可读写数据域,
它指初始化为“
0
值”的可读写数据,
它们也常驻在 RAM
区,因而应用程序可以更改其内容。例如 C
语言中定义的初始值为0的全局变量
(
若定义该变量时没有赋予初始值,编译器会把它当 ZI-data
来对待,初始化为
0)
;


其中ZI-data又分为栈空间和堆空间:
C 语言中,函数内部定义的局部变量属于栈空间,进入函数的时候从向栈空间申请内存给局部变量,退出时释放局部变量,归还内存空间。而使用 malloc 动态分配的变量属于堆空间。
在程序中的栈空间和堆空间都是属于 ZI-data 区域的,这些空间都会被初始值化为 0 值。编译器给出的 ZI-data 占用的空间值中包含了堆栈的大小 (经实际测试,若程序中完全没有使用 malloc 动态申请堆空间,编译器会优化,不把堆空间计算在内)
。
/***********************************************************************************************************/
编译后生成的文件
每个 C 源文件都对应生成了.o、.d 、.crf 后缀的文件,还有一些额外的.dep、.hex、.axf、.htm、.lnp、.sct、.lst 及.map 文件
/***********************************************************************************************************/
工程文件的说明
uvprojx 文件就是我们平时双击打开的工程文件,它记录了整个工程的结构,如芯片类型(记录之前用的是C8T6还是ZET6等)、工程包
含了哪些源文件等内容
uvoptx 文件记录了工程的配置选项,如下载器的类型(记录之前用的是STLINK还是JLINK等)、变量跟踪配置、断点位置以及当前已打开的文件等等
uvguix 文件记录了 MDK 软件的 GUI 布局,如代码编辑区窗口的大小、编译输出提示窗口的位置
等等,使得我们每次重新打开工程时,都能恢复上一次的工作环境。
上面三个工程都是当 MDK
正常退出时才会被写入保存
,
若 MDK 错误退出时 (如使用 Win-dows 的任务管理器强制关闭),工程配置参数的最新更改是不会被记录的
,重新打开工程时要再
次配置。
根据这几个文件的记录类型,
可以知道 uvprojx 文件是最重要的,删掉它我们就无法再
正常打开工程了
,而
uvoptx
及
uvguix
文件并不是必须的,可以删除,重新使用
MDK
打开
uvprojx工程文件后,会以默认参数重新创建 uvoptx
及
uvguix
文件。
(
所以当
使用 Git/SVN 等代码管理的时候,往往只保留 uvprojx 文件
)
/***********************************************************************************************************/
.lib库文件
/***********************************************************************************************************/