Доступ к системным вызовам из пространства пользователя

Доступ к системным вызовам из пространства пользователя

В большинстве случаев системные вызовы поддерживаются библиотекой функций языка С. Пользовательские приложения могут получать прототипы функций из стандартных заголовочных файлов и компоновать программы с библиотекой С для использования вашего системного вызова (или библиотечной функции, которая вызывает ваш системный вызов). Однако если вы только что написали системный вызов, то маловероятно, что библиотека glibc уже его поддерживает!

К счастью, ОС Linux предоставляет набор макросов-оболочек для доступа к системным вызовам. Они позволяют установить содержимое регистров и выполнить машинную инструкцию int $0x80. Эти макросы имеют имя syscalln(), где n — число от нуля до шести. Это число соответствует числу параметров, которые должны передаваться в системный вызов, так как макросу необходима информация о том, сколько ожидается параметров, и соответственно, нужно записать эти параметры в регистры процессора. Например, рассмотрим системный вызов open(), который определен следующим образом.

long open(const char *filename, int flags, int mode)

Макрос для вызова этой системной функции будет выглядеть так.

#define NR_open 5

_syscall3(long, NR_open, const char*, filename, int, flags, int, mode);

После этого приложение может просто вызывать функцию open().

Каждый макрос принимает 2 + 2*n параметров. Первый параметр соответствует типу возвращаемого значения системного вызова. Второй параметр — имя системного вызова. После этого следуют тип и имя каждого параметра в том же порядке, что и у системного вызова. Постоянная NR_open, которая определена в файле <asm/unistd.h>, — это номер системного вызова. В функцию на языке программирования С такой вызов превращается с помощью вставок на языке ассемблера, которые выполняют рассмотренные в предыдущем разделе шаги. Значения аргументов помещаются в соответствующие регистры, и выполняется программное прерывание, которое перехватывается в режиме ядра. Вставка данного макроса в приложение — это все, что необходимо для выполнения системного вызова open().

Напишем макрос, который позволяет вызвать нашу замечательную системную функцию, и соответствующий код, который позволяет этот вызов протестировать.

#define __NR_foo 283

__syscall0()(long, foo)

int main() {

 long stack_size;

stack_size = foo();

 printf("Размер стека ядра равен %ld " , stack_size);

 return 0;

}