[转载]VDSP下.doj文件到uClinx下.O文件的转换

来源:互联网 发布:中国材料数据库 编辑:程序博客网 时间:2024/04/30 15:34

      现在的关键是如何将ADI提供的H264BP/MP源码和目标文件库移植到uClinux下,我们自然想到一个重要的步骤是把由Visual DSP++

生成的目标文件*.doj转换为uClinux下可以识别的目标文件*.o。google了下这方面的资料,lights_joy早在2007年已经做了这方面的工作,下面将直接引用他的文章:

 

1   目标
     本文开发环境:uclinux-2.6、vdsp-5.0、bfin-uclinux-gcc、bf561 dsp
本文致力于从二进制层面上研究VDSP和GCC两种编译器生成代码的异同。目标是将两种不同编译器产生的obj文件进行链接,使之产生一个可以在uclinux下执行的程序。
之所以选择从doj文件入手,主要原因有以下几点:
     1、因为程序最终需要在uclinux下运行,所以一些输入输出的库只能使用uclinux下的库。
     2、根据官方的说法,GCC编译代码的效率大概是VDSP的80%,但是对于一些调用很少的函数来讲,其实没有必要在VDSP下编译。我们所需要做的,只是将一些关键的算法在VDSP下实现就行了。
     3、doj与o都只是在文件中存放了符号表,而没有产生具体的地址信息,这就为跨编译器的库调用提供了可能。
     4、doj和o文件都是ELF格式的,容易相互转换。
2   VDSP程序部分
     在VDSP下按默认设置生成一个带LDF的工程文件,在其中的coreA工程中加入test.c文件,其内容如下:
#include <stdio.h>
 
int add_func(int a, int b)
{
       printf("%d + %d = %d", a, b, a + b);
       return a + b;
}
 
int sub_func(int a, int b)
{
       printf("%d - %d = %d", a, b, a - b);
       return a - b;
}
这个文件提供了两个很简单的函数供uClinux下的文件调用,同时这两个函数也调用了uClinux下提供的printf函数进行输出。
为了尽可能减少干扰,采用Release编译生成test.o。
3   Linux下的程序部分
为了便于与VDSP下生成的OBJ文件相比较,在linux下同样将test.c进行编译生成test.o。只是最终使用VDSP下生成的doj文件进行链接。
在Linux下提供一个主程序main.c,并在主程序中调用VDSP程序提供的add_func和sub_func两个函数。其内容如下:
int main(void)
{
     printf(“3 + 4 = %d/n”, add_func(3, 4));
     printf(“5 - 3 = %d/n”, sub_func(3, 4));
}
4   e_machine的问题
     经过第一步处理后,链接提示为EM_TYPE错误,比较test.doj和main.o的ELF文件头发现:test.doj使用的e_machine值为0x22,而main.o使用的e_machine值为0x6a。这样造成了bfin-uclinux-ld无法识别。
解决方法为直接将test.doj中的e_machine改为0x6a。需要注意的是,VDSP生成的DXE文件所使用的e_machine值为0x6a,这点与doj文件中的值不同。
5   没有为段指定内存区域的问题
经过上一步处理后进行链接,提示:“no memory region specified for loadable section on ‘program’”。
因为VDSP默认的代码是放在program段中的,而uclinux则是放在.text段中的。本程序又没有提供自己的LDS文件进行链接控制,所以产生这样的错误。
不管它,先将program改为.text再说。
下一个错误:“no memory region specified for loadable section on ‘data1’”,与上一个错误类似,VDSP默认的数据段名称是data1,而uclinux则是放在.data中。再改为.data
下一个错误:“no memory region specified for loadable section on ‘constdata’”,与上一个错误类似,VDSP默认的只读数据段名称是constdata,而uclinux则是放在.rodata中。再改为.rodata
6   错误的reloc值
错误:“error: test.o contains a reloc (0x00001306) for section .text that refences a non-existent global symbol”。
reloc是elf文件中定义的一个段,它记录了一些需要在链接时确定地址的符号。在VDSP中默认的reloc段名称为.rela.program,在此段中的第一个reloc值就是:
     r_offset:      0x12
     sym_idx:     19
     r_sym:         .epcrodata
     r_type:        6
     r_addend:   0
     r_info:         0x1306
