리눅스에서 사용되는 시스템 콜(system call) 에 대한 이해와 이를 바탕으로 한 간단한 실습을 정리하고 있다. 교학사에서 나온 '커널 프로그래밍' 이라는 책을 기본으로 하고 있다.
참고로 이 책이 출간된지 4년이 흘렀다. 그래서 이 책에서 다루고 있는 내용들이 많이 달라졌을지 모르지만, 기본적인 큰 틀은 변함이 없다고 본다.
와우(wow) 리눅스 6.2(linux-2.2.14) 를 기준으로 하고 있다. 현재는 구할 길이 없는 관계로 여기서는 레드햇(redhat) 9(linux-2.4.20) 를 기준으로 한다.
들어가기 전에
여기서는 간단하게 콘솔상에서 'hello world' 라는 문자를 출력하는 함수를 커널안에 넣어볼 것이다. 그후에 상위 어플리케이션에서 호출하여 확인하는 것까지 해볼 것이다.
레드햇 9 에는 기본적으로 2.4.20 커널이 있지만, 여기서는 바닐라 커널을 사용하지 않고 따로 2.4.22 커널을 받아서 사용할 것이다.
참고로 이 문서에서는 기본적인 작업들(압축해제와 컴파일 옵션, 커널 설치등)의 설명은 하지 않을 것이다. 이에 대한 사항은 다른 문서를 참고하기 바란다.
기본 커널 디렉토리는 /usr/src/linux 이다.
시스템 콜 추가하기
include/asm-i386/unistd.h 파일에 다음을 추가한다.
#define __NR_alloc_hugepages 250 #define __NR_free_hugepages 251 #define __NR_exit_group 252 #define __NR_newsyscall 259 // 추가 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
arch/i386/kernel/entry.S 파일에 다음을 추가한다.
.long SYMBOL_NAME(sys_ni_syscall) /* sys_remap_file_pages */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_set_tid_address */ .long SYMBOL_NAME(sys_newsyscall) /* sys_set_tid_address */ // 추가 .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) .endr
kernel 디렉토리 아래에 newfile.c 라는 파일을 만들고, 다음을 입력한다.
#include <linux/unistd.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/sched.h> asmlinkage int sys_newsyscall() { printk("hello world!!\n"); return(0); }
앞에서 만든 파일을 커널에 적재하기위해 kernel 디렉토리 아래의 Makefile 에 다음과 같이 추가한다.
obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ sysctl.o acct.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o context.o newfile.o // 추가
커널컴파일 후에 새로 만든 커널이미지로 부팅한다. 이제 어플리케이션 쪽 프로그램을 만들 차례다. 파일이름은 test.c 로 한다. 내용은 아래와 같다.
#include <linux/unistd.h> #include <errno.h> _syscall0(int, newsyscall); main() { int i; i = newsyscall(); }
에러없이 컴파일 되어다면, a.out 파일이 생성되었을 것이다. 실행해보면
hello, world!!
가 출력될 것이다.