학습자료(~2017)/리눅스

커널 특정 모듈만 컴파일

단세포소년 2013. 11. 19. 18:14
반응형

http://tmdgus.tistory.com/116


http://www.troot.co.kr/tc/2671


http://stackoverflow.com/questions/16360689/invalid-parameters-error-when-trying-to-insert-module-that-accesses-exported-s  - insert module 시 Invaild parameters 오류 발생시, 모듈 컴파일시 undefined 오류 발생시 해결법




1. 특정 모듈 컴파일시 필요한것


1. 커널 소스 헤더와 의존되는 모듈이 있다면 해당 모듈의 심볼 테이블이다. 

심볼 테이블의 이름은 Module.symvers 이다.

심볼 테이블은 모듈을 컴파일하면 해당 디렉토리에 생성되며 함수의 위치 정보를 가지고 있다.


2. 커널 소스 혹은 커널 헤더

sudo apt-get install linux-source 나 sudo apt-get install linux-headers-x.x.x 을 통해 받을수 있다. 대체로 위치는 /usr/src 에 존재한다.




2. 특정 모듈 컴파일시 Makefile


obj-m = {modulename}.o

{modulename}-y = {file}.o

PWD = $(shell pwd)

ccflags-y += {추가할 헤더경로}

KBUILD_EXTRA_SYMBOLS = {참조할 심볼 테이블}

all:  
         make -C {헤더나 소스 최상위 경로} M=$(PWD) modules  

clean:  
        make -C {헤더나 소스 최상위 경로} M=$(PWD) clean


예들 들어 

1. test.ko 란 모듈을 제작하려고 하고 해당 모듈은 소스파일 /test/foo.c , /test/bar.c 로 이루어져 있다고 하자. 

그리고 /test/include/foo.h , /test/include/bar.h 헤더가 존재한다고 하자.  그리고 libtest.ko 의 함수를 test.ko 에서 사용한다고 하자.


2. libtest.ko 란 모듈은 소스파일 /libtest/libtest.c 로 이루어져 있다고 하자. 헤더는 따로 없다.


그리고 /usr/src/linux-headers-3.10 에 헤더파일들이 존재한다고 하자.

* 커널 헤더는 sudo apt-get install linux-headers 명령을 통해 받을수 있다. 혹은 그냥 커널 소스 자체를 받아도 된다.



이때 test.ko 에 대한 Makefile 은 /test/ 안에 생성해야한다.

obj-m += test.o

test-y := foo.o bar.o

PWD = $(shell pwd)

ccflags-y += -I/test/include

KBUILD_EXTRA_SYMBOLS += /libtest/Module.symvers

all:

         make -C /usr/src/linux-headers-3.10/ M=${PWD} modules

clean:

         make -C /usr/src/linux-headers-3.10/ M=${PWD} clean



libtest.ko 에 대한 Makefile은 /libtest/ 안에 생성한다.

obj-m += libtest.o

PWD = $(shell pwd)

all:

         make -C /usr/src/linux-headers-3.10/ M=${PWD} modules

clean:

        make -C /usr/src/linux-headers-3.10/ M=${PWD} clean



컴파일은 해당 디렉토리에 가서 make all 하면된다.

test.ko 는 libtest.ko의 함수를 사용하기 때문에 libtest.ko 의 심볼 테이블이 필요하다. 그러므로 libtest.ko 를 우선 컴파일 해야한다.

libtest.ko 를 컴파일하면 해당 디렉토리에 Module.symvers 심볼 테이블 파일이 생성된다.

그후 test.ko 를 컴파일하면 이상없이 컴파일 될것이다.



3. Makefile 설명


1. obj-m : 생성할 모듈 이름이다. 예를 들어 test.ko 를 생성하고 싶다면 test.o 를 인자로 주면된다.(test.ko 가 아니다.)

 obj-m += test.o


2. {module_name}-y : 해당 모듈을 구성하는 소스리스트를 적어주면된다. 주의할 것은 .o 이지 .c 가 아니다. 예를들어 test.ko 를 구성하는 소스가 foo.c, bar.c 라면

 test-y := foo.o bar.o


3. PWD = $(shell pwd) : 그냥 현재 경로이다.


4. ccflags-y : 이것은 컴파일시 gcc 에 포함할 옵션이다. 예를들어 참조하는 헤더의 위치가 /home/include 라면 이 경로는 gcc가 암시적으로 참조하지 않는다. 따라서 옵션을 주어 해당경로에서도 헤더를 찾으라고 해야한다. 헤더가 위치한 경로를 주는 옵션은 대문자 I 이다.

 ccflags-y += -I/home/include



