≡ 리눅스/Ubuntu

우분투 14.04에서 시스템 호출 구현하기


오랜만에 리눅스 카테고리에 포스팅합니다.

학부 때 시스템 프로그래밍 이후에 리눅스를 쓸 일이 없을 거라고 생각했는데, 이번 학기에 관련 수업을 들어서 다시 사용하게 되었네요.


이번 포스팅에서는 우분투 환경에서의 시스템 호출을 구현해보도록 하겠습니다.

(사실 포스팅이 귀찮아서 안 하는데 인터넷에 있는 정보가 대부분 예전 정보라 공부도 할 겸 정리용 포스팅입니다.)


본 포스팅에서 사용한 시스템 환경입니다.

- Ubuntu 14.04.4 LTS (64 bit)

- Oracle VM VirtualBox 5.0.16

※ VMware Player 테스트에서는 커널 빌드후 부팅 불가능 문제가 있었음.


우분투 설치에 대해서는 이전에 포스팅한 #Step 01. 리눅스 설치 포스팅을 참고하세요.

VirtualBox 셋팅 환경은 다음과 같습니다.

이 부분은 여러분의 PC 환경에 따라 알아서 설정하시면 됩니다.


본 포스팅에서는 VIM 설치가 되어있다는 가정하에 설명합니다.

VIM 설치는 이전에 포스팅한 #Step 03. VIM 설치하고 설정하기 포스팅을 참고하세요.



이제 본격적으로 시스템 호출을 구현하도록 하겠습니다.

이 포스팅을 보시는 분들이라면 당연히 시스템 호출에 대해 알고 있는 걸로 알겠습니다.




[ 0 ] 들어가기 앞서...


다음과 같은 과정으로 시스템 호출을 구현합니다.


1.) 새로운 커널 다운로드

2.) 다운로드 받은 커널 압축해제

3.) 시스템 호출 함수 정의

4.) 시스템 호출 번호 등록

5.) 시스템 호출 함수 등록

6.) 커널 컴파일 및 설치

7.) 시스템 호출 테스트



[ 1 ] 커널 다운로드


우분투를 실행시키고, FireFox를 실행시켜 http://www.kernel.org 에 접속합니다.

Least Stable Kernel 4.5 버튼을 눌러 Kernel 4.5를 다운로드합니다.



[ 2 ] 커널 압축 풀기


터미널을 실행시켜, 다운로드 받은 커널이 있는 Downloads 폴더로 들어갑니다.

$ ls

확인하시고 압축 풀기에 앞서 이제 계속 루트 권한을 써야 하니

$ sudo su

루트 권한으로 작업합니다.

* 루트 권한으로 작업할 때에는 주의 하셔야 합니다.


이제 커널 압축파일을 /usr/src에 풀어보겠습니다.

$ tar -xvf linux-4.5.tar.xz -C/usr/src

이제 /usr/src로 이동하여 압축 푼 커널 디렉터리가 있나 확인해봅니다.

$ cd /usr/src
$ ls



[ 3 ] 시스템 호출 함수 정의


/usr/src/linux-4.5/kernel로 이동합니다.

$ cd /usr/src/linux-4.5/kernel/

여기에서 새로운 시스템 호출 함수를 정의합니다.

$ vi mincall.c


mincall.c에 아래 코드를 입력하여 새로운 시스템 호출 함수를 정의합니다.

#include <linux/kernel.h>

/*
    인자를 가지는 시스템 호출은 sys_mincall(int a ...)
    방식으로 코딩하시면 됩니다.
*/
asmlinkage long sys_mincall(void) {
    printk("System Call Example!\n");

    return 0;
}

저장 후 vi 에디터를 종료합니다.


Makefile을 엽니다.

$ vi Makefile

#
# Makefile for the linux kernel.
#

obj-y     = fork.o exec_domain.o panic.o \
            cpu.o exit.o softirq.o resource.o \
            ...
            async.o range.o smpboot.o mincall.o

obj-$(CONFIG_MULTIUSER) += groubs.o
...

obj-y 마지막 부분에 mincall.o 를 추가합니다.

마찬가지로 저장 후 vi 에디터를 종료합니다.



[ 4 ] 시스템 호출 번호 등록


/usr/src/linux-4.5/arch/x86/entry/syscalls로 이동합니다.

$ cd /usr/src/linux-4.5/arch/x86/entry/syscalls

여기에서 보면 syscall_32.tbl, syscall_64tbl 파일이 있습니다.

각각 32비트, 64비트 파일입니다. 이 예제에서는 64비트를 사용하니 syscall_64.tbl을 수정합니다.

