在可执行文件中嵌入文件,又名 Hello World,版本 5967
于 2008 年 6 月 12 日
我最近需要在一个可执行文件中嵌入一个文件。因为我使用gcc等命令行工具,而不是使用花哨的 RAD 工具来神奇地完成这一切,所以我一时没有想到如何实现这一点。在网上搜索了一下,发现了一个技巧,本质上就是cat它到可执行文件的末尾,然后根据一堆我不想知道的信息来解密它的位置。似乎应该有一个更好的方法...
而且确实有,那就是objcopy来救援。objcopy将对象文件或可执行文件从一种格式转换为另一种格式。它理解的格式之一是“binary”,它基本上是任何不属于它理解的其他格式的文件。所以你可能已经设想了这个想法:将我们想要嵌入的文件转换为对象文件,然后它可以简单地与我们的其余代码链接在一起。
假设我们有一个名为data.txt的文件,我们想要嵌入到我们的可执行文件中
# cat data.txt Hello world要将其转换为我们可以与程序链接的对象文件,我们只需使用objcopy来生成一个“.o”文件
# objcopy --input binary \ --output elf32-i386 \ --binary-architecture i386 data.txt data.o这告诉objcopy我们的输入文件是“binary”格式,我们的输出文件应该是“elf32-i386”格式(x86 上的对象文件)。--binary-architecture选项告诉objcopy输出文件是要在 x86 上“运行”的。这是必需的,以便ld将接受该文件,以便与其他 x86 文件链接。人们可能会认为将输出格式指定为“elf32-i386”意味着这一点,但事实并非如此。
现在我们有了一个对象文件,我们只需要在运行链接器时包含它
# gcc main.c data.o当我们运行结果时,我们会得到期待的输出
# ./a.out Hello world当然,我还没有讲完整的故事,也没有向你展示main.c。当objcopy进行上述转换时,它会将一些“链接器”符号添加到转换后的对象文件中
_binary_data_txt_start _binary_data_txt_end链接后,这些符号指定嵌入文件的开始和结束位置。符号名称通过前缀_binary_并附加_start或_end到文件名来形成。如果文件名包含任何在符号名称中无效的字符,则它们将转换为下划线(例如data.txt变成data_txt)。如果在使用这些符号链接时遇到未解析的名称,请执行hexdump -C在对象文件上,并查看转储的末尾以查找objcopy选择的名称。
现在,实际使用嵌入文件的代码应该相当明显了
#include <stdio.h>
extern char _binary_data_txt_start;
extern char _binary_data_txt_end;
main()
{
char* p = &_binary_data_txt_start;
while ( p != &_binary_data_txt_end ) putchar(*p++);
}