지금까진 리눅스 커널의 코드를 긁어와서 그 내용을 테스트했다. 하지만 이런 식으론 복잡하게 연결되어 있는 헤더파일을 불러와서 컴파일하기도 어렵고, 실제 커널 내부에선 동작시킬 수 없다. 결국 커널 소스를 모두 다시 빌드하고 재부팅해서 결과를 확인하는 방법을 거쳐야 하는데 아무리 makefile
을 사용한다고 해도 번거롭고 시간도 매우 오래 걸린다. 이러한 문제를 해결하기 위해 리눅스 커널은 모듈(Module)
을 제공한다. 특정 모듈에 들어갈 코드를 따로 작성하여 해당 모듈만 다시 컴파일하고 삽입하면 원하는 실행결과를 확인할 수 있다. 리눅스 커널 디바이스 드라이버 프로그래밍도 이런한 방식을 사용한다.
0 장에서 확인하긴 했지만 다시 한번 개발 환경에 대해 점검하도록 하겠다. 처음 커널 빌드는 5.12.2
로 했는데 커널 코드 테스트는 4.20
으로 했다. 커널 모듈 프로그래밍(9장
)부턴 다시 5.12.2
의 최신 버전으로 테스트할 예정이므로 git
을 통해 checkout
하고 빌드하기 바란다. 단순히 checkout
하는 것 뿐만 아니라 꼭 build
를 해야 한다. 만일 5.12.2
버전의 모듈과 이미지 파일을 딱히 건드리지 않았다면 그냥 build
만 다시 하면 된다. 그렇지 않다면 modules_install
과 이미지 install
과정을 다시 진행해야 한다.
이름 | 버전 | 정보 |
---|---|---|
운영체제 | Ubuntu 20.04.2 LTS | Linux 5.12.2 |
gcc | 10.2.0 | x86_64-linux-gnu |
PC | Lenovo LEGION 5 | * |
현재 필자의 환경이다. 크게 변동은 없고 gcc
버전이 조금 높은게 차이점인데 8
이상만 되면 큰 문제는 없을 것이다.
위에서 나온 것과 같이 build
와 source
가 올바른 위치의 디렉터리를 가르키고 있어야 한다. 만일 ls /lib/modules/
에서 5.12.2
가 없다거나, source
와 build
가 5.12.2
버전의 파일을 가르키는게 아니라면 무언가 문제가 있는 것이므로 0 ~ 1 장
의 내용을 다시 보고오길 바란다. 따라오는 과정에서 건드린게 없다면 앞에서 말한 것처럼 make
만 다시하면 될 것이다.
hello.c
test/linux-modules/hello.c
/** M: Yeounsu Moon <yyyynoom@gmail.com> W: https://velog.io/@mythos F: test/linux-modules/hello.c This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License */ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> static int __init hello_init(void) { printk("linux-modules: test/hello.c: hello_init(). \n"); return 0; } static void __exit hello_exit(void) { printk("linux-modules: test/hello.c: hello_exit().\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yeounsu Moon"); MODULE_DESCRIPTION("A Hello, World Kernel Module"); MODULE_VERSION("0.1.0");
위 코드는 module_init()
과 module_exit()
매크로를 테스트 해볼 것이다. 이 매크로의 인자로 함수를 전달하면 모듈이 커널 내부에 삽입되어 실행되는 시점에서 인자로 전달한 함수가 실행된다. 반대로 module_exit()
함수는 모듈이 커널에서 제거되는 시점에서 인자로 전달한 함수를 호출한다.
백문불여일견(百聞不如一見)
백번 말하는 것보다 직접 실행 결과를 보는게 빠르다. 이를 확인하기 위한
Makefile
을 작성해보자.
Makefile
작성 Makefile
에 대해 설명하려면 또 새로운 시리즈를 만들어 작성해야 할 만큼 그 내용이 방대하다. 따라서 여기에선 설명하지 않을 예정이다. 다만 어려운 내용은 아니므로 조금만 공부하면 금방 이해할 수 있을 것이다.
Makefile
obj-m += hello.o KDIR := /lib/modules/$(shell uname -r)/build hello: make -C $(KDIR) M=$(PWD) modules clean: make -C $(KDIR) M=$(PWD) clean
$(shell uname -r)
값은 커널의 최신 버전의 문자열로 치환된다. 나머지 내용은 크게 어렵지 않으므로 설명하지 않을 것이다.
Makefile
을 작성했다면 make
명령어를 통해 빌드할 수 있다. 다만 주의할 점은 Makefile
의 첫 번째 문자가 대문자이어야 한다. 첫 make
에서 makefile
자체는 인식하지만 중간에 에러가 발생한다. 따라서 반드시 이름을 Makefile
로 짓기를 바란다.
앞서 제대로 컴파일과 링킹이 되어 파일이 생성 되었다면 그 정보를 modinfo
명령어를 통해 확인 가능하다:
모듈 정보가 제대로 출력되었다면 이를 커널 내부에 삽입해보겠다. 리눅스 명령어 insmod
를 실행하여 hello.ko
모듈을 삽입할 수 있다. 다만 이는 root
권한을 필요로 하므로 앞에 sudo
를 붙여서 실행해야 한다.
혹시 아무런 메세지도 출력되지 않았는가? 괜찮다. 정상이다.
printk
함수로 출력하는 메세지는 명령어 프롬프트에 출력되지 않고 /var/log/syslog
파일에 출력되어진다. 따라서 cat /var/log/syslog
를 실행시키면 다음과 같은 결과를 확인할 수 있다:
May 22 01:16:49 mythos kernel: [11291.557851] linux-modules: test/hello.c: hello_init().
물론 앞쪽의 메세지는 약간씩 다를 수 있다. 바로 뒤에 hello_exit()
이 잇따라 있는데 이는 필자가 테스트하기 위해 다시 모듈을 제거하고 다시 삽입해서 그런 것이다. 그런고로 커널 모듈 리스트 결과만 확인하고 삽입된 모듈을 제거해보자.
삽입된 모듈을 확인하기 위해선 다음의 명령어를 실행시켜야 한다: lsmod
보는 것과 같이 2 행
에서 hello
모듈이 존재하는 것을 확인할 수 있다.
sudo rmmod hello
삽입과 마찬가지로 리눅스에서 제공하는 rmmod
명령어를 사용하면 쉽게 제거가 가능하다. 다시 /var/log/syslog
파일을 확인하면 printk
함수로 출력한 메세지를 확인할 수 있을 것이다.
[책] 리눅스 커널 소스 해설: 기초입문 (정재준 저)
[이미지] https://morioh.com/p/ad7f5c541f59