Linux Tutorial #9 커널 모듈 프로그래밍 1장

문연수·2021년 5월 21일
1

Linux Tutorial

목록 보기
10/25
post-thumbnail

지금까진 리눅스 커널의 코드를 긁어와서 그 내용을 테스트했다. 하지만 이런 식으론 복잡하게 연결되어 있는 헤더파일을 불러와서 컴파일하기도 어렵고, 실제 커널 내부에선 동작시킬 수 없다. 결국 커널 소스를 모두 다시 빌드하고 재부팅해서 결과를 확인하는 방법을 거쳐야 하는데 아무리 makefile 을 사용한다고 해도 번거롭고 시간도 매우 오래 걸린다. 이러한 문제를 해결하기 위해 리눅스 커널은 모듈(Module) 을 제공한다. 특정 모듈에 들어갈 코드를 따로 작성하여 해당 모듈만 다시 컴파일하고 삽입하면 원하는 실행결과를 확인할 수 있다. 리눅스 커널 디바이스 드라이버 프로그래밍도 이런한 방식을 사용한다.

0. 개발 환경

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 LTSLinux 5.12.2
gcc10.2.0x86_64-linux-gnu
PCLenovo LEGION 5*

현재 필자의 환경이다. 크게 변동은 없고 gcc 버전이 조금 높은게 차이점인데 8 이상만 되면 큰 문제는 없을 것이다.

1. 커널 모듈, 빌드, 소스코드 확인

위에서 나온 것과 같이 buildsource 가 올바른 위치의 디렉터리를 가르키고 있어야 한다. 만일 ls /lib/modules/ 에서 5.12.2 가 없다거나, sourcebuild5.12.2 버전의 파일을 가르키는게 아니라면 무언가 문제가 있는 것이므로 0 ~ 1 장 의 내용을 다시 보고오길 바란다. 따라오는 과정에서 건드린게 없다면 앞에서 말한 것처럼 make 만 다시하면 될 것이다.

1. 최초의 모듈: 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 을 작성해보자.

2. 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) 값은 커널의 최신 버전의 문자열로 치환된다. 나머지 내용은 크게 어렵지 않으므로 설명하지 않을 것이다.

3. 커널 모듈 빌드하기

Makefile 을 작성했다면 make 명령어를 통해 빌드할 수 있다. 다만 주의할 점은 Makefile 의 첫 번째 문자가 대문자이어야 한다. 첫 make 에서 makefile 자체는 인식하지만 중간에 에러가 발생한다. 따라서 반드시 이름을 Makefile 로 짓기를 바란다.

4. 모듈 삽입 및 제거

모듈 정보 확인하기

앞서 제대로 컴파일과 링킹이 되어 파일이 생성 되었다면 그 정보를 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

profile
2000.11.30

0개의 댓글