Минимальной единицей исполнения в UNIX является процесс. Процесс (в простейшем определении) это последовательность операций выполнения программы. Но кроме машинных инструкций еще существуют данные и стек, причем каждый процесс выполняется в собственном адресном пространстве. Поэтому, технически более правильно говорить о процессе, как экземпляре выполняемой программы.
Каждый процесс в UNIX обладает собственным адресным пространством, набором регистров процессора и стеком, - все они определяют состояние процессора, иначе называемое контекстом. В адресном пространстве расположены: сегмент [111] исполняемого кода (в терминологии UNIX называемый «текстом» - text), сегмент данных (BSS - сокращение, позаимствованное из ассемблера для компьютера IBM 7090, расшифровывающиеся как "
Названия секций “text” и “BBS” благополучно перекочевали в среду Windows. Убедиться в этом можно, запустив утилиту dumpbin (входит в SDK, поставляемый с любым Windows-компилятором), например, таким образом:
Процессы UNIX могут исполняться в одном из двух режимов - режиме задачи и режиме ядра. Для обеспечения безопасности каждым из режимов используется свой собственный стек. Возникает вопрос, - каким образом системная функция получает аргументы, если они остаются в стеке задачи?
Понять это можно, разобравшись в механизме переключения из режима задачи в режим ядра. В UNIX для перехода в привилегированный режим используются прерывания. Инструкция, вызывающая прерывание, автоматически переводит процессор в привилегированный режим и передает управление подпрограмме обработки прерывания. Существует специальная таблица прерываний (доступная только ядру операционной системы) в которой индекс каждой ячейки численно равен номеру прерывания и содержит адрес, на который будет передано управление в случае возникновения данного прерывания. Более подробно о прерываниях можно прочитать в любой толковой книге по ассемблеру и технической документации процессора.
В операционной системе LINUX для вызова системных функций используется прерывание 0x80, а в операционных системах, совместимых с System V для той же цели необходимо передать управление по фиксированному адресу 0007:00000000 (сегмент семь, смещение ноль). Номер вызываемой функции и передаваемые ей аргументы задаются в регистрах (в LIUX) или заталкиваются в стек (в системах, совместимых с System V).
Таким образом, использование прерываний (или фиксированного адреса) позволяет пользовательской задаче передать управление только на предусмотренные ядром подпрограммы, а не произвольный адрес памяти. Однако стек ядра прикладному коду не доступен, и передать аргументы функции обычным путем невозможно. Тем не менее, ядру доступно пространство памяти всех задач и оно в состоянии «вытащить» требуемые параметры самостоятельно. Конкретная реализация зависит от выбранной аппаратной платформы и поэтому не будет рассмотрена. Достаточно понять - прикладные программы не могут пагубно воздействовать на ядро (конечно при отсутствии в нем ошибок реализации).
В операционных системах наподобие MS-DOS (и первых версиях UNIX) существовала возможность обращаться с оборудованием в обход операционной системы, манипулируя непосредственно с портами ввода-вывода [112]. Современные процессоры при попытке пользовательского кода обратиться к порту, генерируют исключение, передавая управление операционной системе, предоставляя ей возможность самой расправиться со злоумышленником. В результате, доступ может быть отвергнут, а приложение, нарушившие субординацию - закрыто, или же ядро может эмулировать чтение (запись) в порт, не выполняя ее на самом деле.