嵌入式单地址空间OS中实现动态加载的过程
来源:互联网 发布:c语言且或非符号 编辑:程序博客网 时间:2024/05/01 19:51
嵌入式单地址空间OS中实现动态加载的过程
李振鹏
版权所有请勿转载
之前有一篇文章是关于嵌入式单地址空间实现动态加载的想法,里面描述的是我根据相关资料进行猜测的地方,以及从技术上来说,可能需要的技术,最近难得有空闲时间,我实现了一下动态加载的。目前已经成功实现,下面说一下实现的过程。
先说一下实现此技术需要的平台:
OS:Nucleus
CPU:ARM7+cache
Baseband:VT3406
ADS1.2
说一下这些东西的来历,Nucleus是实时嵌入式单地址空间操作系统,CPU是介于ARM7与ARM9之间的CPU,BB芯片是VIA出的,这些东西目前都已经收掉不再使用,我也正好离职,从而有时间去实现一下动态加载的问题。
从理论上来说,动态加载很简单,只需要把当前的PC指针指向下一句执行的语句即可。也就是使用如下的ASM就可以实现:
MOV PC, Address
这样就可以顺利执行程序,在我实现的时候,考虑如下问题,程序执行如何返回,参数如何传递,程序执行完毕返回到哪里。
这些问题的解决,看起来比较复杂,其实很简单,程序的返回是放在LR中,这样在上一个函数调用的时候,只要LR的值不变,这样可以在下一个函数调用的时候,同样使用LR,这样就可以顺利返回。关于参数传递,由于ARM中使用r0-r3传递参数,这样只要不更改r0-r3,就可以顺利传递参数。这个地方想明白,我用了好久,特别是返回地址的问题,程序如何执行,应该返回哪里。解决方法如下
实现DynamicLoader(UINT8 *pAddress)
MOV PC, R0
这个地方一定要用ASM实现,否则无法完成需要的功能。由于在调用此函数时,已经把函数的返回地址放到LR中,具体ASM如下:
MOV r0,address
BL DynamicLoader
由于DynamicLoaer的实现问题,没有实际的返回,也就是不需要使用
BX lr
这样来做为函数的返回。这是由于R0所指向的一个函数的开始地址,从DynamicLoader开始,其实执行的是另一个函数,这里的DynamicLoader只是起到了一个跳转的作用。但是又必须使用函数调用的方式来进行,而不能直接跳转,否则函数没有办法返回。由于BL的时候填充了LR,这样在下一个由于实际调用不是使用的B指令,因为并没有设置LR,这样仍旧是在调用DynamicLoader时的LR,因此可以正确返回。
函数可以正确调用并返回,这是程序很大的一个进步,这样就可以实际构造可以运行的程序了。
下面说一下ADS编译为二进制可执行文件的问题,使用编译器如果一开始把所有的数据都放好,这样包括全局变量和静态变量,以及函数的执行地址等,都已在LINK的时候根据指定规则确定实际的运行地址,也就是说所有的函数的实际运行地址在LINK的时候已经确定。这样对于动态运行来说是不可行的,因为既然要动态加载,就需要所有地址都是静态的,因为每次对于读入内存的数据,起始地址是不缺定的,因此不能再LINK时把所有的地址固定死。
解决这个问题有两种方式,一种是在scatter loader中把程序的可执行地址固定好,在LINK时不LINK实际的数据,而在系统启动的时候,把这部分可执行文件拷贝的固定的地址,这样可以作为一个整体运行。但是这种方式由问题,就是应用的大小什么的都是固定死的,不能太灵活,不能根据应用实际调整。
这里使用另外一种方式,选择程序不在LINK的时候把所有的地址固定死,而是使用相对独立的函数调用方式。如下:
原来的方式可能使这这样
BL 0x10008;
而使用相对的地址程序如下:
ADD r5,pc,#18
BL r5
这样虽然多了一句,但是可以做到函数的运行地址是动态指定的,而不是编译为固定的地址。
其实ADS提供了把函数编译为独立地址的方式,
COMPILER使用如下的参数/ropi/rwpi
LINK使用如下的参数-rwpi –ropi
就可以把编译的程序做到运行时地址是独立的。
从上面来开,编译时地址的问题,还有运行时加载的问题,都已经顺利解决。但是这里还有一个问题,就是如何确保动态应用如何每次在使用的时候,都从固定的入口进入的问题。也就是说,虽然有了内存中的运行地址,但是如何保证每次都从固定的函数开始执行呢?如果每次都从编译的可执行文件0地址开始执行,没有办法保证每次调用的是同一个函数。
这个可以通过LINK来保证每次是同一个函数在0地址,使用如下的参数
-first DyanmicAppEntry
这样就可以保证DyanmicAppEntry的入口地址为可执行文件的开始了。
上面的文章解决了动态编译和加载的问题,下面说一下动态应用的问题。如果要使一个应用有价值,比然需要提供本地的功能调用,而且对于手机来说,系统已经基本上实现了大多数的功能,如果在动态应用中再重复实现一些功能,可以说既浪费了空间,又浪费了时间。而且对于硬件相关的功能,必须通过本地调用来进行,这样就需要如何把本地调用传入动态应用中。如上文所说,本地的调用地址都是在LINK的时候确定的没有办法直接在动态应用中使用,这样需要在运行时把本地调用传入动态应用,由于动态应用的入口还有好几个参数可以使用,这样就可以构造一张系统调用的表,在运行的时候传入动态应用,这样可以通过表来调用系统功能,这样就解决了系统本地调用的问题。
这里要特别说一下安全的问题,由于动态应用是直接更改PC指针运行的,这样,如果应用出错,系统可能就CRASH了,无法再继续运行,而且由于可以调用本地系统调用,可能做许多意想不到的功能,这样就可以在系统调用的时候
增加一个中间层,一些核心功能,必须满足一定的权限在可以调用。
- 嵌入式单地址空间OS中实现动态加载的过程
- 在嵌入式单地址空间OS中实现动态加载的问题
- [OS] 进程的虚地址空间
- 实现类似微博、QQ空间等的动态加载
- 实现类似微博、QQ空间等的动态加载
- 嵌入式 C语言实现在0x1000地址处写入一个单字节的整数
- STM32系统中应用的动态加载可行性研究过程<一>
- STM32系统中应用的动态加载可行性研究过程<三>
- [OS] 进程地址空间与虚拟存储空间的理解 很好!!!
- OS-地址空间和地址生成
- 单例方式的加载过程
- 嵌入式 单播与多播地址的区别
- 嵌入式os的实现一之任务切换的实现
- 用于实现EXT单页面的动态js加载.(修复版)
- 关于jQuery的getScript()实现动态js加载,原理,实现过程是怎么样的?
- 实现数据加载过程中菊花的方法
- ASP.NET中实现模版的动态加载
- ASP.NET中实现模版的动态加载
- VS2005下水晶报表如何实现动态数据源绑定?
- 关于linux的进程管理
- linux防火墙管理
- 「基础」C#中的索引器
- 内存泄漏的检测
- 嵌入式单地址空间OS中实现动态加载的过程
- 「基础」C#中的随机数
- 我学java
- Asp.net性能优化-性能优化总结
- oracle序列专题
- None
- Asp.net性能优化-性能优化总结
- 关于Schema-based AOP support 遇到的问题解决
- Test