ARM与C语言的混合编程【嵌入式系统】
ARM与C语言的相互调用【嵌入式系统】
- 前言
- 推荐
- ARM与C语言的相互调用
- 说明
- ARM7汇编语言与C语言间的模块接口
- ARM7汇编程序与C程序间变量互访
- ARM7汇编程序调用C程序
- C程序调用汇编程序
- C程序中内嵌ARM7汇编代码
- 最后
前言
以下内容源自《【嵌入式系统】》
仅供学习交流使用
推荐
Keil 4 安装教程及简单使用【嵌入式系统】
ARM简单程序设计【嵌入式系统】
ARM与C语言的相互调用
说明
需要下载Keil for C51
可以看Keil 4 安装教程及简单使用【嵌入式系统】
ARM7汇编语言与C语言间的模块接口
略
ARM7汇编程序与C程序间变量互访
①汇编程序访问C程序中的变量
具体操作步骤:
在C程序中,将供汇编程序访问的变量用关键字extern声明为全局外部变量;
汇编程序中,用伪指令IMPORT引入C程序中声明的全局变量;
使用伪指令LDR读取这个全局变量的地址;
使用指令LDR读取这个全局变量的值;
在汇编程序中使用这个全局变量;
②C程序访问汇编程序中的变量
具体操作步骤:
在汇编语言程序中,用伪指令“global”定义全局变量,变量名必须是下划线“_”为首字符的字母数字串;
C程序中将该变量声明为外部变量,即可访问汇编程序定义的全局变量。
例:汇编程序和C程序间变量互访
/* print.c 定义全局变量,并作为主程序 */
#include <stdio.h>
extern int g_var = 124; /* 全局变量 */
extern asmVisit(void); /* 汇编程序中声明的全局函数 */
extern int _multiple; /* 声明汇编程序中的全局变量_multiple为外部变量 */
int main()
{
printf("Original value of g_var is: %d \n ", g_var);
asmVisit(); /* 调用汇编程序中的函数,访问全局变量g_var */
printf("mult is %d",_multiple); /* 访问汇编程序中全局变量_multiple */
printf(" Modified value of g_var is: %d", g_var);
return 0;
}
; visit.s文件
AREA asmfile, CODE, READONLY
EXPORT asmVisit ; 声明全局函数,供C程序调用??
IMPORT g_var ; 引入在C程序中声明定义的全局变量
GLOBAL _multiple ; 声明全局变量,供C程序访问
asmVisit
LDR R0, =g_var
LDR R1, [R0]
LDR R2, =_multiple
LDR R2, [R2]
MOV R3, R1, LSL R2 ; 将R1中的值扩大指定的倍数
STR R3, [R0]
MOV PC, LR
AREA asmData, DATA, READWRITE
_multiple DCD 2
END
ARM7汇编程序调用C程序
汇编程序中调用C函数,只需在汇编程序中用伪指令IMPORT将需要调用的C函数名引用即可,然后将C函数放在一个独立的C文件中进行编译,剩下的工作就由链接器来处理。
汇编程序与C函数间参数的传递规则遵守ATPCS(ARM Thumb Procedure Call Standard)规则:用ARM处理器寄存器组中的{R0 - R3}作为参数传递和结果返回寄存器;如果参数数目超过4个,则使用堆栈进行传递。
; asmfile.s文件
AREA asmfile, CODE, READONLY
IMPORT cFun ; 声明引用外部函数
ENTRY
CODE32
start
MOV R0, #1
MOV R1, #2
MOV R2, #3
BL cFun ; 此时结果和在R0中
stop
MOV R0, #0x18 ; 程序结束返回编译器调试环境
LDR R1, =0x20026
SWI 0x123456
END
/* cFun.c文件,由asmFile.s文件调用 */
int cFun(int a, int b, int c)
{
return a + b + c;
}
C程序调用汇编程序
C程序调用汇编程序子程序,要做的主要工作有两个:
一是在C程序中用关键字extern声明汇编子程序的函数原型(C程序是函数结构的程序设计风格),声明该函数的实现代码在其他文件中;
二是在汇编程序中用伪指令EXPORT导出子程序名,并且用该子程序名作为汇编代码段的标识,最后用mov pc, lr返回。
这样,在C程序中就可以像调用C函数一样调用该汇编子程序了。
具体操作步骤:
汇编程序中,用该子程序名作为汇编代码段的标识,定义程序代码,最后用“MOV PC, LR”指令返回;
汇编程序中用伪指令EXPORT导出子程序名;
C程序中用关键字extern声明该汇编子程序的函数原型;然后就可在C程序中访问该函数;
函数调用时的参数传递规则:寄存器组中的{R0 - R3}作为参数传递而返回值用寄存器R0返回;如果参数数目超过4个,则使用堆栈进行传递。
/* cfile.c */
#include <stdio.h>
extern void strcpy(const char *src, char *dest);
int main()
{
char *s = "this string is in C file";
char temp[32];
strcpy(s, temp);
printf("Source string : %s \n", s);
printf("Destination sting: %s", temp);
return 0;
}
; asmfile.s
AREA strcpy,CODE, READONLY
EXPORT strcpy ; 完成源字符串R0到目的字符串R1的拷贝
loop
LDRB R5, [R0], #1
CMP R5, #0 ; 是否到字符串结束
BEQ exit
STRB R5, [R1], #1
B loop
exit
MOV PC, LR
END
C程序中内嵌ARM7汇编代码
C 程序中内嵌的汇编代码可使用大部分的ARM 和Thumb 指令,存在一些限制,主要有下面几个方面:
不能直接向寄存器PC赋值,程序跳转要使用指令B或者BL;
在访问物理寄存器时,不要使用过于复杂的C表达式,避免物理寄存器冲突;
R12和R13常被编译器用来存放中间编译结果,计算表达式值时可能将R0~R3、R12及R14用于子程序调用,因此要避免直接使用这些物理寄存器;
在C程序中使用“__asm”关键字标记内嵌汇编代码,
格式如下:
__asm ; 注意是双下划线
{
...... ; 汇编指令编写的代码
}
#include <stdio.h>
void strcpy(const char *src, char *dest)
{
char ch; ; 检查字符串是否结束的标志
__asm
{ ; 功能:完成将源字符串src中的数据拷贝到目的字符串dest中
LOOP:
LDRB ch, [src], #1
STRB ch, [dest], #1
CMP ch, #0
BNE LOOP
}
}
int main()
{
char *s= "this is a example AsmInC !";
char temp[64];
strcpy(s , temp);
printf("Original string: %s \n ", s);
printf("Copyed string: %s", temp);
return 0;
}
最后
2023-4-11 20:06:34
你对我百般注释,并不能构成万分之一的我,却是一览无余的你。
祝大家逢考必过
点赞收藏关注哦