Системный вызов exec заменяет адресное пространство вызывающего процесса на адресное пространство новой программы. Если процесс был создан при помощи vfork, то вызов exec возвращает старое адресное пространство родительскому процессу. В ином случае этот вызов высвобождает старое адресное пространство. Вызов exec предоставляет процессу новое адресное пространство и загружает в него содержимое новой программы. По окончании работы exec процесс продолжает выполнение с первой инструкции новой программы. Адресное пространство процесса состоит из нескольких определенных компонентов:
• Текст (text). Содержит выполняемый код. • Инициализированные данные (initialized data). Содержат объекты данных, которые в программе уже имеют начальные значения и соответст¬вуют секции инициализированных данных в выполняемом файле. • Такое разделение представляется весьма функциональным в теории, однако ядро не распознает так много различных компонентов. Например, в системе SVR4 адресное пространство видится просто как набор разделяемых или приватных отображений. • Неинициализированные данные (uninitialized data). Имеет исторически сложившееся название блока статического хранения (block static storage, bss)1. Содержит переменные, которые были в программе описаны, но значения им присваивались. Объекты в этой области всегда заполнены нулями при первом обращении к ним. Так как хранение нескольких страниц нулей в выполняемом файле представляется нерациональным, в заголовке программы принято просто описывать общий размер этой области и предоставлять операционной системе самой сгенерировать заполненные нулями страницы. • Разделяемая память (shared memory). Многие системы UNIX позволяют процессам совместно использовать одни и те же области памяти. • Разделяемые библиотеки (shared libraries). Если система поддержи¬вает библиотеки динамической связи, процесс может обладать не¬сколькими отдельными областями памяти, содержащими библиотечный код, а также библиотечные данные, которые могут использоваться и другими процессами. • Куча (heap). Источник динамически выделяемой памяти. Процесс берет память из кучи при помощи системных вызовов brk или sbrk, либо используя функцию malloc() из стандартной библиотеки С. Ядро предоставляет кучу каждому процессу и расширяет ее по мере необходимости. • Стек приложения (user stack). Ядро выделяет стек каждому процессу. В большинстве традиционных реализаций системы UNIX ядро прозрачно отслеживает возникновение исключительных состояний, связанных с переполнением стека, и расширяет стек до определенного в системе максимума. Применение разделяемой памяти является стандартной возможностью System V UNIX, но не поддерживается в системе 4BSD (до версии 4.3). Многие коммерческие реализации UNIX, основанные на BSD, поддерживают как разделяемую память, так и некоторые формы разделяемых библиотек в качестве дополнительных возможностей системы. В последующем описании работы exec мы рассмотрим программу, которая не использует ни одну из этих возможностей.
Система UNIX поддерживает различные форматы выполняемых файлов. Первым поддерживаемым форматом был a.out, имеющий 32-байтовый заголовок с последующими секциями текста, данных и таблицы символов. Заголовок программы содержит размеры текста, областей инициализированных и неинициализированных данных, а также точку входа, которая является адресом первой инструкции программы, которая будет выполнена.
Морис Бах в широко известной книге «Архитектура операционной системы UNIX* пишет, что сокращение bss имеет происхождение от ассемблерного радиооператора для машины IBM 7090 и расшифровывается как block started by symbol (блок, начинающийся с символа). — Прим. ред. во также содержит магическое число, идентифицирующее файл как действительно выполняемый и дающее дополнительную информацию о его формате, такую как: требуется ли ему разбиение на страницы или начинается ли секция данных на краю страницы. Набор поддерживаемых магических чисел определен в каждой реализации UNIX по-своему.
Системный вызов exec выполняет следующие действия: 1. Разбирает путь к исполняемому файлу и осуществляет доступ к нему. 2. Проверяет, имеет ли вызывающий процесс полномочия на выполнение файла. 3. Читает заголовок и проверяет, что он действительно исполняемый1. 4. Если для файла установлены биты SUID или SGID, то эффективные идентификаторы UID и GID вызывающего процесса изменяет на UID и GID, соответствующие владельцу файла. 5. Копирует аргументы, передаваемые в exec, а также переменные среды в пространство ядра, после чего текущее пользовательское пространство готово к уничтожению. 6. Выделяет пространство свопинга для областей данных и стека. 7. Высвобождает старое адресное пространство и связанное с ним пространство свопинга. Если же процесс был создан при помощи vfork, производится возврат старого адресного пространства родительскому процессу. 8. Выделяет карты трансляции адресов для нового текста, данных и стека. 9. Устанавливает новое адресное пространство. Если область текста активна (какой-то другой процесс уже выполняет ту же программу), то она будет совместно использоваться с этим процессом. В других случаях пространство должно инициализироваться из выполняемого файла. Процессы в системе UNIX обычно разбиты на страницы, что означает, что каждая страница считывается в память только по мере необходимости. 10. Копирует аргументы и переменные среды обратно в новый стек приложения. 11. Сбрасывает все обработчики сигналов в действия, определенные по умолчанию, так как функции обработчиков сигналов не существуют в новой программе. Сигналы, которые были проигнорированы или заблокированы перед вызовом exec, остаются в тех же состояниях. 12. Инициализирует аппаратный контекст. При этом большинство регистров сбрасывается в 0, а указатель команд получает значение точки входа программы.
Вызов exec также может выполнять сценарии командного интерпретатора, имеющие первую строку типа #!shell_name.
Если у Вас есть подобный портал, то Вам понадобиться аудит сайтов.