На вопрос уже есть отличные ответы, но я думаю, что могу что-то добавить (один сегмент из ostep , которого нет в других ответах
Иногда системный вызов и вызов функции имеют одну и ту же подпись, например, open()
:
open()
-системный вызов
--- ~/Documents » man open(2)
OPEN(2) Linux Programmer's Manual OPEN(2)
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
...
open()
-функция вызова
$ man open(3)
--- ~/Documents »
OPEN(3P) POSIX Programmer's Manual OPEN(3P)
...
int open(const char *path, int oflag, ...);
...
Форма цитирования OSTEP
Вас может удивить, почему вызов системного вызова , такого как open()
или read()
, выглядит точно так же, как обычный вызов процедуры в C; то есть, если он выглядит как вызов процедуры , как система узнает, что это системный вызов , и делает все правильно? Простая причина: это вызов процедуры , но скрытый внутри этого вызова процедуры является знаменитой инструкцией прерывания . Более конкретно, когда вы вызываете open()
(например), вы выполняете вызов процедуры в библиотеке C. При этом, будь то для open()
или для любых других системных вызовов , библиотека использует согласованное соглашение о вызовах с ядром для размещения аргументов для открытия в известных местах (например, на стек , или в определенных регистрах ), помещает номер системного вызова в хорошо известное место (опять же, в стек *) 1050 * или регистр ), а затем выполняет вышеупомянутую команду прерывания . Код в библиотеке после trap распаковывает возвращаемые значения и возвращает управление программе, которая выполнила системный вызов . Таким образом, части библиотеки C, которые выполняют системные вызовы , кодируются в сборке вручную, так как они должны тщательно следовать соглашению, чтобы правильно обрабатывать аргументы и возвращать значения, а также выполнять аппаратно-зависимые инструкция ловушки . И теперь вы знаете, почему лично вам не нужно писать ассемблерный код для trap в ОС; кто-то уже написал эту сборку для вас.