嵌入式技术论坛
直播中

ss

6年用户 8762经验值
擅长:电源/新能源 制造/封装 RF/无线
私信 关注
[经验]

动态模块加载的调试经验分享

问题一
在调试基于 ZYNQ7000 的动态模块加载功能时,发现动态模块在加载到内存中后,去执行相关代码时,大概率系统会跑飞掉,有时会执行一些莫名其妙的指令,出现 undefined instruction 错误,或者是代码跑飞掉,pc 运行到一些神奇的地址,例如 0x00000004,这种位置,导致 data abort。
经过几轮调试,没有发现系统中有什么逻辑上的 bug,陷入僵局。后来经高手提示,检查在动态加载的过程中对 cache 是否进行了正确处理,这才找到问题所在。
如果在跳转到动态模块的入口地址运行程序前,没有对 cache 进行正确操作,那么很有可能加载的数据还在 cache 中,还没有被成功写入到内存中正确的位置,此时去运行该地址中的指令,则会发现,这些指令都是一些乱码,导致系统行为异常。
因此,在跳转到动态模块入口地址运行前,需要对 cache 执行如下操作:
flush dcache 将数据 cache 中的数据写入到内存中
invalid icache 将指令 cache 中的数据无效化,重新读取后续要执行的指令
通过这两个操作,就可以保证我们加载的动态模块被实实在在地写入了内存中,无效指令cache,使得接下来 cpu 要执行的指令也确实是我们加载到内存中的,动态模块的指令。
结论
发现数据异常,执行的相关指令为非常奇怪的指令时,可以查看相关内存,检查是否是由于 cache 没能同步导致的。
问题二
目前动态模块加载功能还有如下待完善的地方:
在初始化全局指针的时候,不能将其设置为某个全局变量的地址,因为全局变量的地址是在加载完成后才确定的(利用寄存器指定加载基地址加偏移量进行寻址),这种写法可能会导致初始化失败。
动态模块中所有需要重定位的符号,都需要在加载的过程中就进行重定位,而没有进行延时加载(即第一次调用时去查找替换),又不可以利用系统调用,这就导致了加载速度较慢。
使用动态模块加载时,如果发现有些符号在系统中找不到,在编译的过程中是不会提示错误的,只有在代码运行时,尝试查找相关符号时才会报错,这将加大调试难度。
结论
使用微内核(通过设备访问驱动程序,通过系统调用与内核交互)可以解决这些问题,内核与应用就可以单独编译,并且不存在加载慢的问题。但是有些芯片可能没有附带 MMU,不是很方便使用微内核。
问题三
在使用 coremark 进行动态模块性能测试时,运行时解析发现缺少 __aeabi_uidiv 符号,该符号是工具链 c 库函数中提供的。在代码中没有显式调用,在编译过程中,如果发现代码中进行了除法运算,则尝试使用工具链 C 库中提供的 __aeabi_uidiv 函数来完成,该调用过程满足 arm 过程调用标准。
解决这个问题有两种思路:
第一种是将缺少的符号实现链接到动态模块上,但是这种方式目前无法实现,目前的编译方法(编译成 elf 共享库的方式),如果遇到这种符号的处理办法是,先不进行重定位,到加载运行时在进行重定位。
第二种思路是在内核中,将缺少的符号导出到动态模块查询的符号表中,理论上在实际内核中肯定是调用了这个符号的,但是因为没有使用 RTM_EXPORT 命令导出,所以在重定位时找不到相应的符号。添加该符号的方法如下所示:
extern __aeabi_uidiv;
RTM_EXPORT(__aeabi_uidiv);
结论
需要了解 elf 的不同格式以及加载方式,可以参考 ELF for the ARM® Architecture。


更多回帖

发帖
×
20
完善资料,
赚取积分