본문 바로가기
linux

모듈 개발.

by 상레알 2010. 6. 1.
출처 : 리눅스 커널 프로그래밍  저 한동훈,원일용, 하홍준  / 한빛 미디어


모듈 개발 절차

1. 모듈프로그램 작성
2. 모듈 프로그램 컴파일
3. 모듈 로드 (insmod 명령 )
4. 로드된 모듈 확인(lsmod 명령)
5. 모듈 제거(rmmod 명령)

시스템 에 로드된 모듈은 lsmod 명령으로 확인할 수 있으며, insmod명령은 모듈을 커널에 로드할 떄 사용하며, rmmod 명령은 커널에서 모듈을 제거할 때 사용합니다.

모듈 프로그램의 구성


1)  커널, 모듈 프로그램의 구성 

2.4 커널 모듈 프로그램 구성

#include <linux/kernel.h>     -
#include <linux/module.h>   -    => "헤더파일 선언"

// 모듈을 로드할 때 수행되는 초기화 루틴

int __init init_module(void)
{
  . . . . . .// 초기화 루틴
  return 0;
}
// 모듈을 제거할 때 수행되는 초기화 루틴

void __exit cleanup_module(void)
{
    . . . . .  // 정리 루틴
}

MODULE_LICENSE ("GPL");

모듈에서는 커널과 관련된 자료구조와 printk()함수 등이 정의된 kernel.h 헤더파일과 모듈과 관련된 자료구조와 매크로가 정의된 module.h 헤더파일을 사용합니다. 자원의 초기화 작업은 init_module()에 작성하며, 정리와 관련된 코드는 cleanup_module()에 작성합니다.. 예상할 수 있는 것처럼 init_module()함수는 insmod 명령을 실행할 때 수행됩니다. 반환값이 0이면 모듈이 커널 영역에 로드되지만, 다른 값이면 실패합니다. cleanup_module()함수는 rmmod 명령을 수행할 때 실행되며, 반환값이 없는 것이 특징이다.
이들 함수를 보면 __init과 __exit이 있습니다. 이들은 매크로로 정의되어 있으며, 사용해도 되고 사용하지 않아도 됩니다. 이들 매크로의 정의는 2.4와 2.6에서 약간 다릅니다.

2.4 커널의 정의 , include/linux/init.h

#define __init
#define __exit

2.6 커널의 정의, include/linux/init.h

#define __init __attribute__ ((__section__ (".init.text")))
#define __exit __attribute__ ((__section__(".exit.text")))

모듈을 작성하지도 않았는데, 너무 거창하게 나가는 걸까요? 2.4 커널에서는 아무 역할도 하지 않습니다. 빈 매크로입니다. 2.6 커널에서는 gcc에게 컴파일러 힌트를 제공하는 역할을 합니다. 리눅스에서 메모리는 text 섹션, data 섹션, bss 섹션으로 나뉜다. text 섹션은 실행되는 코드가 저장되며, data 섹션은 코드에서 사용하는 초기화된 데이터, bss 섹션은 static 또는 초기화되지 않은 데이터를 위해 사용된다.

2.6 커널에서는 초기화에만 사용할 코드 섹션, init.text와 정리할 때만 사용할 코드 섹션, exit.text 를 사용한다. __init으로 지정된 코드는 초기화가 끝나면 메모리에서 제거됩니다. __exit으로 지정된 코드는 코드가 종료되면 메모리에서 제거됩니다.

2.4 커널에서 init.text와 exit.text 섹션을 사용하는 것은 모듈이 아니라 커널 내에 포함되는 경우에 한해서만 사용되며, 이는 각각 __INIT과 __EXIT으로 정의되어 있다.

