Linux ELF文件格式分析---objcopy命令的使用

Linux ELF文件格式分析—objcopy命令的使用

最近在看《程序员的自我修养—链接、装载与库》一书,对书中提到的一个小问题,自己做了个试验验证一番,然后记录之。其具体问题如下:
如果我们将一个二进制文件,比如图片,MP3音乐,词典一类的东西作为目标文件的一段,该怎么做?
可以使用objcopy工具,比如我们有一个图片文件”image.jpg” 大小为8846Bytes :


[james_xie@james-desk testforobjcopy]$ ls -al image.jpg  
-rw-rw-r-- 1 james_xie james_xie 8846 Jun 21 12:51 image.jpg

[james_xie@james-desk testforobjcopy]$ objcopy -I binary -O elf64-x86-64 -B i386 image.jpg image.o 

[james_xie@james-desk testforobjcopy]$ objdump -ht image.o 

image.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .data         0000228e  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
0000000000000000 l    d  .data      0000000000000000 .data
0000000000000000 g       .data      0000000000000000 _binary_test_jpg_start
000000000000228e g       .data      0000000000000000 _binary_test_jpg_end
000000000000228e g       *ABS*      0000000000000000 _binary_test_jpg_size

符号“_binary_test_jpg_start”,“ _binary_test_jpg_end”和“_binary_test_jpg_size”分别表示该图片文件在内存中的起始地址,结束地址和大小,我们可以在程序里面直接声明并使用它们。
下面结合一个简单的例子来尝试,新建一个文件名为test.c的文件:

#include 

extern char _binary_test_jpg_start;
extern char _binary_test_jpg_end;
extern char _binary_test_jpg_size;

int main()
{
      int i = 0;
      unsigned char *p = NULL;
      printf("_binary_test_jpg_start 0x%lx\n",(unsigned long)&_binary_test_jpg_start);
      printf("_binary_test_jpg_end 0x%lx\n",(unsigned long)&_binary_test_jpg_end);
      printf("_binary_test_jpg_size %ld\n",(unsigned long)&_binary_test_jpg_size);

      p = (unsigned char *)(unsigned long)&_binary_test_jpg_start;
      printf("First 8 bytes of the Image : \n");
      for(i=0;i<8;++i){
            printf("0x%02x ",*p++);
      }
      printf("\n");

      return 0;
}

首先把该文件编译成目标文件(.o文件):

gcc -c test.c

链接生成最后的可执行文件:

gcc test.o image.o -o test

运行结果如下:

[james_xie@james-desk testforobjcopy]$ ./test 
_binary_test_jpg_start 0x601044
_binary_test_jpg_end 0x6032d2
_binary_test_jpg_size 8846
First 8 bytes of the Image : 
0xff 0xd8 0xff 0xe0 0x00 0x10 0x4a 0x46

代码非常简单,没什么值得深入分析的,但是还有个小小的疑问,符号的值(即symbol’s value),通常可通过如下命令去查看:

[james_xie@james-desk testforobjcopy]$ objdump -t test

test:     file format elf64-x86-64

SYMBOL TABLE:
......
0000000000601044 g       .data      0000000000000000              _binary_test_jpg_start
......
000000000000228e g       *ABS*      0000000000000000              _binary_test_jpg_size
00000000006032d2 g       .data      0000000000000000              _binary_test_jpg_end
......

为了更加直观,其他的符号表的输出结果被删除,其结果中第一列就是我所说的符号的值(即symbol’s value),按照我的理解这个值应该是该符号(symbol)的虚拟内存地址,为了验证我这个想法,我上面的例子代码中尝试去打印_binary_test_jpg_start开始位置的连续8个字节的值,跟我直接通过hexdump命令查看图片文件的值一样:

[james_xie@james-desk testforobjcopy]$ hexdump -C image.jpg 
00000000  ff d8 ff e0 00 10 4a 46  49 46 00 01 01 00 00 01  |......JFIF......|
00000010  00 01 00 00 ff db 00 43  00 0f 0f 0f 0f 0f 0f 0f  |.......C........|
00000020  0f 0f 0f 0f 0f 0f 0f 0f  0f 0f 0f 0f 0f 0f 0f 0f  |................|
*

这说明我的理解是对的,但是我还有个疑问就是这个符号“_binary_test_jpg_size”,这个符号的值(即symbol’s value)是000000000000228e,转换位十进制刚好是8846,即为我们图片文件的大小,这很明显应该不是一个地址,但是我上面的代码中,确确实实是通过

printf("_binary_test_jpg_size %ld\n",(unsigned long)&_binary_test_jpg_size);

地址取操作符&来访问的,而且如果我要是去掉这个地址操作符,如下方操作的话:

printf("_binary_test_jpg_size %ld\n",(unsigned long)_binary_test_jpg_size);

会直接出现:Segmentation fault (core dumped),即我们常碰到的段错误,这时我就有点方了,为了验证这个问题,我绝对去研究下objcopy的代码,看看它里面定义绝对符号(Absolute Symbol)表是具体怎么操作的,将在下一篇文章中来进行分析,未完待续。

你可能感兴趣的:(Linux,学习,linux,二进制,图片)