Выполнение мужественных файлов
Для выполнения их целей программы должны выполнить процессы и ссылку к динамическим совместно используемым библиотекам. Для работы с другими библиотеками или модулями приложение должно определить ссылки на символы в тех модулях; во время выполнения разрешены те ссылки. Во время выполнения имена символа всех модулей Ваше приложение использует живой в совместно используемом пространстве имен, подобном каталогу. Для обеспечения будущих улучшений к приложениям, а также библиотекам, они используют, приложение и разработчики библиотеки должны гарантировать имена, которые они выбирают для их функций, и данные не конфликтуют с именами, используемыми в других модулях.
Двухуровневая функция пространства имен OS X v10.1 и позже добавляет имя модуля как часть имени символа символов, определенных в нем. Этот подход гарантирует, чтобы имена символа модуля не конфликтовали с именами, используемыми в других модулях. Чтобы выполнить специальные задачи или обеспечить улучшенный пользовательский опыт, Ваше приложение, возможно, должно запустить другие приложения или создать процессы для выполнения инструментов командной строки. Чтобы поддержать высокую степень функциональной совместимости и обеспечить непротиворечивый пользовательский опыт, Ваши приложения должны использовать определенные системные функции и платформы для выполнения приложений запуска и процессов.
Эта статья обеспечивает обзор OS X динамический процесс загрузки. Процесс загрузки и соединения программы в OS X в основном включает два объекта: ядро OS X и динамический компоновщик. При выполнении программы ядро создает процесс для программы и загружает программу, и динамический компоновщик совместно использовал библиотеку, обычно /usr/lib/dyld
, в адресном пространстве программы. Ядро тогда выполняет код в динамическом компоновщике, загружающем библиотеки ссылки программы. Эта статья также описывает символы видимости в модуле, добираются в зависимости от того, как они определяются и процесс разрешения ссылок символа во время выполнения.
Запуск приложения
При запуске приложения от Средства поиска или Прикрепления, или когда Вы выполняете программу в оболочке, система в конечном счете вызывает две функции от Вашего имени, fork
и execve
. fork
функция создает процесс; execve
функционируйте загружает и выполняет программу. Существует несколько различных исполнительных функций, такой как execl
, execv
, и exect
, каждое обеспечение немного отличающегося способа передать параметры и переменные окружения к программе. В OS X каждая из этих других исполнительных подпрограмм в конечном счете вызывает подпрограмму ядра execve
.
При записи приложения Mac необходимо использовать платформу Launch Services для запуска других приложений. Launch Services понимает пакеты приложений, и можно использовать ее для открытия и приложений и документов. Средство поиска и Прикрепление используют Launch Services для поддержания базы данных отображений от типов документов до приложений, которые могут открыть их. Приложения какао могут использовать класс NSWorkspace
запустить приложения и документы; NSWorkspace
самостоятельно использование Launch Services. Launch Services в конечном счете вызывает fork
и execve
выполнять фактическую работу создания и выполнения нового процесса. Для получения дополнительной информации о Launch Services см. Руководство по программированию Launch Services.
Разветвление и выполнение процесса
Для создания процесса с помощью системных вызовов BSD процесс должен вызвать fork
системный вызов. fork
вызов создает логическую копию Вашего процесса, затем возвращает ID нового процесса к Вашему процессу. И исходный процесс и новый процесс продолжают выполняться от вызова до fork
; единственная разница - это fork
возвращает ID нового процесса к исходному процессу и нуля к новому процессу. ( fork
функциональные возвраты -1
к исходному процессу и наборам errno
к определенному ошибочному значению, если не мог бы быть создан новый процесс.)
Для выполнения различной исполнимой программы процесс должен вызвать execve
системный вызов с путем, указывающим расположение альтернативной исполнимой программы. execve
вызовите в настоящее время заменяет программу в памяти с различным исполняемым файлом.
Мужественный исполняемый файл содержит заголовок, состоящий из ряда команд загрузки. Для программ, пользующихся совместно используемыми библиотеками или платформами, одна из этих команд указывает расположение компоновщика, чтобы использоваться для загрузки программы. При использовании XCode это всегда /usr/lib/dyld
, стандартный OS X динамический компоновщик.
Когда Вы вызываете execve
подпрограмма, ядро сначала загружает указанный программный файл и исследует mach_header
структура в начале файла. Ядро проверяет, что файл, кажется, допустимый Мужественный файл, и интерпретирует команды загрузки, сохраненные в заголовке. Ядро тогда загружает динамического компоновщика, указанного командами загрузки в память, и выполняет динамического компоновщика на программном файле.
Динамический компоновщик загружает все совместно используемые библиотеки, которые основная программа соединяет против (зависимые библиотеки) и обязывает достаточно символов запускать программу. Это тогда вызывает функцию точки входа. Во время изготовления статический компоновщик добавляет стандартную функцию точки входа к основному исполняемому файлу от объектного файла /usr/lib/crt1.o
. Эта функция устанавливает состояние среды выполнения для ядра и вызывает статические инициализаторы для объектов C++, инициализирует время выполнения Objective C, и затем вызывает программу main
функция.
Нахождение импортированных символов
Когда динамический компоновщик загружает Мужественный файл (который, в целях этого раздела, вызывается клиентской программой), это подключает импортированные символы файла к их определениям в совместно используемой библиотеке или платформе. В этом разделе описываются процесс привязки импортированных символов в одном Мужественном файле к их определениям в других Мужественных файлах. Это также объясняет процесс нахождения символа. См. также Загружающийся Сменный Код С Пакетами в Загружающемся Коде во Время выполнения для получения информации о нахождении символов в плагинах.
Привязка символов
Привязка является процессом разрешения ссылок модуля на функции и данные в других модулях (неопределенные внешние символы, иногда называемые импортированными символами). Модули могут быть в том же Мужественном файле или в различных Мужественных файлах; семантика идентична в любом случае. Когда приложение сначала загружается, динамический компоновщик загружает импортированные совместно используемые библиотеки в адресное пространство программы. Когда привязка выполняется, компоновщик заменяет каждую из импортированных ссылок программы с адресом фактического определения от одной из совместно используемых библиотек.
Динамический компоновщик может связать программу на нескольких этапах во время загрузки и выполнения, в зависимости от опций, которые Вы указываете во время изготовления:
Со своевременной привязкой (также названный ленивой привязкой), динамический компоновщик связывает ссылку (и все другие ссылки в том же модуле), когда программа сначала использует ссылку. Динамический компоновщик загружает совместно используемые библиотеки, клиентская программа зависит от того, когда загружается программа. Однако динамический компоновщик не связывает ссылки программы на символы в совместно используемых библиотеках, пока не используются символы.
Со временем загрузки, связывая, динамический компоновщик связывает все импортированные ссылки непосредственно после загрузки программы, или, для пакетов, после загрузки пакета. Для использования времени загрузки, связывая со стандартными инструментами укажите
-bind_at_load
опция кld
указать, что динамический компоновщик должен сразу связать все внешние ссылки, когда загружается файл. Без этой опции,ld
устанавливает выходной файл для своевременной привязки.С предварительной привязкой, формой времени загрузки, связывая, совместно используемые библиотеки, на которые ссылается программа, каждый предварительно связываются в указанном адресе. Статический компоновщик устанавливает адрес каждой неопределенной ссылки в программе для установки по умолчанию к этим адресам. Во время выполнения динамический компоновщик должен только проверить, что ни один из адресов не изменился, так как программа была создана (или так как предварительная привязка была повторно вычислена). Если адреса изменились, динамический компоновщик должен отменить предварительную привязку путем очистки предсвязанных адресов для всех неопределенных ссылок и затем продолжиться, как будто программа была своевременная связанный. Иначе, это не должно выполнять действие для привязки программы.
Предварительная привязка требует, чтобы каждая платформа указала свой желаемый основной адрес виртуальной памяти и что ни один из предсвязанных адресов загруженного перекрытия платформ. Чтобы предварительно связать файл со стандартными инструментами, укажите
-prebind
опция кld
.Слабые ссылки, функция, представленная в OS X v10.2, полезны для того, чтобы выборочно реализовать опции, которые могут быть доступными в некоторых системах, но не в других. Этот режим привязки позволяет программе дополнительно связывать с указанными совместно используемыми библиотеками. Если динамический компоновщик не может найти определения для слабых ссылок, это устанавливает их в
NULL
и продолжает загружать программу. Программа может проверить во время выполнения, чтобы узнать, является ли ссылка нулем и, если так, избегайте использования ссылки. Можно указать и библиотеки и отдельные символы, на которые слабо сошлются.
Если никакой другой тип привязки не указан для данной библиотеки, статический компоновщик устанавливает неопределенные ссылки программы на ту библиотеку для использования своевременной привязки.
Поиск символов
Символ является универсальным представлением расположения функции, переменной данных, или постоянный в исполняемом файле. Ссылки на функции и данные в программе являются ссылками на символы. Для обращения к символу при использовании подпрограмм динамического подключения Вы обычно передаете имя символа, несмотря на то, что некоторые функции также принимают число, представляющее упорядочивание символа в исполняемом файле. Имя символа, представляющего функцию, приспосабливающую стандарту C соглашениям о вызовах, является именем функции с префиксом подчеркивания. Таким образом, имя символа, представляющего функцию main
был бы _main
.
Программы, создаваемые OS X v10.0 средства разработки, добавляют все символы от всех загруженных совместно используемых библиотек в единственный глобальный список. Любой символ, что Ваши ссылки программы могут быть расположены в любой совместно используемой библиотеке, пока та совместно используемая библиотека, является одной из зависимых библиотек программы (или одной из зависимых библиотек зависимых библиотек).
OS X v10.1 представил двухуровневую функцию пространства имен символа. Первый уровень двухуровневого пространства имен является именем библиотеки, содержащей символ, и вторым является имя символа. С двухуровневой активированной опцией пространства имен, когда статический компоновщик записывает ссылки на импортированные символы, это записывает ссылку на имя библиотеки, содержащей символ и имя символа. Соединение Ваших программ с двумя функциями пространства имен уровня предлагает два преимущества по плоскому пространству имен:
Улучшенная производительность при поиске символов. С двухуровневым пространством имен динамический компоновщик знает точно, где начать искать реализацию символа. С плоским пространством имен динамический компоновщик должен искать все загруженные библиотеки ту, содержащую символ.
Улучшенная прямая совместимость. В плоском пространстве имен две или больше библиотеки не могут содержать символы с различными реализациями, совместно использующими то же имя, потому что динамический компоновщик не может знать, какая библиотека содержит предпочтительную реализацию. Это не первоначально проблема, потому что статический компоновщик ловит любые такие проблемы, когда Вы сначала создаете приложение. Однако, если поставщик одного из Вашего зависимого совместно использовал библиотеки более поздние выпуски новая версия библиотеки, содержащей символ с тем же именем, как один в Вашей программе или в другом зависимом совместно использовал библиотеку, Ваша программа не будет работать.
Ваше приложение должно соединиться непосредственно с совместно используемой библиотекой, содержащей символ (или, если библиотека является частью платформы зонтика к платформе зонтика, содержащей его).
Когда получение символов в программе создало с двухуровневой активированной опцией пространства имен, необходимо указать ссылку на совместно используемую библиотеку, содержащую символы.
По умолчанию, статический компоновщик в OS X v10.1 и более позднее использование двухуровневое пространство имен для всех Мужественных файлов.
Для программ, не имеющих двухуровневого пространства имен, можно сказать компоновщику определять ссылки на неопределенные символы, даже если компоновщик не может найти библиотеку, содержащую их. При создании исполнимой программы с такими неопределенными символами Вы делаете предположение, что один из других файлов, загруженных как часть исполняемого файла во время выполнения, содержит те символы. Пакеты и совместно использованные библиотеки иногда используют эту опцию сослаться на символы, определенные в основной исполнимой программе. Однако это заставляет Вас терять производительность и преимущества совместимости двухуровневых пространств имен. Обычно лучше явно соединиться против исполнимой программы, определяющей ссылки. Однако, если необходимо соединиться с неопределенными ссылками, можно сделать это путем активации плоской опции пространства имен и подавления неопределенных ссылочных предупреждений, использования опций -flat_namespace
и -undefined suppress
как в следующей командной строке:
ld -o my_tool -flat_namespace -undefined suppress peace.o love.o |
При создании исполнимых программ с двухуровневым пространством имен можно позволить остающимся неопределенным символам искаться динамическим компоновщиком, если программа предназначена для OS X v10.3 и позже ( MACOSX_DEPLOYMENT_TARGET
переменная окружения установлена в 10.3
или выше). Для использования в своих интересах этой функции используйте -undefined dynamic_lookup
опция.
Для создания исполнимых программ с двухуровневым пространством имен статический компоновщик должен быть в состоянии найти исходную библиотеку для каждого символа. Это может представить трудности для авторов пакетов и динамических совместно используемых библиотек, принимающих плоское, глобальное пространство имен символа. Для создания успешно с двухуровневым пространством имен помните следующие моменты:
Пакеты, которые должны сослаться на символы, определенные в основной исполнимой программе программы, должны использовать
-bundle_loader
статическая опция компоновщика. Статический компоновщик может тогда искать основную исполнимую программу неопределенные символы.Совместно используемые библиотеки, которые должны сослаться на символы, определенные в основной исполнимой программе программы, должны загрузить символ динамично с помощью функции, не требующей справочного руководства по библиотеке, такой как
dlsym
илиNSLookupSymbolInImage
(OS X ABI динамическая ссылка загрузчика).
Объем и обработка определений символа
Символы в объектном файле могут существовать на нескольких уровнях объема. В этом разделе описываются каждый из возможных объемов, что символ может быть определен в и обеспечивает, выборки кода C раньше создавали каждый тип символа. Эти выборки работают со стандартными инструментами разработчика; сторонний комплект инструментальных средств может иметь различные соглашения.
Определенный внешний символ является любым символом, определенным в текущем объектном файле, включая функции и данные. Следующий код C определяет внешние символы:
int x = 0; |
double y = 99 __attribute__((visibility("default"))); // GCC 4.0 only |
Неопределенный внешний символ является любым символом, определенным в файле за пределами текущего файла. Следующий код C определяет два внешних символа, переменную и функцию:
extern int x; |
extern void SomeFunction(void); |
Обычный символ является символом, который может появиться в многократных промежуточных объектных файлах. Статический компоновщик разрешает многократные определения обычного символа с тем же именем во входных файлах и копирует тот с самым большим размером к конечному продукту. Если существует другой символ с тем же именем как обычный символ, статический компоновщик игнорирует обычный символ вместо этого.
Стандарт C компилятор генерирует обычный символ, когда это видит предварительное определение — глобальная переменная, не имеющая никакого инициализатора и не отмеченная extern
. Следующая строка является примером предварительного определения:
int x; |
Мультимодуль совместно использовал библиотеку, который ld
сборки по умолчанию, не может иметь обычных символов. Однако можно создать совместно используемую библиотеку как единственный модуль с -single_module
флаг. Для устранения обычных символов в существующей совместно используемой библиотеке необходимо или явно определить символ (с помощью инициализированного значения, например) в одном из модулей в совместно используемой библиотеке, или передать -fno-common
отметьте к компилятору.
Частный определенный символ является символом, который не видим к другим модулям. Следующий код C определяет частный символ:
static int x; |
Частный внешний символ является определенным внешним символом, который видим только к другим модулям в том же объектном файле как модуль, содержащий его. Типичный статический компоновщик изменяет частные внешние символы в частные определенные символы, если Вы не указываете иначе (использующий -keep_private_externs
флаг).
Можно отметить символ как частный внешний при помощи __private_extern__
ключевое слово (который работает только в C), или visibility("hidden")
атрибут (который работает и в C и в C++ с GCC 4.0), как в этом примере:
__private_extern__ int x = 0; // C only |
int y = 99 __attribute__((visibility("hidden"))); // C and C++, GCC 4.0 only |
Объединенный символ является символом, который может быть определен в многократных объектных файлах, но что статический компоновщик генерирует только одну копию в выходном файле. Это может сохранить много памяти с определенными функциями языка C++, которые компилятор должен генерировать для каждого файла отдельного объекта, такого как таблицы виртуальной функции, информация о типах во время выполнения (RTTI) и шаблонные инстанцирования C++. Компилятор определяет, какие конструкции должны быть объединены; никакая работа с Вашей стороны не требуется.
Слабая ссылка является неопределенным внешним символом, который, как должны находить, для клиентской программы успешно не соединяется. Если символ не существует, динамический компоновщик обнуляет адрес символа. Файлы со слабыми ссылками могут использоваться только в OS X v10.2 и позже. Следующий код C демонстрирует conditionalizing вызов API с помощью слабой ссылки:
/* Only call this API if it exists */ |
if ( SomeNewFunction != NULL ) |
SomeNewFunction(); |
Чтобы указать, что функция должна быть обработана как слабая ссылка, используйте weak_import
атрибут на прототипе функции, как продемонстрировано следующим кодом:
void SomeNewFunction(void) __attribute__((weak_import)); |
Объединенная слабая ссылка является неопределенной внешней ссылкой на символ, определенный в многократных объектных файлах. В OS X v10.4 и позже (с GCC 4.0 и позже), можно указать, что символ превращен в объединенную слабую ссылку путем добавления слабого атрибута к объявлению символа. Например:
void SomeNewFunction(void) __attribute__((weak)); |
Слабое определение является символом, проигнорированным компоновщиком, если существует иначе идентичное, но nowness определение. Это используется стандартным компилятором C++ для поддержки шаблонных инстанцирований C++. Неявные метки компилятора — и не явные — обрабатывают инстанцирования по шаблону как слабые определения. Статический компоновщик тогда предпочитает любое явное шаблонное инстанцирование неявному для того же символа, обеспечивающего корректную семантику соединения C++. Как с объединенными символами, компилятор определяет конструкции, требующие слабой функции определений; никакая работа с Вашей стороны не требуется.
Отладочный символ является символом, сгенерированным компилятором, позволяющим отладчику отображаться от адресов в машинном коде к расположениям в исходном коде. Стандартные компиляторы генерируют отладочную информацию с помощью или формата Ударов или формата DWARF (поддерживаемый в Xcode 2.4 и позже). При использовании формата Ударов отладочная информация, как другие символы, сохранена в таблице символов (см. OS X ABI Мужественная Ссылка Формата файла). Но с форматом DWARF, отладочная информация сохранена в специализированном сегменте: __DWARF
сегмент. С DWARF у Вас также есть опция хранения отладочной информации в отдельном файле отладочной информации, сокращающем размер двоичных файлов при разрешении полного опыта отладки, когда соответствующие файлы отладочной информации доступны.