[b]引 言 [/b] 跟着对高处理才干、实时多任务、超低功耗等方面需求的增加,高端嵌入式处理器现已进入了国内开发人员的视界,并在国内得到了遍及的注重和运用。ARM是现在嵌入式范畴运用最广泛的RISC微处理器结构,凭仗低成本、低功耗、高性能等长处占有了嵌入式体系运用范畴的领先地位。ADS是ARM公司推出的ARM集成开发环境,供给了对C和C++的支撑,是现在开发ARM的首要东西。本文针对日益缩短的嵌入式开发周期,结合ARM体系开发调试经历,对运用ARM规范库进行运用程序开发作了比较体系的剖析。 1 ARM规范库介绍 ADS供给了ANSI C和C++规范库,本文仅评论ANSI C库,该库包含下面几个部分: ◇IS0 C库规范所界说的函数; ◇在semlhosted环境下用来完结C库函数与方针相关的函数; ◇C和C++编译器要运用的heIper函数。 该库供给的比如文件输入输出之类的设备,运用了规范的ARM semihosted履行环境(semihosting是针对ARM方针机的一种机制,它能够依据运用程序代码的输入/输出恳求,与运转有调度功用的主机通讯,这种技能答应主机为一般没有输入和输出功用的方针硬件供给主机资源)。ARMulator、Angel和Multi-lCE都支撑这个环境,能够运用ADs中供给的开发东西开发运用程序,然后在ARMulator或者是开发板上运转和调试该程序。假如要使运用体系独立于这个环境,则有必要从头完结C库中依赖于这个环境的相关函数,依据用户体系的运转环境对C库进行恰当的削减。 运用ANSI规范C库进行程序开发,不只能够进步开发功率而且能够增强程序的可移植性。在程序中运用库函数,有必要先树立一个库函数能够履行的环境,这些作业都由库中的函数完结。当运用程序链接了C库中的函数时,C库中的函数将完结: ◇创立C程序所需的履行环境(树立栈,假如需求创立一个堆,初始化程序运用的部分库); ◇调用main()函数开端履行C程序; ◇支撑程序运用的Is0界说的函数; ◇捕获运转时的过错和信号,假如需求,依据过错停止履行或程序退出。 2 削减ARM规范C函数库 规范库中包含了部分依赖于ARM semihosted履行环境的函数,这部分函数的函数名中包含有单个或两个下划线“-”,需求从头完结这部分函数。假如在程序中界说这些函数,则编译器就会运用新界说的函数,这个进程称为库函数的削减。一般情况下,只需求从头界说很少的几个函数就能够运用C库。 ARM运用体系开端履行用户运用程序,有必要先将运用程序加载到履行域,树立运用程序的履行环境。运用C库时,这些繁琐的作业就大部分由c函数来完结了。汇编程序完结体系初始化后,跳转到C程序的人口_main()(留意:不是main(),当C程序中界说了main()主函数时,编译器就会生成_main 代码)。由_main()引导库函数完结C履行环境的初始化,详细进程如下: ◇将非发动代码的RO和RW履行域代码从加载域地址复制到履行域地址; ◇将ZI域清零; ◇跳转到_rt_entry。 调用_main()将大大简化汇编发动代码的编写,汇编代码仅需完结体系硬件的初始化,而没有必要将代码从加载域地址复制到履行域地址,以及ZI域清零等作业。特别是当运用分布式加载时_main()的效果就愈加显着了。可是_main()并没有树立C库运转有必要的环境,这项作业由_rt_entry() 完结,首要调用进程为: ◇调用_rt_stackheap_init()树立堆和栈; ◇调用_rt_lib_init()初始化引证的库函数;假如需求,树立main()函数的参数argc和argv等; ◇调用main()函数,履行运用程序,能够运用库函数; ◇用main()函数的回来值作参数调用exit()。 _rt_entry并不是C函数,它是用ARM C库编程的起始点。_rt_entry不能用C言语宴现,由于这时候仓库还没有树立,仓库由_ rt_stackheap_init()来树立。 上面简略介绍了C程序运用库函数时的调用进程,由_rt—stackheap_init()树立C库运用的内存模型–堆和栈。由于ARM库是树立在 semihosted履行环境的,它完结的内存模型是依据这个环境的,所以有必要修正这个内存模型树立机制。表1列出了需求从头完结的函数,完结了这些函数,运用程序就能够脱离宿主机环境独立运转了。其间,有必要从头完结的是_user initial_stackheap(),由于默许的完结是依据semihosted履行环境的,该函数被_n_stackheap_init()调用创立内存模型,其他两个函数没有默许的完结。
完结该函数,有必要满意下面的条件: ◇运用不超越96字节的栈空间; ◇除了R12(ip)外不要污染其他寄存器; ◇将堆基址、栈基址、堆鸿沟和栈鸿沟别离存在RO~R3作为回来参数; ◇堆有必要坚持8个字节对齐。 完结例程如下:
为了进步运用程序开发功率和可移植性,期望在方针体系上运用ARM库供给的规范输人输出库函数。 高层输入输出函数是不依赖于方针体系环境的,可是高层输入输出函数有必要调用依赖于方针体系的底层函数,才干完结运用体系的输入输出。依据方针体系硬件环境从头界说这些底层函数,就能够运用库供给的规范input/output库函数了。下面以削减ARM规范库供给的printf系列输出函数为例来作阐明。 规范I/O库中最常用的是printf系列函数,包含_printf()、printf()、_fprintf()、fprintf()、 vprintf()和vfprintf()。所有这些函数非透明地运用_FILE,而且仅依赖于fputc()和ferror()两个函数。函数 _printf()和_fprintf()与printf()和fprintf()的差异仅在于前两个函数不能格式化浮点值。只需界说了自己的_FILE 版别和fputc()、ferror()函数,外加界说一个具有FILE类型的_stdout变量,就能够不作任何修正地运用printf系列、 fwrite()、fputs()和puts()函数了。 下面给出了详细完结的模板,能够依据实践需求修正。 #include struct__FILE { int handle; /*用户需求的任何代码(假如运用文件仅是为了调试运用prinft在规范输出端输出信息,则不需求任何文件处理代码)*/ }; FlLE_stdout;/*FILE在stdio.h中界说为:typedef struct_ FILE FILE;*/ int fputc(int ch,FILE*f){ /*用户完结的fpute代码。输出一个字符,能够依据需求完结*/ return ch; } int ferror(FILE*f){ /*用户完结的ferror代码*/ return EOF; } 结语 本文剖析了ARM规范库的作业机理,给出了削减C库进行程序开发的关键步骤。实践运用时需求依据详细的硬件环境和运用要求削减C库,进步代码履行功率。