HOWTO: Cross-compiling a 32-bit (i386) Linux kernel on 64-bit Machine (amd64)
Purpose: These days 64-bit hardware and Operating System are getting more and more common and affordable. Now if you are use to compile a custom Linux kernel on a regular Intel architecture 32-bit machine (i386) for a 32-bit machine itself then there were no issues. But now when you are trying to compile a custom Linux kernel for a 32-bit on your 64-bit machine things start getting different. One cannot directly compile a 32-bit kernel on a 64-bit machine in an easy fashion. I have asked in several forums but did not get a proper answers, so I decided to research on my own. In this blog post we will learn how to compile a 32-bit kernel on a 64-bit machine.
If you are looking for how to run a 32-bit graphical (X Windows) application on a 64-bit operating system, click here.
Terminology: Usually in the Linux world:
- i386 – Refers to 32-bit
- amd64 – Refers to 64-bit
Note: “amd64″ does not mean only 64-bit AMD machines. The term amd64 is used in general for all 64-bit machine – Intel, AMD and VIA. To give credit to AMD for first coming up with 64-bit architectures, the word amd64 is used.
Scenario: Here is my current scenario which I will be using throughout this entire blog post
Host Machine: AMD Athlon X2 Dual Core 64-bit machine with 64-bit Debian OS install
Target Machine: Intel Celeron 32-bit machine
Now, I would like to compile a Linux kernel for my Target machine on my Host machine. Typically people do these because usually Host machine are faster than than Target machine or just as in my case I have decided to compile all my Linux kernel on Host machine. However if you have installed a 32-bit OS (Operating System) on a 64-bit machine then you can just compile your kernel the way you use to do before. You don’t need to follow this post.
Step 1: Create a 32-bit debootstrap system
The fist step is to create a 32-bit Debian bootstrap system on your host machine. You can follow this link for step-by-step guide on how to do that.
The end result of this step will be that you will have a brand new 32-bit system in the following directory:
/home/kushalk/chroots/debian32
on your 64-bit machine
Step 2: Setup your kernel sources
Now just “chroot” into your bootstrap system gy giving the following command:
amd64# chroot /home/kushalk/chroots/debian32
debian32# cd /usr/src/
debian32# apt-get install linux-source-2.6.26
debian32# tar -xjvf linux-source-2.6.26.tar.bz2
and you are ready to start compiling the kernel
Note: Instead of downloading sources all over again from the Internet, you can also copy the source folder from your /usr/src/ directory on your host machine. Linux kernel sources are not 32-bit/64-bit dependent meaning that the same source tarball file can be used to compile 32-bit and 64-bit kernels.
Step 3: Configure your Linux kernel
Now either you can just create a default kernel .config file by :
debian32# cd /usr/src/linux-source-2.6.26
debian32# make defconfig
or else you can copy an existing .config file by:
debian32# cp </path-to-config-file/.config> .config
or else you can configure your kernel to generate a .config file by:
debian32# make menuconfig
Now if you want to use graphical kernel configuration like “make xconfig” or “make gconfig”, you won’t be able to do with the above setup so far. If you try to do you will end up getting following error messages:
debian32# make xconfig
scripts/kconfig/qconf arch/x86/Kconfig
No protocol specified
qconf: cannot connect to X server :0.0
make[1]: *** [xconfig] Error 1
make: *** [xconfig] Error 2
debian32#
We need to do some additional steps in order to get the graphical configuration screen which I will explain in my next post (see Step 5).
Step 4: Compile your Linux kernel
Now there are two ways to compile a Linux kernel – the “Standard” way or the “Debian” way which involves using “make-kpkg” utility. I usually compile the Debian way.
debian32# make-kpkg --initrd --append-to-version=-32bit kernel_image kernel_headers
Now go and grab a coffee and you should have your kernel ready in few minutes.
Now you can come out from your “chroot” environment and copy the kernel image back on your host system.
debian32# exit
amd64# cp /home/kushalk/chroots/debian32/usr/src/*.deb /root/
In the above command, I am copying all the *.deb files (which should be your compiled kernel and headers files) from my 32-bit bootstrap system to the “root” user directory on my host system (amd64). Although we used the notion of “32-bit system” it just means a directory which resides on your host system. Your 32-bit bootstrap system in on your 64-bit machine itself.
That’s it. Happy 32-bit’ing!


