The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Создание нового системного вызова в ОС Linux (sysctl lib linux assembler gcc)


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: sysctl, lib, linux, assembler, gcc,  (найти похожие документы)
From: uncle Bob <ubob at mail.ru> Newsgroups: http://www.lowlevel.ru Date: Mon, 24 May 2004 14:31:37 +0000 (UTC) Subject: Создание нового системного вызова в ОС Linux Оригинал: http://www.lowlevel.ru/articles/new_call.htm Создание нового системного вызова в ОС Linux Автор: uncle Bob <ubob at mail.ru> Дата: 11.01.2004 Раздел: Низкоуровневое программирование в Linux В статье рассмотрена методика добавления в состав ядра ОС Linux нового системного вызова. Общий механизм выполнения системных вызовов рассмотрен здесь: http://zaya.spb.ru/intercept_lnx.txt Задача - добавить в состав ядра версии 2.4.23 новый системный вызов, который будет выполнять следующие действия: - принимает от приложения пользователя указатель на строку ASCII-символов с кодами 32 - 127 и длину этой строки в байтах; - преобразует символы строки, находящиеся в диапазоне 0x61 - 0x7A (a - z) в верхний регистр и возвращает эту строку обратно; Для решения этой задачи необходимо добавить запись о новом системном вызове в таблицу системных вызовов ядра sys_call_table. Эта таблица находится в файле /usr/src/linux/arch/i386/kernel/entry.S. Новый вызов добавляем в самый конец таблицы: ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ .long SYMBOL_NAME(sys_exit) /* 1 */ . . . .long SYMBOL_NAME(sys_upcase) /* новый системный вызов, 259 */ Новый системный вызов назовем sys_upcase. Его порядковый номер (для ядра версии 2.4.23) равен 259. Теперь необходимо добавить запись о новом вызове в файл /usr/src/linux/include/asm-i386/unistd.h: #define __NR_upcase 259 и в файл /usr/include/bits/syscall.h: #define SYS_upcase __NR_upcase Теперь осталось написать код, реализующий новый системный вызов. Вот как он выглядит: asmlinkage int sys_upcase(char *src, char *dst, int lenght) { int i = 0; char *tmp_buff; tmp_buff = (char *)kmalloc(lenght, GFP_KERNEL); memset(tmp_buff, 0, lenght); copy_from_user(tmp_buff, src, lenght); printk(KERN_INFO "%s\n", tmp_buff); printk(KERN_INFO "%d\n", lenght); for(; i < lenght; i++) if((tmp_buff[i] >= 0x61) && (tmp_buff[i] <= 0x7A)) tmp_buff[i] -= 0x20; printk(KERN_INFO "%s (after)\n", tmp_buff); copy_to_user(dst, tmp_buff, lenght); kfree(tmp_buff); return lenght; } Системный вызов принимает три параметра - указатель на строку, которую необходимо преобразовать, длину этой строки и указатель на область памяти, куда необходимо поместить результат. Функция copy_from_user() копирует исходную строку из адресного пространства пользователя в адресное пространство ядра, а затем в цикле производится смена регистра символов, находящихся в диапазоне 0x61 - 0x7A. Результат (преобразованная строка) копируется из адресного пространства ядра в пространство пользователя при помощи функции copy_to_user(). Эту функцию поместим в файл /usr/src/linux/fs/open.c, хотя место размещения особой роли не играет. После внесения всех изменений в ядро необходимо перекомпилировать. Для того, чтобы процесс пользователя мог обращаться к новому системному вызову, создадим в каталоге /usr/include заголовочный файл upcase.h следующего содержания: /* Заголовочный файл upcase.h */ #ifndef _UPCASE_H #define _UPCASE_H 1 #include unistd.h> static inline _syscall3(int,upcase,char *,src,char *,dst,int,lenght) #endif Макрос _syscall3 определен в файле usr/src/linux/include/asm-i386/unistd.h: #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ type name(type1 arg1,type2 arg2,type3 arg3) \ { \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ "d" ((long)(arg3))); \ __syscall_return(type,__res); \ } Таким образом, системный вызов sys_upcase будет выполняться стандартным для всех системных вызовов способом: сначала в регистры процессора загружаются параметры вызова, а затем следует вызов прерывания int 0x80. __NR_##name будет преобразована в номер системного вызова. Рассмотрим пример обращения к новому системному вызову из приложения пользователя: #include #include int main() { char *src = "ab12cd34ef"; // эту строку будем преобразовывать char *dst; // сюда будет помещен результат int lenght = 0, rez = 0; lenght = strlen(src); // определяем длину строки dst = (char *)malloc(lenght); memset(dst, 0, lenght); Выведем для контроля информацию: printf("Lenght - %d\n", lenght); printf("Source - %s\n", src); printf("Destin - %s\n", dst); Выполняем обращение к новому системному вызову sys_upcase для преобразования символов исходной строки в верхний регистр: rez = upcase(src, dst, lenght); Отобразим результаты: printf("Source - %s\n", src); printf("Destin - %s\n", dst); printf("rez - %d\n", rez); return 0; } Для получения исполняемого модуля создадим Makefile: INCDIR = /usr/src/linux/include .PHONY = clean new_call: new_call.o gcc -I$(INCDIR) $^ -o $@ %.o: %.c gcc -I$(INCDIR) -c $^ clean: rm -f *.o rm -f ./new_call

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

 Добавить комментарий
Имя:
E-Mail:
Заголовок:
Текст:




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру