当前位置:首页 > 单片机 > 单片机
[导读] 于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure Call Standard),ATPCS主要是定义了函数呼叫时参数的传递规则以及如何从函数返回,详细内容可以查看ADS1.2 Onl

于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure Call Standard),ATPCS主要是定义了函数呼叫时参数的传递规则以及如何从函数返回,详细内容可以查看ADS1.2 Online Books ——Developer Guide的2.1节。这篇文档要讲的是 汇编代码中对C函数调用时如何进行参数的传递以及如何从C函数正确返回。
不同于x86的参数传递规则,ATPCS建议函数的形参不超过4个,如果形参个数少于或等于4,则形参由R0,R1,R2,R3四个寄存器进行传递;若形参个数大于4,大于4的部分必须通过堆栈进行传递。

ATPCS中个寄存器使用规则及别名

说明:

1子程序中通过r0~r3传递参数,被调用的子程序返回前无需恢复r0~r3的内容。

2子程序中使用r4~r11保存局部变量,如果子程序中使用了它们中某些寄存器,子程序进入时要保存这些寄存器的值,在返回时恢复它们。在Thumb程序中,通常只能使用r4~r7来保存局部变量。

1.在C 语言中内嵌汇编
在C 中内嵌的汇编指令包含大部分的ARM 和Thumb 指令,不过其使用与汇编文件中的指令有些不同,存在一些限制,主要有下面几个方面:
a. 不能直接向PC 寄存器赋值,程序跳转要使用B 或者BL 指令
b. 在使用物理寄存器时,不要使用过于复杂的C 表达式,避免物理寄存器冲突
c. R12 和R13 可能被编译器用来存放中间编译结果,计算表达式值时可能将R0 到R3、R12 及R14
用于子程序调用,因此要避免直接使用这些物理寄存器
d.一般不要直接指定物理寄存器,而让编译器进行分配内嵌汇编使用的标记是__asm 或者asm 关键字,用法如下:__asm {
instruction [; instruction]
...
[instruction]
}
asm("instruction [; instruction]");


下面通过一个例子来说明如何在C 中内嵌汇编语言,
#include
void my_strcpy(const char *src, char *dest)
{ char ch; __asm {
loop:
ldrb ch, [src], #1
strb ch, [dest], #1
cmp ch, #0
bne loop
}
}

int main()

{ char *a = "forget it and move on!"; char b[64];
my_strcpy(a, b);
printf("original: %s", a); printf("copyed: %s", b);
return 0;
}


在这里C 和汇编之间的值传递是用C 的指针来实现的,因为指针对应的是地址,所以汇编中也可以访问。

2.在汇编中使用C 定义的全局变量

内嵌汇编不用单独编辑汇编语言文件,比较简洁,但是有诸多限制,当汇编的代码较多时一般放在单独的汇编文件中。这时就需要在汇编和C 之间进行一些数据的传递,最简便的办法就是使用全局变量。

/* cfile.c

* 定义全局变量,并作为主调程序
*/ #include int gVar_1 = 12; extern asmDouble(void);
int main()
{ printf("original value of gVar_1 is: %d", gVar_1); asmDouble();
printf(" modified value of gVar_1 is: %d", gVar_1); return 0; }
对应的汇编语言文件

;called by main(in C),to double an integer, a global var defined in C is used.

AREA asmfile, CODE, READONLY EXPORT asmDouble
IMPORT gVar_1
asmDouble ldr r0, =gVar_1 ldr r1, [r0] mov r2, #2 mul r3, r1, r2 str r3, [r0] mov pc, lr END

3.在C 中调用汇编的函数

在C 中调用汇编文件中的函数,要做的主要工作有两个,一是在C 中声明函数原型,并加extern 关键字;二是在汇编中用EXPORT 导出函数名,并用该函数名作为汇编代码段的标识,最后用mov pc, lr 返回。然后,就可以在C 中使用该函数了。从C 的角度,并不知道该函数的实现是用C 还是汇编。更深的原因是因为C 的函数名起到表明函数代码起始地址的左右,这个和汇编的label 是一致的。

