ARM中C语言调用汇编语言方法浅析
C语言与汇编语言互相调用
浅谈C程序中调用汇编模块的方法C语言是目前非常流行的一种编程语言,除具有高级语言使用方便灵活、数据处理能力强、编程简单等优点外,还可实现汇编语言的大部分功能,如可直接对硬件进行操作、生成的目标代码质量较高且执行的速度较快等。
所以在工程上对硬件处理速度要求不很高的情况下,基本可以用C代替汇编语言,编写接口电路的控制软件。
但C也不能完全取代汇编语言,如在一些对速度要求很高的实时控制系统中,以及对硬件的特殊控制方面,C有时也不能完全很好胜任,还需要汇编语言来编写。
因为汇编语言目标代码更精练,对硬件直接控制能力更强和执行速度更快,但汇编语言编程烦难、表达能力差也显而易见。
比较好的解决办法是C与汇编语言混合编程,即用C编写软件的调度程序、用户界面以及速度要求不高的控制部分,而用汇编语言对速度敏感部分提供最高速度的处理模块,供C调用。
这种方法提供了最佳的软件设计方案,做到了兼顾速度效率高和灵活方便。
由于本人的毕业设计需要C 程序中调用汇编模块的方法来提高ARM定点指令的执行速度,故对这方面进行了学习。
学习心得如下:对于C和汇编语言的接口主要有两个问题需要解决。
一、调用者与被调用者的参数传递这种数据传递通过堆栈完成,在执行调用时从调用程序参数表中的最后一个参数开始,自动依次压入堆栈;将所有参数压入堆栈后,再自动将被调用程序执行结束后的返回地址(断点)压入堆栈,以使被调程序结束后能返回主调程序的正确位置而继续执行。
例如一调用名为add汇编程序模块的主函数:main( ){...... add(dest,op1,op2,flages);......}。
在此例中对主函数进行反汇编,主函数在调用add函数前自动组织的堆栈。
...lea 0xfffffffe8(%ebp),%eax #flages数组的首地址入栈push %eaxpushl 0xfffffff8(%ebp) #OP2入栈pushl 0xfffffffc(%ebp) #OP1 入栈pushl 0xfffffff0(%ebp) #dest地址入栈call 0x80483f0 <add> #调用add函数..执行完add调用语句后,栈内数据结果如图一所示。
arm汇编调用c语言
arm汇编调用c语言在嵌入式系统开发中,ARM汇编语言是一种重要的编程语言,它可以直接操作硬件资源,提高系统的性能和效率。
然而,ARM汇编语言的编写相对复杂,可读性较差,因此在实际开发中,我们通常会使用C语言来编写大部分的代码。
那么,如何在ARM汇编中调用C语言函数呢?本文将介绍一种常用的方法。
首先,我们需要了解一些基本的概念。
在ARM架构中,函数调用的过程可以简化为以下几个步骤:保存寄存器、传递参数、调用函数、恢复寄存器、返回结果。
在ARM汇编中,我们可以使用一些特殊的指令来完成这些操作。
首先,我们需要保存寄存器。
在ARM架构中,R0-R3寄存器用于传递参数,R4-R11寄存器用于保存临时变量。
在调用C语言函数之前,我们需要将这些寄存器的值保存起来,以免被C语言函数修改。
可以使用STMFD指令将这些寄存器的值保存到栈中。
接下来,我们需要传递参数。
在ARM架构中,函数的参数通常通过寄存器传递。
如果参数的个数超过了寄存器的数量,多余的参数将通过栈传递。
可以使用MOV指令将参数的值保存到相应的寄存器中。
然后,我们可以调用C语言函数。
在ARM汇编中,可以使用BL指令来调用函数。
BL指令会将当前函数的返回地址保存到LR寄存器中,并跳转到目标函数的地址。
在C语言函数执行完毕后,可以使用BX LR指令返回到调用函数的地址。
最后,我们需要恢复寄存器。
在调用C语言函数之前,我们将寄存器的值保存到了栈中,因此在函数执行完毕后,需要将这些值从栈中恢复出来。
可以使用LDMFD指令将这些值恢复到相应的寄存器中。
除了上述的基本操作,还需要注意一些细节。
例如,栈的大小需要根据实际情况进行调整,以免发生栈溢出的情况。
另外,C语言函数的返回值通常保存在R0寄存器中,可以使用MOV指令将其保存到其他寄存器中,以便后续的操作。
总结起来,ARM汇编调用C语言函数的过程可以简化为以下几个步骤:保存寄存器、传递参数、调用函数、恢复寄存器、返回结果。
ARMC语言调用汇编函数实现冒泡排序
ARMC语⾔调⽤汇编函数实现冒泡排序使⽤冒泡排序将指定数组排序后输出排序函数使⽤汇编语⾔编写,C语⾔调⽤汇编语⾔在控制台显⽰排序前后的结果⼀、问题分析本程序的关键是如何使⽤汇编语⾔实现冒泡排序算法。
可以仿照C语⾔的代码流程,分步骤写出汇编的代码。
⾸先要写出最内层的代码部分,也就是数据交换的汇编代码,数据交换可以使⽤str数据装载指令实现。
之后要考虑内层循环的代码,可以通过cmp指令控制循环次数。
最后是编写最外层的循环代码,也是使⽤cmp指令,来控制整个排序的次数。
⼆、代码编写2.1 C语⾔代码#include <stdio.h>extern void sort(char* num, int count);int main(){char number[10] = {'a', 'c', 'b', 'e', 'd', 'f', 'h', 'g', 'j', 'i'};printf("Before: %s\n", number);sort(number, 10);printf("After: %s\n", number);return 0;}C语⾔中⽐较重要的是,⾸先要声明外部函数sort,也就是由汇编代码实现的函数。
其代码流程为:初始化1个10字节的char类型的数组在控制台输出初始化的数据调⽤汇编函数进⾏排序显⽰排序后的结果2.2 汇编代码area sort, code, readonlyglobal sortstartmov r2, #-1 ; r2->i, i=-1sub r8, r1, #1 ; r1->countloopcmp r2, r8 ; 控制外层循环bge stopadd r2,r2, #1 ; i=i+1mov r3, #-1 ; r3=j, j=-1loop0add r3, r3, #1 ; j=j+1add r4, r3, #1 ; r4=j+1sub r7, r8, r2 ; 控制内层循环cmp r3, r7bge loopldrb r5, [r0, r3] ; r5=a[j]ldrb r6, [r0, r4] ; r6=a[j+1]cmp r5, r6 ; ⽐较 a[j] 和 a[j+1]blt loop0swapstrb r5, [r0, r4] ; 交换 a[j] 和 a[j+1]strb r6, [r0, r3]b loop0stopend汇编语⾔代码是仿照的C语⾔的冒泡排序流程实现的,其⼤致流程为:⾸先初始化R2,R2⽤来控制外层循环的次数。
C程序访问ARM汇编程序中的函数
C程序访问ARM汇编程序中的函数
C 程序调用ARM 汇编子程序,要做的主要工作有两个:一是在C 程序中用关键字EXTERN 声明ARM 汇编子程序的函数原型(C 程序是函数结构的程
序设计风格),声明该函数的实现代码在其他文件中;二是在ARM 汇编子程序
中用伪指令EXPORT 导出子程序名,并且用该子程序名最为ARM 汇编代码段
的标识,最后用MOV PC,LR 指令返回。
这样,在C 程序中就可以像调用C 函数一样调用该ARM 汇编子程序了。
无论是C 语言中的函数名还是ARM 汇编语言中的标号,其作用一样,都只是起到表明该函数名或标号存储单元起始地
址的作用。
具体操作步骤如下:
(1)ARM 汇编程序中,用该子程序名作为ARM 汇编代码段的标识,定义
程序代码,最后用MOV PC,LR 指令返回;
(2)ARM 汇编程序中用伪指令EXPORT 导出子程序名;
(3)C 程序中用关键字EXTERN 声明该ARM 汇编子程序的函数原型,然
后就可在C 程序中访问该函数;
(4)函数调用时的参数传递规则:寄存器组中的【R0R3】作为参数传递而
返回值用寄存器R0 返回,如果参数数目超过4 个,则使用堆栈进行传递。
程序清单如下:
// main.c
#include
extern void my_strcpy(const char *src,char *dest);
int main(){ char *strsrc = “Welcome to XU”;char temp[32] = {0};。
关于在ARM中(MDK下)C与汇编混合编程的问题
loopLDRBr2,[r0],#1//R0保存第一个参数
STRBr2,[r1],#1//R1保存第二个参数
CMPr2,#0
BNEloop
BLXlr//返回指令须要手动加入
}
intmain(void)
{
constchar*a=“Helloworld!”;
charb[20];
my_strcpy(a,b);
关于在ARM中(MDK下)C与汇编混合编程的问题
于:bbs.21ic/icview-156494-1-1.html([微控制器/MCU]小窍门:Cortex-M3
在MDK C语言中嵌入汇编语言的方法)
==================================
==========================
如果须要访问C程式中的变量,可以使用_cpp关键字,编译器如LDRr0,=__cpp(&some_variable)
LDRr1,=__cpp(some_function)
BL__cpp(some_function)
MOVr0,#__cpp(some_constant_expr)
**********************************
***************************
在传统的ARM处理器中(ARM7/ARM9),如果要在C程式中嵌入汇编,可以有
两种方法:
一、内联汇编的方式方法如下:intPCBsheji(inti)
{
intr0;
__asm
{
ADDr0,i,1
EORi,r0,i
}
returni;
}
在汇编语句可以直接做用C语言中的变量.编译器会对这些代码进一步优化,
armc语言调用汇编函数
armc语言调用汇编函数
ARM系列处理器的程序开发,可以采用ARM汇编语言和C语言来实现,而两者可以互相调用。
本文主要介绍一种ARM处理器下,C语言调用汇编语言编写的函数的实现过程。
二、C语言调用汇编函数的实现
1. 首先,要在汇编代码中定义函数,函数的开始以及结束用特定的指令来表示,如下所示:
MyAdd PROC
;
MyAdd ENDP
2. 接着,定义C语言源程序中的函数,以下是MyAdd函数在C 语言源程序中的定义:
int MyAdd ( int a, int b ) //定义函数MyAdd,参数a,b
{
int c;
asm{
add a,b,c //汇编语言指令,将参数a ,b的和结果送给c
}
return c;
}
3. 若要将汇编语言定义的函数MyAdd引入C语言源程序,那么只需要在C语言源程序的前面加上如下的宏定义:
#define MyAdd ( int a, int b )
( {
int c ;
asm{
add a,b,c
}
c ;
} )
4. 最后,在C语言源程序的其他地方,就可以用MyAdd函数来调用汇编代码中定义的函数,实现C语言调用汇编函数的功能。
三、结论
ARM系列处理器的程序开发可以采用ARM汇编语言和C语言来实现,两者之间可以互相调用,C 语言也可以调用汇编语言编写的函数,只需要定义一个宏,就可以实现C语言调用汇编函数。
浅谈单片机中C语言与汇编语言的转换
浅谈单⽚机中C语⾔与汇编语⾔的转换⼀、单⽚机课设题⽬要求与软件环境介绍做了⼀单⽚机设计,要⽤C语⾔与汇编语⾔同时实现,现将这次设计的感受和收获,还有遇到的问题写下,欢迎感兴趣的朋友交流想法,提出建议。
单⽚机设计:基于51单⽚机的99码表设计软件环境:Proteus8.0 + Keil4要求:1,开关按⼀下,数码管开始计时。
2,按两下,数码管显⽰静⽌。
3,按三下,数码管数值清零。
⼆、C语⾔程序1 #include<reg51.h>2#define uint unsigned int3#define uchar unsigned char4 uchar shi,ge,aa,keycount=0,temp;5 sbit anjian=P1^7;6 uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};7void display(shi,ge);8void key ();9void init();10void delay(uint z);11/*-----主程序-----*/12void main()13 {14 init(); //初始化15while(1)16 {17 key ();18if(keycount==1)19 TR0=1; //开中断20if(keycount==2)21 TR0=0;22if(keycount==3)23 {24 temp=0;25 keycount=0;26 }27if(aa==10){aa=0;28if(temp<=99)29 {30 temp++;display(shi,ge);31 }32else33 temp=0;}34 }35 }363738/*------初始化程序-------*/39void init()40 {41 keycount=0;42 temp=0;43 TMOD=0x01;44 TH0=(65536-50000)/256;45 TL0=(65536-50000)%256;46 EA=1;47 ET0=1;48//TR0=0;49 }50/*-----定时器中断-----*/51void timer0() interrupt 152 {53 TH0=(65536-50000)/256;54 TL0=(65536-50000)%256;55 aa++;56 }57/*-----显⽰⼦程序-----*/58void display(shi,ge)59 {60 shi=temp/10;61 ge=temp%10;62 P0=table[shi];;delay(70);63 P2=table[ge]; ;delay(70);64 }65/*-----按键检测⼦程序-----*/66void key ()67 {68if(anjian==0)69 {70 delay(5); //消抖71if(anjian==0)72 keycount++;73 }74//while(anjian==0);75//display(shi,ge); //等待按键弹起76 }77/*-----延时⼦程序-----*/78void delay(uint z) //延时约1ms79 {80uint x,y;81for(x=z;x>0;x--)82for(y=100;y>0;y--);83 }电路仿真结果如下:三、C语⾔转汇编语⾔步骤好了,那么接下来我们就开始C语⾔——>汇编语⾔之旅(1)C语⾔1-10⾏改为1 ORG 0000H //汇编起始伪指令,功能是规定程序存储器中源程序或数据块存放的起始地址2 ajmp STAR //ajmp⽆条件跳转指令3 ORG 000bh4 ajmp timer05 anjian equ P1.7 //位定义6 keycount equ 40h7 shi equ 41h8 gewei equ 42h9 aa equ 43h10 temp equ 44h11tab: db 3fh,6h,5bh,4fh,66h //建表12 db 6dh,7dh,7h,7fh,6fh(2)C语⾔中的初始化函数 12-14⾏和39-49⾏改为1STAR:2 acall init //⼦程序近程调⽤指令,功能是主程序调⽤⼦程序,调⽤⼦程序的范围为2kb1init:2mov keycount,#0 //keycount=03mov temp,#0 //temp=14mov tmod,#01h //TMOD=0x015mov TH0,#606mov TL0,#1767setb EA //位置位指令,对操作数所指出的位进⾏置1操作8setb ET09setb TR010retacall为⼦程序近程调⽤指令,返回⽤ret。
基于ARM的C语言与汇编语言混合编程
基于ARM的C语言与汇编语言混合编程2009-07-30 19:12:34| 分类:ARM学习| 标签:|字号大中小订阅1、C语言与汇编语言混合编程应遵守的规则ARM编程中使用的C语言是标准C语言,ARM的开发环境实际上就是嵌入了一个C语言的集成开发环境,只不过这个开发环境与ARM的硬件紧密相关。
在使用C语言时,要用到和汇编语言的混合编程。
若汇编代码较为简洁,则可使用直接内嵌汇编的方法;否则要将汇编程序以文件的形式加入到项目中,按照ATPCS(ARM/Thumb过程调用标准,ARM/Thumb Procedure Call Standard)的规定与C程序相互调用与访问。
在C程序和ARM汇编程序之间相互调用时必须遵守ATPCS规则。
ATPCS规定了一些子程序间调用的基本规则,哪寄存器的使用规则,堆栈的使用规则和参数的传递规则等。
1)寄存器的使用规则子程序之间通过寄存器r0~r3来传递参数,当参数个数多于4个时,使用堆栈来传递参数。
此时r0~r3可记作A1~A4。
在子程序中,使用寄存器r4~r11保存局部变量。
因此当进行子程序调用时要注意对这些寄存器的保存和恢复。
此时r4~r11可记作V1~V8。
寄存器r12用于保存堆栈指针SP,当子程序返回时使用该寄存器出栈,记作IP。
寄存器r13用作堆栈指针,记作SP。
寄存器r14称为链接寄存器,记作LR。
该寄存器用于保存子程序的返回地址。
寄存器r15称为程序计数器,记作PC。
2)堆栈的使用规则ATPCS规定堆栈采用满递减类型(FD,Full Descending),即堆栈通过减小存储器地址而向下增长,堆栈指针指向内含有效数据项的最低地址。
3)参数的传递规则整数参数的前4个使用r0~r3传递,其他参数使用堆栈传递;浮点参数使用编号最小且能够满足需要的一组连续的FP寄存器传递参数。
子程序的返回结果为一个32位整数时,通过r0返回;返回结果为一个64位整数时,通过r0和r1返回;依此类推。
ARM在汇编代码中调用C函数.
ARM在汇编代码中调用C函数对于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是ATPCS(ARM-Thumb Procedure Call Standard),ATPCS主要是定义了函数呼叫时参数的传递规则以及如何从函数返回,关于ATPCS的详细内容可以查看ADS1.2 Online Books ——Developer Guide的2.1节。
这篇文档要讲的是汇编代码中对C函数调用时如何进行参数的传递以及如何从C函数正确返回不同于x86的参数传递规则,ATPCS建议函数的形参不超过4个,如果形参个数少于或等于4,则形参由R0,R1,R2,R3四个寄存器进行传递;若形参个数大于4,大于4的部分必须通过堆栈进行传递。
我们先讨论一下形参个数为4的情况.实例1:test_asm_args.asm//--------------------------------------------------------------------------------IMPORT test_c_args ;声明test_c_args函数AREA TEST_ASM, CODE, READONLYEXPORT test_asm_argstest_asm_argsSTR lr, [sp, #-4]! ;保存当前lrldr r0,=0x10 ;参数 1ldr r1,=0x20 ;参数 2ldr r2,=0x30 ;参数 3ldr r3,=0x40 ;参数 4bl test_c_args ;调用C函数LDR pc, [sp], #4 ;将lr装进pc(返回main函数)ENDtest_c_args.c//--------------------------------------------------------------------------------void test_c_args(int a,int b,int c,int d){printk("test_c_args:\n");printk("%0x %0x %0x %0x\n",a,b,c,d);}main.c//--------------------------------------------------------------------------------int main(){test_asm_args();for(;;);}程序从main函数开始执行,main调用了test_asm_args,test_asm_args调用了test_c_args,最后从test_asm_args返回main.代码分别使用了汇编和C定义了两个函数,test_asm_args 和test_c_args,test_asm_args调用了test_c_args,其参数的传递方式就是向R0~R3分别写入参数值,之后使用bl语句对test_c_args进行调用。
第三章 ARM中的C语言和汇编混合编程
数据栈的基地址:是指数据栈的最高地址。
已占用的数据栈:是指数据栈的基地址和数据栈栈指针之 间的区域。
未占用的数据栈:是指数据栈指针和数据栈界限之间的区 域。
数据栈中的数据帧:是指在数据栈中,为子程序分配的用 来保存寄存器和局部变量的区域。
3.1.3 参数传递规则
第3章 ARM中的C语言和汇编混合编程
本章内容 ATPCS介绍 内嵌汇编器的使用 汇编和C的相互调用 汇编程序和C程序调用举例
3.1.1 寄存器的使用规则
寄存器R14用做连接寄存器,记作LR。它用于保 存子程序的返回地址。如果再子程序中保存了返 回地址,则R14可用做其他的用途。
寄存器R15是程序计数器,记作PC,它不能用做 其他用途。
2. 物理寄存器 在内嵌的汇编指令中,使用物理寄存器有以下规则: (1)不能直接向PC寄存器中赋值,程序的跳转只能通过B
指令和BL指令实现。
(2)在使用物理寄存器的内嵌汇编指令中,不要使用过多 复杂的C表达式,因为当表达式过于复杂时,将会需要较 多的物理寄存器,这些寄存器可能与指令中的物理寄存器 使用冲突。当编译器发现了寄存器分配冲突时,会产生相 应的错误信息,报告寄存器分配冲突。
2)常量前的#号可以省略 3)只有指令B可以使用C程序中的标号,指令BL不可以使
用 4)不支持汇编语言中用于内存分配的伪操作 5)内嵌汇编不支持通过“.”指示符或PC获取当前指令地
址 6)不支持LDR Rn,=expression 伪指令,而使用
MOV Rn,expression指令向寄存器赋值
8)不支持ADR和ADRL伪指令 9)不支持BX和BLX指令 10)不可以向PC赋值 11)使用0x前缀替代 &表示十六进制数 12)不使用寄存寻址变量 13)ldm和stm指令的寄存器列表只允许物理寄存
ARM实验报告汇编调用C语言
XI`AN TECHNOLOGICAL UNIVERSITY 实验报告西安工业大学实验报告一丶实验目的1)阅读Embest Arm EduKit II 启动代码,观察处理器启动过程;2)学会使用Embest IDE 辅助信息窗口来分析判断调试过程和结果;3)学会在Embest IDE 环境中编写、编译与调试汇编和C 语言相互调用的程序。
二、实验内容用汇编语言编写一段程序,调用C语言程序进行运算,并输出结果三、实验原理程序只要遵守ATPCS 相应规则,就可以使用不同的源代码编写程序。
程序间的相互调用最主要的是解决参数传递问题。
应用程序之间使用中间寄存器及数据栈来传递参数,其中,第一个到第四个参数使用R0-R3,多于四个参数的使用数据栈进行传递。
这样,接收参数的应用程序必须知道参数的个数。
但是,在应用程序被调用时,一般无从知道所传递参数的个数。
不同语言编写的应用程序在调用时可以自定义参数传递的约定,使用具有一定意义的形式来传递,可以很好地解决参数个数的问题。
常用的方法是把第一个或最后一个参数作为参数个数(包括个数本身)传递给应用程序。
四、实验过程1)打开Embest IDE Pro软件,选择菜单项File-->New Workspace,系统弹出对话框,创建名为explasm的新工程,并同时创建一个与工程名相同的工作区。
此时在工作窗口将打开该工作区和工程。
2)编写源代码文件并分别保存为randtest.c,random.s和ldscript,并把它们加入到工程里面。
3)基本配置:选择菜单项Project-->Settings,弹出工程设置对话框,在工程设置对话框中,选择Processor设置对话框,选择ARM7对目标板所用处理器进行配置。
4)生成目标代码:选择菜单项Build-->Build xxx_a.s,生成目标代码。
5)调试设置:使用快捷键Alt+F7,弹出设置对话框,在工程设置对话框中,选择Remote设置对话框,对相应模块进行配置。
C代码中嵌入汇编(ARM)
C代码中嵌⼊汇编(ARM)C 代码中嵌⼊汇编⽽ C 中嵌⼊汇编代码由 gcc 编译器实现的,实现也⾮常简单,使⽤由编译器提供的 asm 或者 __asm__ 关键字即可,这两者没有任何区别,然后将需要执⾏的汇编指令使⽤("")包含起来即可,对应的汇编指令就会被执⾏。
我们来看看下⾯的嵌⼊汇编代码:void func(void){...asm("mov r1,r0");__asm__("mov r2,r1");...}代码⾮常简单,将寄存器 r0 的值赋值给 r1,然后赋值给 r2。
这是最简单的汇编指令,但是,通常情况下,这样的汇编代码没有产⽣输⼊输出的⾏为,也就对函数的执⾏不能做出正向的贡献。
事实上,在⼦程序的调⽤时,这种代码可能是有⽤的,因为在 arm 中 r0~r3 被⽤来传递参数和返回值。
之所以说正向的贡献是因为这种操作可能产⽣负⾯的影响,因为 r0~r2 寄存器很可能正在被程序的其它部分使⽤⽽在这⾥被意外地修改。
⽽更多地情况是,C 函数中调⽤汇编函数,是需要汇编指令进⾏⼀些特定的操作,然后在 C 函数中使⽤相应的操作结果,实现 C 和嵌⼊汇编代码的"交互",这就需要使⽤到嵌⼊汇编的另⼀种表达形式:asm(code : output operand list : input operand list : clobber list);这种嵌⼊汇编的形式⼀共分为四个部分:code[attr]output operand list[attr]input operand listclobber listoutput operand list:表⽰输出的操作数,通常是⼀个或者多个 C 函数中的变量。
input operand list:表⽰输⼊的操作数,通常是⼀个或者多个 C 函数中的变量,attr 部分表⽰操作数的属性,以字符串的形式提供,是必须的参数。
ARM汇编语言调用C语言
汇编语言调用C语言实验目的了解ATPCS基本规则;学会在ADS1.2环境中编写、编译与调试汇编和C语言相互调用的程序。
实验设备硬件:PC机。
软件:ADS1.2集成开发环境,Windows 2000/XP/2003。
实验原理(1)汇编与C程序相互调用规则在C 程序和ARM汇编程序之间相互调用必须遵守ATPCS。
C编译器编译的C 语言子程序满足ATPCS类型。
而对于汇编语言来说,完全要依赖用户来保证各个子程序满足选定ATPCS 类型。
ATPCS(ARM Thumb过程调用标准): R0-R3用于传参,R0用于返回值,R4-R11通用变量寄存器R12临时过渡寄存器R13堆栈指针R14链接寄存器R15程序计数器PC 所以函数内的局部变量最好不要超过12个。
关于传参:如果一个函数的参数多于4个,C++的参数多于3个,其他的参数会通过堆栈进行传递,降低效率,因此将多个相关的参数组织到一个结构体中,传递该结构的指针,是一个好办法。
(2)汇编程序调用C程序汇编程序的设置要遵循ATPCS规则,保证程序调用时参数的正确传递。
在汇编程序中使用IMPORT伪指令声明将要调用的C程序函数;在调用C程序时,要正确设置入口参数,然后使用BL调用。
实验思考题1.汇编语言调用C语言.思考:return通过什么寄存器返回值.int fun(int a, int b,int c){return a+b+c;}AREA f,CODE,READONLYENTRYIMPORT funMOV R0,#1MOV R1,#2MOV R2,#3BL funstopB stopEND2、下列C 语言调用汇编程序实验的参考程序见程序清单3.1。
汇编加法函数代码见程序清单3.程序清单3.1 C语言调用汇编程序实验参考程序程序清单3.2 汇编加法函数代码思考:该实例中通过什么寄存器传递参数。
ARM中C和汇编的相互调用(5个数求和、字符串拷贝)
ARM中C和汇编的相互调⽤(5个数求和、字符串拷贝)开发环境:Keil5⼯程⽬录:⼀、汇编调⽤C——多数相加使⽤汇编调⽤C,需要注意的是参数的传递。
不同于X86的传参规则,在ARM体系中,如果形参的个数不超过4个,使⽤特殊寄存去R0~R3传递;⽽如果参数⼤于4个,就要将多出来的那部分参数使⽤堆栈传递。
压栈的之后移动位置指针,压栈顺序别忘了是最后⼀个参数先⼊栈->倒数第⼆个参数->,,,,下⾯的代码实现了五个参数求和,⾸先使R0=0,R1=1,R2=2,R3=3,第五个参数使⽤栈传递,并移动堆栈指针。
(1)startup.sStack_Size EQU 0x100 ;初始化栈的⼤⼩为256BAREA STACK, NOINIT, READWRITE, ALIGN = 3Stack_Mem SPACE Stack_Size__initial_spPRESERVE8THUMBAREA RESET, DATA, READONLY;中断向量表DCD __initial_spDCD Reset_HandlerAREA RESET, DATA, READWRITEAREA Sum, CODE, READONLY ;声明⼀个叫Sum的代码段,可读Reset_Handler PROC; ;复位函数,从这⾥开始执⾏IMPORT main ;main函数不在此⽂件中,所以需要引⼊IMPORT sum5 ;sum5函数不在此⽂件中,所以需要引⼊CALLSUM5MOV R0,#0MOV R1,#1MOV R2,#2MOV R3,#3MOV R4,#4;前4个参数使⽤R0~R3传递,STR R4,[SP, #-4]! ;第5个使⽤栈传递BL sum5 ;调⽤c程序LDR R0, = mainBX R0 ;回到C的main函数ENDPEND(2)main.cint sum5(int a, int b, int c, int d, int e) {return (a+b+c+d+e);}int main(void) {return0;}⼆、C调⽤汇编——strcopy逻辑上⽐较好理解,⾸先在汇编⽂件中定义C要调⽤的函数,然后在.c⽂件extern这个函数,调⽤即可。
ARM汇编与C调用的若干问题(一般函数调用情况)
ARM汇编与C调⽤的若⼲问题(⼀般函数调⽤情况)ARM 汇编与C之间的函数调⽤需要符合ATPCS,建议函数的形参不超过4个,如果形参个数少于或等于4,则形参由R0,R1,R2,R3四个寄存器进⾏传递;若形参个数⼤于4,⼤于4的部分必须通过堆栈进⾏传递。
R0 ⽤来存放函数的第⼀个参数,R1⽤来存放第⼆个参数,R2⽤来存放第三个参数,R3⽤来存放第四个参数。
其中R0还⽤来返回函数的调⽤结果,对应C函数⾥⾯的return value语句中的value 存放在R0中。
ARM堆栈的是满栈FULL STACK,SP指针指向的位置是存放有效数据的地⽅,若压栈新的数据,必须先改变SP,再向SP⾥⾯压⼊数据。
下⾯结合博客,的内容进⾏分析。
情景(⼀)函数形参的个数<= 4test_asm_args.asmIMPORT test_c_args ;声明test_c_args函数AREA TEST_ASM, CODE, READONLYEXPORT test_asm_argstest_asm_argsSTR lr, [sp, #-4]!;保存当前LR.栈是满递减栈FD,⾸先调整SP指针,然后压⼊LR地址。
ldr r0,=0x10 ;参数 1ldr r1,=0x20 ;参数 2ldr r2,=0x30 ;参数 3ldr r3,=0x40 ;参数 4bl test_c_args ;调⽤C函数LDR pc, [sp], #4;将LR装进PC(返回main函数) ,PC = LR,SP = SP+4,恢复原来的栈。
ENDvoid test_c_args(int a,int b,int c,int d){printk("test_c_args:\n");printk("%0x %0x %0x %0x\n",a,b,c,d);}int main(){test_asm_args();for(;;);}情景⼆:函数的参数是8个test_asm_args.asm//--------------------------------------------------------------------------------IMPORT test_c_args ;声明test_c_args函数AREA TEST_ASM, CODE, READONLYEXPORT test_asm_argstest_asm_argsSTR lr, [sp, #-4]! ;保存当前lrldr r0,=0x1 ;参数 1ldr r1,=0x2 ;参数 2ldr r2,=0x3 ;参数 3ldr r3,=0x4 ;参数 4ldr r4,=0x8str r4,[sp,#-4]! ;参数 8 ⼊栈ldr r4,=0x7str r4,[sp,#-4]! ;参数 7 ⼊栈ldr r4,=0x6str r4,[sp,#-4]! ;参数 6 ⼊栈ldr r4,=0x5str r4,[sp,#-4]! ;参数 5 ⼊栈bl test_c_args_lotsADD sp, sp, #4 ;清除栈中参数 5,本语句执⾏完后sp指向参数6ADD sp, sp, #4 ;清除栈中参数 6,本语句执⾏完后sp指向参数7ADD sp, sp, #4 ;清除栈中参数 7,本语句执⾏完后sp指向参数8ADD sp, sp, #4 ;清除栈中参数 8,本语句执⾏完后sp指向 lrLDR pc, [sp],#4 ;将lr装进pc(返回main函数)ENDtest_c_args.c//--------------------------------------------------------------------------------void test_c_args(int a,int b,int c,int d,int e,int f,int g,int h) {printk("test_c_args_lots:\n");printk("%0x %0x %0x %0x %0x %0x %0x %0x\n",a,b,c,d,e,f,g,h);}main.c//--------------------------------------------------------------------------------int main(){test_asm_args();for(;;);}。
arm汇编调用c函数
arm汇编调用c函数在嵌入式领域,arm汇编是一种常用的编程语言。
它可以直接操作硬件,实现高效的程序执行。
而C语言则提供了更高级的抽象和易用性。
在实际开发中,我们往往需要将这两种语言结合起来使用,以充分发挥它们的优势。
在arm汇编中调用C函数是一种常见的需求。
这样可以在汇编程序中使用C函数提供的功能,避免重复编写代码。
下面我们将以arm 汇编调用C函数为主题,介绍如何实现这一过程。
我们需要了解一些基本的汇编语法和C函数调用的规则。
在arm汇编中,函数的调用和返回是通过栈来实现的。
调用方将参数和返回地址压入栈中,然后跳转到被调用函数的入口地址。
被调用函数执行完毕后,将返回值放入特定的寄存器中,并将栈恢复到调用前的状态,最后通过跳转指令返回到调用方。
在C语言中,函数的声明和定义是通过函数原型来完成的。
函数原型包含函数的返回类型、函数名和参数类型。
在调用函数时,需要按照函数原型的规定传递参数,并使用函数返回的值。
在arm汇编中调用C函数的步骤如下:1. 在汇编代码中定义函数原型。
这可以通过使用.extern 或.global指令来实现。
例如,要调用一个名为add的C函数,可以使用如下指令:.extern add2. 在需要调用C函数的地方,使用BL指令跳转到函数入口地址。
BL指令可以将返回地址保存在链接寄存器中,以便函数返回时使用。
例如,要调用add函数,并将参数1和2传递给它,可以使用如下指令:LDR R0, =1LDR R1, =2BL add3. 在C函数中,使用BX LR指令返回到调用方。
BX LR指令可以将链接寄存器中保存的返回地址恢复到程序计数器,并跳转到该地址。
例如,在add函数中,可以使用如下指令:BX LR通过以上步骤,我们就可以在arm汇编中成功调用C函数了。
需要注意的是,汇编代码和C代码之间的调用约定需要保持一致。
这包括参数传递的顺序、寄存器的使用和栈的操作等。
如果不遵守调用约定,可能会导致程序出错或结果异常。
ARM中C和汇编混合编程及示例.
ARM中C和汇编混合编程及示例参数的传递规则.根据参数个数是否固定,可以将子程序分为参数个数固定的子程序和参数个数可变的子程序.这两种子程序的参数传递规则是不同的.1.参数个数可变的子程序参数传递规则对于参数个数可变的子程序,当参数不超过4个时,可以使用寄存器R0~R3来进行参数传递,当参数超过4个时,还可以使用数据栈来传递参数.在参数传递时,将所有参数看做是存放在连续的内存单元中的字数据。
然后,依次将各名字数据传送到寄存器R0,R1,R2,R3;如果参数多参数的传递规则.根据参数个数是否固定,可以将子程序分为参数个数固定的子程序和参数个数可变的子程序.这两种子程序的参数传递规则是不同的.1.参数个数可变的子程序参数传递规则对于参数个数可变的子程序,当参数不超过4个时,可以使用寄存器R0~R3来进行参数传递,当参数超过4个时,还可以使用数据栈来传递参数. 在参数传递时,将所有参数看做是存放在连续的内存单元中的字数据。
然后,依次将各名字数据传送到寄存器R0,R1,R2,R3; 如果参数多于4个,将剩余的字数据传送到数据栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈. 按照上面的规则,一个浮点数参数可以通过寄存器传递,也可以通过数据栈传递,也可能一半通过寄存器传递,另一半通过数据栈传递.2.参数个数固定的子程序参数传递规则对于参数个数固定的子程序,参数传递与参数个数可变的子程序参数传递规则不同,如果系统包含浮点运算的硬件部件,浮点参数将按照下面的规则传递: 各个浮点参数按顺序处理;为每个浮点参数分配FP寄存器;分配的方法是,满足该浮点参数需要的且编号最小的一组连续的FP寄存器.第一个整数参数通过寄存器R0~R3来传递,其他参数通过数据栈传递.子程序结果返回规则1.结果为一个32位的整数时,可以通过寄存器R0返回.2.结果为一个64位整数时,可以通过R0和R1返回,依此类推.3.结果为一个浮点数时,可以通过浮点运算部件的寄存器f0,d0或者s0来返回.4.结果为一个复合的浮点数时,可以通过寄存器f0-fN或者d0~dN来返回.5.对于位数更多的结果,需要通过调用内存来传递.本文通过几个简单的例子演示了嵌入式开发中常用的C和汇编混合编程的一些方法和基本的思路,其实最核心的问题就是如何在C和汇编之间传值,剩下的问题就是各自用自己的方式来进行处理。
arm汇编(c内嵌汇编及c和汇编互调)
arm汇编(c内嵌汇编及c和汇编互调)C语⾔编译成汇编:arm-linux-gcc -S test.c -o test.SC语⾔编译成可执⾏⽂件:arm-linux-gcc test.c -o test多个⽂件编译链接:arm-linux-gcc –c main.c –o main.oarm-linux-gcc –c abc.S –o abc.oarm-linux-gcc main.o abc.o –o test.o汇编编译两种⽅式:arm-linux-as test.S -o test.oarm-linux-gcc –c test.S –o test.oARM裸机程序编译:arm-linux-gcc -c start.S -o start.oarm-linux-ld -Ttext=0x40000000 start.o -o start.elfarm-linux-objcopy -I elf32-littlearm -O binary start.elf –o start.bin查看代码地址信息:arm-linux-objdump -h testARM反汇编:arm-linux-objdump -D elf_file > dis_file⼀、arm内嵌汇编#include <stdio.h>int main(void){int a = 88;__asm__ __volatile__("mov r0, %1\n""mov r1, #1\n""add %0, r0, r1\n": "=r" (a):"r" (a): "r0", "r1");printf("a = %d\n",a);return 0;}有些知识:a) __asm__(下划线每次两根):表⽰嵌⼊汇编。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
ARM中C语言调用汇编语言方法浅析在嵌入式系统开发中,目前使用的主要编程语言是C 和ARM指令汇编。
在一些对性能非常敏感的代码块,基于汇编与机器码一一对应的关系,这时不能依靠C编译器的生成代码,而要手工编写汇编,从而达到优化的目的。
一、在C语言中内嵌汇编
在C中内嵌的汇编指令包含大部分的ARM和Thumb指令,不过使用与单纯的汇编程序使用的指令略有不同,存在一些限制,主要有下面几个方面:
①不能直接向PC 寄存器赋值,程序跳转要使用B或者BL指令;
②在使用物理寄存器时,不要使用过于复杂的C表达式,避免物理寄存器冲突;
③R12和R13可能被编译器用来存放中间编译结果,计算表达式值时可能把R0-R3、R12及R14用于子程序调用,因此避免直接使用这些物理寄存器;
d 一般不要直接指定物理寄存器;
④让编译器进行分配内嵌汇编使用的标记是__asm或asm关键字,用法如下:__asm{instruction [; instruction]}或asm("instruction [; instruction]")。
下面是一个例子来说明如何在C中内嵌汇编语言:
//C语言文件*.c
#include <stdio.h>
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语言的指针来实现的,因为指针对应的是地址,所以汇编中也可以访问。
二、在汇编中使用C定义的全局变量
内嵌汇编不用单独编辑汇编语言文件,比较简洁,但是有很多的限制。
当汇编的代码较多时一般放在单独的汇编文件中,这时就需要在汇编文件和C文件之间进行一些数据的传递,最简便的办法就是使用全局变量。
下面是一个C语言和汇编语言共享全局变量的例子:
//C语言文件*.c
#include <stdio.h>
int gVar=12;
extern asmDouble(void);
int main(){
printf("original value of gVar is: %d", gVar_1);
asmDouble();
printf(" modified value of gVar is: %d", gVar_1);
return 0;
}
;汇编语言文件*.S
AREA asmfile, CODE, READONLY EXPORT asmDouble
IMPORT gVar
asmDouble
ldr r0, =gVar
ldr r1, [r0]
mov r2, #2
mul r3, r1, r2
str r3, [r0]
mov pc, lr
END
在此例中,汇编文件与C文件之间相互传递了全局变量gVar和函数asmDouble,留意声明的关键字extern和IMPORT
三、在C中调用汇编的函数
有一些对机器要求高的敏感函数,通过C语言编写再通过C编译器翻译有时会出现误差,因此这样的函数一般采用汇编语言来编写,然后供C语言调用。
在C文件中调用汇编文件中的函数,要注意的有两点:
一、是要在C文件中声明所调用的汇编函数原型,并加入extern关键字作为引入函数的声明;
二、是在汇编文件中对对应的汇编代码段标识用EXPORT关键字作为导出函数的声明,函数通过mov pc, lr指令返回。
这样,就可以在C文件中使用该函数了。
从C语言的角度的角度,并不知道调用的函数的实现是用C语言还是汇编汇编语言,原因C语言的函数名起到表明函数代码起始地址的作用,而这个作用和汇编语言的代码段标识符是一致的。
下面是一个C语言调用汇编函数例子:
//C语言文件*.c
#include <stdio.h>
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;
}
;汇编语言文件*.S
AREA asmfile, CODE, READONLY
EXPORT asm_strcpy
asm_strcpy
loop
ldrb r4, [r0], #1
cmp r4, #0
beq over
strb r4, [r1], #1
b loop
over
mov pc, lr
END
在此例中,C语言和汇编语言之间的参数传递是通过对应的用R0-R3来进行传递,即R0传递第一个参数,R1传递第二个参数,多于4个时借助栈完成,函数的返回值通过R0来传递。