본문 바로가기
코스웨어/12년 내장형하드웨어

[linux kernel]모듈 프로그래밍

by 알 수 없는 사용자 2012. 10. 20.
728x90
반응형

운영체제의 커널구성은 크게 두 가지로 나뉜다.

-일체형 커널( Monlithic Kernel )

-마이크로 커널( Micro Kernel )

리눅스는 일체형 커널을 사용했지만, 모듈을 도입함으로써 커널의 일부를 동적으로 커널안에 코드를 삽입하고 제거 할 수 있는 방법을 사용할 수 있게 되었다.



-모듈 프로그램의 구성-


모듈이 커널에 올라가기 앞서 모듈을 로드할떄 수행되는 초기화 루틴(init_module) 이있고 

모듈을 제거할떄 수행되는 초기화 루틴(cleanup_module) 가 있다. 


-모듈작성 기본 소스구성

#include<linux/kernel.h> // 커널과 관련된 자료구조와 printf()함수등이 정의되어있다.

#include<linux/module.h>//모듈과 관련된 자료구조와 매크로가 정의되어있다.


int __init init_module(void)      //로드할떄 수행되는 초기화 루틴(init_module)  insmod 명령어수행시 실행        

{

.....

return 0;

}


void __exit cleanup_module(void) //제거할떄 수행되는 초기화 루틴(cleanup_module) rmmod 명령어 수행시 실행

{

.....

}

MODULE_LICENSE("GPL");  //라이센스 


-모듈 컴파일

리눅스 2.6 커널은 kbuild 시스템을 사용하기 떄문에 컴파일시 gcc를 사용할수없고 Makefile을 정의하고 kbuild시스템으로 모듈빌드 가능

 실제 예제 코드작성과 Makefile 내용은 책에 잘 나와있다.


예)

cc -D__KERNEL__ -DMODULE -wall -O2 -i/usr/src/linux~~/include -c  파일명.c

-D    :define

-W   :warning를 출력

all   : 모든것을

-O2 : 최적화

-i    : include

-c   :complie만 하자(모듈컴파일 할떄는 링킹을 하면 안되니깐 -c를 붙여준다)





-모듈에 대해 알아야 할 것들-


-모듈과 커널버젼

/usr/src/linux~~~/include/linux/version.h

해당하는 커널버젼을 정수값으로 미리 #define 해놓은것을 확인할수 있다.


특전버전 이상에서만 동작하는 모듈이라던지,커널 버전에 따라 다르게 동작하는 모듈을 작성하고 싶으면 다음의 코드작성

#if LINUX_VERSION-CODE >= KERNEL_VERSION(3 , 2, 0) //해석은 알아서..
MODULE_PARM( user_name, "charp");
#else
MODULE_PARM( user_name, "s");
#endif

-모듈과 static 선언
리눅스 커널은 커널 전체가 하나의 프로그램이기 때문에 같은 이름을 가진 변수나 함수를 만들 수 없다.
만약 a라는 모듈에서 hello()함수를 작성하고 커널에 로드했다면  b라는 모듈에서 사용되는 hello()를 로드할수 없게된다.
해당모듈에서만 함수가 작동이 되고 다른커널에서 참조할  필요가 전혀없다면 커널영역에서 보이지않게하기위해 static를 사용해야한다.
(즉 커널 심볼테이블에 등록하기 싫으면 함수선언 하는것 앞에 static를 붙인다.)
예)
static void hello_cleanup(void)
{
printf("cleanup_module()\n");
}

.init_module()와 cleanup_module()함수는 예외적으로 static를 사용하지않아도 커널영역에 공개 되지 않는다.
.2.5커널에서는 모듈내에서 static 없이 선언된 함수는 커널 영역에 공개되었지만 2.6에선 공개되지 않는다.
.커널영엑에 공개된함수  2.4(/proc/ksyms) 2.6(proc/kallsysms) = 커널심볼테이블 확인

-모듈과 커널 심볼
모듈은 커널 영역에서만 실행되기때문에 표준 C함수들을 사용할수없습니다.
커널영역에서 사용할수있는 함수나 자료구조의 목록을 커널에서 제공하는데 확인은 버젼마다 다르다.
.커널영엑에 공개된함수  2.4(/proc/ksyms) 2.6(proc/kallsysms) = 커널심볼테이블 확인

리눅스 3.2커널 심볼테이블 (2.6과 같은 proc/kallsysms  곳에 위치)


심볼타입 (대문자로 사용되면 전역심볼, 소문자로 사용되면 지역 심볼)

A = 절대 주소로 변경되지 않음
B = bss 영역의 심볼
C = 공용심볼로 초기화되지 않은 변수를 의미
D = data영역의 심볼로 초기화된 변수를 의미
R = rdata영역, 즉 읽기 전용변수를 의미
T = text영역의 심볼로 함수를 의미
U = 해당 모듈에서 정의하지 않은 (undefined)심볼을 의미
I  = 다른 심볼에 대한 간접(indirect) 참조를 의미하는 GNU확장
N = 디버깅 심볼


-심볼 2.4 와 2.6의 차이
2.4에선 모듈 안에서 static로 선언되지 않은 함수는 모두 커널 심볼로 공개되어 있지만
2.6에선 static으로 선언되지 않은 함수여도 커널심볼로 등록 하지 않으면 공개되지 않게 변경됨

2.6에서 커널 심볼로 공개시키는 방법
EXPORT() 나 EXPORT_SYMBOL_GPL() 같은 매크로를 사용해서 공개할 심볼을 지정하면된다. (관련 매크로는 include/linux/module.h 에 정의)
이렇게하면 커널이나 모듈내에서 자유롭게 사용이 가능해지는 것이다.
  
-모듈의 상호참조
.책에 있는 caller 모듈과 callee 모듈을 작성하여 연습하자.
.위에서 언급했듯이 두 모듈간에 상호참조를 위해서 2.6에선 EXPORT_SYMBOL 을 함수앞에써줘서 심볼을 공개하고 2.4는 그렇지 않다.
.caller 모듈에서 callee 모듈을 참조하기때문에 callee 모듈은 먼저 insmod 해줘야 한다.


-시스템 호출 래핑
우리가 배웠던 시스템 호출(sys_call_table->sys_fork())을 대체하는 기법인데 sys_call_table->sys_my_fork()->sys_fork()  
이렇게 시스템 호출을 (wrapping)형태로  한단계 둘러싸서 변경하는것, 2.6커널에선 금지된 방법이다.


-참고할 리눅스 명령어
버젼 확인  cat /proc/version (현재 우분투 12.04 LTS 는 리눅스 커널 3.2를 쓰고있음)


커널에 올라간 모듈 확인  lsmod


올라간 모듈중에 해당되는 문자가 들어있는 모듈찾기   lsmod | grep 찾을문자열


루트경로부터 하부디렉토리까지  한페이지씩보기

(space 한페이지씩 보기, enter  한줄씩 보기, q  당장 빠져나오기) 

ls -aiR | more



요기까지 ... 

728x90