$ vi syscall_64.tbl

파일을 열고 쭉 내리다 보면 for native 64-bit operation 위에 새로운 번호를 등록하고, [ 3 ]에서 정의한 함수를 적습니다.

시스콜 번호는 기존의 마지막 번호 +1로 적습니다.

마지막 항목에는 sys_함수명을 적습니다.


32비트의 경우 맨 마지막에 추가하시면 됩니다.

326        ...
327        common        mincall        sys_mincall
#
# x32-specific system call number start at 512 to avoid cache impact
# for native 64-bit operation.
#
512        ...

저장 후 vi 에디터를 종료합니다.



[ 5 ] 시스템 호출 함수 등록


/usr/src/linux-4.5/include/linux로 이동합니다.

$ cd /usr/src/linux-4.5/include/linux

시스템 호출 함수의 헤더 파일인 syscalls.h 파일을 수정합니다.

$ vi syscalls.h

이제 syscalls.h 파일 마지막 부분인 #endif 바로 윗줄에 시스템 호출 함수를 적습니다.

...
asmlinkage long sys_mincall(void);
#endif

저장 후 vi 에디터를 종료합니다.


이로써 시스템 호출 정의와 등록은 끝났습니다.

이제 커널을 컴파일 하고, 설치하여 적용해 봅시다.



[ 6 ] 커널 컴파일 및 빌드


우선적으로 다음 커맨드를 사용하여 최신 상태로 업데이트 하고, 패키지를 설치한다.

$ apt-get install gcc
$ apt-get install libncurses5-dev
$ apt-get update
$ apt-get upgrade

먼저, 커널 경로로 이동한다.

$ cd /usr/src/linux-4.5

그리고 커널 설정은 기본 설정으로 셋팅하여 컴파일 하겠다.

$ make defconfig


자 이제 컴파일 하기 전에, 멀티코어 사용자라면 다음 커맨드를 통해서 코어수를 확인후 작업하자.

작업이 더 빨라진다.


$ cat /proc/cpuinfo

그리고 나오는 화면은 다음과 같다.

...
cpu cores : 4
...

이 항목이 컴퓨터의 코어수 이다.

(가상머신의 경우 셋팅값에 따라 다를수 있다.)


이제 Make -j 코어수 옵션을 사용하여 컴파일 하자.

필자의 가상머신의 코어수는 4개라 다음과 같이 사용하였다.

$ make -j4

이제 기다리자....

기다리자...


정상적으로 작업이 완료되면 아래와 같이 나온다.


자 이제 커널을 설치하자.



[ 7 ] 커널 설치



$ make modules_install install

위 명령어를 입력하여 설치한다.


설치가 완료되면 위 사진처럼 뜬다.


재부팅 전, 현재 커널 버전을 확인한다.

$ uname -r

그리고 이제 아래 명령어를 이용하여 재부팅 한다.

$ shutdown -r now



[ 8 ] 시스템 호출 테스트


$ uname -r

재부팅이 완료되면 마찬가지로 위 명령어를 입력하여 커널 버전을 확인한다.

정상적으로 설치가 완료되었다면 4.5.0으로 나온다.



이제, 앞에서 구현한 시스템 호출을 프로그램상에서 호출하여 테스트 해봅시다.


$ vi syscall_test.c
#include <stdio.h>
#include <sys/syscall.h>

int main(void) {
    /* 앞서 등록한 시스템 호출 번호를 적습니다.
       a에는 327번 시스템 호출의 반환값이 저장됩니다.

       만약 인자를 가지는 시스템 호출의 경우에는
       syscall(327, argument) 방식으로 호출하면 됩니다. */
    long int a = syscall(327);

    // 327 syscall의 반환값은 printf()를 이용하여 출력합니다.
    printf("System Call returned %ld\n", a);

    return 0;
}

위 코드를 입력하고 vi 에디터를 종료 합니다.

$ gcc syscall_test.c

gcc를 이용하여 컴파일및 빌드 합니다.


$ ./a.out

파일을 실행하여 시스템 호출이 정상적으로 이루어졌는지 확인합니다.

예제를 그대로 따라 하셨다면, 0이 리턴되어야 정상입니다.



시스템 호출에 작성했던 printk( )부분은 다음 명령어를 사용하여 확인합니다.

$ dmesg

그러면 "System Call Example!" 이란 메시지를 보실 수 있습니다.




이제 모든 작업이 완료되었습니다.

수고하셨습니다. ^^




본 포스팅은 아래 글들을 참고로 작성되었습니다.

