eCos模块动态加载支持——objloader组件

eCos包含了2个用于模块动态加载的组件,一个叫loader,另一个叫objloader。loader出现比较早,在2000年的时候由eCos的开发团队添加到eCos系统中,loader的实现原理与应用程序的动态链接库(.so,.dll)是一样的,动态链接库的实现需要编译器的支持,通常情况下只有为Linux等系统准备的编译器才支持动态链接库编译,eCos使用的编译器大多数是不支持动态链接库的。objloader出现比较晚,在2005年的时候由Anthony Tonizzo贡献,objloader的实现原理与Linux内核模块(.o,.ko)是一样的,.o文件是普通的ELF格式的可重定向目标文件,生成.o文件是每个编译器都可以支持的工作,因此没有loader的编译器问题。(俄罗斯的那颗卫星上使用的object loader大概就是objloader组件吧,Anthony Tonizzo这个名字看起来像俄国人的名字吗?)

eCos官网:http://ecos.sourceware.org
eCos中文技术网:http://www.52ecos.net
eCos交流QQ群:144940146。
http://blog.csdn.net/zoomdy/article/details/19763473
mingdu.zheng<at>gmail<dot>com

基本原理

通常情况下,嵌入式系统软件最终得到的是一个静态编译的可执行映像文件。编译器将每一个.c文件编译成对应的.o文件,.o文件是符号地址未确定需要进行重定位的目标文件,最后由链接器将所有.o文件链接在一起,链接的过程也就是对.o文件符号进行解析重定位的过程。

使用动态加载模块时,部分代码被编译成.o文件后不会参与最终的链接过程,而在运行时刻,objloader加载该.o文件并对.o文件符号进行解析重定位。从本质上看,objloader扮演了运行时链接器的角色。使用链接器链接.o文件所得的可执行文件是静态不可变的,而objloader由于在运行时才进行链接动作,可以在运行时指定objloader加载哪个.o文件,因此是动态的,可以根据运行时刻的需求加载和卸载.o文件。

支持的硬件架构

最新版本(CVS或Hg)的eCos支持PowerPC、i386和ARM处理器的动态模块加载。

加载器支持

objloader包含两种类型的加载器,分别支持从文件系统和存储器中加载模块。从文件系统加载是更加普遍和灵活的加载方式,如果文件系统是可写的,那么还可以在运行时更新或添加删除模块,实现运行时模块管理。从存储器加载则适合没有文件系统支持的场合或者是调试阶段,调试阶段通过gdb将模块写入内存后使用存储器加载方式进行加载。

使用方法

objloader以独立的组件包存在,要使用objloader首先需要添加objloader组件包,通过eCos配置工具添加Object file loader组件。该组件的部分选项依赖于其他组件,根据冲突解决提示添加所需的组件包或者取消选项。

objloader提供的主要API有:cyg_ldr_open_library、cyg_ldr_find_symbol、cyg_ldr_close_library。

cyg_ldr_open_library

函数原型:

PELF_OBJECT cyg_ldr_open_library(CYG_ADDRWORD ptr, cyg_int32 mode);

 

这个函数的作用是加载一个模块,目前mode参数的有效值为CYG_LDR_MODE_FILESYSTEM和CYG_LDR_MODE_MEMORY,如果mode为CYG_LDR_MODE_FILESYSTEM,那么ptr应该是指向模块的文件路径字符串,objloader将从文件系统加载该模块,如果mode为CYG_LDR_MODE_MEMORY,那么ptr为模块所在的存储器地址,objloader将从存储器加载该模块。如果模块加载成功,那么函数返回PELF_OBJECT类型的句柄指针,这个句柄指针被其它两个函数所引用;如果模块加载失败,那么返回NULL。

cyg_ldr_find_symbol

函数原型:

void *cyg_ldr_find_symbol(void* handle, char* sym_name);

 

这个函数的作用是根据符号名查找对应的地址。handle为cyg_ldr_open_library返回的句柄指针,sym_name为需要查找的符号名。如果指定符号存在,那么函数返回符号地址;如果指定符号不存在,那么返回NULL。

cyg_ldr_close_library

函数原型:

void cyg_ldr_close_library(void* handle);

 

这个函数卸载handle句柄对应的模块并释放资源。

简单示例

// 模块代码 hello.c
void print_message(void)
{
    printf("Hello World!\n");
}
# 编译模块
gcc -c -o hello.o hello.c
// 引用模块
void* handle;
void (*fn)(void);

// 加载模块
handle = cyg_ldr_open_library((CYG_ADDRWORD)"/hello.o", CYG_LDR_MODE_FILESYSTEM);
// 查找print_message函数地址
fn = cyg_ldr_find_symbol(handle, "print_message");
// 调用模块内的print_message函数
fn();
// 卸载模块
cyg_ldr_close_library(handle);

完整的示例可以查看objloader组件包的测试用例。

调试

一个系统被分割成多个部分后,调试开始变得复杂甚至不可能,不过万能的gdb还是提供了解决办法。按照往常的做法,gdb是无法得知动态加载模块的调试信息的。一方面,gdb不知道被调试程序又加载了额外的代码,毕竟这不是常规的动态链接库。另一方面,gdb不知道模块被加载到内存的什么位置。这两方面的信息都必须通过gdb的add-symbol-file告知gdb。

add-symbol-file的用法

add-symbol-file <文件> <加载地址> [-s <节名称> <节加载地址> -s <节名称> <节加载地址> ...]

<文件>为动态加载的模块.o文件名,需要注意的是<文件>是宿主机上的文件路径而不是在目标机上的文件路径,<加载地址>是指.o文件的.text节的加载地址,后面可以追加不限数目的-s参数指定除.text节之外的其它节的加载地址。

add-symbol-file的示例

下面的示例告知gdb加载hello.o的调试符号,并且该文件的.text节定位到地址0,.text.library_open节定位到地址0x20142e0,.text.print_message节定位到地址0x20140b8,.text.thread_a节定位到地址0x20143d0。该示例在Linux Synthetic Target下验证。

(gdb)add-symbol-file ~/ecos/configs/synth/objloader_build/services/objloader/current/testobj/hello.o 0 -s .text.library_open 0x20142e0 -s .text.print_message 0x20140b8 -s .text.thread_a 0x20143d0
add symbol table from file "/home/user/ecos/configs/synth/objloader_build/services/objloader/current/testobj/hello.o" at
 .text_addr = 0x0
 .text.library_open_addr = 0x20142e0
 .text.print_message_addr = 0x20140b8
 .text.thread_a_addr = 0x20143d0
(y or n) [answered Y; input not from terminal]
Reading symbols from /home/user/ecos/configs/synth/objloader_build/services/objloader/current/testobj/hello.o...done.

自动化的add-symbol-file

实际上只有objloader知道加载的节和地址,上面的示例中的加载地址是我使用gdb跟踪调试,查看objloader的内部数据结构才知道的,实际上完全可以让objloader在加载完一个模块后将加载的节及地址按照add-symbol-file要求的格式打印出来,然后只需要简单的拷贝objloader的打印输出到gdb中就好了,甚至可以编写gdb脚本进行自动交互。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值