SoC : : Architecture/: : Raspberry

리눅스 커널(Linux Kernel) 전처리 파일 생성하기

Jay.P Morgan 2024. 6. 18. 18:48

 

  1.  리눅스 커널 전처리 파일 생성 목적

 

  1.1  전처리 코드 생성 목적

 

  리눅스 커널 소스 코드를 분석하다 보면  많은 매크로 만납니다. 그런데  매크로가 소스 분석의  걸림돌입니다. 리눅스 커널에서 캡슐화와 다형성과 객체지향 방식을 구현하다 보니 매크로로 구현된 코드가 많습니다.

 

  전처리 코드는 이 매크로를 모두 풀어서 표현해서 훨씬 편하게 소스 코드를 분석할 수 있습니다. 리눅스 커널 코드를 분석할  전처리 코드를 함께 보시기 바랍니다.

 

  전처리 코드는 GCC 컴파일 오브젝트를 생성하는 과정에서 추출됩니다

 

 

  2.   전처리 파일 전체 생성방법

 

  2.1  MakeFile 수정

먼저 리눅스 커널 전체 소스 코드를 전처리 파일로 추출하는 방법을 소개합니다.  

 

$ ~ /rpi_kernel_src/linux/Makefile
KBUILD_CFLAGS:=   이 부분에  -save-temps=obj  를 추가합니다.

 

 

 

CFLAGS는 gcc의 옵션임.

 

-Wall : 모든 경고메시지 활성화

-std=gnu11은 C11 표준

-f는 flag나 feature로 예상.

 

 

 

Makefile 파일 421 라인 다음에 아래 코드를 입력하면 됩니다.

 -save-temps=obj \

 

"-save-temps=obj \" 코드를 입력한  Makefile 다음과 같습니다

417 KBUILD_AFLAGS   := -D__ASSEMBLY__

418 KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \

419            -fno-strict-aliasing -fno-common -fshort-wchar \

420            -Werror-implicit-function-declaration \

421            -Wno-format-security \

422         -save-temps=obj \

423            -std=gnu89

424 KBUILD_CPPFLAGS := -D__KERNEL__

425 KBUILD_AFLAGS_KERNEL :=

426 KBUILD_CFLAGS_KERNEL :=

427 KBUILD_AFLAGS_MODULE  := -DMODULE

 

Makefile   방식으로 수정한 다음 이전 절에 소개한 build_RPi_kernel.sh 커널 빌드 스크립트를 실행합시다. 전처리 코드는 out 폴더에 생성됩니다. 전처리 코드가 어떻게 생성됐는지 확인합시다.

 

커널 스케줄링 공통 코드가 있는 kernel/sched/core.c 파일에 대한 전처리 코드를 찾아 보겠습니다.

root@raspberrypi:/home/pi/RPi_kernel_src/out/kernel/sched# ls -al

total 33692

...

-rw-r--r--  1 root home  613852 Mar 19 09:35 .tmp_completion.i

-rw-r--r--  1 root home 20953 Mar 19 09:35 .tmp_completion.s

-rw-r--r--  1 root home 2800883 Mar 19 09:57 .tmp_core.i

-rw-r--r--  1 root home 368699 Mar 19 09:57 .tmp_core.s

-rw-r--r--  1 root home 1262723 Mar 19 09:35 .tmp_cpuacct.i

-rw-r--r--  1 root home 17772 Mar 19 09:35 .tmp_cpuacct.s

 

C 포멧 리눅스 커널 소스 파일은 다음 위치에서 전처리 파일로 생성됩니다

linux/kernel/sched/core.c

out/kernel/sched/.tmp_core.i

 

소스 파일 이름 앞에 ".tmp_" 접두사와 가장 마지막에 i 붙습니다.

 

그러면 다른 리눅스 커널 소스 코드는 어떻게 전처리 파일로 생성될까요?

linux/init 폴더에 있는 아래 파일을 예로 들겠습니다.

calibrate.c  do_mounts.c do_mounts_initrd.c

 

 파일들은 전처리 과정으로 out/init 폴더에 다음 이름으로 생성됩니다.

.tmp_calibrate.i  .tmp_do_mounts.c  .tmp_do_mounts.i  .tmp_do_mounts_initrd.i

 

root@raspberrypi:/home/pi/RPi_kernel_src/out/init# ls -al

total 12912

-rw-r--r--  1 312538 Mar 19 09:34 .tmp_calibrate.i

-rw-r--r--  1 10928 Mar 19 09:34 .tmp_calibrate.s

-rw-r--r--  1 2830878 Mar 19 09:34 .tmp_do_mounts.i

-rw-r--r--  1 1616189 Mar 19 09:34 .tmp_do_mounts_initrd.i

-rw-r--r--  1 7311 Mar 19 09:34 .tmp_do_mounts_initrd.s

-rw-r--r--  1 1621237 Mar 19 09:34 .tmp_do_mounts_rd.i

-rw-r--r--  1 14425 Mar 19 09:34 .tmp_do_mounts_rd.s

 

위와 같이 커널 Makefile 수정해 모든 리눅스 커널 소스 파일을 전처리 코드가 담긴 *.i 파일로 변환할  있습니다. 문제는 "*.i" 뿐만 아니라 "*.s" 파일로 생성되 용량이 5GB 까지 커진다는 점입니다

 

대부분 우리는 보고 싶은 커널 소스 파일에 대한 전처리 파일을 열어 보는 경우가 많습니다.

 

