В вычислительной технике системный вызов (обычно сокращенно syscall ) — это программный способ, которым компьютерная программа запрашивает службу у операционной системы [a] , на которой она выполняется. Это может включать службы, связанные с оборудованием (например, доступ к жесткому диску или доступ к камере устройства), создание и выполнение новых процессов и связь с интегральными службами ядра , такими как планирование процессов . Системные вызовы обеспечивают важный интерфейс между процессом и операционной системой.
В большинстве систем системные вызовы могут быть сделаны только из процессов пользовательского пространства , в то время как в некоторых системах, например , OS/360 и ее преемниках , привилегированный системный код также выполняет системные вызовы. [1]
Для встраиваемых систем системные вызовы обычно не изменяют режим привилегий ЦП.
Архитектура большинства современных процессоров, за исключением некоторых встроенных систем, включает модель безопасности . Например, модель колец определяет несколько уровней привилегий, под которыми может выполняться программное обеспечение: программа обычно ограничена своим собственным адресным пространством , так что она не может получить доступ или изменить другие запущенные программы или саму операционную систему, и обычно не может напрямую манипулировать аппаратными устройствами (например, буфером кадров или сетевыми устройствами).
Однако многим приложениям необходим доступ к этим компонентам, поэтому системные вызовы предоставляются операционной системой для предоставления четко определенных, безопасных реализаций таких операций. Операционная система выполняется на самом высоком уровне привилегий и позволяет приложениям запрашивать службы через системные вызовы, которые часто инициируются через прерывания . Прерывание автоматически переводит ЦП в некоторый повышенный уровень привилегий, а затем передает управление ядру, которое определяет, следует ли предоставить вызывающей программе запрошенную службу. Если служба предоставлена, ядро выполняет определенный набор инструкций, над которыми вызывающая программа не имеет прямого контроля, возвращает уровень привилегий вызывающей программе, а затем возвращает управление вызывающей программе.
Обычно системы предоставляют библиотеку или API , которая находится между обычными программами и операционной системой. В Unix-подобных системах этот API обычно является частью реализации библиотеки C (libc), такой как glibc , которая предоставляет функции-оболочки для системных вызовов, часто именуемых так же, как и системные вызовы, которые они вызывают. В Windows NT этот API является частью Native API в библиотеке ntdll.dll ; это недокументированный API, используемый реализациями обычного Windows API и напрямую используемый некоторыми системными программами в Windows. Функции-оболочки библиотеки раскрывают обычное соглашение о вызове функций ( вызов подпрограммы на уровне сборки ) для использования системного вызова, а также делают системный вызов более модульным . Здесь основная функция оболочки заключается в размещении всех аргументов, которые должны быть переданы системному вызову, в соответствующих регистрах процессора (и, возможно, также в стеке вызовов ), а также в установке уникального номера системного вызова для вызова ядром. Таким образом, библиотека, существующая между ОС и приложением, повышает переносимость .
Вызов самой библиотечной функции не приводит к переключению в режим ядра и обычно является обычным вызовом подпрограммы (используя, например, инструкцию ассемблера "CALL" в некоторых архитектурах набора инструкций (ISA)). Фактический системный вызов передает управление ядру (и более зависим от реализации и платформы, чем абстрагирующий его библиотечный вызов). Например, в Unix-подобных системах fork
и execve
являются библиотечными функциями C, которые, в свою очередь, выполняют инструкции, вызывающие системные вызовы fork
и exec
. Выполнение системного вызова непосредственно в коде приложения более сложно и может потребовать использования встроенного ассемблерного кода (в C и C++ ), а также требует знания низкоуровневого двоичного интерфейса для операции системного вызова, который может со временем меняться и, таким образом, не быть частью двоичного интерфейса приложения ; библиотечные функции предназначены для абстрагирования этого.
В системах на основе экзоядра библиотека особенно важна как посредник. В экзоядрах библиотеки защищают пользовательские приложения от API ядра очень низкого уровня и предоставляют абстракции и управление ресурсами .
IBM OS/360 , DOS/360 и TSS/360 реализуют большинство системных вызовов через библиотеку макросов языка ассемблера , [b] хотя есть несколько служб с вызовом связи. Это отражает их происхождение в то время, когда программирование на языке ассемблера было более распространено, чем использование языков высокого уровня . Поэтому системные вызовы IBM не были напрямую выполнены программами на языке высокого уровня, но требовали вызываемой подпрограммы-оболочки языка ассемблера. С тех пор IBM добавила много служб, которые могут быть вызваны из языков высокого уровня, например, z/OS и z/VSE . В более позднем выпуске MVS/SP и во всех более поздних версиях MVS некоторые макросы системных вызовов генерируют Program Call (PC).
В Unix , Unix-подобных и других POSIX -совместимых операционных системах популярными системными вызовами являются open
, read
, write
, close
, wait
, exec
, fork
, exit
, и kill
. Многие современные операционные системы имеют сотни системных вызовов. Например, Linux и OpenBSD имеют более 300 различных вызовов, [2] [3] NetBSD имеет около 500, [4] FreeBSD имеет более 500, [5] Windows имеет около 2000, разделенных между системными вызовами win32k (графический) и ntdll (ядро) [6], в то время как Plan 9 имеет 51. [7]
Такие инструменты, как strace , ftrace и truss , позволяют процессу выполняться с самого начала и сообщать обо всех системных вызовах, которые вызывает процесс, или могут присоединиться к уже запущенному процессу и перехватить любой системный вызов, сделанный указанным процессом, если операция не нарушает разрешения пользователя. Эта особая способность программы обычно также реализуется с помощью системных вызовов, таких как ptrace или системных вызовов файлов в procfs .
Реализация системных вызовов требует передачи управления из пространства пользователя в пространство ядра, что подразумевает некоторую архитектурно-специфическую функцию. Типичный способ реализации этого — использование программного прерывания или ловушки . Прерывания передают управление ядру операционной системы , поэтому программному обеспечению просто нужно настроить некоторый регистр с необходимым номером системного вызова и выполнить программное прерывание.
Это единственная техника, предоставляемая для многих процессоров RISC , но архитектуры CISC , такие как x86, поддерживают дополнительные техники. Например, набор инструкций x86 содержит инструкции SYSCALL
/ SYSRET
и SYSENTER
/ SYSEXIT
(эти два механизма были независимо созданы AMD и Intel , соответственно, но по сути они делают одно и то же). Это «быстрые» инструкции передачи управления, которые предназначены для быстрой передачи управления ядру для системного вызова без накладных расходов на прерывание. [8] Linux 2.5 начал использовать это на x86 , где это было доступно; ранее он использовал INT
инструкцию, где номер системного вызова помещался в EAX
регистр до выполнения прерывания 0x80. [9] [10]
Более старый механизм — это call gate ; первоначально использовался в Multics и позже, например, см. call gate на Intel x86 . Он позволяет программе вызывать функцию ядра напрямую, используя безопасный механизм передачи управления, который операционная система настраивает заранее. Этот подход был непопулярен на x86, предположительно из-за требования far call (вызов процедуры, расположенной в другом сегменте, чем текущий сегмент кода [11] ), который использует сегментацию памяти x86 и вызванное ею отсутствие переносимости , а также существование более быстрых инструкций, упомянутых выше.
Для архитектуры IA-64EPC
используется инструкция (Enter Privileged Code). Первые восемь аргументов системного вызова передаются в регистрах, а остальные — в стеке.
В семействе мэйнфреймов IBM System/360 и его последователях инструкция Supervisor Call ( SVC ) с номером в инструкции, а не в регистре, реализует системный вызов для устаревших функций в большинстве [c] собственных операционных систем IBM и для всех системных вызовов в Linux. В более поздних версиях MVS IBM использует инструкцию Program Call (PC) для многих новых функций. В частности, PC используется, когда вызывающий может находиться в режиме Service Request Block (SRB).
Миникомпьютер PDP-11 использовал инструкции EMT , TRAP и IOT , которые, подобно IBM System/360 SVC и x86 INT , помещали код в инструкцию; они генерируют прерывания по определенным адресам, передавая управление операционной системе. 32-битный преемник серии PDP-11 VAX использовал инструкции CHMK , CHME и CHMS для выполнения системных вызовов привилегированного кода на различных уровнях; код является аргументом инструкции.
Системные вызовы можно условно разделить на шесть основных категорий: [12]
fork
в Unix-подобных системах или NtCreateProcess
в Windows NT Native API )Системные вызовы в большинстве Unix-подобных систем обрабатываются в режиме ядра , что достигается путем изменения режима выполнения процессора на более привилегированный, но переключение контекста процесса не требуется — хотя переключение контекста привилегий происходит. Аппаратное обеспечение видит мир с точки зрения режима выполнения в соответствии с регистром состояния процессора , а процессы являются абстракцией, предоставляемой операционной системой. Системный вызов обычно не требует переключения контекста на другой процесс; вместо этого он обрабатывается в контексте того процесса, который его вызвал. [13] [14]
В многопоточном процессе системные вызовы могут быть сделаны из нескольких потоков . Обработка таких вызовов зависит от конструкции ядра конкретной операционной системы и среды выполнения приложения. В следующем списке показаны типичные модели, которым следуют операционные системы: [15] [16]
{{cite web}}
: CS1 maint: числовые имена: список авторов ( ссылка )