Я хотел бы понять термин «системный вызов». Мне знакомо, что системные вызовы используются для получения служб ядра из приложения пользовательского пространства.
Часть, с которой мне нужно уточнить, - это разница между «системным вызовом» и «реализацией системного вызова на C».
Вот цитата, которая смущает меня:
В Unix-подобных системах этот API обычно является частью реализации библиотеки C (libc), такой как glibc, которая предоставляет функции-оболочки для системных вызовов, часто называемых так же, как системные вызовы, которые они вызывают
Каковы «системные вызовы, которые они вызывают»? Где их источник? Могу ли я включить их непосредственно в мой код?
Является ли «системный вызов» в общем смысле просто интерфейсом, определенным POSIX, но чтобы реально увидеть реализацию, можно изучить источник C и посмотреть, как на самом деле происходит фактическое пространство пользователя для связи с ядром?
Фоновое примечание: я пытаюсь понять, в конце концов, каждая функция c заканчивается взаимодействием с устройствами из /dev
.
источник
getpid
системного вызова в ядре Linux: lxr.free-electrons.com/source/kernel/timer.c?v=2.6.35#L1337 . И это функция-обертка в стандартной библиотеке GNU C glibc-2.19: fossies.org/dox/glibc-2.19/… .Системный вызов является способом задать операционную систему (ядро) , чтобы сделать некоторые операции от имени вашей программы, что программа не может сделать сам по себе (или просто неудобно). Причина неспособности выполнить какую-либо операцию обычно заключается в том, что случайное выполнение программы может поставить под угрозу целостность системы, например, выполнение ввода-вывода (непосредственно в ОЗУ, перезапись чего-либо).
POSIX определяет интерфейс для программ, определенные функции, которые ваша программа может вызывать. Некоторые из них переводят более или менее непосредственно на системные вызовы, другие требуют более тщательной проработки. Это среда выполнения для вашего языка, например, библиотеки C, которая отвечает за предложение интерфейса POSIX, а также за упаковку аргументов и получение результатов для передачи вызывающей стороне.
Системы Unixy предлагают интерфейсы POSIX более или менее напрямую, как системные вызовы. Обычно есть способ вызывать системные вызовы напрямую, ищите
syscall(2)
подробности о том, как использовать эту возможность в Linux.источник
strlen
,strcpy
,sqrt
, иqsort
) может быть и , вероятно , находится в пространстве пользователя, загружается из библиотеки. (В основном libc; математические функции, подобныеsqrt
и тригонометрические и гиперболические функции, вероятно, находятся в libm, математической библиотеке.)… (Продолжение)fork
,kill
илиopen
функцию, так как они требуют доступа к пространству ядра операционной системы в памяти (например, таблицы процесса) или привилегированные команды (например, I / O). Поэтому код, выполняющий эти функции, должен находиться в ядре операционной системы; следовательно, системные функции или системные вызовы.Конечно, давайте сделаем «как много направлений мы можем посмотреть на этого слона»? вещь.
Фактический системный вызов в вашей встроенной программе - машинная инструкция, которая запускает повышение привилегий в режиме ядра, а в самом ядре это код, который эта инструкция вызывает. Код libc (и каждая языковая среда выполнения) настраивает машинные регистры и параметры хранения, где код ядра ожидает их найти, что может быть странным местом из-за ограничений на эту машинную инструкцию.
Когда-то в самом коде ОС, есть немного раскручивания зеркального отображения машинно-специфических вещей, которые выполняла среда выполнения пользователя, а затем совершенно обычный вызов подпрограммы.
Если вы хотите увидеть, как это работает в полномасштабную ОС, вытаскивать исходный код ядра (
git clone https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/
) и сделать , напримерgit grep -i system\ call
. Потяните источник glibc и сделайте то же самое.источник
В Linux, по крайней мере, механизм системных вызовов работает в большинстве архитектур, помещая некоторые специально отформатированные данные (обычно это своего рода структура) в некоторые регистры или предопределенные адреса памяти.
Однако проблема заключается в том, чтобы заставить процессор переключаться в пространство ядра, чтобы он мог запустить привилегированный код ядра для обслуживания вызова. Это делается путем принудительной обработки какой-либо ошибки (ошибка деления на 0, неопределенного переполнения или ошибки сегмента и т. Д.), Что заставляет ядро взять на себя выполнение для обработки ошибки.
Обычно ядро обрабатывает ошибки, либо убивая вызывающий процесс, либо запуская пользовательский обработчик. Однако в случае системного вызова он вместо этого проверит предопределенные регистры и области памяти, и если они содержат запрос системного вызова, он выполнит это, используя данные, предоставленные пользовательским процессом в структуре в памяти. Обычно это нужно делать с какой-то специально созданной вручную сборкой, и чтобы упростить использование системного вызова для пользователя, системная библиотека C должна обернуть его как функцию. Для интерфейса более низкого уровня, пожалуйста, смотрите http://man7.org/linux/man-pages/man2/syscall.2.html для получения некоторой информации о том, как работают системные вызовы и как вы можете тогда вызывать без оболочки C.
Это слишком упрощено, это не так во всех архитектурах (в mips есть специальная инструкция syscall) и не обязательно работает одинаково на всех ОС. Тем не менее, если у вас есть какие-либо комментарии или вопросы, пожалуйста, задавайте.
Исправлено: Обратите внимание, что относительно вашего комментария о вещах в / dev / это на самом деле интерфейс более высокого уровня с ядром, а не нижний. Эти устройства фактически используют около 4 системных вызовов. Запись для них аналогична системному вызову записи, чтению системного вызова чтения, открытию / закрытию их, эквивалентным системным вызовам open и close, и запуску ioctl вызывает специальный системный вызов ioctl, который сам по себе является интерфейсом для доступа к одному из многих системных ioctl. вызовы (специальные, обычно вызовы, специфичные для устройства, с слишком узким использованием, чтобы написать для них целый системный вызов).
источник
С каждым системным вызовом связано целое число. Это целое число является функцией возвращаемого значения системного вызова, количества аргументов системного вызова и типа аргументов. Этот номер системного вызова является не чем иным, как смещением в глобальный вектор системных вызовов, этот вектор, который доступен только в привилегированном режиме, содержит указатель на соответствующие обработчики. В процессе вызова системного вызова будет сгенерировано программное прерывание (прерывание прерывания), следовательно, будет запущен обработчик прерываний, который определяет, какой системный вызов следует вызывать. Затем ядро скопирует аргументы системного вызова, переданного пользователем, находящимся в стеке, в регистры процессора, и по завершении запрошенной услуги данные будут скопированы обратно в стек из регистров процессора. Это одна из причин, по которой аргументы системных вызовов ограничены,
источник