Thursday, December 3, 2009

Compiling linux kernel for x86 on x86_64

Now, that's nothing overly exotic. Yet a search through the web suggests some wild solutions like setting up a real x86_64 -> x86 cross-compiler or even setting up a 32-bit linux distribution inside a chroot.

The reasoning is simple:
  • If you have 32-bit chroot environment with a compiler, you can just compile the 32-bit kernel there in the usual fashion.
  • If you have the right cross-compiler, you can use the standard kernel cross-compilation procedure.
The downside is that both options are gonna eat some space off your HDD and take some time to set up.

But if you're on x86_64, you can install the multilib version of gcc that adds support for building 32-bit binaries with a simple "-m32" option.

Then I found this hint:
$ (echo ‘#! /bin/sh’; echo ‘exec gcc -m32 “$@”‘) >~/bin/i486-linux-gnu-gcc
$ chmod +x ~/bin/i486-linux-gnu-gcc
$ for i in ar ld nm objcopy strip; do
$ ln -s `which $i` ~/bin/i486-linux-gnu-$i
$ done

This basically creates a "fake" i486-linux-gnu cross-toolchain out of the multilib x86_64/x86 toolchain. Then it can be used with kernel Makefile like this:
make ARCH=i386 CROSS_COMPILE=i486-linux-gnu- <target>

That's a way I've been using for some time. But as I was preparing this post, I fired up google once again and discovered this very brief answer:
make CROSS-COMPILE=i686-pc-linux-gnu- ARCH=i386 <target>

And that command works despite me having neither real nor "fake" i686-pc-linux-gnu- cross-toolchain installed. Experimenting further reveals that all that is needed is:
make ARCH=i386 <target>

Just don't forget you need to keep that ARCH=i386 parameter throughout the make invocations (modules_install doesn't seem to need them), e.g.:
make ARCH=i386 menuconfig
make ARCH=i386 bzImage modules

In this case of building the kernel on a different machine than the one it's supposed to run on, you certainly don't want to install the built modules into /lib/modules, so invoke the make like this:
make INSTALL_MOD_PATH=prefix modules_install

Also, don't do any of the steps as root. -- There's no need to. If you build the kernel as root, you risk accidentally overwriting your host modules or causing some other damage.


  1. Three years later and still usable, thanks!

    1. true dat, 4 years later and still.

    2. freaking godsend.

  2. only "objdump" is missing in your for-loop

    1. Is objdump required for the kernel? Also, if you're building the kernel, then I suggest you just stick to the "ARCH=i386" way. That's how it's supposed to be done (I believe) and it works and is simple.

      OTOH if you do need a fake 32bit toolchain for some other reason, then yup, you might need objdump and possibly more.

  3. Yes, ARCH=i386 is best for naked kernel.
    Doesn't work for cross-compiling ubuntu kernel packages which re-override ARCH,
    so now trying a hint from the debian ancestors, which appears to work...
    make-kpkg --cross-compile - --arch i386 binary
    Watching logs, the critical piece it injects into makefile args seems to be KPKG_ARCH=i386,
    So, if you're building modern debian/ubuntu kernel packages, the simplest invocation might be
    debian/rules KPKG_ARCH=i386 CROSS_COMPILE=- binary-generic