混合语言编程.doc

上传人:asd****56 文档编号:70333403 上传时间:2023-01-19 格式:DOC 页数:5 大小:75KB
返回 下载 相关 举报
混合语言编程.doc_第1页
第1页 / 共5页
混合语言编程.doc_第2页
第2页 / 共5页
点击查看更多>>
资源描述

《混合语言编程.doc》由会员分享,可在线阅读,更多相关《混合语言编程.doc(5页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、2.6 混合语言编程目前,在嵌入式系统开发中,使用的主要编程语言是C语言和汇编语言。在稍大规模的嵌入式软件中,例如含有OS,大部分的代码都是用C编写的,主要是因为C语言的结构比较好,便于人的理解,而且有大量的支持库。尽管如此,很多地方还是要用到汇编语言,例如开机时硬件系统的初始化,包括CPU状态的设定、中断的使能、主频的设定、RAM的初始化等,一些中断处理也可能涉及汇编。另外,对性能非常敏感的代码,需要手工编写汇编语言程序。汇编语言是和CPU的指令集紧密相关的。作为涉及底层的嵌入式系统开发,必须熟练对汇编语言的使用。使用C语言和汇编语言进行混合编程,可以充分发挥各自的优势,取得显著效果。在C中

2、嵌入汇编的格式为:asm(汇编语句:输出寄存器:输入寄存器:会被修改的寄存器);其中:汇编语句:是写汇编指令的地方;输出寄存器:表示当这段嵌入汇编执行后,用于存放输出数据的寄存器。这些寄存器会分别对应一个C语言表达式或一个内存地址;输入寄存器:表示在开始执行汇编指令时,指定一些寄存器中应存放输入值,它们也分别对应着一个C变量或常数值。会被修改的寄存器:在gcc知道会被修改的寄存器后,能够对代码进行优化。示例:01 #define get_seg_byte(seg, addr) 02 ( 03 register char _res;04 _asm_(push %fs; 05 mov %ax, %

3、fs; 06 movb %fs:%2, %al; 07 pop %fs 08 :=a(_res) 09 :(seg), m(*(addr); 10 _res;)这段10行的代码定义了一个嵌入汇编语言宏函数。用圆括号括住的组合语句(花括号中的语句)可以作为表达式使用,第10行变量_res是该表达式的输出值。宏语句要在一行上定义,因此使用“”将这些语句连成一行。宏的名字是get_seg_byte(seg, addr)。第3行定义寄存器变量_res。第4行的_asm_表示嵌入汇编语句的开始。4-7行是AT&T格式的汇编语句。第8行是输出寄存器,其含义是此段代码结束后将eax所代表的寄存器的值放入_r

4、es变量中,作为本函数的输出值,=a中的a称为加载代码,=表示这是输出寄存器。第9行表示此段代码开始运行时将seg放到eax寄存器中,表示使用与上面同个位置的输出相同的寄存器。m表示使用一个内存偏移地址值。为了在上面的汇编语句中使用该地址值,嵌入汇编程序规定把输出和输入寄存器统一按顺序编号,从输出寄存器序列开始,从左到右,从上到下,以%0开始,分别记为%0、%1、%9。因此,输出寄存器的编号是%0(这里只有一个输出寄存器),输入寄存器前一部分((seg))的编号是%1,而后部的编号是%2。上面第6行上的%2即代表(*(addr)这个内存偏移量。第4行代码的作用是将fs段寄存器的内容入栈;第5行

5、将eax中的段值赋给fs段寄存器;第6行是把fs:(*(addr)所指定的字节放入al寄存器中。当执行完汇编语句后,输出寄存器eax的值将被放入_res,作为该宏函数的返回值。这段程序中,seg代表一个指定的内存段值,而addr表示一个内存偏移地址量。该宏函数的功能是从指定段和偏移值的内存地址处取一个字节。一些可能会用到的寄存器加载代码及其具体的含义见表2.19。表2.19 寄存器加载代码及其具体的含义代码含义代码含义a使用寄存器eaxm使用内存地址b使用寄存器ebxo使用内存地址并可以加偏移量c使用寄存器ecxI使用常数031d使用寄存器edxJ使用常数063S使用esiK使用常数0255D

6、使用ediL使用常数065535q使用动态字节可寻址寄存器(eax、ebx、ecx或edx)M使用常数03r使用任意动态分配的寄存器N使用1字节常数(0255)g使用通用有效的地址即可(eax、ebx、ecx、edx或内存变量)O使用常数031A使用eax与edx联合(64位)下面主要介绍基于ARM的C语言与汇编语言的混合编程。1C语言与汇编语言混合编程应遵守的规则ARM编程中使用的C语言是标准C语言。在使用C语言时,要用到和汇编语言的混合编程。若汇编代码较为简洁,则可使用直接内嵌汇编的方法;否则要将汇编程序以文件的形式加入到项目中,按照ATPCS(ARM/Thumb Procedure Ca

7、ll Standard,ARM/Thumb过程调用标准)的规定与C程序相互调用与访问。在C和ARM汇编语言程序之间相互调用时,必须遵守ATPCS规则。ATPCS规定了一些子程序间调用的基本规则、寄存器的使用规则、堆栈的使用规则以及参数的传递规则等。(1)寄存器的使用规则子程序之间通过寄存器R0R3来传递参数,当参数个数多于4个时,使用堆栈来传递参数。此时R0R3可记作A1A4。在子程序中,使用寄存器R4R11保存局部变量。因此当进行子程序调用时要注意对这些寄存器的保存和恢复。此时R4R11可记作V1V8。寄存器R12用于保存堆栈指针SP,当子程序返回时使用该寄存器出栈,记作IP。寄存器R13用

8、作堆栈指针,记作SP。寄存器R14称为链接寄存器,记作LR,该寄存器用于保存子程序的返回地址。寄存器R15称为程序计数器,记作PC。(2)堆栈的使用规则ATPCS规定堆栈采用满递减类型(FD,Full Descending),且对堆栈的操作是8字节对齐。使用STMFD/LDMFD指令。(3)参数的传递规则整数参数的前4个使用R0R3传递,其它参数使用堆栈传递;浮点参数使用编号最小且能够满足需要的一组连续的FP寄存器传递参数。子程序的返回结果为一个32位整数时,通过R0返回;返回结果为一个64位整数时,通过R0和R1返回;依此类推。结果为浮点数时,通过浮点运算部件的寄存器F0、D0或者S0返回。

9、2在汇编语言程序中调用C函数的方法汇编语言程序的书写要遵循ATPCS规则,以保证程序调用时参数能够正确传递。在汇编语言程序中调用C函数的方法是:首先,将C代码在一个独立的C源程序文件中译;然后,在汇编程序中使用IMPORT伪指令声明将要调用的C语言函数;接着,通过BL指令调用C函数。示例:在一个C源文件中定义了如下求和函数int add(int x,int y)return(x+y);调用add()函数的汇编语言程序结构如下:IMPORT add;声明要调用的C函数MOV R0,1MOV R1,2BL add;调用C函数add进行函数调用时,使用R0和R1实现参数的传递,返回结果由R0带回。函

10、数调用结束后,R0的值为3。示例:;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 sum END/*C file, called by asmfile */C源文件int sum(int a, int b, int c)r

11、eturn a+b+c;3C语言程序调用汇编子程序(函数)的方法C语言程序调用汇编子程序时,汇编子程序的书写也要遵循ATPCS规则,以保证程序调用时参数正确的传递。在C语言程序中调用汇编子程序的方法为:首先,在汇编语言程序中使用EXPORT伪指令声明被调用的子程序,表示该子程序将在其它文件中被调用;然后,在C语言程序中使用extern关键字,声明要调用的汇编子程序为外部函数;接着,就可以在C语言程序中调用该子程序了。注意:从C的角度来看,其并不知道该函数是用C还是汇编实现的。因为C的函数名用来表示函数代码的起始地址,这个和汇编中的label是一样的。示例:在一个汇编语言源文件中定义了求和函数E

12、XPORT add;声明add子程序将被外部函数调用add ;求和子程序addADD R0,R0,R1MOV pc,lr在一个C语言程序的main()函数中,对add汇编子程序进行了调用。extern int add (int x,int y); /声明add为外部函数int main()int a=1,b=2,c;c=add(a,b); /调用add子程序当main()函数调用add汇编子程序时,变量a、b的值分别赋给R0和R1,返回结果由R0带回,并赋值给变量c。函数调用结束后,变量c的值为3。示例:/* cfile.c/C源文件* in C,call an asm function, a

13、sm_strcpy* Sep 9, 2004*/#include extern void asm_strcpy(const char *src, char *dest); /声明asm_strcpy为外部函数int main() const char *s = seasons in the sun; char d32; asm_strcpy(s, d); /调用asm_strcpy子程序 printf(source: %s, s); printf( destination: %s,d); return 0;asm function implementation/汇编语言程序文件 AREA as

14、mfile, CODE, READONLY EXPORT asm_strcpyasm_strcpyloop ldrb r4, r0, #1 ;address increment after read cmp r4, #0 beq over strb r4, r1, #1 b loopover mov pc, lr END4C语言程序中内嵌汇编语句在C语言程序中内嵌汇编语句可以实现一些高级语言不能实现或不容易实现的功能。对于时间效率要求比较高的程序段,也可以通过在C语言中内嵌汇编语句来实现。嵌入式汇编语句在形式上为独立定义的函数体,其语法格式为:_asm指令;指令指令或asm(指令;指令);其中

15、_asm或asm为内嵌汇编语句的关键字,需要特别注意的是前面有两个下划线。指令之间用分号分隔,如果一条指令占据多行,除最后一行外都要使用连字符“”。在C语言程序中内嵌的汇编指令包含大部分ARM/Thumb指令,但是,其使用与汇编语言程序文件中的指令有些不同,存在一些限制,主要有以下几个方面:(1)不能直接修改PC来实现跳转的底层功能,程序跳转要使用B或BL指令。(2)在使用物理寄存器时,不要使用过于复杂的C表达式,避免物理寄存器冲突。(3)R12和R13可能被编译器用来存放中间编译结果,计算表达式的值时,可能会将R0到R3、R12及R14用于子程序调用,因此要避免直接使用这些物理寄存器。(4)

16、一般不要直接指定物理寄存器,最好让编译器进行分配。(5)不能直接引用C语言中的变量。示例:在C语言程序中内嵌汇编语句#include void strcpy_tmp(const char *src, char *dest)char ch;_asmloop:ldrb ch, src, #1strb ch, dest, #1cmp ch, #0bne loopint main()char *a = aaawwwasd;char b16;strcpy_tmp(a, b);printf(src: %s, a);printf(dest: %s, b);return 0;在这里C程序和汇编语句之间的值传递

17、,是使用C指针来实现的,因为C指针对应的是地址,因此汇编语句中可以访问。5在汇编语言程序中使用C语言程序中定义的全局变量内嵌汇编的优点是不用单独编辑汇编语言文件,比较简洁,但是,当汇编代码较多时,一般要放在单独的汇编文件中。这时就需要在汇编和C之间进行一些数据的传递,此时最简便的办法就是使用全局变量。示例:/* cfile.c/C源文件* 定义全局变量,并作为主调程序*/#include int gVar_1 = 12;extern asmDouble(void);int main() printf(original value of gVar_1 is: %d, gVar_1); asmDo

18、uble(); 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_1asmDouble ldr r0, =gVar_1 ldr r1, r0 mov r2, #2 mul r3, r1, r2 str r3, r0 mov pc, lr END

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