Путь программы до системного вызова

Когда мы пишем программу на Си и подключаем библиотеку например <unistd.h> и делаем вызов write(), то это вызов библиотечной функции Си (вопрос где она лежит в linux), в которой есть вызов системного вызова write(где он лежит в линукс), а write() где то скомпилирован в ядре ОС. А что такое syscall? Как раз он и передает номер и аргументы в ос для вызова нужного кода выполнения? Почему столько вопросов? Везде в инете написано, это интерфейс между пользовательскими программами и ядром ОС. А хочется понять, вот наша программа она дергает вот эту функцию, та в свою очередь вот эту... А там еще бывает linux-gateway это вот прослойка между этим и этим. И в итоге системный вызов это код в ядре для исполнения в ring0? Можно ли напрямую вызвать системный вызов без библиотеки?


Ответы (1 шт):

Автор решения: KoVadim

Просто так взять и позвать (через call) "ядерную" функцию нельзя - обычно они работают на другом уровне защиты. И если можно было бы просто так позвать, то система безопасности ядра была бы под угрозой. Именно syscall и решает эту проблему. А вот как именно он устроен - это другое дело.

В Linux для x86 долгое время применялось 128 прерывание (0x80). Когда срабатывает прерывание, то процессор вызывает "специальную подпрограмму", которая просто вызывает соответствующую функцию ядра, но уже в на уровне ядра. Как стает понятно, что именно вызывать? вызывающая программа оставляет в регистрах процессора данные об этом. Например, в eax хранится номер нужной функции (их можно подсмотреть в файлах /usr/include/asm*/unistd.h и они имеют вид

#define __NR_connect 203
__SYSCALL(__NR_connect, sys_connect)

файлов может быть несколько - они платформенно-зависимые)

И так как теперь процессор находится на уровне ядра, а пользовательская программа "поставлена на паузу", ядро может для начала понять, а нужно ли что то делать, может вообще лучше прибить приложение. А потом запланировать выполнение задач пользователя. И когда будут результаты, разместить в нужных регистрах и дать указание планировщику задач поставить задачу на выполнение. А для самой задачи как будто ничего и не произошло, но результаты уже есть.

Если подобных прерываний нет (какая-нибудь экзотическая платформа), то используют другие приемы. Например, какую то несуществующую команду. Процессор генерирует исключение и оно перехватывается. а дальше по известной описанной выше схеме.

Потом поняли, что некоторые функции так "невыгодно" вызывать. Например, узнать текущее время (тут нет проблем с защитой ядра, это же не открытие какого то файла). И начали придумывать, как это ускорить. В результате начали появляться новые способы, некоторые даже являются инструкциями процессора. Например, amd придумала syscall/sysret.

→ Ссылка