最近在将一个图片内置到程序中时,遇到了符号相关的问题,下面是将图片内置到程序中的方法:
1、 使用objcopy将图片转化成elf格式的目标文件:objcopy -I binary -O elf32-i386 -B i386 test.jpgimage.o
2、 查看目标文件中的符号,objdump、readelf、nm均可,符号_binary_test_jpg_start是数据开始的地址,_binary_test_jpg_end是数据结束的地址, _binary_test_jpg_size是数据字节数。
3、 使用符号对图片数据进行操作
插一句,这种方法相比于将图片转换成数组更加灵活,可以方便地更换图片,缺点是没有可移植性。
运行程序的时候出现了segment fault,原因是我在引用image.o的符号时声明错误:
extern char *_binary_test_jpg_start;
extern char *_binary_test_jpg_end;
extern int _binary_test_jpg_size;
正确的声明应该这样:
extern char _binary_test_jpg_start[];
extern char _binary_test_jpg_end[];
extern char _binary_test_jpg_size[];
下面深入研究下错误的原因:符号是如此定义的:
Typedef struct {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
Unsigned char st_info;
Unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
符号指代的值是st_value,符号的值的类型取决于符号的类型(st_info),可能是一个地址值,也可能是一个绝对值。我们可以”readelf –s image.o”看下符号类型,可以看到里面的_binary_test_jpg_start 、_binary_test_jpg_end、_binary_test_jpg_size 都是NOTYPE,为未知符号类型(还有OBJECT数据对象、FUNC函数等)。
再回到上面的那个错误,当将符号声明为指针的时候(extern char *symbol_name),在使用的时候,连接器会取该符号的st_value做为指针symbol_name的地址值,该地址值对应的数据既为该变量的值。当将符号声明为数组的时候(extern char symbol_name[]),symbol_name既为st_value的值。既:如若声明为数组,_binary_test_jpg_start[0]相当st_value[0],既图片的第一个字节;若声明为指针,相当于(*st_value)[0],自然会出现segment default了~
1、 全局的变量及数组,编译后产生的elf格式可执行文件(linux)会有相应的符号记录在符号表中。
2、 变量的值即是该变量编译后对应符号值所指向的值(*(st_value)),其地址是对应符号的值st_value。
3、 数组名的值就是对应符号的值st_value,我们想要使用符号的值的时候,声明为数组名即可。数组名是指针的说法不正确,不过我们当然可以将数组名指代的值赋值给指针。