嵌入式系统实践实验报告--汇编和C 语言的相互调用.docx
计算机科学技术系上机实践报告课程名称:嵌入式系统实践年级:上机实践成绩:指导教师:姓名:创新实践成绩:上机实践名称:汇编和C语言的相学号:上机实践日期:互调用上机实践编号:No.3组号:上机实践时间:V实验目的1. 阅读EmbCStEduKit-III启动代码,观察处理器启动过程;2. 学会使用EnlbeStIDE辅助信息窗口来分析判断调试过程和结果;3. 学会在EmbeStIDE环境中编写、编译与调试汇编和C语言相互调用的程序。二、实验设备1. 硬件:EmbestEDUKIT-111(实验平台)PC机2. 软件:EmbestIDEProARM集成开发环境,Windows98/2000/NT/XP。三、实验内容使用汇编完成一个随机数产生函数,通过C语言调用该函数,产生一系列随机数,存放到数组里面。1 .C语言的编译过程C语言程序一汇编语言程序f目标可执行程序2 .汇编语言的函数调用过程参数准备函数返回汇编函数间调用3 .函数调用举例C语言调用汇编函数汇编语言调用C语言函数4 .命令脚本文件和链接脚本文件四、实验原理1. ARM过程调用ATPCS(ARM)ATPCS是一系列用于规定应用程序之间相互调用的基本规则,这此规则包括:支持数据栈限制检查;支持只读段位置无关(ROPI);支持可读/写段位置无关(RVVPI);支持ARM程序和ThUmb程序的混合使用;处理浮点运算。使用以上规定的ATPCS规则时,应用程序必须遵守如下:程序编写遵守ATPCS;变量传递以中间寄存器和数据栈完成;汇编器使用-apes开关选项。关于其他ATPCS规则,用户可以参考ARM处理器相关书籍或登录ARM公司网站。程序只要遵守ATPCS相应规则,就可以使用不同的源代码编写程序。程序间的相互调用最主要的是解决参数传递问题。应用程序之间使用中间寄存器及数据栈来传递参数,其中,第一个到第四个参数使用R0R3,多于四个参数的使用数据栈进行传递。这样,接收参数的应用程序必须知道参数的个数。但是,在应用程序被调用时,一般无从知道所传递参数的个数。不同语言编写的应用程序在调用时可以自定义参数传递的约定,使用具有一定意义的形式来传递,可以很好地解决参数个数的问题。常用的方法是把第一个或最后一个参数作为参数个数(包括个数本身)传递给应用程序。ATPCS中寄存器的对应关系如表35所列:表35ATPCS规则中寄存器列表ARM寄存器ATPCS别名ATPCS寄存器说明RO-R3<=>al-a4参数/结果/scratch寄存器1-4R4<=>vl局部变量寄存器1R5<=>v2局部变量寄存器2R6<=>v3局部变量寄存器3R7<=>V4、wr局部变量寄存器4ThUmb状态工作寄存器R8<=>v5ARM状态局部变量寄存器5R9<=>V6、sbARM状态局部变显寄存器6RWPI的静态基址寄存器RlO<=>V7、siARM状态局部变星寄存器7数据栈限制指针寄存器Rll<=>v8ARM状态局部变量寄存器8R12<=>P子程序内部调用的临时(SCmtCh)寄存器R13<=>sp数据栈指针寄存器R14<=>Ir链接寄存器R15<=>PC程序计数器2.main()函数与gccmain()当应用程序中包含了main。函数,将会引起对C运行时库的初始化。该初始化是通过函数gccmain()实现的,即在main。函数入口处,编译器会首先调用gccmain()函数,然后才是执行编写的代码。_gccmain()函数在gcc的标准库里面实现。当应用程序中没有包含main。函数,将不会引起对C运行时库的初始化。这时,C运行时库的很多功能在应用程序中是不能使用的。在基础实验的课程里面,我们没有涉及到函数库的内容,因此,我们不打算在这里加入函数库的使用。因此,如果我们使用main函数作为应用程序的主函数,可以在源代码中加入一个空的.gccmain。函数(用C语言或者汇编语言均可)。图3-14 explasm工程文件设置界面五、实验步骤1 .考本章其他实验,创建新的工程,工程名为:explasm:2 .按照参考程序,重新编写源代码文件并分别保存为randtest.c,init.s,random.s和IdSCript,并把它们加入工程里面;3 .参照其他基础实验操作,按照编译一汇编器配置一链接器配置一调试器配置设置新工程,并编译、链接工程,如图3-14所示;4 .下载调试文件,打开memoryregisterWatCh/variable/CaIlStaCk窗口,单步执行程序。通过以上窗口,跟踪程序运行,观察分析运行结果,通过实验学会使用EmbeStlDE进行应用程序的开发与调试;5 .理解和掌握实验后,完成实验练习题。6 .习题:- 编写一个汇编程序mixop.s- 实现函数y=mixop(xl,x2,x3)- y=xl+x2*x3- 调用c2.c中的multiply函数- C程序1:cl.c- 实现函数voidinit();- 作为启动时的起始地址- 在该函数内要调用mixop函数完成6+40*50,结果存放在变量y中。- C程序2:c2.c- 实现函数y=multiply(xl,x2)- y=xl*x2提示:init()函数结尾时,设置死循环调试过程、结果和分析编写三个函数八、×JBuildingproject:exparm-elf-gcc-gdwarf-cC:EmbestIDEExamplesexpc2.c-o.debugc2.oarn-elf-as-gdarF2C:EmbestIDEExamplesexpmixop.s-o.debugi×oarn-elF-ld-Ttext0×0-o.debugexp.elF.debugd.o.debugc2.o.cygdriuecEnbestIDEBuildxgcc-arm-elFbinaru-elF-ld:Warning:caComnand(三)successfullyexecuted.运仃cl.c§R10:0X00000000。R10:0×00000000。R11:0X00000000。R11:0×FffFfffcqR12:0x00000000。R12:0×00O0OOOOqR13:O×FfFfffF0NR13:OxFFFFffec0R14:0×00000O0O。R14:0X00000000。R15:O×OO090008。R15:O×0O0OOO1OqSP:0xfFFFFFF0/SP:GXffffffeCGLR:0×0000000WLR:0X00000000*PC:×00000008。PC:×000000109CPSR:O×0000OOd3。CPSR:0×0O0000d3qSPSR:0x00000000jSPSR:O×OOOOOO0将常数赋值给r,rl,r20 12 RRR O <>0×000000060X000000280X00000032R3:0×O0000000R4:O×00O00000R5:0×0000O00OR6:O×O00O0OO0R7:0×00000000R8:0×O0OOOO00DQ-AvAAAAAAAmixop.s俣存当前地址R11:GXFFFFFffCR12:0×O00000O0R13:OxFFFFFFecR14:0×OOOO002OR15:0×O00OOO58SP:OxFFFFFFec1.R:0×000000200PC:0×0OO0OO58。CPSR:0×00OOO0d3。SPSR:0X00000000将r3的值放入rRO:0x00000032R1:0×OOOOO028R2:O×0OO00O32R3:0X0O0000O0R4:0x00000006R5:OxO0O0OOOOR6:0X0O000000R7:0x00000000R8:0×O00O00O0R9:OxOOOOOOOr*rl的值放入rqR0:0×0O0O07dO。R1:0X00000028。R2:x00000032PR3:0×00O0O7dO。R4:0x00000006。R5:0X00000000。R6:0x00000000。R7:O×O00000OO。R8:0X00000000&R9:0X00000000R0+r4的结果存入rR:0×000007d6R1:0x00000028R2:0x00090032R3:0×00OOO7dORU:O×O0OOOO6R5:O×0000OO00R6:0×00000000R7:0x00000000R8:0x00000000R9:0x00000000七、总结本次实验主要是将两个C函数与一个汇编函数连接,从而实现相互调用。编译之后调试过程中遇到了一些错误,后来发现是程序入口的地址应该和连接脚本写得一样,之后调试成功。八、附件cl.cexternintunsignedmixop(intxl,intx2,intx3);voidinit()(inty;y=mixop(6,40,50);while(1)()Mixop.s.globalmixop.externmultipy.textmixop:movip,spstmdbsp!,fp,ip,Ir,pcsubfp,ip,#4movr4,rmovr,r2blmultiplyaddr,r,r4Idmdbfp,fp,sp,pc).endC2.cunsignedintmultiply(xl,x2)inty;y=xl*x2;returny;