本文的开发环境为:bf561, uclinux-2.6(已移植到VDSP下),VDSP 5.0
日前看到一篇文章《Implementation of Dynamically Loaded Software Modules》,原始文件可从 http://www.analog.com/ee-notes下载到(EE-323)。这篇文章的目标是从Flash中动态加载一个DXE文件,调用其中的函数并可用VDSP进行调试。其基本方法是将DXE由ELF格式转换为FLT格式并存储在FLASH中,使用时将这个FLT文件读取到内存的指定区域,再查找需要的函数所在的位置并进行调用。如果需要对调用的函数进行调试,则通过VDSP中的File -> Load Symbols加载原始的DXE文件中的调试信息即可。在调用完成后再加载调用程序的符号文件切换回来。
由此得到启发,uClinux本身不就支持FLT格式吗,这种方法是否也可以应用在uClinux中呢?
1 在VDSP中建立要调试的程序
1、利用VDSP5的向导在VDSP中建立一个要调试的DXE程序,注意不生成crt代码和LDF文件。
2、添加主程序main.c
/* Function prototypes */
int mean ( int *pArray, const unsigned int dwSize );
int g_iTimesCalled = 0;
/* Calculate the mean of an array pArray of length dwSize */
int mean ( int *pArray, const unsigned int dwSize )
{
unsigned int sum = 0;
unsigned int i;
++g_iTimesCalled;
for ( i = 0 ; i < dwSize; ++i )
sum += pArray[ i ];
return sum / dwSize;
}
void main(void)
{
int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int n = mean(array, 10);
array[0] = n;
return;
}
这是很简单的一个求平均数的程序。我们希望能够由uclinux加载这一程序并在VDSP中进行调试。
3、添加一个LDF文件,内容如下:
#ifndef __NO_STD_LIB
SEARCH_DIR( $ADI_DSP/Blackfin/lib )
#endif
$OBJECTS = $COMMAND_LINE_OBJECTS;
$LIBRARIES = libdsp561.dlb;
#define DBG_TEXT_BEGIN
0x10000
#define DBG_TEXT_END
0x20000
#define DBG_DATA_BEGIN
0x30000
#define DBG_DATA_END
0x40000
#define DBG_BSS_BEGIN
0x50000
#define DBG_BSS_END
0x60000
MEMORY
{
// The sizes here are arbitrary and should be large enough to hold the inputs
// sections they will contain. Specific START and END are unimportant as these
// addresses will be "abstracted" away by elf2flt.
MEM_TEXT { START(DBG_TEXT_BEGIN) END (DBG_TEXT_END) TYPE(RAM) WIDTH(8) }
MEM_DATA { START(DBG_DATA_BEGIN) END (DBG_DATA_END) TYPE(RAM) WIDTH(8) }
MEM_BSZ { START(DBG_BSS_BEGIN) END (DBG_BSS_END) TYPE(RAM) WIDTH(8) }
}
DYNAMIC p0
{
OUTPUT( $COMMAND_LINE_OUTPUT_FILE )
SECTIONS
{
// Note the presence of three, and only three, output sections. They must
// be called .text, .data, and .bsz. .bsz must be a zero-fill section
// (ZERO_INIT keyword)
.text
{
INPUT_SECTION_ALIGN(4)
INPUT_SECTIONS( $OBJECTS(program) $LIBRARIES(program))
} >MEM_TEXT
.data
{
INPUT_SECTION_ALIGN(4)
INPUT_SECTIONS( $OBJECTS(data1) $LIBRARIES(data1))
} >MEM_DATA
.bss ZERO_INIT
{
INPUT_SECTION_ALIGN(4)
INPUT_SECTIONS( $OBJECTS(bsz) $LIBRARIES(bsz))
} >MEM_BSZ
}
}
注意以上的存储区域的定义,由于我们事先并不知道uclinux会把我们的程序放到哪个位置,因此这只是一个粗略的定义。
4、编译生成dxe文件。
5、利用VDSP5提供的elf2flt工具将这个dxe文件转换成flt格式。
2 在uclinux中加载FLT文件
1、将生成的flt格式文件放到uclinux的rootfs中。
2、为了在VDSP中调试这个文件,我们需要知道uclinux将这个文件加载到内存中的位置。在uclinux中,对FLT文件的加载是由fs/binfmt_flat.c这个文件来完成的,我们所需要做的是在这个文件的合适位置断下来,并取得相关的指针。
经过对此文件的分析,我们可以在load_flat_file这个函数中设置断点,并进行单步跟踪。在此过程中还发现VDSP 5.0转换生成的flt格式文件将rev设置为5,而uclinux只支持2和4的版本,在此处还需要将rev的值改为4。
跟踪到以下语句时(671行):
/* The main program needs a little extra setup in the task structure */
start_code = textpos + sizeof (struct flat_hdr);
end_code = textpos + text_len;
if (id == 0) {
current->mm->start_code = start_code;
current->mm->end_code = end_code;
current->mm->start_data = datapos;
current->mm->end_data = datapos + data_len;
/*
* set up the brk stuff, uses any slack left in data/bss/stack
* allocation. We put the brk after the bss (between the bss
* and stack) like other platforms.
*/
current->mm->start_brk = datapos + data_len + bss_len;
current->mm->brk = (current->mm->start_brk + 3) & ~3;
current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len;
current->mm->context.stack_start = current->mm->context.end_brk;
}
我们就可以取得这个FLT文件在内存中的分布位置了,将code,data,bss这三个段的起始位置和结束位置记录下来。
3、在code的起始位置设置断点并运行,直到VDSP在此位置中断下来,就进入了我们需要调试的程序。
3 加载调试信息
为了保证VDSP中生成的DXE文件中的调试信息地址与uclinux加载的地址一致,还需要回过头修改LDF文件中的几个地址。
将
#define DBG_TEXT_BEGIN
0x10000
#define DBG_TEXT_END
0x20000
#define DBG_DATA_BEGIN
0x30000
#define DBG_DATA_END
0x40000
#define DBG_BSS_BEGIN
0x50000
#define DBG_BSS_END
0x60000
中的几个值改为uclinux实际加载的地址,并重新编译生成一个DXE文件。
在VDSP中选择File -> Load Symbols,并加载这个刚刚生成的DXE文件。哈哈,看到了吗,在汇编窗口出现了mean和main函数的符号。再打开变量监视器,输入g_iTimesCalled,马上就看到这个变量的值了。单步执行程序,VDSP自动打开main.c文件并将光标定位在mean函数的第一行语句上。
至此就意味着这种方法基本上是成功的。之所以只是基本,是因为这个程序还只能加载符号信息,但还无法运行。因为在uclinux下的用户程序要正常运行,它需要做一些初始化的工作,这部分工作是由uClibc来完成的,显然我们没有进行这样的过程,这个程序不能运行也就是理所当然的了。
下一步工作就是将uClibc移植到VDSP上,开发应用程序时链接进来应该就OK了!