网站开发技术架构,广德网站建设,最近在线观看免费大全电视剧,企业网站建设主要类型及选择在一些嵌入式场合#xff0c;我们经常看到C程序和汇编程序相互调用#xff0c;混合编程#xff0c;如在ARM启动代码中#xff0c;系统上电首先运行的是汇编代码#xff0c;等初始化好内存堆栈环境之后#xff0c;才会跳到C程序中执行#xff0c;对嵌入式软件进行优化时我们经常看到C程序和汇编程序相互调用混合编程如在ARM启动代码中系统上电首先运行的是汇编代码等初始化好内存堆栈环境之后才会跳到C程序中执行对嵌入式软件进行优化时在一些性能要求比较高的场合通常会在C语言中内嵌一些汇编代码作为一名嵌入式工程师掌握C语言和汇编的混合编程还是有必要的。 3.6.1 ATPCS规则 无论是在汇编程序中调用C程序还是在C程序中调用汇编往往都要涉及子程序调用子程序的返回参数传递这些问题。从指令集层面看C语言和汇编语言两种其实无差别。最终都会被翻译成二进制机器指令在学习C语言和ARM汇编语言混合编程之前我们需要先了解一下ATPCS规则。 ATPCS的全称是ARM-thumb procedure call standard, 其核心内容就是定义了ARM子程序调用的基本规则以及堆栈的使用约定等如ATPCS规定了ARM程序要使用满递减堆栈入栈/出栈操作要使用STMFD/LDMFD指令只要所有的程序都遵循这个约定ARM程序的格式也就统一了。我们编写的ARM程序也就可以在各种各样的ARM处理器上运行了。 ATPCS最重要的内容就是定义了子程序调用的具体规则无论是程序员编写程序还是编译器开发商开发编译器工具一般都要遵循它规则的主要内容如下。 1 子程序间要通过寄存器R0-R3 传递参数当参数大于4个时剩余的参数使用堆栈来传递。 2 子程序通过r0-r1返回结果 3 子程序使用r4-r11来保存局部变量 4 r12作为调用过程中的临时寄存器一般用来保存函数的栈帧基址记作FP。 5 r13作为堆栈指针寄存器一般记作SP 6 R14作为链接寄存器用来保存函数调用者的返回地址记作LR。 7 R15作为程序计数器总是指向当前正在运行的指令记作PC。 在ARM平台下无论是C程序还是汇编程序只要大家遵守ARM子程序之间的参数传递和调用规则就可以很方便的在C程序中调用汇编子程序或者在一个汇编程序中调用C程序。 我们在main.c 中定义了main函数和sum函数在一个汇编文件SUM.S中定义了一个汇编子程序SUM_ASM。 在main() 函数中我们直接调用了汇编子程序SUM._ASM 而在SUM_ASM的汇编代码实现中又调用了在C源文件中定义的sum 函数使用较差编译器arm-linux-gcc编译这两个源文件运行。 IMPORT sum; AREA SUM_ASM,CODE,READONLY EXPORT SUM_ASM SUM_ASM STR LR.[SP, #-4] ;去栈变量 LDR R0,0x3 LDR R1, 0x4 BL sum LDR PC,[SP],#4 END int sum(int a, int b) { int result a b; return result; } int main(void) { SUM_ASM(); return 0; } 3.6.2 在C程序中内嵌汇编代码 为了能在C程序中内嵌汇编代码ARM编译器在ANSI C标准的基础上扩展了一个关键字__asm, 通过这个关键字我们就可以在C程序中内嵌AMR汇编代码在C程序中内嵌汇编代码的格式如下。 __asm { 指令 [指令] } 这里有个细节需要注意下想再内嵌的汇编代码中添加注释记得要使用C语言的注释符号而不是汇编语言的注释。接下来我们通过一个数据块复制的例子。 int src[10] {1,2,3,4,5,6,7,8,9}; int dst[10] {0}; //数据块复制的C语言实现 int data_copy_c(void) { for (int i 0; i 10; i) dst[i] src[i]; return 0; } //数据块复制的内容ARM汇编实现 int data_copy_asm(void) { __asm { LDR R0,src LDR R1,dst MOV R2, #10 LOOP: LDR R3, [R0], #4 STR R3,[R1],#4 SUBS R2,R2,#1 BNE LOOP } } 为了能在C程序中内嵌汇编代码不同的编译器给予ANSI C标准扩展了不同的关键字使用的汇编风格也不一样。