/* cfile.c
*
in C,call an asm function, asm_strcpy
*
Sep 9, 2004
*/

#include
extern void asm_strcpy(const char *src, char *dest);
int main()
{ const char *s = "seasons in the sun"; char d[32];
asm_strcpy(s, d);
printf("source: %s", s);
printf(" destination: %s",d);
return 0;
}

;asm function implementation
AREA asmfile, CODE, READONLY
EXPORT asm_strcpy
asm_strcpy
loop
ldrb r4, [r0], #1 address increment after read
cmp r4, #0
beq over
strb r4, [r1], #1
b loop
over mov pc, lr
END
在这里,C 和汇编之间的参数传递是通过ATPCS(ARM Thumb Procedure Call Standard)的规定来进行的。简单的说就是如果函数有不多于四个参数,对应的用R0-R3 来进行传递,多于4 个时借助栈,函数的返回值通过R0 来返回。

4.在汇编中调用C 的函数
在汇编中调用C 的函数,需要在汇编中IMPORT对应的C 函数名,然后将C 的代码放在一个独立的C 文件中进行编译,剩下的工作由连接器来处理。

;the details of parameters transfer comes from ATPCS
;if there are more than 4 args, stack will be used EXPORT asmfile AREA asmfile, CODE, READONLY IMPORT cFun ENTRY mov r0, #11 mov r1, #22 mov r2, #33 BL cFun END

/*C file, called by asmfile */

PDF created with pdfFactory trial version www.pdffactory.com
int cFun(int a, int b, int c)
{
return a + b + c; }
在汇编中调用C 的函数,参数的传递也是通过ATPCS 来实现的。需要指出的是当函数的参数个数大于4 时,要借助stack,具体见ATPCS 规范。

在C和汇编混合编程的时候,存在C语言和汇编语言的变量以及函数的接口问题。
在C程序中定义的变量,编译为.asm文件后,都被放进了.bss区,而且变量名的前面都带了一个下划线。在C程序中定义的函数,编译后在函数名前也带了一个下划线。例如:

extern int num就会变成 .bss _num, 1
extern float nums[5]就会变成.bss _nums, 5
extern void func ( )就会变成 _func,

一 汇编和C的相互调用可以分以下几种情况:

(1) 汇编程序中访问c程序中的变量和函数。
在汇编程序中,用_XX就可以访问C中的变量XX了。访问数组时,可以用_XX+偏移量来访问,如_XX+3访问了数组中的XX[3]。

在汇编程序调用C函数时,如果没有参数传递,直接用_funcname 就可以了。如果有参数传递, 则函数中最左边的一个参数由寄存器A给出,其他的参数按顺序由堆栈给出。返回值是返回到A寄存器或者由A寄存器给出的地址。同时注意,为了能够让汇编语言 能访问到C语言中定义的变量和函数,他们必须声明为外部变量,即加extern 前缀。

(2) c程序中访问汇编程序中的变量

如果需要在c程序中访问汇编程序中的变量,则汇编程序中的变量名必须以下划线为首字符,并用global使之成为全局变量。

如果需要在c程序中调用汇编程序中的过程,则过程名必须以下划线为首字符,并且,要根据c程序编译时使用的模式是stack-based model还是register argument model来正确地编写该过程,使之能正确地取得调用参数。

(3) 在线汇编

在C程序中直接插入 asm(“ *** ”),内嵌汇编语句,需要注意的是这种用法要慎用,在线汇编提供了能直接读写硬件的能力,如读写中断控制允许寄存器等,但编译器并不检查和分析在线汇编语 言,插入在线汇编语言改变汇编环境或可能改变C变量的值可能导致严重的错误。

二 汇编和C接口中寻址方式的改变:

