当前位置:   article > 正文

ARM实验-C语言主程序调用ARM子程序_基于arm的c语言程序设计实验

基于arm的c语言程序设计实验

一、实验名称:C语言主程序调用ARM子程序

二、实验目的:

  1. 了解ARM应用程序框架。
  2. 了解ARM汇编程序函数和C语言程序函数相互调用时,遵循的ATPCS标准;
  3. 了解和掌握C语言程序调用ARM语言程序函数的基本方法;
  4. 了解和掌握C语言程序调用ARM汇编程序函数的参数传递过程;
  5. 掌握内联汇编和嵌入式汇编的编程方法。

三、实验原理:

  1. ARM工程

由于C语言便于理解,有大量的支持库,所以它是当前ARM程序设计所使用的主要编程语言。

对硬件系统的初始化、CPU状态设定、中断使能、主频设定 以及RAM控制参数初始化等C程序力所不能及的底层操作,还是要由汇编语言程序 来完成。

在应用系统的程序设计中,若所有的编程任务均用汇编语言 来完成,其工作量是可想而知的,这样做也不利于系统升级或应用软件移植。

通常汇编语言部分完成系统硬件的初始化;高级语言部分完成用户的应用。

执行时,首先执行初始化部分,然后再跳转到C/C++部分。整个程序结构显得清晰明了,容易理解。为方便工程开发,ARM公司的开发环境ARM ADS为用户提供了一个可以选用的应用程序框架。该框架把为用户程序做准备工作的程序分成了: 启动代码 和 应用程序初始化 两部分。

用于硬件初始化的汇编语言部分叫做 启动代码;用于应用程序初始化的C部分叫做初始化部分。

2.过程调用标准ATPCS

在ARM工程中,C程序调用汇编函数和汇编程序调用C函数是经常发生的事情。为此人们制定了ARM-Thumb过程调用标准ATPCS(ARM-Thumb Procedure Call Standard)。

  1. ATPCS规定,ARM的数据堆栈为FD型堆栈,即递减满堆栈。
  2. ATPCS标准规定,对于参数个数不多于4的函数,编译器必须按参数在列表中的顺序,自左向右为它们分配寄存器R0~R3。其中函数返回时,R0还被用来存放函数的返回值。
  3. 如果函数的参数多于4个,那么多余的参数则按自右向左的顺序压入数据堆栈,即参数入栈顺序与参数顺序相反。
  4. 根据ATPCS的C语言程序调用汇编函数,参数由左向右依次传递给寄存器R0~R3的规则

 3.C/C++语言和汇编语言的混合编程之: 内联汇编和嵌入式汇编

除了上面介绍的函数调用方法之外,ARM 编译器 armcc 中含有的内嵌汇编器还允许在 C 程序中 内联或嵌入式汇编代码,以提高程序的效率。

所谓内联汇编程序,就是在 C 程序中直接编写汇编程序段而形成一个语句块,这个语句块可以使用除了 BX 和 BLX之外的全部ARM指令来编写,从而可以使程序实现一些不能从C获得的底层功能。

其格式为:

    __asm

   {

      汇编语句块

    }

内联汇编 与 真实汇编 之间有很大区别,会受到很多限制。

(1)它不支持 Thumb 指令;除了程序状态寄存器 PSR 之外,不能直接访问其他任何物理寄存器等;

(2)如果在内联汇编程序指令中出现了以某个寄存器名称命名的操作数,那么它被叫做虚拟寄存器,而不是实际的物理寄存器。编译器在生成和优化代码的过程中,会给每个虚拟寄存器分配实际的物理寄存器,但这个物理寄存器可能与在指令中指定的不同。唯一的一个例外就是状态寄存器 PSR ,任何对 PSR 的引用总是执行指向物理 PSR;

(3)在内联汇编代码中不能使用寄存器 PC(R15)、LR(R14)和SP(R13),任何试图使用这些寄存器的操作都会导致出现错误消息;

(4)虽然内联汇编代码可以更改处理器模式,但更改处理器模式会禁止使用 C 操作数或对已编译 C 代码的调用,直到将处理器模式恢复为原设置之后。

嵌入式汇编

