Since version 2.6.23 linux started using build id, which is just a kind of dummy version string in ELF binary.
Code:
$ arm-linux-objdump -h vmlinux
vmlinux: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .note.gnu.build-id 00000024 00000000 00000000 00008000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_DISCARD
<snip>
This piece of string is useless run-time and objcopy (from vmlinux to arch/arm/boot/Image) is supposed to remove it, but it doesn't.
Code:
$ grep -i OBJCOPYFLAGS arch/arm/Makefile
OBJCOPYFLAGS :=-O binary -R .note -R .comment -S
Parameters to objcopy (-R .note) do not match the actual section (.note.gnu.build-id), so the build id is never removed, and this leads to 3G+ sized image. You can fix this by editing the line with OBJCOPYFLAGS in arch/arm/Makefile. Just replace the .note with correct section name (which you can see with objdump -h vmlinux, like above).
I haven't tracked down what really causes the mismatch in section names in my (and apparently your) build process when most other people don't seem to run into this. The above however fixes it.