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, вместо того, чтобы конвертировать все в байты, чтобы большая часть текста была все еще читаемой в сгенерированном включаемом файле.