5. KBUILD_EXTRA_SYMBOLS : 참조할 심볼 테이블 파일의 경로이다. 심볼 테이블 파일의 이름은 Module.symvers 이다. 예를 들어 참조하는 심볼 테이블의 경로가 /libtest/Module.symvers 라면

 KBUILD_EXTRA_SYMBOLS += /libtest/Module.symvers


6. all , clean : 여기의 make -C 옵션 값은 커널 헤더 최상위 경로거나 커널 소스 최상위 경로이면 된다.

셋중 하나면 된다. 중요한 것은 현재 커널 버젼 uname -r 과 동일해야한다는 것이다.

 make -C /usr/src/linux-headers-$(shell uname -r)/ M=$(PWD)  modules

혹은

 make -C /usr/src/linux-$(shell uname -r)/ M=$(PWD)  modules

혹은 

 make -C /lib/modules/$(shell uname -r)/build M=$(PWD)  modules

기본 linux/xxxx.h 헤더는 /usr/src/linux-$(shell uname -r)/include 에서 찾는다.




4. 예시



아래와 같이 많이 쓴다.

CONFIG_TEST = m

obj-$(CONFIG_TEST) += test.o


test-y := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \

export.o caps.o snap.o 


PWD = $(shell pwd)

BASE_DIR =  $(shell dirname $(PWD))

#ccflags-y += -I/home/user/include

#KBUILD_EXTRA_SYMBOLS += /home/user/lib/Module.symvers


all:

make -C /usr/src//linux-headers-$(shell uname -r)/ M=$(PWD) ccflags-y+=-I$(BASE_DIR)/include KBUILD_EXTRA_SYMBOLS+=$(BASE_DIR)/net/Module.symvers  modules


clean:

make -C /usr/src/linux-headers-$(shell uname -r)/ M=$(PWD) clean

대충 이런식으로 많이 쓴다.

ccflags-y 나 KBUILD_EXTRA_SYMBOLS 변수 같은 경우

cflags-y += -I${BASE_DIR}/include 이런식으로 쓰면 오류가 나더라.

그래서  make cflags-y += -I${BASE_DIR}/include 이런식으로 make 명령에 직접 옵션으로 붙인다.




5. 모듈 추가


추가는 쉽다.

해당 모듈이 존재하는 디렉토리에서 

sudo insmod test.ko 라고 치면 된다. 여기서 중요한 점은 test.ko 가 libtest.ko 의 함수를 쓴다면 우선 libtest.ko 모듈을 로드한 후에 test.ko 를 로드해야한다.


insmod 는 해당 모듈이 존재하는 곳에서 로드하는 방법이고 modprobe를 사용하기 위해서는

/lib/modules/`uname -r`/kernel/ 밑에 적절한 디렉토리를 선택하거나 디렉토리를 생성하고 .ko 파일을 복사하면 된다.

복사한 후에는 modprobe 로 추가하기 전에 depmod -a 명령을 우선 수행해서 복사한 .ko 파일을 인식시켜야한다.


$ sudo depmod -a

$ sudo modprobe {module}.ko



아 그리고 test.ko 가 libtest.ko 의 함수를 사용할 때 즉 test.ko 가 libtest.ko 를 의존할때는 libtest.ko 를 우선 로드후에 test.ko를 로드해야한다.





6. 모듈 정보 보기


modinfo {모듈경로}


예를 들어

$ modinfo /lib/modules/3.11.8/kernel/fs/xfs/xfs.ko

filename:       /lib/modules/3.11.8/kernel/fs/xfs/xfs.ko
license:        GPL
description:    SGI XFS with ACLs, security attributes, realtime, large block/inode numbers, no debug enabled
author:         Silicon Graphics, Inc.
alias:          fs-xfs
srcversion:     F107BA901126B3EA796F27D
depends:        libcrc32c
intree:         Y
vermagic:       3.11.8 SMP mod_unload modversions 



7. 오류


만약 컴파일 중에 undefined 에러나, 모듈을 insmod 중에 Invalid parameters 에러가 발생한다면 현재 모듈이 다른 모듈의 함수를 사용했을 경우다. 이때는 사용하려는 해당 모듈이 컴파일 되기전에 함수에 대한 심볼 테이블이 필요하다.

만약 foo.ko 가 bar.ko 의 함수를 사용한다면 우선 bar.ko 를 컴파일 한다. 컴파일하면 해당 폴더에 Module.symvers 란 파일이 생성된다. 이 파일을 foo.ko 가 컴파일될 폴더에 복사한후 foo.ko를 컴파일하면 에러 없이 컴파일되고 에러 없이 insmod 될 것이다.
혹은 makefile 에 KBUILD_EXTRA_SYMBOLS += {Module.symvers} 를 추가한다.




글이 참.. 설명 능력좀 키워야하나..



반응형