嵌入式汇编程序是一个编写在C程序外的单独汇编程序,该程序段可以像函数那样被 C 程序调用。

与内联汇编不同,嵌入式汇编具有真实汇编的所有特性,数据交换符合 ATPCS 标准,同时支持 ARM 和Thumb,所以它可以对目标处理器进行不受限制的低级访问。但是不能直接引用 C/C++ 的变量。

用 _ _asm 声明的嵌入式汇编程序,像 C 函数那样,可以有参数和返回值。定义一个嵌入式汇编函数的语法格式为:

__asm return–type function–name(parameter-list)

  {

    汇编程序段

   }

灵活地使用内联汇编和嵌入式汇编,有助于提高程序效率。

三、实验内容:

  1. C语言主程序调用ARM指令子程序;
  2. 程序的参数个数要求至少6个,ARM子程序实现的功能为:(i1+i2+i3+i4)*i5-i6,并返回计算结果。观察参数是如何传递的。
  3. 在C语言的main函数中,使用内联汇编编写一个函数,使得c语言中定义的3个int类型的变量(a,b,tmp)有如下的关系:tmp =(a+b)*8。
  4. 以嵌入式汇编的方式,编写一个子程序,实现字节序的转换。该子程序的函数的格式要求如下:int convertNum(int i);要求把输入的整数i(32位,四个字节顺序为ABCD),转换为另一种字节序(转换后的字节序为DCBA),返回结果为转换后的int值。在主程序中调用该子程序,并验证其结果的正确性。

四、实验器材(设备、元器件):

  1. PC机一台;
  2. Keil MDK-ARM uVision4开发工具。

五、实验步骤:

  1. 打开Keil MDK-ARM uVision4开发工具;
  2. 新建一个工程文件;
  3. 在新建的工程文件中,添加新的源程序文件
  4. 编写代码
  5. 选择“Build target”菜单对编写好的工程文件进行编译链接。
  6. 点击““Start/Stop Debug Section””按键,对程序进行跟踪调试,在调试界面,单步执行,对CPU各寄存器的值的变化、以及相关内存的变化进行分析比较,判断程序的执行是否符合预期要求。

六、实验结果与分析(含重要数据结果分析或核心代码流程分析)

  1. 程序代码

C语言代码如代码4所示。

代码4  C语言主程序代码

#include<stdio.h>

#include<stdlib.h>

extern int arm_subfunction(int,int,int,int,int,int);

int convertNum(int);

int main(){

 int x1 = arm_subfunction(1,2,3,4,5,6);

 int a = 0,b = 1,tmp = 2;

 __asm{

  ADD tmp,a,b

MOV R0,#0x08

MUL tmp,R0,tmp

 }

 int num = 0xAABBCCDD;

 num = convertNum(num);

}

__asm int convertNum(int i){

EOR R1,R0,R0, ROR #16

BIC R1,R1,#0xFF0000

MOV R0,R0,ROR #8

EOR R0,R0,R1,LSR #8

BX LR

}

汇编程序代码如代码5所示。

代码5  C语言主程序调用ARM指令子程序的汇编程序部分

AREA armcode,CODE,READONLY

EXPORT arm_subfunction

arm_subfunction

STMDB SP!,{R4-R5}

LDR R4,[SP,#0x08]

LDR R5,[SP,#0x0c]

ADD R0,R0,R1

ADD R0,R0,R2

ADD R0,R0,R3

MUL R4,R0,R4

SUB R0,R4,R5

LDMIA SP!,{R4-R5}

BX LR

END

2、结论分析

(1)C语言调用ARM子程序时,在输入参数多余4个(比如是6个)的情况下前四个参数通过R0-R3传递,后面多余的参数会按照从右向左的顺序压栈。 (2)结果通过R0返回。

(3)ARM通过R0-R3获取前四个参数,后面剩余的参数,通过访问堆栈获取。

3、实验结论

由上述实验结果可知,C语言主程序在调用ARM汇编子程序时,当参数个数多于四个时,前四个参数通过R0-R3传递,多余的参数通过堆栈传递。调用嵌入书汇编程序函数的过程与之类似。C语言程序执行内联汇编代码时,可以直接使用C语言程序中的变量。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/172759
推荐阅读
相关标签
  

闽ICP备14008679号