Difference between native and cross compilation and how to compile simple program for x86 and ARM ?

If we consider that we are working on two platforms,
1. x86 – 32 or 64 bit i.e. laptop / desktop
2. ARM – Lets say Raspberry Pi

In this case, we will need to compile some programs which needs to run on x86 / desktop and some programs which needs to run on ARM platform. So, the programs which are compiled on x86 and runs on x86 i.e. compilation and execution on same platform, are called as “native compilation”

Now, when we need to run some programs on ARM, in normal scenario we download toolchain for ARM, and compile the program on x86, so in this case we compile a program on one platform i.e. x86 but run on another platform i.e. ARM, this is called as “cross compilation”

Now, lets see how native compilation happens,

1. create a hello world program with vim on ubuntu desktop / laptop as,

 vim helloworld.c
#include <stdio.h>
int main(int argc, char **argv) { printf("hello world\n"); return 0;

Now, compile the program on ubuntu and to run here ( on ubuntu ) itself as,

 $ gcc -o helloworld helloworld.c

Now, if you see the output binary generated, you will see like this,

 $ file helloworld
helloworld: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=325434d898d793ab3439389f750e4d4d7949b3b3, not stripped

So, it shown that generated binary is executable for intel 80386 / x86 since my laptop is 32 bit. Now, we will be able execute the same program on same terminal since we compile on x86 to execute on x86 as,

 $ ./helloworld
hello world

Now, lets try to understand cross compilation i.e. compile on x86 which will generate binary for ARM and to run on ARM.

READ  How compile and run time dependencies for packages are managed in yocto / bitbake recipes ?

for this, we need set of tools which are called as cross compiler or standard word is “toolchain” which helps to compile for ARM on x86 as,

 $ git clone https://github.com/raspberrypi/tools --depth 1
 $ cd tools
 $ git branch
* master

export toolchain path

 $ export PATH=$PATH:/home/myuser/rpi/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin
 $ arm-bcm2708-linux-gnueabi-gcc -o helloworld helloworld.c

here, as we see, for native compilation we have used only gcc, but for cross compilation we have to use arm-bcm2708-linux-gnueabi-gcc i.e. cross gcc.

Now, if we check, how output binary is generated, we will see as,

 $ file helloworld
helloworld: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.1.9, not stripped

It will show that now generated binary is for ARM , so we compiled on x86 ubuntu for ARM using toolchain.

Problem: Now if you have used the root filesystem created using Yocto, there are chances that this helloworld program compiled may not work on RPi console due to some mismatch and might show like this,

root@raspberrypi3:~# ./helloworld
-sh: ./helloworld: not found

In this case instead of above arm-bcm2708-linux-gnueabi toolchain, we need to use gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-gcc for compilation of program. For this you can export path like,

 $ export PATH=$PATH:/home/myuser/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin

and compile the program as,

 $ arm-linux-gnueabihf-gcc -o helloworld helloworld.c
 $ file helloworld ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.26, BuildID[sha1]=4a95b9df54776ae6240b17d0f3d4d9aa4ab00715, not stripped

And now try this compiled program on RPi.

Leave a Reply

Your email address will not be published. Required fields are marked *