Как встроить содержимое двоичного файла в исполняемый файл в Mac OS X?

Процесс сборки моей программы командной строки генерирует двоичный файл (более 500 КБ), на который в настоящее время нужно ссылаться по пути из argv. Вместо этого я хотел бы встроить этот файл в исполняемый файл.

В Linux возможно используйте objcopy для создания объектного файла из двоичного файла:

objcopy --input binary --output elf32-i386 --binary-architecture i386 myfile.dat myfile.o

Однако цепочка инструментов разработчика OS X не включает команду objcopy. Если не считать установки binutils, каковы возможности?

Я создаю свой проект из Xcode, и файл создается с помощью пользовательского правила сборки.


person zneak    schedule 06.01.2016    source источник


Ответы (2)


На этапе компоновки передайте аргументы -sectcreate <segname> <sectname> <file> компоновщику. Если вы управляете компоновщиком через вызов компилятора, что довольно часто, вы должны передать его как -Wl,-sectcreate,<segname>,<sectname>,<file>.

Вы бы составили названия сегментов и разделов.

Вы должны использовать функцию getsectdata() вместе с _dyld_get_image_vmaddr_slide() чтобы получить указатель на данные во время выполнения.

person Ken Thomases    schedule 06.01.2016
comment
Есть ли правда в getsectiondata, избегающая необходимости использования подчеркнутых функций? - person zneak; 06.01.2016
comment
Кроме того, есть ли более приятный способ получить заголовок Mach, чем вызов _dyld_get_image_header? - person zneak; 06.01.2016
comment
Единственный способ, которым вы могли бы полагаться на getsectiondata(), был бы в том случае, если бы он был задокументирован, чего, похоже, нет. Почему вы так суеверны в отношении подчеркнутых функций? Они задокументированы и совершенно безопасны в использовании. Если вам нужен заголовок Mach исполняемого файла, а не любой динамической библиотеки, и вы пишете код в исполняемом файле, вы можете просто обратиться к &_mh_execute_header. См. /usr/include/mach-o/ldsyms.h. Кстати, вы можете передать индекс 0 функциям dyld(3) (например, _dyld_get_image_vmaddr_slide()), чтобы ссылаться на основной исполняемый файл. - person Ken Thomases; 07.01.2016
comment
Если мы собираемся копаться в том, что задокументировано, а что нет, нигде не говорится, что getsectdata не регулирует значение для слайда ASLR, поэтому, возможно, мне следует опасаться, что Apple в конечном итоге исправит это, и мой код сломается. Я уверен, что мы оба подозреваем, что они этого не сделают, но я также подозреваю, что getsectiondata не уходит именно из-за этого. В любом случае, я смотрю на это, это кажется таким же хакерским и странным, как использование dlsym для получения дескриптора глобальной переменной (потому что это в основном то, чем оно является), так что я мог бы также взять функцию, которая заставляет ее чувствовать себя наименее плохо об этом. - person zneak; 07.01.2016
comment
Последняя миля заключается в том, что, похоже, нет удобного способа автоматически связывать выходные файлы независимо от их имени. Если я переименую файл или добавлю новые, мне также нужно изменить флаги компоновщика. Я приму ответ, если найду способ сделать это, но я могу оставить его открытым, если появится что-то еще. - person zneak; 07.01.2016
comment
На справочной странице для getsectdata() (на которую я ссылался не потому, что она, похоже, не подключена к сети) говорится, что Getsectdata такая же, как и getsectdatafromheader, с ее первым аргументом, определяемым редактором ссылок символом _mh_execute_header. На той же справочной странице сказано, что вы должны добавить слайд к результату из getsectdatafromheader(). Хотя я предполагаю, что это указывает, что это только для динамических библиотек, но исполняемые файлы также перемещаются ASLR, если только они не были построены независимо от позиции. - person Ken Thomases; 07.01.2016

Как видно из этого другого вопроса о objcopy, еще один способ включить двоичный файл в исполняемый файл заключается в использовании директивы ассемблера .incbin. Это решение имеет два основных преимущества по сравнению с objcopy: разработчик контролирует имена символов (у objcopy, похоже, есть фиксированная схема их именования), и, ну, objcopy не требуется.

Решение также имеет преимущества по сравнению с решением -sectcreate на основе компоновщика. Он кроссплатформенный, и доступ к данным намного проще.

Я использую этот сценарий правила сборки Xcode для создания файла, который нужно включить, и файла сборки с директивой .incbin:

my_generation_tool -o $DERIVED_FILE_DIR/$INPUT_FILE_NAME.out $INPUT_FILE_PATH

export AS_PATH=$DERIVED_FILE_DIR/$INPUT_FILE_NAME.out.s

echo "\t.global _data_start_$INPUT_FILE_BASE" > $AS_PATH
echo "\t.global _data_end_$INPUT_FILE_BASE" >> $AS_PATH
echo "_data_start_ $INPUT_FILE_BASE:" >> $AS_PATH
echo "\t.incbin \"$INPUT_FILE_NAME.out\"" >> $AS_PATH
echo "_data_end_$INPUT_FILE_BASE:" >> $AS_PATH

Тогда для файла «somefile.gen», который обрабатывается этим правилом, сборка будет выглядеть так:

    .global _data_start_somefile
    .global _data_end_somefile
_data_start_somefile:
    .incbin "somefile.gen.out"
_data_end_somefile:

Доступ к данным на языке C можно получить с помощью символов data_start_somefile и data_end_somefile (компоновщик macOS ставит перед именами C фиктивный префикс _, поэтому они есть в файле сборки):

extern char data_start_somefile, data_end_somefile;

for (const char* c = &data_start_somefile; c != &data_end_somefile; ++c)
{
    // do something with character
}

Ответ в другой ветке содержит больше наворотов, которые некоторые люди могут найти полезными (например, символ length).

person zneak    schedule 06.01.2016