objcopy добавляет путь к каталогу к имени символа

Я привязываюсь к использованию 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 ответа

Как ни странно, вы можете использовать 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

Общий метод включения необработанных данных в ELF поддерживается директивой ассемблера .incbin.

Хитрость в том, чтобы создать шаблонный файл.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

Другой альтернативой, которую я использовал, является 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. Таким образом, вы получите 0x41,0x42,0x43,0x30,0x31,0x32 для "ABC012". Затем вы можете #include эту последовательность байтов. Вы также можете экранировать все символы, не входящие в ASCII, вместо того, чтобы конвертировать все в байты, чтобы большая часть текста была все еще читаемой в сгенерированном включаемом файле.

Другие вопросы по тегам