王 茹
辽宁装备制造职业技术学院(沈阳 110161)
在嵌入式应用程序的设计中,如果所有的编程任务都由汇编语言来完成,虽然目标代码执行效率高,但其工作量会很大且不易维护;如果全部任务由C/C++语言来完成,虽然简洁明了,但是目标代码执行效率低,尤其在实时性较强的应用中更会突显C/C++的不足。因此,一个嵌入式应用程序通常是由汇编语言和 C/C++语言混合编程来实现的,除了初始化部分用汇编语言编程外,其主要的编程任务一般都由C/C++来完成。主要介绍了ARM汇编语言与C/C++语言混合编程的两种实现方法:内嵌汇编和ATPCS规则。
ARM处理器核能通过相应的编译器实现汇编语言与 C/C++等语言之间的调用/切换。为了这些调用能够顺利的实施,ARM规定了一套标准——ATPCS过程调用标准。
ATPCS对 ARM 通用寄存器给以了不同的命名,在进行编程时一般使用ATPCS命名寄存器。ARM寄存器与ATPCS对照表如表1所示。
表1 ARM寄存器与ATPCS对照表
ATPCS规定堆栈采用满递减类型(FD,Full Descending),即堆栈通过减小存储器地址而向下增长,堆栈指针指向内含有效数据的最低地址。
整数参数的前4个使用R0~R3传递,其他参数使用堆栈传递,所以要想参数传递简单,最好函数的参数个数小于等于4。
子程序的返回结果为1个32位整数时,通过R0返回;返回结果为1个64位整数时,通过R0和R1返回;依此类推。结果为浮点数时,通过浮点运算部件的寄存器F0中。
嵌入式应用程序开发一般由汇编语言完成初始化后,切换到C语言实现应用功能的开发。汇编语言中要用IMPORT伪操作声明该C语言程序;汇编语言中通过BL实现程序的调用。
实例1 用汇编语言调用C语言方法实现字符串的复制。
在C语言程序中,用EXTERN声明汇编程序;在汇编程序中,用EXPORT 声明可以被调用的程序。
C++程序调用C程序时,在C++程序中使用关键词 extern "C"声明被调用的 C程序。对于C++中的类(class)或者结构(struct),如果它没有基类和虚函数,则相应的对象的存储结构和ARM C相同。
汇编程序调用 C++程序时,在 C++程序中使用关键词 extern "C"声明被调用的 C++程序。对于C++中的类或者结构,如果它没有基类和虚函数,则相应的对象的存储结构和ARM C相同。在汇编程序中使用伪操作 IMPORT声明被调用的C++程序。在汇编程序中将参数存放在数据栈中,而存放参数的数据栈的单元地址放在r0寄存器中,这样被调用的 C++程序就能访问相应的参数。
在 CC++语言中内嵌汇编语句可以实现一些高级语言不能实现或者不容易实现的功能。对于时间紧迫的功能也可以通过在 CC++语言中内嵌汇编语句来实现。内嵌的汇编器支持大部分ARM指令和Thumb指令,但是不支持诸如直接修改PC实现跳转的底层功能,也不能直接引用C语言中的变量。
在ARM C语言程序中使用关键词_asm来标识一段汇编指令程序,其格式如下:
在 ARM C++程序中除了可以使用关键词_asm来标识一段汇编指令程序外,还可以使用关键词 asm来标识一段汇编指令程序,其格式如下: asm("instruction[; instruction]");
(1)在汇编指令中,逗号(,)用作分隔符。因此如果指令中的 C\C++表达式中包含有逗号(,),则该表达式应该被包含在括号中。例如:
asm {ADD x, y, (f(), z)}其中,(f(), z)为C\C++表达式
(2)如果在指令中使用的物理寄存器,应该保证该寄存器不会被编译器在计算表达式值时破坏。
(3)不要使用物理寄存器去引用一个 C变量。
(4)对于内嵌汇编器可能会用到的寄存器,编译器自己会保存和恢复这些寄存器,用户不用保存和恢复这些寄存器。常量寄存器CPSR和寄存器SPSR外,别的寄存器必须先赋值然后再读取,否则编译器将会报错。3.3 内嵌汇编指令的应用
实例3 C程序中内嵌汇编语句,实现字符串的复制。
本文主要通过几个简单的例子演示了嵌入式开发中常用的C/C++和ARM汇编混合编程的一些方法和基本的思路,其中内嵌汇编的方法比较简洁,而ATPCS规则中调用方法较多。以上只是抛砖引玉,更详细和复杂的使用方法要结合实际应用并参考相关的资料。本文涉及的实例全部在ADS集成开发环境中运行实现。
[1]杜春雷.ARM 体系结构与编程.北京:清华大学出版社,2003.
[2]史斌.ARM汇编语言与C/C++混合编程方法,电子测量技术.2006(6).
[3]孙晔.ARM 嵌入式系统及应用.南京:江苏教育出版社,2011.