vmlinux 란?

리눅스 커널을 한 번이라도 빌드한 경험이 있다면 vmlinuxvmlinuz라는 파일을 본 경험이 있을 것입니다. 빌드 경험이 없더라도, 리눅스 루트 파일시스템을 돌아다니다가 /boot 디렉토리 내에 있는 vmlinuz 혹은 bzImage를 보았을 수도 있고요.

이번 글에서는 위 파일들이 무엇이며, 어떤 역할을 하는지 한 번 알아보도록 하겠습니다.

vmlinux

우선 리눅스 커널은 다른 프로그램과 마찬가지로 하나의 실행 가능한 프로그램입니다. gcc를 통해 c언어 소스코드 main.c를 빌드했을 때 a.out 이름의 ELF 바이너리가 나오는 것 처럼 커널도 빌드하면 ELF 바이너리가 나오게 됩니다. 그리고 이 바이너리가 vmlinux입니다.

vmlinux는 기본적으로 정적 링크되어 있으며, 디버그 인포가 포함되어 있습니다. 또한 압축되어 있지 않습니다.

$ readelf -h vmlinux
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x1000080
  Start of program headers:          64 (bytes into file)
  Start of section headers:          65012128 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         5
  Size of section headers:           64 (bytes)
  Number of section headers:         38
  Section header string table index: 37

vmlinux는 사이즈가 크기 때문에 부트로더가 직접 로드할 수 없으며, 후에 알아볼 vmlinuz라는 형태로 압축해서 사용합니다. vmlinux는 주로 커널을 디버깅하는 용도로 사용하게 됩니다.

vmlinuz / bzImage

vmlinuzvmlinux를 압축하여 부팅 가능하도록 만든 커널 이미지입니다. /boot 디렉토리를 보면 vmlinuz가 존재할 텐데, 바이오스가 lilo 혹은 GRUB과 같은 부트로더를 실행하고, 부트로더는 해당 이미지를 로드하여 커널을 실행하게 됩니다.

vmlinuz는 gzip 등으로 압축되어 약 15MB 정도의 크기를 가집니다. 또한 내부에 gzip의 압축 해제 코드가 내장되어 있어 런타임에 자가로 압축이 해제됩니다.

# /boot/grub/grub.cfg
...
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-ab65a1a2-0f26-4a66-a006-9c56630134a4' {
	recordfail
	load_video
	gfxmode $linux_gfx_mode
	insmod gzio
	if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
	insmod part_gpt
	insmod ext2
	set root='hd0,gpt2'
	if [ x$feature_platform_search_hint = xy ]; then
	  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  7d85336e-2019-4132-b599-e10bdb4f832b
	else
	  search --no-floppy --fs-uuid --set=root 7d85336e-2019-4132-b599-e10bdb4f832b
	fi
	linux	/vmlinuz-6.8.0-84-generic root=/dev/mapper/ubuntu--vg-ubuntu--lv ro
	initrd	/initrd.img-6.8.0-84-generic
}
...

grub의 설정 파일을 보면 여러가지 부팅 옵션들을 볼 수 있는데, 그 중linux 옵션에 vmlinuz-6.8.0-84-generic를 지정해 주는 것을 볼 수 있습니다.

make bzImage

bzImagevmlinuz의 원본이라고 보면 좋을 것 같습니다. 리눅스 커널을 위 명령어로 빌드하면 arch/x86/linux/boot/와 같은 디렉토리 아래에 bzImage가 생성됩니다.

cp arch/x86/linux/boot/bzImage /boot/vmlinuz

이후에는 bzImagevmlinuz라는 이름으로 카피하여 사용합니다.

vmlinuz 로부터 vmlinux 추출하기

/usr/src/linux-headers-$(uname -r)/scripts/extract-vmlinux vmlinuz > vmlinux

커널이 제공하는 스크립트를 사용하여 vmlinuz로부터 vmlinux를 추출할 수 있습니다.

결론

이번 글에서는 vmlinuxvmlinuz에 대해 알아보았습니다.

정리하자면 vmlinux는 압축되지 않은 원본 ELF 커널 바이너리이고, vmlinuz/bzImage는 압축된 부팅 가능한 커널 이미지입니다. vmlinux는 주로 커널 개발자가 커널을 디버깅할 때 사용하며, vmlinuz는 부트로더가 실제로 로드하는 파일로, /boot 디렉토리에 저장되어 있습니다.

다음 글에서는 initramfsinitrd에 대해 알아보도록 하겠습니다.