使用gcc mingw嵌入二进制文件

55

我想将二进制数据嵌入到exe文件中。我正在使用mingw gcc。

我像这样生成目标文件:

ld -r -b binary -o binary.o input.txt

然后我查看objdump的输出以获取符号:

objdump -x binary.o

它会给出以下命名的符号:

_binary_input_txt_start
_binary_input_txt_end
_binary_input_txt_size

然后我尝试在我的C程序中访问它们:

#include <stdlib.h>
#include <stdio.h>

extern char _binary_input_txt_start[];

int main (int argc, char *argv[])
{
    char *p;
    p = _binary_input_txt_start;

    return 0;
}

然后我这样编译:

gcc -o test.exe test.c binary.o

但是我总是得到:

undefined reference to _binary_input_txt_start

有人知道我做错了什么吗?


8
顺便说一下,我不知道这种将任意数据引入可执行文件的方法——不错。 - Michael Burr
这个方法提供了什么,.rc文件没有提供的? - rubenvb
1
@rubenvb 更便捷地访问内容。它不需要调用任何资源API。 - user877329
也请访问 https://github.com/graphitemaster/incbin/。 - kervin
4个回答

40

在你的C程序中删除前导下划线:

#include <stdlib.h>
#include <stdio.h>

extern char binary_input_txt_start[];

int main (int argc, char *argv[])
{
    char *p;
    p = binary_input_txt_start;

    return 0;
}

很多 C 编译器似乎(总是?)在 extern 名称前添加下划线。我不完全确定为什么会这样——我猜测这里的维基百科文章中有一些真相:

C 编译器普遍将程序的所有外部作用域标识符前加一个下划线,以避免与运行时语言支持的贡献发生冲突。

但是,我认为如果所有的 extern 都添加下划线,那么你并没有将命名空间分区得很好。无论如何,这是另一个问题,事实上下划线确实被添加了。


哇...非常感谢。这让我疯狂了。我知道它一定是一些简单的东西。我刚刚调试了它,发现它正在更改为__binary_input_txt_start。 - myforwik
@myforwik:如果你感兴趣的话,我已经发布了一个问题,询问为什么C会这样做:https://dev59.com/IHE85IYBdhLWcg3wwWUb - Michael Burr
1
有人知道通过这种方式可以嵌入多少数据吗? - user877329
1
@aditya:也许这个细节取决于目标的不同?当针对Win32 x86时,Windows工具链往往会自动在外部名称中添加下划线。如果针对其他目标(甚至是Win32 x64),这种情况可能不会发生,这并不奇怪。 - Michael Burr
@MichaelBurr:嗯...有趣的话题,而且也很有用...还有很多东西要学 :) - aditya
显示剩余3条评论

9

来自ld man page:

--leading-underscore

--no-leading-underscore

对于大多数目标,默认符号前缀是下划线,并在目标描述中定义。通过此选项,可以禁用/启用默认的下划线符号前缀。

所以

ld -r -b binary -o binary.o input.txt --leading-underscore

应该是解决方案。


6

我在Linux(Ubuntu 10.10)中进行了测试。

  1. 资源文件:
    input.txt

  2. gcc(Ubuntu/Linaro 4.4.4-14ubuntu5)4.4.5 [生成Linux的ELF可执行文件]
    生成符号_binary__input_txt_start
    接受符号_binary__input_txt_start(带下划线)。

  3. i586-mingw32msvc-gcc(GCC)4.2.1-sjlj(mingw32-2)[生成Windows的PE可执行文件]
    生成符号_binary__input_txt_start
    接受符号binary__input_txt_start(不带下划线)。


使用 tdm-gcc 4.8.1,我必须使用下划线来引用变量。 - hauzer

0

显然,OSX的ld中没有这个功能,因此您必须使用添加的自定义gcc标志完全不同来完成它,并且不能直接引用数据,而必须进行一些运行时初始化以获取地址。

因此,更具可移植性的方法可能是在构建时创建一个包含二进制文件的汇编源文件,就像这个答案所示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接