Email Subscription









June 5th, 2009 at 7:12 pm
[...] We have already seen how to create a debootstrap system and we also learned how to compile a 32-bit application (like Linux kernel) from within the debootstrap system in Debian Linux. [...]
October 23rd, 2009 at 12:05 pm
$ (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
$ fakeroot make-kpkg –arch i386 kernel-image
Works for me…
Reply to this comment
Admin Reply:
October 26th, 2009 at 10:14 pm
I am now curious to try that. I will really appreciate if you can briefly explain what you are doing in the commands before the “fakeroot” command.
Thanks.
Reply to this comment
October 27th, 2009 at 10:31 am
Making sure that the necessary binaries are present for the target. They’re needed because make-kpkg does this:
make CROSS_COMPILE=i486-linux-gnu- ARCH=i386 prepare
Symlinking is mostly fine since the same binaries are normally used for x86 and amd64 anyway. The odd one out is the compiler, which needs “-m32″ (though I’ve not tested without this, it seems reasonable to specify it anyway for correctness; and the compiler will target amd64 by default).
Reply to this comment
Admin Reply:
November 3rd, 2009 at 12:37 pm
Hi Ds,
Now I do see what you are trying to do in your little script before fakeroot. However before I try that, I would like to know how to un-do the steps (in a clean manner) to restore it to the original state (for building amd64 kernels).
Reply to this comment
November 1st, 2009 at 9:00 am
Nice post, but I am wondering (a bit lazzy to try myself) if
$ linux32 make defconfig
$ linux32 make
would not do the job? Did you investigate this possiblity?
Reply to this comment
ds Reply:
November 1st, 2009 at 3:37 pm
That seems fine.
“fakeroot linux32 make deb-pkg” also works, but doesn’t provide the sometimes-useful “you’re replacing the running kernel – are you sure?” questions.
However, “fakeroot linux32 make-kpkg kernel-image” builds 64-bit (this is clear from what happens when it runs “make oldconfig”).
Reply to this comment
pat Reply:
November 2nd, 2009 at 10:18 am
I agree my answer would not work to build a debian package.
I did try however to build the kernel from the sources tarball, and it worked. I was even able to boot on it with another 32-bit system I have. The only problem is that the configuration is not easy, only console mode config worked…
And installing the modules is not that easy. So let’s keep my answer for the archives… ;-p
Reply to this comment
pat Reply:
November 2nd, 2009 at 10:22 am
Just thinking to it a bit late, but installing the modules will be much easier through a simple chroot.
Reply to this comment
April 17th, 2010 at 8:31 am
“Note: ‘amd64′ does not mean only 64-bit AMD machines. The term amd64 is used in general for all 64-bit machine – Intel, AMD and VIA. To give credit to AMD for first coming up with 64-bit architectures, the word amd64 is used.”
That’s utterly wrong. There are 64-bit architectures since a long, long time, e.g. DEC Alpha. AMD did not “first come up with 64-bit architectures”. In fact, even Intel was earlier, with the Itanium. AMD, however, upgraded the old Intel 32-bit *x86 architectur* to 64-bit, and gets the credit for that.
Reply to this comment
Uszui Reply:
June 28th, 2012 at 3:06 am
Another thing, just giving the credits to the wrong vendor is one thing, the other thing is that the note suggests that all 64 bit machines were amd64, which is also wrong.
Not so long ago Intel started its own 64-bit CPUs. Those were completely incompatible with the 32-bit ones, and Linux world called them ia64. AMD came up with its competitor, also 64-bit processor but with 32-bit compatibility, called amd64 or x86_64. It turned out that amd64 was a greater success than ia64, so Intel started to use the amd64 architecture in its newer models, dropping the ia64. This way, there is a chance that a number of Linux users actually have an ia64 computer, for them, amd64 is the wrong choice.
Reply to this comment
October 6th, 2010 at 1:55 pm
[...] year, I wrote a blog article on bootstrapping your system using debootstrap. Later on, I wrote another article which used debootstrap again for creating a cross-compiling environment for Linux [...]
November 14th, 2011 at 1:48 am
I built i686 32 bit kernel in 64 bit AMD system. ^^ I did not do chroot method. It looks too much overhead honestly. I knew gcc is cross architecture compiler.
Build system: 2.6.39 AMD 64 bit
2.6.39amd64hp #1 SMP PREEMPT Fri Nov 11 21:33:44 KST 2011 x86_64 GNU/Linux
Target system: 2.6.39 Intel 32 bit Pentium M
Linux laptop 2.6.39 #1 PREEMPT Mon Nov 14 03:36:14 KST 2011 i686 GNU/Linux
It’s excerpt of dmesg of 32 bit system – a laptop.
[ 0.000000] Initializing cgroup subsys cpuset
[ 0.000000] Initializing cgroup subsys cpu
[ 0.000000] Linux version 2.6.39 (2.6.39) (penguin@theblue) (gcc version 4.4.5 (Debian 4.4.5-8
) ) #1 PREEMPT Mon Nov 14 03:36:14 KST 2011
Below did the cross architecture build.
“$ export KBUILD_VERBOSE=1″ is irrelvant. It shows messages during the kernel build.
$ export CFLAGS=”-march=pentium-m -O2 -pipe -fomit-frame-pointer”
gcc compiler optimization option for Intel Pentium M 1.8 GHz is pentium-m.
“-O2 -pipe -fomit-frame-pointer” are code optimization. “-pipe” is for the speed of compilation not binary build.
$ export CXXFLAGS=”${CFLAGS}”
I think CXXFLAGS is irrelevant too. It’s for g++ compiler.
“$ DEB_HOST_ARCH=i386 setarch i386 make-kpkg –revision “1″ –cross-compile – –arch=i386 –us –uc –initrd –rootcmd fakeroot kernel-image kernel-headers”
It injects cross-compile settings to Linux kernel build Makefile and manage the building process. As you see below, it executes two commands.
exec make kpkg_version=12.036+nmu1 -f /usr/share/kernel-package/ruleset/minimal.mk debian DEBIAN_REVISION=1 KPKG_ARCH=i386 CROSS_COMPILE=- INITRD=YES ROOT_CMD=fakeroot
I think this command starts Linux kernel build.
“exec debian/rules DEBIAN_REVISION=1 KPKG_ARCH=i386 CROSS_COMPILE=- INITRD=YES ROOT_CMD=fakeroot UNSIGN_CHANGELOG=YES UNSIGN_SOURCE=YES kernel-image kernel-headers”
I did not create symbolic links for i386. make-kpkg complains missing 32 bit gcc compiler, triggered “menu oldconfig”
$ export KBUILD_VERBOSE=1
$ export CFLAGS=”-march=pentium-m -O2 -pipe -fomit-frame-pointer”
$ export CXXFLAGS=”${CFLAGS}”
$ DEB_HOST_ARCH=i386 setarch i386 make-kpkg –revision “1″ –cross-compile – –arch=i386 –us –uc –initrd –rootcmd fakeroot kernel-image kernel-headers
It created two package files:
6.9M Nov 14 03:59 linux-headers-2.6.39_1_i386.deb
15M Nov 14 03:58 linux-image-2.6.39_1_i386.deb
Kernel files in the laptop:
5.4M Nov 14 04:09 initrd.img-2.6.39
1.6M Nov 14 03:57 System.map-2.6.39
3.6M Nov 14 03:57 vmlinuz-2.6.39
Files below are generic Debian i686 kernels.
8.4M Nov 12 19:15 initrd.img-2.6.32-5-686
6.0M Jul 14 13:44 initrd.img-2.6.26-2-686
908K Jun 12 01:35 System.map-2.6.26-2-686
1.5M Jun 12 01:34 vmlinuz-2.6.26-2-686
Reply to this comment
December 3rd, 2011 at 7:49 am
The deboostrap system does not know the command “make”. What should I do?
Reply to this comment
March 21st, 2012 at 7:13 am
Did you never try:
make ARCH=i386
Reply to this comment
March 23rd, 2012 at 10:34 am
[...] Nach dem obligaten Behaken einschlägiger Suchmaschen fand ich schliesslich drei Artikel [1] [2] [3], welche mich zur Lösung [...]