其中sym_idx就指明了这个符号在符号表中的序号。经过查找,在.symtab这个符号表段中确实存在,那么为什么会发生这样的错误呢?
比较VDSP生成的test.o和gcc生成的test.o后发现,在.symtab这个符号表段中有一处不同,那就是sh_info的值。通过查阅elf格式手册后发现,sh_info的值在此处应该指明LOCAL的符号的个数,在gcc生成的test.o中就指明了这点,而VDSP生成的test.o中这个值则为0,这也是提示中出现global symbol的原因。
OK,将sh_info改为LOCAL的符号数量27(0x1b)。
7   final link failed
错误:“final link failed: 错误的值”。
查看所有的section信息,发现了.annotations,.align.program,.align.data1,.align.constdata这几个段的类型无法识别,直接删除这几个段。
还是final link failed。
比较.rela.program段,可以发现VDSP生成的test.o中包含了一些手册中未出现的链接操作类型。即r_info的值。很遗憾没有找到VDSP中对这个字段的定义,只能根据GCC生成的test.o来比较猜测。
以下为VDSP生成的test.o中的rela表:
Index      *r_offset          sym_idx         *r_sym        *r_type       r_addend         r_info
1               0x12                19                  .epcrodata      0x6            0x0(0)          0x1306
2               0x16                19                  .epcrodata      0x7            0x0(0)          0x1307
3               0x1a                28                  _printf             0xe0          0x0(0)          0x1ce0
4               0x1a                  7                  .__operator     0xe           0x0(0)          0x70e
5               0x42                19                  .epcrodata       0xe0         0x0(0)          0x13e0
6               0x42                  6                   .__constant    0xe1         0x10(16)       0x6e1
7               0x42                  7                   .__operator    0xe2         0x0(0)           0x7e2
8               0x42                  7                   .__operator    0x6           0x0(0)           0x706
9               0x46                19                   .epcrodata      0xe0         0x0(0)            0x13e0
10             0x46                  6                   .__constant    0xe1         0x10(16)        0x6e1
11             0x46                  7                   .__operator    0xe2         0x0(0)            0x7e2
12             0x46                  7                   .__operator    0x7           0x0(0)            0x707
13             0x4a                28                   _printf             0xe0         0x0(0)           0x1ce0
14             0x4a                  7                   .__operator    0xe            0x0(0)           0x70e

以下为GCC生成的test.o中的rela表:
Index       *r_offset       sym_idx             *r_sym         *r_type        r_addend          r_info
1               0x10                5                                             0x7             0x0(0)          0x507
2               0x14                5                                             0x6             0x0(0)          0x506
3               0x20                8                      _printf             0xa             0x0(0)          0x80a
4               0x40                5                                              0x7            0x10(16)      0x507
5               0x44                5                                             0x6             0x10(16)      0x506
6               0x50                8                      _printf             0xa             0x0(0)          0x80a

对照修改后的rela表为:
Index        *r_offset         sym_idx           *r_sym        *r_type           r_addend         r_info
1                 0x12              24                     constdata        0x6              0x0(0)         0x1306
2                 0x16              24                     constdata        0x7              0x0(0)         0x1307
3                 0x1a              28                     _printf             0xa              0x0(0)         0x1ce0
4                 0x42              24                     constdata        0x6              0x10(16)     0x6e1
5                 0x46              24                     constdata        0x7             0x10(16)      0x6e1
6                 0x4a              28                    _printf              0xa              0x0(0)          0x1ce0

8   运行错误
经过上述的修改,程序可以正常链接,但是运行时错误,不断产生exception。
仔细比较两个ELF文件后,发现在rela表中还有一个不是很明显的区别。
链接器在链接时要把一些符号替换为具体的值,比如
R0.h = 0x33这样的汇编语句,它的机器码为 00 e3 00 33,而生成的OBJ文件中,0x33的值将存放在.rodata段中,其保留的机器代码为00 e3 00 00。再由链接器在链接时将值写入到00 00这个位置,从而完成替换工作,而替换的地址就写在rela表的r_offset字段中。但是VDSP生成的test.o中,这个偏移地址指向这四个字节的首地址,即00 e3 00 00的第一个字节但是GCC生成的test.o中,这个偏移地址却指向第三个字节,即00 00的位置,也就是说它们将相差两个字节。
将这个地址偏差修改后再链接,一切OK。
 
附:lights_joy编写的elf修改工具: elfeditor,可以在资源中查找。欢迎给他提意见。
 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lights_joy/archive/2007/12/17/1944224.aspx

原创粉丝点击