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

 
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。
 
附:本人自己写的一个简单修改工具, elfeditor,请在资源中查找。欢迎提意见喔!
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值