需要注意的是,在C语言中,对于局部变量的建立和访问,是通过堆栈实现的,它的寻址是通过堆栈寄存器SP实现的。而在汇编语言中,为了使程序代码变得更为 精简,TI在直接寻址方式中,地址的低7位直接包含在指令中,这低7位所能寻址的具体位置可由DP寄存器或SP寄存器决定。具体实现可通过设置ST1寄存 器的CPL位实现,CPL=0,DP寻址,CPL=1,SP寻址。在DP寻址的时候,由DP提供高9位地址,与低7位组成16位地址;在SP寻址的时 候,16位地址是由SP(16位)与低7位直接相加得来。

由于在C语言的环境下,局部变量的寻址必须通过SP寄存器实现,在混合编程的时候,为了使汇编语言不影响堆栈寄存器SP,通常的方式是在汇编环境中使用DP方式寻址,这样可以使二者互不干扰。编程中只要注意对CPL位正确设置即可

中断异常事件:

ADS编译器中有一个特殊的声明_iaq,这是专门用来处理异常程序而写C语言的声明。有三个用途:

1.进入程序第一件事,将C语言及异常要用到的寄存器存入堆栈中.

2.离开的时候将保存的寄存器取出来

3.改变程序计数器PC的值为lr-4,用于中断返回

例:

irq void IsrIRQ () 对应的汇编: IsrIRQ

{

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

Arm CPU正在从根本上推动AI变革,并造福地球。Arm架构是未来AI计算的基石。​

关键字: ARM AI

近日,Arm推出了Arm® Ethos™-U85神经网络处理器(NPU)和Arm Corstone™-320物联网参考设计平台,旨在满足海量的数据处理和大规模计算,加速推进边缘AI的发展进程。

关键字: ARM

为了赶超云计算市场上的竞争对手,谷歌正试图通过定制的Arm服务器芯片降低云计算服务成本。

关键字: 谷歌 ARM 定制芯片

嵌入式开发作为一个融合了计算机软硬件和系统工程的综合性领域,其成功与否往往取决于三个核心要素的有效整合与协调。这三个要素分别是:硬件平台的选择与设计、软件开发及其优化、以及系统级的设计与集成。深入理解并熟练掌握这三个方面...

关键字: 嵌入式开发 ARM

随着汽车软件数量爆发式的增长,整个行业都需要重新思考汽车产品的开发流程。为此,Arm推出了丰富的硬件IP、新的系统IP,以及全新的汽车计算与计算子系统产品路线图,旨在为各种汽车应用实现性能、功能安全、可扩展等方面的支持。

关键字: ARM 汽车电子

知名移动芯片设计公司ARM最近迈出重要一步,它正式推出汽车芯片设计。ARM推出的芯片设计方案名叫Neoverse,随同芯片一起推出的还有面向汽车制造商、汽车供应商的新系统。

关键字: ARM 汽车芯片 芯片

随着通用人工智能的发展,数据中心的计算需求逐步提高。针对多模态数据、大模型的推理和训练需要更高的算力支持,而随着算力提升与之而来的还需更关注在功耗方面的优化。对于头部云计算和服务厂商而言,针对专门用例提高每瓦性能变得至关...

关键字: ARM 服务器 AI Neoverse CSS

一直以来,riscv架构都是大家的关注焦点之一。因此针对大家的兴趣点所在,小编将为大家带来riscv架构的相关介绍,详细内容请看下文。

关键字: riscv ARM riscv架构

最新消息报道,知情人士透露Arm近日裁掉了中国70多名软件工程师,并会将部分职位转移到中国以外的地区。Arm通过“全球服务”部门已经将支持其中国客户的工作外包给安谋科技,该部门曾经拥有约200名员工。

关键字: ARM 裁员

凭借着在个人计算机领域的广泛应用打下的坚实基础,X86自始至终统治着整个服务器生态。而这并不是业界希望看到的,因此Arm服务器被给予厚望。业界期盼Arm能够带来新的服务器CPU替代:打破一个同质化的数据中心架构,实现更高...

关键字: ARM 服务器 AI
关闭
关闭