만약 잘못된 내용이 있다면 댓글로 알려주시면 감사하겠습니다.


https://tssurya.wordpress.com/2014/08/19/adding-a-hello-world-system-call-to-linux-kernel-3-16-0/

http://stackoverflow.com/questions/17652555/where-is-the-system-call-table-in-linux-kernel



신고
  1. 수정/삭제 답글

    비밀댓글입니다

  2. 송진욱 수정/삭제 답글

    위에 댓글 달은 사람인데.. 비밀번호를 잘 못입력해서요.. 답글 여기에 달아 주실수 있나요?

    • min0628 수정/삭제

      예제로 돌린 시스템 호출 반환값이 0이라서요..

  3. sjw 수정/삭제 답글

    그러면 어떻게 해야지 되는지 알 수 있을까요?
    #include <stdio.h>
    #include <linux/kernel.h>
    #include <sys/syscall.h>
    #include <unistd.h>
    int main(){
    long int amma = syscall(354);
    printf(“System call sys_hello returned %ld\n”, amma);
    return 0; }
    여기서 무엇을 수정해야지 returned -1이 나오지 않을까요?

    • min0628 수정/삭제

      그부분 새로 등록한 시스템 호출을 호출해서 반환값을 받는 부분입니다.
      일반적으로 시스템 호출 실패시 반환값이 음수이니 시스템 호출부분을 다시 한번 확인해보세요.

  4. isk00286 수정/삭제 답글

    재부팅을 하니까 busy box랑 initramfs 뜨면서 우분투로 들어가지지가 않습니다.
    해결방법이 있나요? 똑같이 따라했고 mincall 이름만 mysyscall로 바꿨습니다.

    • min0628 수정/삭제

      음...그러면 일단 다른 커널로 부팅해보세요.

  5. isk00286 수정/삭제 답글

    결국 버츄얼 박스로 바꿔서 해결했습니다 위에 써놔주셨는데 제가 못봤네요 ㅠㅠㅠ 감사합니다 포스팅이 큰 도움이 되었습니다!!!

    • min0628 수정/삭제

      앗... VMware였나보네요.
      저도 VMware로 하다가 포기하고 VirtualBox로 넘어간거라..^^;
      도움이 되었다니 다행입니다.

  6. sjhh9311 수정/삭제 답글

    위에 순서대로 다 잘따라오다가 커널 컴파일에서 막혔는데요
    가상머신 코어수가 1이라 make -j1해서 입력햇는데
    kernel/sys_numname.c:1:24:fatal error: linux/kernel: No such file or directory compilation terminated.
    scripts.Makefile.build:291: recipe for target 'kernel/sys_numname.o' failed
    Make[1]: *** [kernel/sys_numname.o] Erro 1
    Makefile:963: recipe for target 'kernel' failed
    make: **** [kernel] Error 2
    라고뜨는데 뭐가문제인지 알수있을까요?

    • min0628 수정/삭제

      답이 늦었네요.
      작성하신 파일에 오류?오타?가 있어서 그런겁니다.
      확인해보세요.

  7. sjhh9311 수정/삭제 답글

    답변 감사합니다. 결국 마무리지었네요
    좋은 포스팅 감사합니다

    • min0628 수정/삭제

      해결하셨다니 다행입니다. ^^

    • ㅜ.ㅜ 수정/삭제

      뭐가문제엿나요? 저도그렇게뜨네요 ㅜ

  8. giseopkim 수정/삭제 답글

    감사합니다 완전 큰 도움되었어요!

  9. 아이고감사합니다 수정/삭제 답글

    아이고 감사합니다 이거 덕분에 진짜 큰일 해결했네요 증말

    이거만큼 섬세하고 자세한 포스팅이 다른곳에는 즈은혀 없어요 즌혀

    진짜 이거덕에 큰 도움 받고 갑니다 감사합니다 증말루다가

  10. ffam 수정/삭제 답글

    커널설치 후 재부팅을하니 부팅이 안되네요
    주요 문제 :
    Boot args (cat / proc/cmdline)
    Check rootdelay = (did the system wait long enough?)
    Check root = (did the system wait for the right device?)
    Missing modules (cat /proc/modules; ls /dev)

    이라는 오류가 뜨네요 맨 밑에는 (initramfs) _ (<- 입력가능)
    이렇게 뜨고...
    vmware에 우분투를 설치했습니다

    • min0628 수정/삭제

      VMWARE에서는 부팅이 안되는 문제가 있습니다.
      상단 내용을 확인바랍니다.

카운터

Today : 63
Yesterday : 74
Total : 483,451