天天看点

【ARM汇编学习实例】汇编语言与C语言混合编程

实验内容

(1)在C程序中调用汇编语言子程序addt,实现三个数的加法运算。

(2)在汇编程序中调用C语言函数

int addt(int x,int y,int z)

,实现三个数的加法运算。

(3)在C程序中内嵌汇编程序,由内嵌汇编实现三个数的加法运算。

实验原理

  1. 参数传递规则
  • 根据ATPCS规则,C语言与汇编语言混合编程时,当参数不超过4个时使用寄存器R0~R3,依次将各字数据传送到寄存器;参数超过4个时将剩余的字数据传送到数据栈,入栈的顺序与参数顺序相反,即最后一个参数先入栈。
  1. C程序调用汇编
  • 在C语言程序中调用用汇编语言程序的方法是使用

    EXTERN

    关键词,以声明该汇编程序。在汇编程序中使用

    EXPORT

    伪操作声明该程序段可以被其它程序引用。
  • 例如
AREA StrCopy,CODE,READONLY
	EXPORT strcopy				;声明strcopy为导出符号
strcopy
	LDRB R2,[R1],#1				;R1中的值为源数据块首地址
	STRB R2,[R0],#1				;R0中的值为目标数据块首地址
	CMP R2,#0
	BEN strcopy					;未复制完,循环
	MOV PC,LR					;复制完毕,返回
	END
           
extern void strcopy(char * d, const char * s);//声明strcopy为外部引用符号
int main(void)
{
	const char * str = "source";
	char dest[10];
	//···
	strcopy(dest,src);//调用汇编函数strcopy
	//···
}
           
  1. 汇编程序调用C程序
  • 为保证调用时参数能够正确的传递,汇编程序的设计要遵守基本的ATPCS规则,在汇编语言程序中应该使用

    IMPORT

    伪操作来声明要引用的C语言程序,并通过BL指令来调用子程序。
  • 在C语言程序中不需要做特别的声明,和编写通常的C程序一样。
  • 例如,现在有C函数g()如下,。
int g(int a, int b, int c, int d, int e)
{
	return a + b + c + d + e;
}
           
要求在汇编函数f中调用函数g(),以实现下面的功能
int f(int i){return -g(i, 2*i, 3*i, 4*i, 5*i);}
           

整个汇编函数f的代码如下:

;-----------------------------------------------------------------------------------------------------
	; 汇编函数 int f(int i){return -g(i, 2*i, 3*i, 4*i, 5*i);}
	; 在汇编程序中调用时,预先把i的实参存入寄存器R0
;-----------------------------------------------------------------------------------------------------
	EXPORT f
	AREA f,CODE,READONLY
	IMPORT g				;声明g为外部引用符号
	STR LR,[SP,#-4]			;断点存入堆栈
	ADD R1,R0,R0			;(R1)=i*2
	ADD R2,R1,R0			;(R2)=I*3
	ADD R3,R1,R2			;(R3)=i*5
	STR R3,[SP,#-4]			;将第5个参数i*5存入堆栈
	ADD R3,R1,R1			;(R3)=i*4
	BL g					;调用C函数g(),返回值在寄存器R0中
	ADD SP,SP,#4			;清栈
	RSB R0,R0,#0			;函数f的返回值(R0)=0-(R0)
	LDR PC,[SP],#4			;恢复断点并返回
	END

           
  1. 内嵌汇编
  • 所谓内嵌汇编程序,就是在C程序中直接编写汇编程序段而形成一个语句块,这个语句块可以使用除了

    BX

    BLX

    之外的全部ARM指令来编写,从而可以使程序实现一些不能从C获得的底层功能。
  • 在使用c编译器时,定义一个内嵌汇编程序需要使用关键字

    __asm

    ,当编译器遇到这个关键字时,会启动内嵌汇编器对关键字下面的程序进行汇编工作,其格式如下:
__asm //声明内嵌汇编代码
{
	//汇编语句
}
           
  • 例如
void enable_IRQ(void)
{
	int tmp;
	__asm
	{
		MRS tmp, CPSR
		BIC tmp, tmp, #0x80
		MSR CPSR_c, tmp
	}
}
           

(1)在C程序中调用汇编语言子程序addt,实现三个数的加法运算。

代码实现

main.c

#define uint32 unsigned int
extern uint32 Addt(uint32 x,uint32 y,uint32 z);
uint32 sum;
int main(void)
{    
        sum=Addt(1,2,3);
}

           

asmfile.s

AREA addt,CODE,READONLY
       EXPORT Addt   
Addt   ADD R0,R0,R1
	   ADD R0,R0,R2
       MOV PC,LR
       END
       
           

(2)在汇编程序中调用C语言函数int addt(int x,int y,int z),实现三个数的加法运算。

代码实现

main.c

#define uint32 unsigned int
uint32 addt(uint32 x,uint32 y,uint32 z)
{
	return x+y+z;
}
int main()
{
	asm_main();
}

           

asmfile.s

EXPORT asm_main   
    AREA asm_main, CODE, READONLY 
	IMPORT addt    
    ENTRY  
START
	MOV R0,#1
	MOV R1,#2
	MOV R2,#3
	BL addt
	END
	
           

(3)在C程序中内嵌汇编程序,由内嵌汇编实现三个数的加法运算。

代码实现

main.c

#define uint32 unsigned int
uint32 addt(uint32 x,uint32 y,uint32 z);

int main(void)
{
	addt(1,2,3);
	return 0;
}

uint32 addt(uint32 x,uint32 y,uint32 z)
{
	uint32 temp;
	__asm
	{
		add temp, x, y
		add temp, temp, z
	}
}

           

参考文章

ARM汇编程序设计之C程序调用汇编程序

C语言调用汇编函数 实现超过32位数的加法

ARM 汇编和C语言代码的相互调用