이번에 특정 소스 파일만 전처리 파일로 생성하는 방법을 소개합니다.

 

 스크립트는 다음과 같습니다.

[build_preprocess_rpi_kernel.sh]

 

#!/bin/sh

echo "configure build output path"

KERNEL_TOP_PATH="$( cd "$(dirname "$0")" ; pwd -P )"
OUTPUT="$KERNEL_TOP_PATH/out"
echo "$OUTPUT"

KERNEL=kernel7
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 bcm2709_defconfig

echo "kernel build"
make $PREPROCESS_FILE O=$OUTPUT zImage modules dtbs -j4 2>&1 | tee $BUILD_LOG

 

위와 같은 코드를 입력한  build_preprocess_rpi_kernel.sh 이름으로 저장합시다.

파일을 저장한  다음 명령어로 실행 권한을 줍시다.

root@raspberrypi:/home/pi/rpi_kernel_src# chmod +x build_preprocess_rpi_kernel.sh

 

이전에 소개했던 build_rpi_kernel.sh 빌드 스크립트 코드에 3 정도 명령어를 추가했습니다.

12 PREPROCESS_FILE=$1

13 echo "build preprocessed file: $PREPROCESS_FILE"

 

12~13 번째 줄은  스크립트를 실행할  전달하는 소스 코드 이름입니다.

 

22 번째  코드를 보겠습니다.

22 make $PREPROCESS_FILE O=$OUTPUT zImage modules dtbs -j4 2>&1 | tee $BUILD_LOG

 

커널 코드를 빌드할  "$PREPROCESS_FILE" 구문이 추가됐습니다.

지정한 파일만 전처리 파일로 추출하라는 의도입니다.

 

이번에 build_preprocess_rpi_kernel.sh  스크립트를 실행하는 방법을 알아봅시다. build_preprocess_rpi_kernel.sh  스크립트를 실행할  디렉토리를 포함한 파일 이름을 지정해야 합니다

build_preprocess_rpi_kernel.sh [파일이름.i]

 

예를 들어 linux/sched/core.c 파일을 전처리 코드로 추출하려면 다음 형식으로  스크립트를 실행하면 됩니다.

build_preprocess_rpi_kernel.sh linux/sched/core.i

 

이번엔 라즈베리파이에서 다음 명령어로 실행해 봅시다.

root@raspberrypi:/home/pi/RPi_kernel_src# build_preprocess_RPi_kernel.sh kernel/sched/core.i

configure build output path

build preprocessed file: kernel/sched/core.i

make[1]: Entering directory ' root@raspberrypi:/home/pi/RPi_kernel_src/out '

  GEN     ./Makefile

#

# configuration written to .config

#

make[1]: Leaving directory '/home/pi/RPi_kernel_src/out'

make[1]: Entering directory '/home/pi/RPi_kernel_src/out'

  GEN     ./Makefile

scripts/kconfig/conf  --silentoldconfig Kconfig

  CHK     include/config/kernel.release

  GEN     ./Makefile

  CHK     include/generated/uapi/linux/version.h

  Using  /home/pi/RPi_kernel_src/linux as source for kernel

  CHK     include/generated/utsrelease.h

  CHK     scripts/mod/devicetable-offsets.h

  CHK     include/generated/timeconst.h

  CHK     include/generated/bounds.h

  CHK     include/generated/asm-offsets.h

  CALL    /home/pi/RPi_kernel_src/linux/scripts/checksyscalls.sh

  CHK     include/generated/compile.h

  CPP     kernel/sched/core.i

  GZIP    kernel/config_data.gz

  CHK     kernel/config_data.h

  Kernel: arch/arm/boot/Image is ready

  Building modules, stage 2.

  Kernel: arch/arm/boot/zImage is ready

  MODPOST 1506 modules

make[1]: Leaving directory '/home/pi/RPi_kernel_src/out'

 

제대로 전처리 파일을 생성하면 위와 같은 빌드 메시지를   있습니다.

 

out/kernel/sched 디렉토리로 가면 core.i 파일만 전처리 코드로 생성된 것을 확인할  있습니다

root@raspberrypi:/home/pi/RPi_kernel_src/out/kernel/sched# ls

autogroup.o  clock.o       core.i  cpuacct.o      cpufreq.o            cpupri.o

 

 

소스 코드 디렉토리를 잘못 지정하면 다음 에러 메시지와 함께 빌드가 중단됩니다.

austin.kim@LGEARND20B15:~/src/book_RPi_kernel$ ./build_preprocess_RPi_kernel.sh  sched/core.i

configure build output path

build preprocessed file: sched/core.i

make[1]: Entering directory '/home001/austin.kim/src/book_RPi_kernel/out'

  GEN     ./Makefile

#

# configuration written to .config

#

make[1]: Leaving directory '/home/pi/RPi_kernel_src/out'

make[1]: Entering directory '/home/pi/RPi_kernel_src/out'

  GEN     ./Makefile

scripts/kconfig/conf  --silentoldconfig Kconfig

make[1]: *** No rule to make target 'sched/core.i'.  Stop.

make[1]: Leaving directory '/home/pi/RPi_kernel_src/out'

Makefile:146: recipe for target 'sub-make' failed

make: *** [sub-make] Error 2

 

  스크립트를 실행할 때는 디렉토리와 소스 파일을 이름을 정확히 지정해야 합니다.

 

 

 

 

 

 

출처: Austin Kim 블로그