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.

7 comments:

  1. Three years later and still usable, thanks!

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

    ReplyDelete
    Replies
    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.

      Delete
  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

    ReplyDelete