Thursday, January 22, 2009

How to add system call in Linux Kernel 2.4.22


--------------------------------------------------------------------------------


First, search for the include file: "/usr/src/linux/include/asm/unistd.h" and add the following:

#define __NR_test 259

under the line

#define __NR_set_tid_address 258

After that, search for the source file: "/usr/src/linux/kernel/sys.c" and add a function as following:

asmlinkage int sys_test(int a)

{

return a*2;

}

.Note that this function is just a test, and it will return twice of the input value (int a). Now, it comes to a difficult step, goto a source file: "/usr/src/linux/arch/i386/kernel/entry.S". Search for the last few lines, it should be like this:

.long SYMBOL_NAME(sys_lookup_dcookie)

.long SYMBOL_NAME(sys_ni_syscall)

.long SYMBOL_NAME(sys_ni_syscall) /* 255 sys_epoll_ctl */

.long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_wait */

.long SYMBOL_NAME(sys_ni_syscall) /* sys_remap_file_pages */

.long SYMBOL_NAME(sys_set_tid_address)



.rept NR_syscalls-(.-sys_call_table)/4

.long SYMBOL_NAME(sys_ni_syscall)

.endr

You should change the code to:

.long SYMBOL_NAME(sys_lookup_dcookie)

.long SYMBOL_NAME(sys_ni_syscall)

.long SYMBOL_NAME(sys_ni_syscall) /* 255 sys_epoll_ctl */

.long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_wait */

.long SYMBOL_NAME(sys_ni_syscall) /* sys_remap_file_pages */

.long SYMBOL_NAME(sys_set_tid_address)

.long SYMBOL_NAME(sys_test)



.rept NR_syscalls-(.-sys_call_table)/4

.long SYMBOL_NAME(sys_ni_syscall)

.endr


Another thing need to note is the last few lines, it defines the remaining
space for the system call symbol table. "NR_syscalls" is the
maximum system call.

.rept NR_syscalls-(.-sys_call_table)/4

.long SYMBOL_NAME(sys_ni_syscall)

.endr

OK, all the modification has been done. The next step is to recompile
the kernel. Follow the step in the note in here

After the compilation of kernel, you can use the following code to build a user-level process, which make use of the new system call:

/*

* use_syscall.c

*

*/

#include < stdio.h >

#include < stdlib.h >

#include < linux/unistd.h >

#include < errno.h >



static inline _syscall1(int, test, int, a)



void main()

{

printf("Return value: %d\n", test(5));

}

IMPORTANT: you will experience a series compiling error in this stage. It is because Rehat has done some nasty things:

"#include < linux/unistd.h >" means to include the file "/usr/include/linux/unistd.h".
The "/usr/include/linux/unistd.h", on the other hand, includes another file "/usr/include/asm/unistd.h".
However, in Redhat, "/usr/src/linux/include/asm/unistd.h" != "/usr/include/linux/asm/unistd.h".
Again, we use sysmbolic link to remedy this problem.
mv /usr/include/asm /usr/include/asm.old
ln -s /usr/src/linux/include/asm /usr/include/asm

No comments: