在前面两篇文章中(《
在uclinux中调试DXE文件》《 DXE
文件到FLAT文件格式转换的几个问题》),都使用的是动态加载DXE文件的方式。这种方法的明显缺点是在每次运行之前都要修改DXE文件中的几个地址,而且reloc值的计算非常麻烦,这就让它的实用价值大打折扣。那么是否还有其它的方法呢?
最直接的一种方法当然是为DXE文件寻找一块固定的存储空间,下面就是我的一个尝试过程。
1 内存区域划定
我们知道,uclinux将内存空间划分为几个部分:
0 ~ uclinux代码开始:这段空间空闲
uclinux代码:存放uclinux的代码和数据及堆栈等
用户空间:这一块是uclinux管理的存储空间,通常情况下用户程序就是加载到这一区域运行的。
rootfs:当使用MTD的时候,uclinux会将rootfs的内容复制到SDRAM的最高部分并在其中映射几个RAMDISK。
从以上几个部分的划分可以看出,最适合存放DXE代码和数据的显然是在0 ~ uclinux代码开始的这一段空间。为保留0地址及考虑到地址对齐的问题,可以使用0x1000开始直到uclinux代码开始的这段空间,当然在此之前还需要将uclinux代码往后移动,直到空间足够大为止。
在默认情况下,这一段空间在uclinux中是不允许进行写入的,因此我们还需要修改arch/blackfin/kernel/process.c中的_access_ok函数,在其中添加一段代码:
if (addr >= 0 && (addr + size) <= _stext)
return 1;
这样就可以允许往这段空间中写入数据了。
2 对加载部分代码的改写
在划定内存区域之后,还需要对uclinux中加载flat文件的部分代码进行改写,使之能够适应需要。主要修改fs/finfmt_flat.c中的load_flat_file函数。
1、允许uclinux加载版本号为5的flat文件
if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION && rev != 5) {
printk("BINFMT_FLAT: bad flat file version 0x%x (supported 0x%x and 0x%x)/n", rev, FLAT_VERSION, OLD_FLAT_VERSION);
return -ENOEXEC;
}
2、不分配存储空间而使用固定地址
down_write(¤t->mm->mmap_sem);
if(rev == 5)
textpos = 0x1000;
else
textpos = do_mmap(0, 0, text_len + data_len + extra +
MAX_SHARED_LIBS * sizeof(unsigned long),
PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
3、将BSS段清0时避免地址转换的错误
/* zero the BSS, BRK and stack areas */
if(rev == 5)
memset((void*)(datapos + data_len), 0, bss_len);
else
memset((void*)(datapos + data_len), 0, bss_len +
(memp + ksize((void *) memp) - stack_len - /* end brk */
libinfo->lib_list[id].start_brk) + /* start brk */
stack_len);
4、在程序结束运行时uclinux要释放内存,此处也需要进行相应的修改。但由于对此部分代码不甚了解,暂时搁置。
3 VDSP应用程序开发
对于VDSP而言,只要使用普通应用程序的配置就可以了,而不需要使用DYNAMIC这样的关键字,也可以使用任意的VDSP中的库。下面是几个需要注意的问题:
1、在LDF文件中指定代码的起始位置时要指定0x1040而不是0x1000,因为FLT文件会插入0x40字节的文件头。
2、转换为FLT格式时,代码段.data必须向前减去4个字节,因为uclinux加载时会在data之前插入4个字节。如数据段实际从0x2000开始,那么在FLT中的data_start值只能指定为0x1ffc。
3、不能使用VDSP生成的CRT代码,只能使用uclibc中的CRT代码。
4、可以使用任意的VDSP库,但是注意要在CRT代码中插入对VDSP库的初始化工作。如果要使用C++支持,只能调用VDSP库的ctor和dtor的初始化函数,而不能使用uclibc的初始化函数。
5、最好不用VDSP提供的elf2flt,自己写一个!免得改完了还得用uedit再处理一道!
经过上述的处理,在VDSP中就很容易调试了。只要在0x1040这个位置上断下来,再加载dxe中的符号信息,就可以像普通VDSP程序一样进行调试了!
当然,在此处只研究了调用一个DXE程序的方法,如果有多个DXE程序要调用,那么在uclinux中可能还需要进行进一步的修改。如果哪位达人有兴趣,大家一起探讨呦!