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

本文介绍如何利用objcopy工具将图片等二进制文件嵌入到ELF目标文件中,并通过示例代码展示了如何在程序中访问这些资源。文中详细解释了符号表的作用及如何通过符号访问资源的起始、结束地址和大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文转自:https://blog.csdn.net/xj178926426/article/details/73777611 

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 <stdio.h>

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)表是具体怎么操作的,将在下一篇文章中来进行分析,未完待续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值