在ARM平台下从事嵌入式软件开发,大家会遇到各种不同的集成开发环境和编译器,例如IAR,ADSI,RVDS Keil MDK RealVidew MDK ARM交叉编译器aarm-linux-gcc等,如果将这些不同的IDE归类,一般可以分为两大类,一类IDE内部集成了ARM编译器,另一类则使用开源的GNU GCC for ARM编译器。为了方便,在后续的文字中我们简称为GNU ARM编译器。
3.7.1 重新认识编译器
编译器到底是什么,在很多人的概念中,编译器可能就是一个gcc命令,用来把C程序编译器成可执行文件,其实编译器不仅仅是一个简单的gcc或者arm-linux-gcc命令,而是一套完整的工具集,一套完整的编译工具集主要包括以下几个部分。
编译器:用来将C源文件编译成汇编文件
汇编器:用来将汇编文件汇编成目标文件,
链接器:将目标文件组装成可执行文件
二进制转化工具:objdump, objcopy, strip等。
库打包工具:ar
调试工具:gdb , nm
库/头文件:根据C语言标准定义的API实现C标准库以及对应的头文件。
一套完整的编译器工具,不仅仅包含编译器,还有各种个样的工具,函数库,头文件等。编译器只不过是我们叫顺口。我们所说的编译器,其实不仅仅是编译器,还有各种二进制工具,C标准库,头文件等等。
不同的ARM编译器开发商,会根据ARM指令集规定的标准指令去开发各自的编译器软件,目前市面上比较常见的编译器有ARM公司开发的ARMCC编译器,IAR,C/C++编译器,开源的GNU GCC for ARM交叉编译器。不同的IDE一般都会内嵌上面三种编译器中的一种,或者IDE和编译器分别独立发布,。甚至有些IDE还可以通过配置,支持多种编译器。
各种厂商的编译器因为遵循统一套ARM指令集标准,因此经过不同编译器编译的程序都可以在同一台ARM处理器上运行,市面上各种ARM编译器之间的唯一区别是汇编指令的格式有所差异,造成差异的原因是各家编译器厂商虽然遵循统一套AMR指令集,但是根据自己的产品需求和定位,各自扩展了不同的伪指令。
ARM 指令集
ARM编译器 ARM GNU编译器
扩展伪指令 扩展伪指令
ARM指令 ARM指令
CPU
图3-8 ARM指令集于伪操作。
以ARM公司官方发布的ARM编译器和开源GNU ARM编译器为例,如图3-8所示,他们之间主要差别在于伪操作,编译器开发商在设计编译器时会参考ARM指令集,将C程序翻译成CPU能够识别并运行的ARM标准指令,除此之外,为了方便使用汇编程序的编写,不同的编译器还会扩展一些各自的语法特性, 这些扩展的伪指令和语法特性被称为伪操作。这些伪操作主要用来辅助程序员在编程时定义数据,定义不同的代码段和数据段,设计汇编程序的分支跳转结构,以及用来将汇编指令组装成一个可以运行的汇编程序,我们学习编写汇编程序,除了要掌握指令中定义的ARM指令,还要了解编译器扩展的微操作以及他们之间的区别。
3.7.2 GNU ARM编译器的伪操作
不同ARM编译器之间的伪操作差别还是挺大的,以ARM编译器和GNU ARM编译器为例,我们可以对比下他们的数据定义,程序结构方面的差别,
如表 3-5 所示。
ARM编译器 | GNU ARM编译器 | 伪操作说明 |
AREA copy, CODE, ... | .text | 定义一个代码段 |
AREA .dat .DATA ... | .data | 定义一个数据段 |
使用;注释 | 使用//注释 | 汇编中的注释方式 |
DCD | .long .word | 分配一片连续的字存储单元 |
Entry | ENTRY(_start) | 汇编程序的执行入口 |
END | .end | 汇编程序结束标记 |
CODE32 | .arm / .code32 | 告诉编译器后面指令为ARM指令 |
CODE16 | .thumb /.code16 | 告诉编译器后面指令为Thumb指令 |
SPACE | .space | 分配一片连续的内存,并初始化为0 |
GBLL,GBLA | .global | 定义一个全局变量 |
EXPORT, GLOBAL | .global | 全局符号声明 |
EQU,SETL,SETA | .extern | 引用其它文件的全局符号前需要先声明 |
IF,ELSE,ENDIF | .ifdef .else .endif | 条件汇编 |
MACRO/MEND | .macro/.endm | 宏定义 |
GET INCLUDE | .include | 文件包含,并展开编译 |
INCBIN | .incbin | 文件包含,不编译 |
在后面的内容中,我们会经常使用ARM反汇编代码来分析C语言的底层运行机制,为了能看懂反汇编代码,我们还需要熟悉一下在一个反汇编文件中经常看到的各种GNU ARM伪指令操作。