Первые дела в первую очередь
Прежде чем мы углубимся в определение системного вызова Linux и изучим детали его выполнения, лучше всего начать с определения различных программных уровней типичной системы Linux.
Ядро Linux - это специализированная программа, которая загружается и работает на самом низком доступном уровне на вашем оборудовании. Его задача - организовать все, что работает на компьютере, включая обработку событий клавиатуры, диска и сети, чтобы предоставить временные интервалы для параллельного выполнения нескольких программ.
Когда ядро выполняет программу пользовательского уровня, оно виртуализирует пространство памяти, чтобы программы считали себя единственным процессом, выполняющимся в памяти. Этот защитный пузырь аппаратной и программной изоляции повышает безопасность и надежность. Непривилегированное приложение не может получить доступ к памяти, принадлежащей другим программам, и если эта программа выйдет из строя, ядро завершится, чтобы не нанести вред остальной части системы.
Преодоление барьера с помощью системных вызовов Linux
Этот уровень изоляции между непривилегированными приложениями обеспечивает отличную границу для защиты других приложений и пользователей в системе. Однако без какого-либо способа взаимодействия с другими элементами в компьютере и с внешним миром программы не смогли бы чего-либо добиться.
Чтобы облегчить взаимодействие, ядро обозначает программный шлюз, который позволяет запущенной программе запрашивать ядро действовать от ее имени. Этот интерфейс известен как системный вызов.
Поскольку Linux следует философии UNIX «все является файлом», многие функции можно выполнять, открывая и читая или записывая в файл, который может быть устройством. В Windows, например, вы можете использовать функцию CryptGenRandom для доступа к случайным байтам. Но в Linux это можно сделать, просто открыв «файл» / dev / urandom и прочитав из него байты, используя стандартные системные вызовы ввода / вывода файлов. Это важное отличие позволяет упростить интерфейс системного вызова.
Тонкая обертка для вафель
В большинстве приложений системные вызовы не выполняются напрямую к ядру. Практически все программы связаны со стандартной библиотекой C, которая предоставляет тонкую, но важную оболочку для системных вызовов Linux. Библиотека гарантирует, что аргументы функции копируются в правильные регистры процессора, а затем выдает соответствующий системный вызов Linux. Когда данные получены от вызова, оболочка интерпретирует результаты и возвращает их обратно в программу согласованным способом.
За кулисами
Каждая функция в программе, которая взаимодействует с системой, в конечном итоге переводится в системный вызов. Чтобы увидеть это в действии, давайте начнем с базового примера.
пустая функция()Это, вероятно, самая простая программа на C, которую вы когда-либо видели. Он просто получает контроль через основную точку входа, а затем выходит. Он даже не возвращает значение, поскольку main определяется как void. Сохраните файл как ctest.c и скомпилируем:
gcc ctest.c -o ctestПосле компиляции мы видим размер файла 8664 байта. Он может незначительно отличаться в вашей системе, но должен быть около 8 КБ. Это много кода для входа и выхода! Причина, по которой это 8k, в том, что включена среда выполнения libc. Даже если убрать символы, все равно чуть больше 6к.
В еще более простом примере мы можем сделать системный вызов Linux для выхода, а не зависеть от среды выполнения C, которая сделает это за нас.
void _start ()asm ("movl $ 1,% eax;"
"xorl% ebx,% ebx;"
"int $ 0x80");
Здесь мы перемещаем 1 в регистр EAX, очищаем регистр EBX (который в противном случае содержал бы возвращаемое значение), затем вызываем прерывание системного вызова Linux 0x80 (или 128 в десятичном формате). Это прерывание заставляет ядро обработать наш вызов.
Если мы скомпилируем наш новый пример под названием asmtest.c, вычеркните символы и исключите стандартную библиотеку:
gcc -s -nostdlib asmtest.c -o asmtestмы создадим двоичный файл размером менее 1 КБ (в моей системе он дает 984 байта). Большая часть этого кода - исполняемые заголовки. Теперь мы вызываем прямой системный вызов Linux.
Для всех практических целей
Почти во всех случаях вам никогда не придется выполнять прямые системные вызовы в ваших программах на C. Однако, если вы используете язык ассемблера, может возникнуть необходимость. Однако при оптимизации было бы лучше позволить функциям библиотеки C выполнять системные вызовы и иметь только ваш критически важный для производительности код, встроенный в директивы сборки.
Как программировать учебные пособия по системному вызову
- Системный вызов Exec
- Форк системного вызова
- Статистический системный вызов
Список всех системных вызовов
Если вы хотите увидеть список всех доступных системных вызовов для Linux, вы можете проверить эти справочные страницы: Полный список системных вызовов в LinuxHint.com, Filippo.io / linux-syscall-table / и / или системные вызовы.kernelgrok.ком