Documentation/ZImageFormat

zImage Format

The Linux zImage has the following structure:

zImage start
        descompression code start
             head.S
             some C code to unzip the data
        decompression code end 

        compressed image start
             piggy.gz
             ?padding
        compressed image end
zImage end

piggy.gz, when decompredded, contains the raw kernel image, as loaded into the ram and executed by the CPU.

The first step, is to get the decompressed kernel image. We know that the gzip header starts with the 0x8b 0x1f magic number, so

armeb-linux-gnu-objdump.zz -EL -b binary -D -m armv5t zImage | grep 8b1f
    30d8:       00088b1f        andeq   r8, r8, pc, lsl fp
   12338:       88b1f9cb        ldmhiia r1!, {r0, r1, r3, r6, r7, r8, fp, ip, sp, lr, pc}
   134a8:       09b8b1fe        ldmeqib r8!, {r1, r2, r3, r4, r5, r6, r7, r8, ip, sp, pc}
....

And the first match is the one we need. We copy the piggy.gz with dd:

dd if=zImage of=piggy.gz bs=1 skip=12504

and decompress it with gunzip:

gunzip piggy.gz

gzip complains about trailing garbage, but I believe there is just some padding.

The piggy image is creatd from the vmlinux, which is the binary kernel image in ELF format, with ELF headers and symbol names. When piggy is created, the precious headers and symbol information is stripped away,

armv5b-softfloat-linux-objcopy -O binary -R .note -R .comment -S  vmlinux arch/arm/boot/Image
gzip -f -9 < arch/arm/boot/compressed/../Image > arch/arm/boot/compressed/piggy.gz

and only the exported symbols preserve their names, to make run-time module loadign possible. Without the symbol information the assembly code becomes really hard to read, as all non-exported functions and variables loose their names.

To ease debugging however, it is possible to build a table containing all symbol names and addresses at the kernel compilation time, and include in into the kernel. This way, when you get a kernel Oops, it prints function names instead of addresses in the call trace. Also the table can be viewed through the /proc/kallsyms file.