GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Was ist der Unterschied zwischen den folgenden Kernel-Makefile-Begriffen:vmLinux, vmlinuz, vmlinux.bin, zimage &bzimage?

vmlinux

Dies ist der Linux-Kernel in einem statisch verknüpften ausführbaren Dateiformat. Im Allgemeinen müssen Sie sich um diese Datei keine Gedanken machen, sie ist nur ein Zwischenschritt im Bootvorgang.

Die rohe vmlinux-Datei kann für Debugging-Zwecke nützlich sein.

vmlinux.bin

Dasselbe wie vmlinux, aber in einem bootfähigen rohen Binärdateiformat. Alle Symbole und Verschiebungsinformationen werden verworfen. Generiert aus vmlinux bis objcopy -O binary vmlinux vmlinux.bin .

vmlinuz

Die vmlinux-Datei wird normalerweise mit zlib komprimiert . Seit 2.6.30 LZMA und bzip2 sind ebenfalls erhältlich. Durch Hinzufügen weiterer Boot- und Dekomprimierungsfunktionen zu vmlinuz kann das Image zum Booten eines Systems mit dem vmlinux-Kernel verwendet werden. Die Komprimierung von vmlinux kann mit zImage oder bzImage erfolgen.

Die Funktion decompress_kernel() behandelt die Dekomprimierung von vmlinuz beim Booten, eine Meldung weist darauf hin:

Decompressing Linux... done
Booting the kernel.

zBild (make zImage )

Dies ist das alte Format für kleine Kernel (komprimiert, unter 512 KB). Beim Booten wird dieses Image in den Speicher niedrig geladen (die ersten 640 KB des RAM).

bzImage (make bzImage )

Das große zImage (hat nichts mit bzip2 zu tun ), wurde erstellt, während der Kernel wuchs und größere Bilder verarbeitet (komprimiert, über 512 KB). Das Bild wird hoch in den Speicher geladen (über 1 MB RAM). Da die heutigen Kernel weit über 512 KB groß sind, ist dies normalerweise der bevorzugte Weg.

Eine Überprüfung auf Ubuntu 10.10 zeigt:

ls -lh /boot/vmlinuz-$(uname -r)
-rw-r--r-- 1 root root 4.1M 2010-11-24 12:21 /boot/vmlinuz-2.6.35-23-generic

file /boot/vmlinuz-$(uname -r)
/boot/vmlinuz-2.6.35-23-generic: Linux kernel x86 boot executable bzImage, version 2.6.35-23-generic ([email protected], RO-rootFS, root_dev 0x6801, swap_dev 0x4, Normal VGA

Führen Sie einen ausführlichen Kernel-Build durch und suchen Sie nach den Dateien

Dieser Ansatz kann einen Einblick geben, wird nie veraltet sein und wird Ihnen helfen, leicht herauszufinden, welcher Teil des Build-Systems was tut.

Sobald Sie eine Build-Konfiguration haben, die eine der Dateien generiert, erstellen Sie mit:

make V=1 |& tee f.log

Ändern Sie einen Kommentar zu einer C-Datei, um eine erneute Verknüpfung zu erzwingen (z. B. init/main.c ist gut), wenn Sie bereits zuvor gebaut haben.

Untersuchen Sie jetzt f.log und suchen Sie nach den gewünschten Bildern.

Zum Beispiel werden wir in v4.19 zu folgendem Schluss kommen:

init/main.c
|
| gcc -c
|
v
init/.tmp_main.o
|
| CONFIG_MODVERSIONS stuff
|
v
init/main.o
|
| ar T (thin archive)
|
v
init/built-in.a
|
| ar T (thin archive)
|
v
built-in.a
|
| ld
|
v
vmlinux (regular ELF file)
|
| objcopy
|
v
arch/x86/boot/compressed/vmlinux.bin
|
| GZIP
|
v
arch/x86/boot/compressed/vmlinux.bin.gz
|
| .incbin
|
v
arch/x86/boot/compressed/piggy.S
|
| gcc -c
|
v
arch/x86/boot/compressed/piggy.o
|
| ld
|
v
arch/x86/boot/compressed/vmlinux (regular ELF file with gzipped code)
|
| objcopy
|
v
arch/x86/boot/vmlinux.bin
|
| arch/x86/boot/tools/build.c
|
v
arch/x86/boot/bzImage

Dünne Archive werden erwähnt unter:https://stackoverflow.com/questions/2157629/linking-static-libraries-to-other-static-libraries/27676016#27676016 Sie sind Archive, die nur auf andere Archive/Objekte verweisen, anstatt sie zu kopieren.

Der Kernel wechselte in v4.9 von inkrementellem Linken zu dünnen Archiven, wie beschrieben unter:https://stackoverflow.com/questions/29391965/what-is-partial-linking-in-gnu-linker/53959624#53959624

Vollständige Protokollinterpretation

Wenn wir beginnen, die ausführlichen Build-Protokolle von der Sicherung zu lesen, sehen wir zuerst:

ln -fsn ../../x86/boot/bzImage ./arch/x86_64/boot/bzImage

diese beiden sind also nur symbolisch verknüpft.

Dann suchen wir etwas weiter nach x86/boot/bzImage und finde:

arch/x86/boot/tools/build \
arch/x86/boot/setup.bin \
arch/x86/boot/vmlinux.bin \
arch/x86/boot/zoffset.h \
arch/x86/boot/bzImage

arch/x86/boot/tools/build ist eine ausführbare Datei, also führen wir sie aus, siehe Hilfenachricht:

Usage: build setup system zoffset.h image

und grep, um die Quelle zu finden:

arch/x86/boot/tools/build.c

Dieses Tool muss also arch/x86/boot/bzImage generieren ab arch/x86/boot/vmlinux.bin und andere Dateien TODO was ist der Sinn von build genau?

Wenn wir arch/x86/boot/vmlinux.bin befolgen wir sehen, dass es nur ein objcopy ist ab arch/x86/boot/compressed/vmlinux :

objcopy \
-O binary \
-R .note \
-R .comment \
-S arch/x86/boot/compressed/vmlinux \
arch/x86/boot/vmlinux.bin

und arch/x86/boot/compressed/vmlinux ist nur eine normale ELF-Datei:

ld \
-m elf_x86_64 \
-z noreloc-overflow \
-pie \
--no-dynamic-linker \
-T arch/x86/boot/compressed/vmlinux.lds \
arch/x86/boot/compressed/head_64.o \
arch/x86/boot/compressed/misc.o \
arch/x86/boot/compressed/string.o \
arch/x86/boot/compressed/cmdline.o \
arch/x86/boot/compressed/error.o \
arch/x86/boot/compressed/piggy.o \
arch/x86/boot/compressed/cpuflags.o \
arch/x86/boot/compressed/early_serial_console.o \
arch/x86/boot/compressed/kaslr.o \
arch/x86/boot/compressed/kaslr_64.o \
arch/x86/boot/compressed/mem_encrypt.o \
arch/x86/boot/compressed/pgtable_64.o \
-o arch/x86/boot/compressed/vmlinux

ls -hlSr sagt, dass piggy.o ist bei weitem die größte Datei, also suchen wir danach, und sie muss stammen von:

gcc \
-Wp,-MD,arch/x86/boot/compressed/.piggy.o.d \
-nostdinc \
-Ilinux/arch/x86/include \
-I./arch/x86/include/generated \
-Ilinux/include \
-I./include \
-Ilinux/arch/x86/include/uapi \
-I./arch/x86/include/generated/uapi \
-Ilinux/include/uapi \
-I./include/generated/uapi \
-include linux/include/linux/kconfig.h \
-D__KERNEL__ \
-m64 \
-O2 \
-fno-strict-aliasing \
-fPIE \
-DDISABLE_BRANCH_PROFILING \
-mcmodel=small \
-mno-mmx \
-mno-sse \
-ffreestanding \
-fno-stack-protector \
-Wno-pointer-sign \
-D__ASSEMBLY__ \
-c \
-o arch/x86/boot/compressed/.tmp_piggy.o \
arch/x86/boot/compressed/piggy.S

.tmp_ Präfix unten erklärt.

arch/x86/boot/compressed/piggy.S enthält:

.incbin "arch/x86/boot/compressed/vmlinux.bin.gz"

siehe auch:https://stackoverflow.com/questions/4158900/embedding-resources-in-executable-using-gcc/36295692#36295692

arch/x86/boot/compressed/vmlinux.bin.gz kommt von:

cat arch/x86/boot/compressed/vmlinux.bin arch/x86/boot/compressed/vmlinux.relocs | \
gzip -n -f -9 > arch/x86/boot/compressed/vmlinux.bin.gz

was kommt von:

objcopy  -R .comment -S vmlinux arch/x86/boot/compressed/vmlinux.bin

was kommt von:

LD      vmlinux

was bedeutet:

ld \
-m elf_x86_64 \
-z max-page-size=0x200000 \
--emit-relocs \
--build-id \
-o vmlinux \
-T ./arch/x86/kernel/vmlinux.lds \
--whole-archive \
built-in.a \
--no-whole-archive \
--start-group \
lib/lib.a \
arch/x86/lib/lib.a \
--end-group \
.tmp_kallsyms2.o

vmlinux ist riesig, aber alle gezeigten Objekte sind winzig gemäß ls -l , also habe ich recherchiert und etwas über einen neuen ar erfahren Funktion, von der ich nichts wusste:dünne Archive.

Unter:

AR      built-in.a

der Build tut:

ar \
rcsTPD \
built-in.a \
arch/x86/kernel/head_64.o \
arch/x86/kernel/head64.o \
arch/x86/kernel/ebda.o \
arch/x86/kernel/platform-quirks.o \
init/built-in.a \
usr/built-in.a \
arch/x86/built-in.a \
kernel/built-in.a \
certs/built-in.a \
mm/built-in.a \
fs/built-in.a \
ipc/built-in.a \
security/built-in.a \
crypto/built-in.a \
block/built-in.a \
lib/built-in.a \
arch/x86/lib/built-in.a \
drivers/built-in.a \
sound/built-in.a \
firmware/built-in.a \
arch/x86/pci/built-in.a \
arch/x86/power/built-in.a \
arch/x86/video/built-in.a \
net/built-in.a \
virt/built-in.a

T gibt das dünne Archiv an.

Wir können dann sehen, dass alle Unterarchive auch dünn sind, z. B. seit ich init/main.c geändert habe , haben wir:

ar \
rcSTPD \
init/built-in.a \
init/main.o \
init/version.o \
init/do_mounts.o \
init/do_mounts_initrd.o \
init/initramfs.o \
init/calibrate.o \
init/init_task.o

die schließlich aus der C-Datei durch einen Befehl wie folgt kommt:

gcc \
-Wp,-MD,init/.main.o.d \
-c \
-o \
init/.tmp_main.o \
/work/linux-kernel-module-cheat/submodules/linux/init/main.c

Ich kann init/.tmp_main.o nicht finden bis init/main.o Treten Sie auf die Protokolle, was eine Schande ist ... mit:

git grep '\.tmp_'

wir sehen, dass das wahrscheinlich von scripts Makefile.build kommt und ist mit CONFIG_MODVERSIONS verknüpft die ich aktiviert hatte:

ifndef CONFIG_MODVERSIONS
cmd_cc_o_c = $(CC) $(c_flags) -c -o [email protected] $<

else
# When module versioning is enabled the following steps are executed:
# o compile a .tmp_<file>.o from <file>.c
# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does
#   not export symbols, we just rename .tmp_<file>.o to <file>.o and
#   are done.
# o otherwise, we calculate symbol versions using the good old
#   genksyms on the preprocessed source and postprocess them in a way
#   that they are usable as a linker script
# o generate <file>.o from .tmp_<file>.o using the linker to
#   replace the unresolved symbols __crc_exported_symbol with
#   the actual value of the checksum generated by genksyms

cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<

cmd_modversions_c =                             \
    if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then     \
        $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes))  \
            > $(@D)/.tmp_$(@F:.o=.ver);                 \
                                        \
        $(LD) $(KBUILD_LDFLAGS) -r -o [email protected] $(@D)/.tmp_$(@F)       \
            -T $(@D)/.tmp_$(@F:.o=.ver);                \
        rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);        \
    else                                    \
        mv -f $(@D)/.tmp_$(@F) [email protected];                  \
    fi;
endif

Die Analyse wurde mit dieser Konfiguration durchgeführt, die CONFIG_KERNEL_GZIP=y enthält .

aarch64 arch/arm64/boot/Image

Nur ein unkomprimiertes objcopy ab vmlinux :

objcopy  -O binary -R .note -R .note.gnu.build-id -R .comment -S vmlinux arch/arm64/boot/Image

vmlinux wird im Grunde genauso wie für x86 durch die dünnen Archive erhalten.

arch/arm/boot/zImage

Sehr ähnlich zu X86 mit einem gezippten vmlinux , aber kein magisches build.c Schritt. Zusammenfassung der Anrufkette:

objcopy -O binary -R .comment -S  arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage

ld \
-EL \
--defsym _kernel_bss_size=469592 \
-p \
--no-undefined \
-X \
-T arch/arm/boot/compressed/vmlinux.lds \
arch/arm/boot/compressed/head.o \
arch/arm/boot/compressed/piggy.o \
arch/arm/boot/compressed/misc.o \
arch/arm/boot/compressed/decompress.o \
arch/arm/boot/compressed/string.o \
arch/arm/boot/compressed/hyp-stub.o \
arch/arm/boot/compressed/lib1funcs.o \
arch/arm/boot/compressed/ashldi3.o \
arch/arm/boot/compressed/bswapsdi2.o \
-o arch/arm/boot/compressed/vmlinux

gcc \
-c \
-o arch/arm/boot/compressed/piggy.o \
linux/arch/arm/boot/compressed/piggy.S

.incbin "arch/arm/boot/compressed/piggy_data"

cat arch/arm/boot/compressed/../Image | gzip -n -f -9 > arch/arm/boot/compressed/piggy_data

objcopy -O binary -R .comment -S  vmlinux arch/arm/boot/Image

QEMU v4.0.0 kann von bzImage booten, aber nicht von vmlinux

Dies ist ein weiterer wichtiger praktischer Unterschied:https://superuser.com/questions/1451568/booting-an-uncompressed-kernel-in-qemu


Linux
  1. Was ist der Unterschied zwischen #!/usr/bin/env bash und #!/usr/bin/bash?

  2. Was ist der Unterschied zwischen ls und l?

  3. Was ist der Unterschied zwischen Kerneltreibern und Kernelmodulen?

  4. Was ist der Unterschied zwischen `su -` und `su --login`?

  5. Was ist der Unterschied zwischen remount zu umount/mount?

Was ist der Unterschied zwischen macOS- und Linux-Kernels

Was ist der Unterschied zwischen Linux und Unix?

Was ist ein Hypervisor? Was ist der Unterschied zwischen Typ 1 und 2?

Was ist der Unterschied zwischen Curl und Wget?

Was ist der Unterschied zwischen partx und kpartx?

Was ist der Unterschied zwischen $(CC) und $CC?