Доступ к системным вызовам из пространства пользователя
Доступ к системным вызовам из пространства пользователя
В большинстве случаев системные вызовы поддерживаются библиотекой функций языка С. Пользовательские приложения могут получать прототипы функций из стандартных заголовочных файлов и компоновать программы с библиотекой С для использования вашего системного вызова (или библиотечной функции, которая вызывает ваш системный вызов). Однако если вы только что написали системный вызов, то маловероятно, что библиотека 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;
}