Application 과 커널 간의 인자를 어떻게 전달하는지를 살펴보기 위한 간단한 시스템 콜을 작성하고 있다.
시스템 콜 작성
먼저 unistd.h 파일에 다음을 추가한다.
#define __NR_show_mult 261
entry.S 파일에 다음을 추가한다.
.long SYMBOL_NAME(sys_ni_syscall) /* sys_set_tid_address */ .long SYMBOL_NAME(sys_newsyscall) /* sys_set_tid_address */ .long SYMBOL_NAME(sys_gettaskinfo) /* sys_set_tid_address */ .long SYMBOL_NAME(sys_show_mult) /* sys_set_tid_address */ // 추가 .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) .endr
이제 시스템 콜 함수를 작성한다. 파일이름은 newfile2.c 이고, kernel 디렉토리 아래에 둔다.
#include <linux/unistd.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/sched.h> #include <asm-i386/uaccess.h> asmlinkage int sys_show_mult(int x, int y, int *res) { int error, compute; error = verify_area(VERIFY_WRITE, res, sizeof(int)); if(error) return error; compute = x*y; put_user(compute, res); return(0); }
Makefile 에 newfile2.o 를 추가한 후, 커널 컴파일을 해서 새로운 커널 이미지로 부팅한다.
Application 작성
파일 이름은 test2.c 이고 /root 아래에 둔다.
#include <linux/unistd.h> #include <errno.h> _syscall3(int, show_mult, int, x, int, y, int *, result); main() { int mult_ret = 0; int x=2; int y=5; printf("%d * %d = %d\n", x,y,mult_ret); show_mult(x,y,&mult_ret); printf("%d * %d = %d\n", x,y,mult_ret); }
/usr/include/asm/unistd.h 파일에 다음을 추가한다.
#define __NR_show_mult 261
마지막으로 컴파일을 한다. 그리고 나서 a.out 을 실행한다.
2 * 5 = 0 2 * 5 = 10
위와 같은 결과가 나온다면 성공이다.
동작 설명
unistd.h 파일을 보면, _syscall 에 대한 여러가지 함수들이 선언되어 있다. 앞에서는 거의 _syscall0 를 사용했었다. 이 함수는 인자가 없는 시스템 콜에 사용되었다. 여기서 사용된 _syscall3 의 경우, 총 8개의 인자를 받는다. 사용자 영역에서 x,y, &mult_ret 인자를 커널로 넘겼다.
put_user() 를 사용하기 전에 res 라는 사용자 공간에 쓰기가 가능한지 확인하기 위해 verify_area() 라는 커널 내부 함수를 사용하였다.