Objcopy将目录路径名添加到符号名之前

objcopy prepends directory pathname to symbol name

本文关键字:符号 添加 路径名 Objcopy      更新时间:2023-10-16

我试图使用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只把文件名的词干作为链接符?还是有其他解决问题的方法?

.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

有点讽刺的是,你可以使用objcopy来解决问题,通过--redefine-sym选项,允许重命名符号…

如果我使用objcopy从另一个PNG中创建一个对象文件目录:

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

结果对象具有以下符号:

$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

这些可以重命名:

$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

生成一个具有objcopy所具有的符号名的对象如果PNG位于当前目录,则生成:

$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

我使用的另一种替代方法是将cd添加到源目录,然后将源的基本名称赋给objcopy。在bash中,这将是:

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

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

我必须用cmake来做这件事,我最终使用/dev/stdin作为输入来获得一致的符号名称,然后重新定义符号字符串(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)

一个简单的解决方案是将文本文件转换为可用于初始化char数组的格式。因此,对于"ABC012",您将得到0x41,0x42,0x43,0x30,0x31,0x32。然后可以#include这个字节序列。您还可以转义所有非ascii字符,而不是将所有内容转换为字节,以便在生成的include文件中大多数文本仍然可读。