C\C++以及汇编语言的混合编程

标签:
arm汇编语言 |
分类: 汇编语言 |
C\C++以及汇编语言的混合编程
在应用系统设计中,如果所有程序都用汇编语言实现,虽然提高了执行效率,但工作量大而且不易于移植和升级;如果全部用C语言来编写,一些对硬件的操作,例如允许和禁止中断就无法实现。因此,通常在实际系统设计中采用汇编和C语言混合编程的方式。ARM体系结构支持汇编和C语言的混合编程。一般在ARM实际编程应用中,程序的初始化部分用汇编语言来实现,然后用C/C++语言完成其他任务。
²
n
n
n
n
n
²
n
n
l
ARM工程中,C程序调用汇编函数和汇编程序调用C函数时经常的事情,遵守ARM-Thumb过程调用标准ATPCS(ARM-Thumb Procedure Call Standard)。
ATPCS标准——ARM编译器使用的函数调用规则(详见下面)
Ø
int main()
{
printf("1234+5678=%d\n",sum(1234,5678));
return 0;
}
请编写sum函数,实现两个数的相加。
int sum(int x,int y)
{
int s;
s=x+y;
return s
}
Ø
要点:
1.
2.
3.
4.
;工程exp10_1_2,实现字符串的复制
;汇编函数文件strcopy.s
;把R1指向的数据块复制到R0指向的存储块。
AREA StrCopy,CODE,READONLY
EXPORT strcopy
strcopy
LDRB R2,[R1],#1
STRB R2,[R0],#1
CMP R2,#0
BNE strcopy
MOV PC,LR
END
;C文件main.c
;调用strcopy函数
extern void StrCopy(char *d,const char
*s);
int main(void)
{
const char *src=”Source”;
char dest[12]=”Destination”;
strcopy(dest,src);
printf(“After copying:\n”);
printf(“%s\n%s\n”,src,dest);
return(0);
}
根据ATPCS的C语言程序调用汇编函数规则,参数由左向右依次传递给寄存器R0~R3,可知汇编函数strcopy在C程序中的原型应该为:
void strcopy(char *d,const char *s);
其中,参数d对应R0,参数s对应R1。函数没有返回值,类型为void。函数名称与汇编函数标号名称一致。
Ø
在汇编程序中调用C程序函数的步骤如下:
在C程序中,无需任何关键字导出或者声明被调用的C语言函数。
在汇编程序中,在调用其他文件的C语言函数前,先用IMPORT伪操作声明该函数。
在汇编程序中,通常使用BL指令来调用其他程序文件中的C语言函数,并保证调用时参数正确传递。参数的传递规则与C程序调用汇编语言函数的规则相同。
;工程Exp10_1_3,累加
C函数
int g(int a,int b,int c,int d,int e)
{
return a+b+c+d+e;
}
汇编函数f中调用C函数g(),以实现下面的功能:
int f(int i)
{
return g(i, 2*i, 3*i, 4*i, 5*i );
整个汇编函数f的代码如下:
EXPORT f
AREA f,CODE,READONLY
IMPORT g
STR LR,[SP,#-4]
ADD R1,R0,R0
ADD R2,R1,R0
ADD R3,R1,R2
STR R3,[SP,#-4]
ADD R3,R1,R1
BL g
ADD SP,SP,#4
RSB R0,R0,#0
LDR PC,[SP],#4
END
;由于函数g()有5个参数,所以该函数用寄存器R0~R3来传递a~d,而用堆栈来传递第5个参数e。
Ø
变量定义是混合编程的基本问题。汇编程序访问C程序中的变量的步骤类似于汇编程序调用C程序中的函数的步骤,具体操作如下:
²
²
在汇编程序中,通常根据该数据的数据类型使用相应的LDR指令读取这个全局变量的地址和值,然后在此基础上,可以使用其他数据处理指令(如ADD、SUB或STR指令等)对这个全局变量进行进一步操作。
实际上是引用不同文件定义的变量:
IMPORT:声明符号为外部引用符号
EXPORT:声明符号为导出符号
例子:
AREA globals,CODE,READONLY
EXPORT
asmsubroutine
IMPORT
globvar
asmsubroutine
Ø
ARM编译器使用的函数调用规则。
1.
R0
R4~R11用来保存局部变量;
R12用做子程序内部调用的scratch寄存器
R13堆栈指针,保存当前处理器模式的堆栈的栈顶
R14链接寄存器
R15程序计数器
进入函数时,必须保存R4~R11中被函数破坏的寄存器。
2.
FD类型。
3.
<4个:R0~R3
>4个:堆栈
4.
R0,R1
l
内联汇编inline assemble
嵌入式汇编embedded assemble
有时候,必须在C/C++语言程序中嵌入汇编指令:
C/C++语言程序中需要对协处理器进行操作。
C/C++语言程序中完成对程序状态寄存器CPSR的操作。
C/C++语言程序中内嵌汇编指令由两种方法,分别是内联汇编和嵌入式汇编,他们都是包含在C/C++编译器中的汇编器,可以实现一些高级语言没有的功能。不仅如此,在C/C++语言程序中灵活使用内联汇编和嵌入式汇编,还有助于提高程序的执行效率。
Ø
在c函数定义中插入汇编语句。
使用关键字__asm来定义一个内联汇编程序段,当ARM编译器遇到这个关键字时,就会启动内联汇编器对关键字下面的程序进行汇编工作。语法格式与编译器相关,不同版本的ARM编译器对内联汇编的语法要求不一样,例如armcc和gcc的汇编格式就不一样。
用法特点:
u
u
u
u
由于内联汇编嵌入在C/C++语言程序中,所以可以在内联汇编代码中执行的操作有某些限制:
u
u
u
u
u
u
语法格式
__asm
{
汇编语句段
}
内嵌内联汇编的两个整型数相加的C语言程序。(工程exp10_1,文件exp10_exa1.c)
#include <stdio.h>
int sum(int i,int j)
{
int total;
return total;
}
int main()
{
printf("1234+5678=%d\n",sum(1234,5678));
return 0;
}
Ø
在形式上表现为独立定义的函数。嵌入式汇编具有真实汇编的所有特性,同时支持ARM和Thumb指令集。
嵌入式汇编程序时一个编写在C程序外的单独汇编程序段,可以像函数那样被C程序调用。可以有参数和返回值。定义嵌入式汇编函数的语法格式为:
__asm return-type function-name(parameter-list)
{
汇编程序段
}
使用嵌入式汇编有以下限制:
²
²
例子:
__asm int add(int i, int j)
{
ADD R0,R0,R1
MOV PC,LR
}
注意参数名只允许在参数列表中,不能用在嵌入式汇编函数体内。
在C中调用嵌入式汇编程序的方法与调用C函数的方法相同。
void main()
{
printf(”%d”,add(123,456));
}
BDHN
内嵌嵌入式汇编的两个整型数相加的C语言程序。(工程exp10_1,文件exp10_exa2.c)
#include <stdio.h>
{
}
void main( )
{
printf("1234+5678=%d\n",add(1234,5678));
return 0;
}
内联汇编和嵌入式汇编的主要区别
功能 |
内联汇编 |
嵌入式汇编 |
指令集 |
仅支持ARM |
支持ARM和Thumb |
ARM汇编伪操作 |
不支持 |
支持 |
C/C++表达式 |
完全支持 |
只支持常量表达式 |
汇编代码优化 |
完全优化 |
无优化 |
能否被内联 |
有可能 |
不可能 |
寄存器访问 |
使用虚拟寄存器不能使用PC、LR和SP |
使用指定的物理寄存器可以使用PC、LR和SP |
是否自动产生返回指令 |
指定产生 |
手工添加返回指令 |
课堂补充实验:
实验目的
Ø
Ø
Ø
实验一 允许和禁止中断程序(ARM7)
本实验使用内联汇编完成允许和禁止中断程序设计,采用ARMulator方式调试,选用ARM7作为目标处理器。
;工程exp10_1,文件exp10_1_1.c
#include<stdio.h>
__inline void enable_IRQ(void)
{
}
__inline void disable_IRQ(void)
{
int main(void)
{
单步调试程序,观察C程序的执行过程,将寄存器的变化情况记录在下表中。
序号 |
执行指令 |
指令执行后的变化情况 |
||||||||||
|
|
寄存器 |
||||||||||
|
|
R0 |
R1 |
R2 |
R3 |
R4 |
R5 |
R12 |
SP |
LR |
PC |
CPSR |
0 |
--------------- |
|
|
|
|
|
|
|
|
|
|
|
1 |
MRS tmp,CPSR |
|
|
|
|
|
|
|
|
|
|
|
2 |
BIC tmp,tmp,#0x80 |
|
|
|
|
|
|
|
|
|
|
|
3 |
MSR CPSR_c,tmp |
|
|
|
|
|
|
|
|
|
|
|
4 |
MRS tmp,CPSR |
|
|
|
|
|
|
|
|
|
|
|
5 |
ORR tmp,tmp,#0x80 |
|
|
|
|
|
|
|
|
|
|
|
6 |
MSR CPSR_c,tmp |
|
|
|
|
|
|
|
|
|
|
|
实验二 伪随机数程序(ARM7)
本实验使用C程序调用汇编函数的方法设计伪随机数程序。本实验中的伪随机数并不是真正的随机数,而只是足够分散的一系列数据,因为它足够分散,所以看起来是随机的。真正的随机数,需要由物理方式来产生。本实验通过移位操作和“异或”运算来产生伪随机数,并采用ARMulator方式调试,选用ARM7作为目标处理器。
(工程exp10_2.mcp)
实验三 验证汇编程序调用C程序函数和访问C程序变量的执行过程(ARM9)
本实验在汇编程序中调用C程序函数和访问C程序变量,采用ARMualtor方式调试,选用ARM9作为目标处理器。(工程Exp10_3.mcp)
序号 |
执行指令 |
指令执行后的变化情况 |
||||||||||
寄存器 |
存储空间 |
变量 |
||||||||||
R0 |
R1 |
R2 |
R3 |
R4 |
SP |
LR |
PC |
0x9FFC |
0x9FF8 |
sum |
||
0 |
----------- |
|
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
|
|
|
|
|
|
|
|
|
|
|
思考:
1.
2.