Atm*_*ons 88 c++ linux gcc shared-libraries elf
有没有人知道如何使用GCC将任何资源文件静态编译到可执行文件或共享库文件中?
例如,我想添加永远不会改变的图像文件(如果他们这样做,我不得不替换文件),并且不希望它们在文件系统中存在.
如果这是可能的(我认为这是因为Visual C++ for Windows也可以这样做),我如何加载存储在自己的二进制文件中的文件?可执行文件是否解析自身,找到文件并从中提取数据?
也许GCC有一个选项,我还没有见过.使用搜索引擎并没有真正吐出正确的东西.
我需要这个用于共享库和普通的ELF可执行文件.
任何帮助表示赞赏
ndi*_*dim 86
更新我已经开始喜欢John Ripley .incbin
基于程序集的解决方案提供的控件,现在使用一个变体.
我使用objcopy(GNU binutils)将文件foo-data.bin中的二进制数据链接到可执行文件的数据部分:
objcopy -B i386 -I binary -O elf32-i386 foo-data.bin foo-data.o
Run Code Online (Sandbox Code Playgroud)
这为您提供了一个foo-data.o
可以链接到可执行文件的目标文件.C界面看起来像
/** created from binary via objcopy */
extern uint8_t foo_data[] asm("_binary_foo_data_bin_start");
extern uint8_t foo_data_size[] asm("_binary_foo_data_bin_size");
extern uint8_t foo_data_end[] asm("_binary_foo_data_bin_end");
Run Code Online (Sandbox Code Playgroud)
所以你可以做类似的事情
for (uint8_t *byte=foo_data; byte<foo_data_end; ++byte) {
transmit_single_byte(*byte);
}
Run Code Online (Sandbox Code Playgroud)
要么
size_t foo_size = (size_t)((void *)foo_data_size);
void *foo_copy = malloc(foo_size);
assert(foo_copy);
memcpy(foo_copy, foo_data, foo_size);
Run Code Online (Sandbox Code Playgroud)
如果您的目标体系结构对存储常量和可变数据的位置有特殊约束,或者您希望将该数据存储在.text
段中以使其适合与程序代码相同的内存类型,则可以objcopy
更多地使用这些参数.
Sim*_*mon 48
您可以使用ld
链接器在可执行文件中嵌入二进制文件 例如,如果您有文件,foo.bar
则可以将其嵌入可执行文件中,并将以下命令添加到ld
--format=binary foo.bar --format=default
Run Code Online (Sandbox Code Playgroud)
如果您正在调用ld
直通gcc
,那么你将需要添加-Wl
-Wl,--format=binary -Wl,foo.bar -Wl,--format=default
Run Code Online (Sandbox Code Playgroud)
这里--format=binary
告诉链接器以下文件是二进制文件并--format=default
切换回默认输入格式(如果您之后指定其他输入文件,这将非常有用foo.bar
).
然后,您可以从代码访问文件的内容:
extern uint8_t data[] asm("_binary_foo_bar_start");
extern uint8_t data_end[] asm("_binary_foo_bar_end");
Run Code Online (Sandbox Code Playgroud)
还有符号命名"_binary_foo_bar_size"
.我认为这是类型,uintptr_t
但我没有检查它.
Fle*_*exo 46
使用imagemagick:
convert file.png data.h
Run Code Online (Sandbox Code Playgroud)
给出类似的东西:
/*
data.h (PNM).
*/
static unsigned char
MagickImage[] =
{
0x50, 0x36, 0x0A, 0x23, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4D, 0x50, 0x0A, 0x32, 0x37,
0x37, 0x20, 0x31, 0x36, 0x32, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
....
Run Code Online (Sandbox Code Playgroud)
为了与其他代码兼容,您可以使用它fmemopen
来获取"常规" FILE *
对象,或者std::stringstream
使用iostream
.std::stringstream
虽然不是很好,你当然可以在任何可以使用迭代器的地方使用指针.
如果你在automake中使用它,请不要忘记适当地设置BUILT_SOURCES.
这样做的好处是:
Nor*_*ame 39
您可以将所有资源放入ZIP文件并将其附加到可执行文件的末尾:
g++ foo.c -o foo0
zip -r resources.zip resources/
cat foo0 resources.zip >foo
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为a)大多数可执行图像格式不关心图像后面是否有额外的数据,b)zip文件签名存储在zip文件的末尾.这意味着,此后您的可执行文件是一个常规zip文件(除了您的前端可执行文件,zip可以处理),可以使用libzip打开和读取.
Joh*_*ley 35
如果要控制确切的符号名称和资源位置,可以使用(或脚本)GNU汇编程序(实际上不是gcc的一部分)来导入整个二进制文件.试试这个:
组装(x86/arm):
.section .rodata
.global thing
.type thing, @object
.align 4
thing:
.incbin "meh.bin"
thing_end:
.global thing_size
.type thing_size, @object
.align 4
thing_size:
.int thing_end - thing
Run Code Online (Sandbox Code Playgroud)
C:
#include <stdio.h>
extern char thing[];
extern unsigned thing_size;
int main() {
printf("%p %u\n", thing, thing_size);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
无论你使用什么,最好是制作一个脚本来生成所有资源,并为所有内容提供漂亮/统一的符号名称.
Haz*_*zok 35
来自http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967:
我最近需要在可执行文件中嵌入一个文件.因为我在gcc等人的命令行工作,而不是使用花哨的RAD工具,这使得一切都神奇地发生在我身上并不是很明显如何实现这一点.在网上进行一些搜索发现了一个hack,基本上把它放到了可执行文件的末尾,然后根据一堆我不想知道的信息来解密它.似乎应该有更好的方式......
而且,这是救援的对象.objcopy将对象文件或可执行文件从一种格式转换为另一种格式.它理解的格式之一是"二进制",基本上任何文件都不是它理解的其他格式之一.所以你可能已经想到了这个想法:将我们想要嵌入的文件转换为目标文件,然后它可以简单地与我们的其余代码链接.
假设我们想要嵌入可执行文件中的文件名data.txt:
# cat data.txt
Hello world
Run Code Online (Sandbox Code Playgroud)
要将其转换为我们可以与程序链接的目标文件,我们只需使用objcopy生成".o"文件:
# objcopy --input binary \
--output elf32-i386 \
--binary-architecture i386 data.txt data.o
Run Code Online (Sandbox Code Playgroud)
这告诉objcopy我们的输入文件是"二进制"格式,我们的输出文件应该是"elf32-i386"格式(x86上的目标文件).--binary-architecture选项告诉objcopy输出文件意味着在x86上"运行".这是必需的,以便ld将接受该文件以链接x86的其他文件.有人会认为将输出格式指定为"elf32-i386"会暗示这一点,但事实并非如此.
现在我们有了一个目标文件,我们只需要在运行链接器时包含它:
# gcc main.c data.o
Run Code Online (Sandbox Code Playgroud)
当我们运行结果时,我们得到了输出的祈祷:
# ./a.out
Hello world
Run Code Online (Sandbox Code Playgroud)
当然,我还没有讲完整个故事,也没有向你展示main.c. 当objcopy执行上述转换时,它会向转换后的目标文件添加一些"链接器"符号:
_binary_data_txt_start
_binary_data_txt_end
Run Code Online (Sandbox Code Playgroud)
链接后,这些符号指定嵌入文件的开头和结尾.符号名称是通过预先添加二进制文件并将_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++);
}
Run Code Online (Sandbox Code Playgroud)
需要注意的一个重要而微妙的事情是添加到目标文件中的符号不是"变量".它们不包含任何数据,而是它们的地址是它们的价值.我将它们声明为char类型,因为它对此示例很方便:嵌入数据是字符数据.但是,您可以将它们声明为任何内容,如果数据是整数数组则为int,如果数据是任何foo条数组,则为struct foo_bar_t.如果嵌入数据不一致,则char可能是最方便的:获取其地址并在遍历数据时将指针强制转换为正确的类型.
小智 5
阅读这里和互联网上的所有帖子我得出的结论是没有资源工具,即:
1)易于在代码中使用。
2) 自动化(易于包含在 cmake/make 中)。
3)跨平台。
我决定自己编写这个工具。该代码可在此处获取。 https://github.com/orex/cpp_rsc
与 cmake 一起使用它非常简单。
您应该将此类代码添加到 CMakeLists.txt 文件中。
file(DOWNLOAD https://raw.github.com/orex/cpp_rsc/master/cmake/modules/cpp_resource.cmake ${CMAKE_BINARY_DIR}/cmake/modules/cpp_resource.cmake)
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}/cmake/modules)
include(cpp_resource)
find_resource_compiler()
add_resource(pt_rsc) #Add target pt_rsc
link_resource_file(pt_rsc FILE <file_name1> VARIABLE <variable_name1> [TEXT]) #Adds resource files
link_resource_file(pt_rsc FILE <file_name2> VARIABLE <variable_name2> [TEXT])
...
#Get file to link and "resource.h" folder
#Unfortunately it is not possible with CMake add custom target in add_executable files list.
get_property(RSC_CPP_FILE TARGET pt_rsc PROPERTY _AR_SRC_FILE)
get_property(RSC_H_DIR TARGET pt_rsc PROPERTY _AR_H_DIR)
add_executable(<your_executable> <your_source_files> ${RSC_CPP_FILE})
Run Code Online (Sandbox Code Playgroud)
使用该方法的真实示例可以在这里下载, https://bitbucket.org/orex/periodic_table
归档时间: |
|
查看次数: |
56579 次 |
最近记录: |