objcopy prepends directory pathname to symbol name

前端 未结 5 797
刺人心
刺人心 2020-12-31 10:30

I am tying to use objcopy to include a binary form of a text file into an executable. (At runtime I need the file as a string). This works fine until the linker

相关标签:
5条回答
  • 2020-12-31 10:47

    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
    
    0 讨论(0)
  • 2020-12-31 10:52

    Another alternative which I have used is to cd to the source directory and then give objcopy the basename of the source. In bash, this would be:

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

    This way the symbols generated are always _binary_file_name_xxx without the path.

    0 讨论(0)
  • 2020-12-31 11:01

    Generic method of including raw data into ELF is supported by .incbin assembler directive.

    The trick is to create template .S file that could look like this:

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

    This file is preprocessed via cpp so we don't have to hardcode file name there, eg. we can write:

            .incbin __raw_file_path__
    

    ... and then pass it while compiling:

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

    Lastly, as we prepare .S file ourself we can add some extra data and/or information. If you include raw "text files" and want these to be available as C strings you can add '0' byte just after raw data:

            .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
    

    If you want full-blown flexibility, you can of course pre-process file manually to alter any part of it, eg.

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

    ... and then compile it:

    sed -e "s,@sym@,passwd,g" -e "s,@file@,/etc/passwd," <foo.S.in | gcc -x assembler-with-cpp - -o passwd.o -c
    
    0 讨论(0)
  • 2020-12-31 11:08

    One simple solution is to transform your text file into what could be used to initialize an array of char. So, you'd get 0x41,0x42,0x43,0x30,0x31,0x32 for "ABC012". You can then #include this sequence of bytes. You can also escape all non-ASCII chars instead of converting everything into bytes so that most of the text is still readable in the generated include file.

    0 讨论(0)
  • 2020-12-31 11:12

    I had to do this with cmake, and I ended up using /dev/stdin as input to get consistent symbols name, then redefining the symbols thanks to string(MAKE_C_IDENTIFIER ...) And then use objcopy --redefine-sym on the resulting object file.

    The resulting function is then :

    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()
    

    And you can use it like this:

    make_binary_object(index.html)
    
    add_executable(my_server
        server.c
        ${CMAKE_CURRENT_BINARY_DIR}/index.html.obj)
    
    0 讨论(0)
提交回复
热议问题