13

我打算使用objcopy将文本文件的二进制形式包含到可执行文件中。(在运行时我需要文件作为字符串)。这工作正常,直到链接器需要从符号名称中找到引用。问题是objcopy在符号名称前面加上文件的路径名。由于我使用 GNU Autotools 来发送包,所以这个前置路径名发生了变化,我不知道在 C/C++ 程序中使用什么外部链接器符号。

nm libtest.a |grep textfile
textfile.o:
00001d21 D _binary__home_git_textfile_end
00001d21 A _binary__home_git_textfile_size
00000000 D _binary__home_git_textfile_start

libtest.a使用(从 Makefile.am 中提取)生成:

SUFFIXES = .txt
.txt.$(OBJEXT):
    objcopy --input binary --output elf32-i386 --binary-architecture i386 $< $@

我怎样才能告诉objcopy我们文件名的词干作为链接器符号?还是有其他解决问题的方法?

4

5 回答 5

11

.incbin汇编器指令支持将原始数据包含到 ELF 中的通用方法。

诀窍是创建可能如下所示的模板 .S 文件:

        .global foo_start
foo_start:
        .incbin "foo.raw"

        .global foo_end
foo_end:    

这个文件是通过 cpp 预处理的,所以我们不必在那里硬编码文件名,例如。我们可以写:

        .incbin __raw_file_path__

...然后在编译时传递它:

gcc -D__raw_file_path__='"data/foo.png"' foo.S -c -o data/foo.o

最后,当我们自己准备 .S 文件时,我们可以添加一些额外的数据和/或信息。如果您包含原始“文本文件”并希望这些作为 C 字符串可用,您可以在原始数据之后添加 '0' 字节:

        .global foo_start
foo_start:
        .incbin "foo.raw"

        .global foo_end
foo_end:    
        .byte 0

        .global foo_size
foo_size:
        .int foo_end - foo_start

如果您想要充分的灵活性,您当然可以手动预处理文件以更改它的任何部分,例如。

.global @sym@_start
@sym@_start:
       .incbin "@file@"
       .global @sym@_end
@sym@_end:

...然后编译它:

sed -e "s,@sym@,passwd,g" -e "s,@file@,/etc/passwd," <foo.S.in | gcc -x assembler-with-cpp - -o passwd.o -c
于 2013-08-23T23:42:29.807 回答
10

Somewhat ironically you can use objcopy to solve the problem via the --redefine-sym option that allows renaming of symbols...

If I use objcopy to create an object file from a PNG in another directory:

$ objcopy -I binary -O elf64-x86-64 -B i386 --rename-section .data=.rodata,alloc,load,data,contents,readonly ../../resources/test.png test_png.o

The resulting object has the following symbols:

$readelf -s test_png.o -W

Symbol table '.symtab' contains 5 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT    1 _binary_______resources_test_png_start
     3: 0000000000003aaa     0 NOTYPE  GLOBAL DEFAULT    1 _binary_______resources_test_png_end
     4: 0000000000003aaa     0 NOTYPE  GLOBAL DEFAULT  ABS _binary_______resources_test_png_size

These can then be renamed:

$objcopy --redefine-sym _binary_______resources_test_png_start=_binary_test_png_start test_png.o
$objcopy --redefine-sym _binary_______resources_test_png_size=_binary_test_png_size test_png.o
$objcopy --redefine-sym _binary_______resources_test_png_end=_binary_test_png_end test_png.o

Resulting in an object with the symbol names that objcopy would have generated if the PNG had been located in the current directory:

$readelf -s test_png.o -W

Symbol table '.symtab' contains 5 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT    1 _binary_test_png_start
     3: 0000000000003aaa     0 NOTYPE  GLOBAL DEFAULT    1 _binary_test_png_end
     4: 0000000000003aaa     0 NOTYPE  GLOBAL DEFAULT  ABS _binary_test_png_size
于 2013-05-03T08:27:57.197 回答
5

我使用的另一种选择是到cd源目录,然后给出objcopy源的基本名称。在bash中,这将是:

cd $(dirname $SOURCE)
objcopy ... $(basename $SOURCE) $TARGET

这样生成的符号总是_binary_file_name_xxx没有路径。

于 2014-04-23T14:55:26.810 回答
0

我不得不用 cmake 来做这件事,我最终使用 /dev/stdin 作为输入来获得一致的符号名称,然后通过 string(MAKE_C_IDENTIFIER ...) 重新定义符号,然后在结果上使用 objcopy --redefine-sym目标文件。

结果函数是:

function(make_binary_object __file)
    get_filename_component(__file_name ${__file} NAME)
    set(__object ${CMAKE_CURRENT_BINARY_DIR}/${__file_name}.obj)
    string(MAKE_C_IDENTIFIER ${__file_name} __file_c_identifier)
    add_custom_command(OUTPUT ${__object}
        COMMAND ${CMAKE_OBJCOPY}
            --input-format binary
            --output-format elf64-x86-64
            --binary-architecture i386:x86-64
            /dev/stdin
            ${__object} < ${__file}
        COMMAND ${CMAKE_OBJCOPY}
            --redefine-sym _binary__dev_stdin_start=_binary_${__file_c_identifier}_start
            --redefine-sym _binary__dev_stdin_end=_binary_${__file_c_identifier}_end
            --redefine-sym _binary__dev_stdin_size=_binary_${__file_c_identifier}_size
            ${__object}
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        DEPENDS ${__file})
    set_source_files_properties(${__object} PROPERTIES EXTERNAL_OBJECT TRUE)
endfunction()

你可以像这样使用它:

make_binary_object(index.html)

add_executable(my_server
    server.c
    ${CMAKE_CURRENT_BINARY_DIR}/index.html.obj)
于 2020-06-02T13:21:31.137 回答
-2

一个简单的解决方案是将文本文件转换为可用于初始化 char 数组的文件。所以,你会得到“ABC012”的 0x41,0x42,0x43,0x30,0x31,0x32。然后您可以#include 这个字节序列。您还可以转义所有非 ASCII 字符,而不是将所有内容转换为字节,以便生成的包含文件中的大部分文本仍然可读。

于 2013-03-24T08:06:21.897 回答