Tuesday, October 23, 2012

Находим код системного вызова mkdir

Еще в первый год моего знакомства с Ubuntu, мне стало интересно, как же работает ядро этой ОС. Я решил со всей серъезностью во всем разобратся, скачал 80-мегабайтовый архив исходников, и… всё! Я не знал ни с чего начать, ни чем закончить. Открывал поочереди случайные файлы и тут же терялся. Думаю такое случалось с каждым бывалым линуксоидом. Сейчас же я набрался опыта и хотел бы им поделиться.

В этой статье я раскажу, как я искал код системного вызова mkdir.

Начнем с того, что функция mkdir определена в sys/stat.h. Прототип выглядит следующим образом:

/* Create a new directory named PATH, with permission bits MODE.  */
extern int mkdir (__const char *__path, __mode_t __mode)
     __THROW __nonnull ((1));

Этот заголовочный файл является частью стандарта POSIX. Linux является почти полностью POSIX-совместим, а значит должен реализовывать mkdir именно с такой сигнатурой.

Но даже зная сигнатуру, найти собственно код системного вызова вовсе не просто…

И в правду ack "int mkdir" вернет:

security/inode.c
103:static int mkdir(struct inode *dir, struct dentry *dentry, int mode)

tools/perf/util/util.c
4:int mkdir_p(char *path, mode_t mode)

tools/perf/util/util.h
259:int mkdir_p(char *path, mode_t mode);

Понятно, что ни одна сигнатура полностью не совпадает. Где же находится реализация функции mkdir? Каков алгоритм нахождения реализаций системных вызовов в ядре Linux?

Системные вызовы работают не так, как обычные функции. Точне функциями они вовсе не являются. Для выполнений системного вызова нужно немного ассемблерного кода. По большому счету, в регистр EAX кладется номер системного вызова (кстати говоря, к системным вызовам обращаются по номеру, а не по адресу), в остальные регистры кладутся аргументы: первый в EBX, второй в ECX, третий в EDX, четвертый в ESX, пятый в EDI. Кстати, именно по этому системный вызов не может иметь более 5 аргументов. После расположения всех нужных значений программа, которыя хочет сделать системный вызов, выполняет 128-е прерывание (на асемблере: int 0x80). Прерывание, переводит процессор в режим ядра и передает управление по заранее оговореному с ядром адресу. Как видим, системные вызовы работают на более низком уровне, чем С-функции.

Номер любого системного вызова можно найти в usr/include/asm*/unistd.h:
#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Тобиш системный вызов mkdir имеет номер 83. 

Если вы програмировали в user space под Linux, вы скорее всего знаете, что как правило для выполнения системных вызовов таки используются C-функции. Откуда они берутся? Те функции — это просто обертки из библиотеки GNU libc. Каждому системному вызову соответствует функция-обертка. Сами же функции делают все те же прерывания.

Read more: Habrahabr.ru
QR: Inline image 1

Posted via email from Jasper-Net