Что требуется для загрузки исполняемого файла Mach-O?

Я пытаюсь вручную написать исполняемый файл Mach-O. Есть три команды загрузки:

  • LC_SEGMENT_64 загрузка __PAGEZERO
  • LC_SEGMENT_64 загрузка __TEXT с одной секцией __text
  • LC_UNIXTHREAD с соответствующим образом настроенным rip

Каждая команда соответствует структурам в mach/loader.h и связанных заголовках. otool -l перечисляет информацию, как и ожидалось, и не сообщает об ошибках. По общему мнению, это правильно сформированный объектный файл, но OS X 10.10.5 завершает задачу (SIGKILL).

Какие функции исполняемого файла Mach-O проверяются перед тем, как OS X загрузит его? Где находится эта информация? Изменяются ли эти функции от версии к версии? (Очевидно, отсутствует часто цитируемый «Справочник OS X ABI Mach-O».)


Вот частично аннотированный шестнадцатеричный дамп двоичного файла.

otool проверка работоспособности (отрывок):

$ otool -l machtest
machtest:
Load command 0
      cmd LC_SEGMENT_64
  cmdsize 72
  segname __PAGEZERO
…
Load command 1
      cmd LC_SEGMENT_64
  cmdsize 152
  segname __TEXT
…
Section
  sectname __text
   segname __TEXT
…
Load command 2
        cmd LC_UNIXTHREAD
…

person wirelyre    schedule 04.10.2016    source источник
comment
Кроме того, было бы уместно опубликовать аннотированный шестнадцатеричный дамп? Я не стал, потому что это 100 строк, но все они имеют отношение к вопросу.   -  person wirelyre    schedule 05.10.2016
comment
Было бы полезно поделиться шестнадцатеричным дампом.   -  person bdash    schedule 05.10.2016
comment
У меня еще не было времени просмотреть его, но нашел повторную версию OS X ABI Справочник по формату файла Mach-O.   -  person Siguza    schedule 10.10.2016


Ответы (2)


Начиная с версии 10.10.5 Yosemite, исполняемый файл должен иметь длину не менее 4096 байт ( PAGE_SIZE ), иначе он будет немедленно уничтожен. Соответствующий код, найденный @Siguza в функции XNU kernel exec_activate_image https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/kern/kern_exec.c#L1456

Без dyld

Предполагая, что вам нужен 64-битный исполняемый файл macOS, использующий только системные вызовы, вам нужно:

  • 64-битный заголовок Mach-O
  • LC_SEGMENT_64 __PAGEZERO (с ненулевым размером, имя может быть любым)
  • LC_SEGMENT_64 __TEXT (имя может быть любым; должно быть читабельным и исполняемым; разделы необязательны)
  • LC_UNIXTHREAD

Вот мой пример для этого случая.

с дилдом

Однако без dyld вы мало что можете сделать, поэтому, если вы хотите его использовать, минимальный набор:

  • 64-битный заголовок Mach-O
  • LC_SEGMENT_64 __PAGEZERO (с ненулевым размером)
  • LC_SEGMENT_64 __TEXT (имя может быть любым; должно быть читабельным и исполняемым; разделы необязательны)
  • LC_SEGMENT_64 __LINKEDIT (должен быть доступен для записи, потому что dyld требует доступный для записи сегмент, в связанном двоичном файле ld доступный для записи сегмент обычно будет __DATA)
  • LC_DYLD_INFO_ONLY (указывает, где фактические dyld команды загрузки физически находятся в исполняемом файле, обычно они будут найдены __LINKEDIT, но на это нет ограничений) или, что интересно, LC_SYMTAB вместо этого, что сделало бы фактические dyld невозможными для использования без LC_DYLD_INFO_ONLY.
  • LC_DYSYMTAB (может быть пустым)
  • LC_LOAD_DYLINKER
  • LC_MAIN or LC_UNIXTHREAD
  • LC_LOAD_DYLIB (по крайней мере, одна фактическая dylib для загрузки, которая в конечном итоге зависит от libSystem или самой libSystem для работы LC_MAIN)

LC_UNIXTHREAD и LC_MAIN

В современных исполняемых файлах (начиная с 10.7 Mountain Lion) LC_UNIXTHREAD заменяется на LC_MAIN, для которого требуется dyld, но LC_UNIXTHREAD по-прежнему поддерживается для любого исполняемого файла начиная с 10.12 Sierra (и это должно быть в будущих версиях MacOS, поскольку оно используется самим исполняемым файлом dyld для собственно начать).

Чтобы dyld заработало, дополнительные шаги зависят от типа привязки:
bind at load — это подход с наименьшими усилиями, где LC_DYLD_INFO_ONLY указывает на допустимый сегмент, dyld load commands указывает на доступный для записи сегмент.
lazy binding дополнительно требует дополнительного кода для конкретной платформы. в __TEXT, который использует привязку во время загрузки dyld_stub_binder к адресу ленивой загрузки загруженной функции dyld.
Существуют и другие типы dyld binding, которые я здесь не рассматриваю.

Более подробную информацию можно найти здесь: https://github.com/opensource-apple/dyld/blob/master/src/ImageLoaderMachO.cpp

person Kamil.S    schedule 22.02.2017

Не уверен на 100%, но вам понадобится команда загрузки LC_LOAD_DYLINKER для запуска dyld перед вашим исполняемым файлом, я почти уверен, что OSX автоматически не сопоставляется с /usr/lib/dyld, если эта команда загрузки недоступна.

Вам нужна /usr/lib/libSystem.B.dylib с командой загрузки LC_LOAD_DYLIB? Я так не думаю, но это тоже хорошо, и не стоит дорого.

person mrdvlpr    schedule 14.11.2016