■ 커널 모듈(개발 및 수정)
ㆍ 커널 수정
- Ubuntu 14.04.3 버전
1. 커널을 빌드하는 데 필요한 패키지 설치
1) build-essential: gcc, libc6-dev 등의 개발 패키지가 설치된다.
2) libssl-dev: SSL 관련 라이브러리 패키지
- $sudo apt-get install build-essential libssl-dev
2. 커널 빌드 및 설치
1) 현재 사용 중인 커널 버전의 소스를 다운
- $apt-get source linux-image-$(uname -r)
=> uname -r : 시스템 정보 + 커널 Release 번호 출력
2) 커널 설정 파일 복사
- 커널 코드를 수정하고 기존 설정 파일을 복사한다.
- $cp /boot/config-$(uname -r) .config
3) 커널 이미지 빌드
- $make -j2 bzImage: 압축된 커널 이미지 생성. -j 옵션은 컴파일에 사용되는 스레드 지정, bzImage는 커널 이미지를 말한다.
- 이미지는 arch/x86/boot/bzImage에 있는 것을 확인할 수 있다.
* 커널 모듈은 자신이 빌드될 때 만들어진 매직 넘버와 일치하는 커널에서만 동작하는데, 이는 의존성 확인을 위한 장치이다. 여기서 커널 전체를 새로 빌드했으니 매직 넘버도 바뀐다. 그렇기 때문에 커널 모듈도 재빌드해야 된다.
전체 빌드 시에만 커널 모듈을 빌드하면 된다. 이후에 커널 코드를 수정할 때는 커널 모듈을 빌드할 필요가 없다.
4) 커널 모듈 컴파일
- $make -j2 modules: 커널 환경설정에서 모듈로 설정한 기능들을 컴파일
5) 커널 모듈 설치
- $sudo make modules_install: 컴파일된 모듈을 /lib/modules 아래에 설치
6) 커널 설치
- $ sudo make install: 모듈 설치 및 설치가 끝났으면, 커널을 설치
ㆍ 커널 모듈 개발
1. 커널 모듈 코드 작성(.c 파일)
2. Makefile 작성
ex>
obj-m += {modulename}.o // 모듈로 생성할 이름 정의, 특별한 지정이 없으면 {modulename}.c -> {modulename}.o로 컴파일된다.
{modulename}-y = {file}.o // 해당 모듈이 다른 파일로 구성되어있을 때 사용. 예로 foo.c와 bar.c로 이루어져 있으면 {modulename}-y = foo.o bar.o와 같이 작성한다.
PWD = $(shell pwd) // 컴파일 대상이 되는 모듈 소스가 위치한 디렉토리 지정
ccflags-y += {추가할 헤더경로}
KBUILD_EXTRA_SYMBOLS = {참조할 심볼 테이블}
all:
make -C {커널의 소스 경로} M=$(PWD) modules
clean:
make -C {커널의 소스 경로} M=$(PWD) clean
ex>
obj-m += pssap_lkm.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
출처: https://onecellboy.tistory.com/306 [신불사 - 신현호라 불리는 사나이]
■ 커널 정리
1. 커널 컴파일 설정 파일 항목
- CONFIG_MESSAGE_LOGLEVEL_DEFAULT: 커널 메시지 기본 로그 레벨
- CONFIG_LOG_BUF_SHIFT: printk 버퍼 설정
2. 리눅스 커널 부팅의 마지막에 호출되는 함수
- init/main.c에 있는 rest_init() 함수
3. __init, __initdata & __exit, __exitdata
- __init나 __initdata는 해당하는 함수나 변수가 초기화 과정에만 사용된다는 것을 의미. start_kernel()이나 kernel/sched.c에 있는 sched_init(), arch/i386/mm/init.c에 있는 mem_init() 처럼 초기화 과정에만 사용되는 함수는 일단 초기화 과정이 끝나면 더 이상 필요가 없다. 초기화를 마친 후에 이들을 계속해서 메모리에 남겨두고 있을 필요가 없다는 의미이다. 그래서 이런 초기화에만 필요한 함수나 변수를 별도의 영역에 따로 모아두었다가, 초기화를 마친 후 이 영역의 메모리를 해제하게 된다. 그렇게 하면 필요 없는 메모리를 제거하여 커널이 차지하는 메모리의 양을 줄일 수 있게 됩니다.
- __exit나 __exitdata는 코드가 종료될 때 필요한 함수나 변수를 지정할 때 사용
ex>
함수: static void __init func(){ ... } // 함수명 앞에 __init, __exit 추가
변수: static int value __initdata = 0; // 변수명 뒤에 __initdata, __exitdata 추가
=> 출처: https://knight76.tistory.com/entry/30001788266 [김용환 블로그(2004-2020)]
'Coding' 카테고리의 다른 글
Java Basic - IO Stream (0) | 2020.08.25 |
---|---|
Linux Programming 정리 (0) | 2020.04.24 |