초기화에만 사용하는 데이터와 종료시에만 사용하는 데이터에 대해서도 각각 __initdata, __exitdata 매크로를 지정해서 init.data와 exit.data 섹션에 저장할 수 있습니다. 미리 초기화되어 있지 않은 변수에 대해서는 __initdata와 같은 매크로를 사용할 수 없습니다. 이렇게 지정된 데이터는 초기화나 정리 작업이 끝나면 메모리에서 해제됩니다. 이는 커널에서 메모리를 효율적으로 사용하기 위한 것입니다.

[init_module(void)]과 같이 함수에 전달할 인자가 없다는 것을 명시적으로 표현하기 위해 (void)를 사용하고 있습니다.

초창기 C언어에서는 다음과 같은 함수 선언을 사용했습니다.


K&R 스타일의 C 함수 선언

int my_function()
   int a;
   char b;
   int c;
{
// 코드들 . . .
return 0;
}
ANSI C 스타일의 C 함수 선언
int my_function(int a, char b, int c)
{
 . . .
}
// 반환값은 초콜릿 개수로 여친 유무와 애정 정도에 따라 다름
int give_me_chocolate(void)            // voud : 인자가 없는 함수의 원형 선언은 반드시 void로 표시합니다.
{
    . . .
}
K&R 스타일의 함수 선언은 [int my_function()]으로 선언한 다음에 인자들의 목록을 적습니다. 떄문에, [int my_function()]
으로 함수를 선언하는 것만으로는 이 함수가 인자를 받아들이는 것인지, 받아들이지 않는 것인지 구분을 할 수 없습니다. 이게 무슨 조선시대 코드냐고 할지도 모르지만, K&R 스타일이라고 불리는 이 선언은 널리 사용되었고, 한국에서도 80년대 작성된 C코드만 해도 이게  정상이였습니다. 90년대 들어서 오늘날과 같은 스타일이 쓰이기 시작했는데, 저도 그만 새로운 스타일에 저항해 버렸다죠.

그래서 함수 선언에서 "()"은 "함수에 전달되는 인자 없음" 을 의미하지 않습니다. 그런 의미로 사용하려면 "(void)"를 사용해야 합니다. 왜, 이런 설명을 하냐고 하면 2.4 커널 모듈 빌드시에는 괜찮은데, 2.6 커널 모듈 빌드시에는 이에 대해서 경고 메시지를 잔뜩 뺕어 냅니다.    " warning: function declaration isn't a prototype

커널 모듈 덕분에 ANSI C99 에 대해서도 한가지 배웠군요

2.4 커널에서는 괜찮았는데, 2.6커널에서는 왜 갑자기 불평을 하게 되었느냐? 라고 질문 할수도 있습니다. sys_getpid()와 같이 프로세스 ID를 반환하는 시스템 호출의 경우 인자가 없는 함수 인데, 이 함수를  다른 함수로 바꿔치기하면서, 원하는 대로 인자를 전달하는 함수로 바꿔버릴 수 있습니다. 때문에 2.6 커널부터는 함수 원형의 선언에 대해서도 보다 꼼꼼하게 점검하게 변경되었습니다.

코드의 마지막에는 [MODULE_LICENSE("GPL")] 과 같이 코드의 라이선스를 지정하는 부분이 있습니다. 이부분을 지정하지 않으면 라이선스와 관련된 경고를 표시하기 때문에 이와 같이 지정한다.

'linux' 카테고리의 다른 글

프로세스와 신호  (0) 2010.08.13
vim 설정  (0) 2010.06.30
모듈의 상호참조  (0) 2010.06.03
모듈에 대해 알아야 할것들  (0) 2010.06.03
Hello 커널 모듈 작성 예제  (0) 2010.06.02
운영체제 커널 분류에대해...  (0) 2010.06.01
커널 소스 컴파일  (0) 2010.06.01
/usr/lib/python2.4/site-packages/_sqlitecache.so: undefined symbol: g_assert_warning  (0) 2010.04.22
Git 1.6.1 설치  (0) 2010.04.22
AttributeError: CHECKSUM_VALUE  (0) 2010.04.22