안녕하세요.
라즈베리 파이 커널을 설치하고 나머지 뒷부분을 마무리하도록 하겠습니다.
리눅스 커널을 빌드하는 과정에서 전처리코드를 생성하는 방법이 나옵니다.
커널에는 많은 양에 매크로가 소스분석에 걸림돌이 됩니다. 그래서 소스코드를 분석할 때 전처리 코드를 함께 보는 것을 추천하며 추출하는 방법 두 가지를 알려 줍니다.
1. 전처리 코드 생성
1) 전체 전처리 파일 추출
이전 글에서 처럼 root 권한을 얻어서 다음 내용을 진행합니다. 리눅스 커널 소스 디렉터리 안에 Makefile이 있습니다.
대략 420번 줄 KBUILD_CLAGS에 "-save-temps=obj \"를 추가해 주고 build 스크립트를 실행해 주면 전체 소스 파일에 전처리코드가 담긴 *.i, *.s 파일이 생성됩니다. 약 5GB 정도 늘어 나는 단점이 있습니다.
rpi_kernel_src# sudo su
rpi_kernel_src# vim linux/Makefile
rpi_kernel_src# ./build_rpi_kernel.sh
2) 특정 전처리 파일 추출
위의 전체 전처리 파일의 단점(?)이 있다 보니 특정 소스파일만 전처리 파일로 생성하는 방법을 소개합니다.
빌드할 때와 유사한 스크립트를 작성합니다. build_preprocess_rpi_kernel.sh로 파일을 생성하고 실행주는 것도 동일합니다.
Raspberry Pi 4 버전에 맞게 작성합니다. 추출할 파일 경로와 이름(kernel/sched/core.i )을 확인하시고 스크립트 파일을 실행하면 됩니다.
rpi_kernel_src# vim build_preprocess_rpi_kernel.sh
rpi_kernel_src# chmod +x build_preprocess_rpi_kernel.sh
rpi_kernel_src# ./build_preprocess_rpi_kernel.sh kernel/sched/core.i
<build_preprocess_rpi_kernel.sh 내용>
#!/bin/bash
echo "configure build output path"
KERNEL_TOP_PATH="$( cd "$(dirname "$0")" ; pwd -P )"
OUTPUT="$KERNEL_TOP_PATH/out"
echo "$OUTPUT"
KERNEL=kernel7l
BUILD_LOG="$KERNEL_TOP_PATH/rpi_preproccess_build_log.txt"
PREPROCESS_FILE=$1
echo "build preprocessed file: $PREPROCESS_FILE"
echo "move kernel source"
cd linux
echo "make defconfig"
make O=$OUTPUT bcm2711_defconfig
echo "kernel build"
make $PREPROCESS_FILE O=$OUTPUT zImage modules dtbs -j4 2>&1 | tee $BUILD_LOG
추가된 내용을 보자면 스크립트를 실행할 때 파일명 인자($1)를 받아 make 옵션에 추가해 주는 것입니다.
생성된 core.i 파일은 out 디렉터리에서 확인할 수 있습니다.
core.c 파일과 core.i파일을 보면 확연한 차이를 볼 수 있습니다. 호출되는 값과 소스파일에 선언된 정보들이 추가되어 있습니다. 코드 줄 수는 7107 vs 73695로 차이가 납니다. 주석이 없는 코드인데도 말이죠.
이것으로 기본적인 전처리 파일 추출 방법을 알아보았습니다.
이후에는 커널의 간단하게 구조와 유틸리티 설명이 나옵니다.
2. 리눅스 커널 소스의 구조
책과 인터넷에 더 자세한 내용이 나와서 여기서는 간단하게 요약해 보겠습니다.
arch : 아키텍처별로 동작하는 코드가 있음 (arm, arm64, x86 등)
include : 커널 코드 빌드에 필요한 헤더 파일 있음
Documentation : 커널 기술 문서, 기본 동작 설명 문서 기본지식 없으면 보기 어려움
kernel : 커널 핵심 코드가 있음 (irq, sched, power, locking, printk, trace), 아키덱처와 무관한 커널 공동 코드가 있음
mm(Memory Management) : 가상 메모리 및 페이징 관련 코드 있음
driver : 모든 시스템의 디바이스 드라이버 코드 있음
fs : 모든 파일 시스템 코드가 담긴 폴더
lib : 커널에서 제공하는 라이브러리 코드 있음
아키텍처에 종속적인 라이브러리는 arch 디렉터리에 있습니다.
3. objdump 유틸리티
리눅스 커널 어셈블리 코드와 섹션 정보를 볼 수 있는 유틸리티
테스트를 위해서 kernel_obj 폴더를 만들고 vmlinux 파일을 복사합니다.
pi# mkdir kernel_obj; cd kernel_obj
pi/kernel_obj# cp ../rpi_kernel_src/out/vmlinux .
pi/kernel_obj# ls
objdump 명령어를 이용해서 해더파일 정보를 확인합니다.
pi/kernel_obj# objdump -x vmlinux | more
아키텍처 정보 (arm), 스타트업 코드 주소(0xc0008000)를 확인할 수 있습니다.
어셈블리 코드도 확인할 수 있습니다. 그러나 너무 많은 코드로 인해 보기가 힘들 수 있습니다.
pi/kernel_obj# objdump -d vmlinux | more
위와 같이 보려면 어려울 수 있기 때문에 특정 함수 어셈블리 코드 보는 방법을 알려줍니다.
커널 빌드 이후에 생성된 System.map 파일 복사해서 내용을 vim, nano 등 에디터로 열어 확인합니다.
심벌별 주소를 확인할 수 있으며, 그중에 유명한 schedule() 함수의 주소 범위를 확인합니다.
0xc09d6c5c ~ 0xc09d6d6c라는 것을 알 수 있습니다.
pi/kernel_obj# cp ../rpi_kernel_src/out/System.map .
pi/kernel_obj# vim System.map
알아낸 시작 주소와 끝 주소를 지정해서 schedule() 함수의 어셈블리 코드만 분석할 수 있습니다.
pi/kernel_obj# objdump --start-address=0xc09d6c5c --stop-address=0xc09d6d6c -d vmlinux
위의 내용은 책을 보면 직접 확인하고 요약한 내용입니다. 그렇다 보니, 글을 보고 이해가 어려울 수 있습니다. 상세한 설명은 책을 보면서 이해하는 것을 추천드립니다.
그러나 책의 내용은 Raspberry Pi 3이다 보니 버전이 맞지 않아 다른다고 느끼는 부분이 있을 것입니다. 그런 부분은 현재 시점에서 테스트해보고 있는 현재 글을 참고하면서 보시면 어떨까 합니다.
감사합니다.
<참고 자료>
1. [도서] 디버깅을 통해 배우는 리눅스 커널의 구조와 원리 1, wikibook
'IT > Operation System' 카테고리의 다른 글
디버깅을 통해 배우는 리눅스 커널의 구조와 원리 1, 도서 공부하기 3 - Raspberry Pi4 설정 및 리눅스 커널 빌드와 설치 (1) | 2025.02.16 |
---|---|
디버깅을 통해 배우는 리눅스 커널의 구조와 원리, 도서 공부하기 2 - Raspberry 4 설치(kernel 4.19) (4) | 2025.02.14 |
디버깅을 통해 배우는 리눅스 커널의 구조와 원리 1, 도서 학습 1 - 시작 준비 (5) | 2025.02.12 |