Create your own cross toolchain for 64-bit & 32-bit ARM Machines

In many of my previous blogs/posts i have used a few cross tools to compile Linux kernel as well as many packages for ARM based platforms. I have used only pre compiled cross toolchains provided by either CodeSourcery or linaro to achieve that. Officially too, i follow the same principle as in many ways this is the easiest way to create binaries which needs to run on the target platform. Some times these are not bleeding edge but they are sufficient for most of the needs of the embedded devices.

So using pre-compiled binaries was kinda of boring and there is not that much control we have expect for untarring the packages and using it.

For absolute kicks I wanted to create a cross tool with latest stable release of GCC and binutils which when combined together forms parts of the cross tool. C compiler and binutils are two different entities which needs to compiled separately and then combined together to form the cross tool which can be used for compilation.

Let us create a separate directory for this activity as things might get a little bit confusing. I have named this directory as crosstool.

kasi@Vostro ~ $ mkdir crosstool

Binutils

This is a collection of tools like assembler, linker and other tools which help to generate symbol tables, create archives, read ELF files, do an object copy or object dump etc. This is a very important package as it help us in all the stages of project execution phase. Especially for people working in hardware level like BSP, these tools are much helpful for debugging issues. Personally, I have used these tools a zillion times to read the symbol table (if they are not stripped), get the assembly instructions of the ELF files, put some debug prints, check them using strings command and a lot more. There is not a day that goes by without me using these tools. Let me put it this way, each tool provided by this package needs a separate blog in itself if we want to understand them more.

For now let us try to compile and create them to suit our specific need.

The Usual ritual

Let us download the binutils package:

kasi@Vostro ~ $ cd crosstool/

kasi@Vostro ~/crosstool $ wget https://ftp.gnu.org/gnu/binutils/binutils-2.28.tar.bz2

Untar and move inside the binutils directory

kasi@Vostro ~/crosstool $ tar xf binutils-2.28.tar.bz2

kasi@Vostro ~/crosstool $ cd binutils-2.28/

kasi@Vostro ~/crosstool/binutils-2.28 $

Now is the time for us to configure the package. Since am doing this just out of curiosity I want to do something different, so i am going to create these tools for 64-bit ARM Machines.

For 64-bit ARM machines we should use the give the below command to configure in properly.
./configure –prefix=/opt/aarch64 –target=aarch64-linux-gnu

–prefix — This is the location in which all the compiled binaries and it helper files will be installed. You can choose any location you want as long as have the correct permissions. As i stick to old school habits, am going to give the location as /opt directory and sub directory as aarch64.

Pls note I will share details on how to compile it for 32-bit ARM machines also.

kasi@Vostro ~/crosstool/binutils-2.28 $ ./configure –prefix=/opt/aarch64 –target=aarch64-linux-gnu

checking build system type… x86_64-pc-linux-gnu

checking host system type… x86_64-pc-linux-gnu

checking target system type… aarch64-unknown-linux-gnu

checking for a BSD-compatible install… /usr/bin/install -c

< — Cut here to minimize logs — >

checking whether to enable maintainer-specific portions of Makefiles… no

configure: creating ./config.status

config.status: creating Makefile

kasi@Vostro ~/crosstool/binutils-2.28 $

Makefile has been generated which means that we have now successfully configured binutils and its time to fire make and wait for the machine to complete its work.

kasi@Vostro ~/crosstool/binutils-2.28 $ make -j 8

In my laptop the compilation was qqqsuccessfully completed without any issues. Now it is time to install these tools in the already provided prefix directory.

kasi@Vostro ~/crosstool/binutils-2.28 $ sudo make install

The compilation is really simple and just with execution of three commands we have the latest binutils package.

Let us look into the list of created binaries which is copied to /opt/aarch64.

kasi@Vostro ~/crosstool/binutils-2.28 $ ls -l /opt/aarch64/

total 12

drwxr-xr-x 4 root root 4096 Apr 6 23:16 aarch64-linux-gnu

drwxr-xr-x 2 root root 4096 Apr 6 23:16 bin

drwxr-xr-x 5 root root 4096 Apr 6 23:16 share

We got three directories and the directory which contains the binaries are in bin.

kasi@Vostro ~/crosstool/binutils-2.28 $ ls -l /opt/aarch64/bin/

total 92024

-rwxr-xr-x 1 root root 5542128 Apr 6 23:16 aarch64-linux-gnu-addr2line

-rwxr-xr-x 2 root root 5722432 Apr 6 23:16 aarch64-linux-gnu-ar

-rwxr-xr-x 2 root root 8000064 Apr 6 23:16 aarch64-linux-gnu-as

-rwxr-xr-x 1 root root 5497472 Apr 6 23:16 aarch64-linux-gnu-c++filt

-rwxr-xr-x 1 root root 105440 Apr 6 23:16 aarch64-linux-gnu-elfedit

-rwxr-xr-x 1 root root 6125848 Apr 6 23:16 aarch64-linux-gnu-gprof

-rwxr-xr-x 4 root root 8811544 Apr 6 23:16 aarch64-linux-gnu-ld

-rwxr-xr-x 4 root root 8811544 Apr 6 23:16 aarch64-linux-gnu-ld.bfd

-rwxr-xr-x 2 root root 5585992 Apr 6 23:16 aarch64-linux-gnu-nm

-rwxr-xr-x 2 root root 6588800 Apr 6 23:16 aarch64-linux-gnu-objcopy

-rwxr-xr-x 2 root root 8323088 Apr 6 23:16 aarch64-linux-gnu-objdump

-rwxr-xr-x 2 root root 5722432 Apr 6 23:16 aarch64-linux-gnu-ranlib

-rwxr-xr-x 2 root root 1696480 Apr 6 23:16 aarch64-linux-gnu-readelf

-rwxr-xr-x 1 root root 5535400 Apr 6 23:16 aarch64-linux-gnu-size

-rwxr-xr-x 1 root root 5529816 Apr 6 23:16 aarch64-linux-gnu-strings

-rwxr-xr-x 2 root root 6588792 Apr 6 23:16 aarch64-linux-gnu-strip

kasi@Vostro ~/crosstool/binutils-2.28 $

Let us download the GCC C compiler package

kasi@Vostro ~/crosstool $ wget https://ftp.gnu.org/gnu/gcc/gcc-6.3.0/gcc-6.3.0.tar.bz2

Untar and move inside the gcc directory.

kasi@Vostro ~/crosstool $ tar xf gcc-6.3.0.tar.bz2

kasi@Vostro ~/crosstool $ cd gcc-6.3.0/

kasi@Vostro ~/crosstool/gcc-6.3.0 $

Before doing this let us export the compiled binutils tools which will be used in the future.

kasi@Vostro ~/crosstool/gcc-6.3.0 $ export PATH=$PATH:/opt/aarch64/bin

With the above command we have exported the binutils tools into our current path.

To configure GCC to compile code that runs on 64-bit ARM machine use the below command:

./configure –prefix=/opt/aarch64 –target=aarch64-linux-gnu –with-newlib –without-headers –disable-shared –enable-languages=c

–without-headers and–with-newlib — This makes sure that libgcc will be built without requiring the presence of any header

–enable-languages — This is self-explanatory as it says to enable only C language for compiling.

kasi@Vostro ~/crosstool/gcc-6.3.0 $ ./configure –prefix=/opt/aarch64 –target=aarch64-linux-gnu –with-newlib –without-headers –disable-shared –enable-languages=c

checking build system type… x86_64-pc-linux-gnu

checking host system type… x86_64-pc-linux-gnu

checking target system type… aarch64-unknown-linux-gnu

checking for a BSD-compatible install… /usr/bin/install -c

checking whether ln works… yes

checking whether ln -s works… yes

checking for a sed that does not truncate output… /bin/sed

< — Cut here to minimize logs — >

checking how to compare bootstrapped objects… cmp –ignore-initial=16 $$f1 $$f2

checking for objdir… .libs

checking for the correct version of gmp.h… no

configure: error: Building GCC requires GMP 4.2+, MPFR 2.4.0+ and MPC 0.8.0+.

Try the –with-gmp, –with-mpfr and/or –with-mpc options to specify

their locations. Source code for these libraries can be found at

their respective hosting sites as well as at

ftp://gcc.gnu.org/pub/gcc/infrastructure/. See also

http://gcc.gnu.org/install/prerequisites.html for additional info. If

you obtained GMP, MPFR and/or MPC from a vendor distribution package,

make sure that you have installed both the libraries and the header

files. They may be located in separate packages.

kasi@Vostro ~/crosstool/gcc-6.3.0 $

OK, there come the first road bump. We need the above tools for cross compiling GCC compiler. As always “apt install” comes to our rescue.

We need to install the development files of these missing packages.

kasi@Vostro ~/crosstool/gcc-6.3.0 $ sudo apt install libgmp-dev libmpfr-dev libmpc-dev

This one did it for me and the configuration was successful.

kasi@Vostro ~/crosstool/gcc-6.3.0 $ ./configure –prefix=/opt/aarch64 –target=aarch64-linux-gnu –with-newlib –without-headers –disable-shared –enable-languages=c

< — Cut here to minimize logs — >

checking whether to enable maintainer-specific portions of Makefiles… no
configure: creating ./config.status
config.status: creating Makefile
kasi@Vostro ~/crosstool/gcc-6.3.0 $

Like in binutils package the Makefile got generated here too and it is time again to execute the make command to compile the C compiler.

kasi@Vostro ~/crosstool/gcc-6.3.0 $ make all-gcc -j8

This should complete the compilation in few minutes. We can now do a make install from the current location which copies the created C compiler to the /opt/aarch64 directory.

kasi@Vostro ~/crosstool/gcc-6.3.0 $ sudo make install

If you list the directories present now in /opt/aarch64/ you can see that a few more directories has been newly created.

kasi@Vostro ~/crosstool/gcc-6.3.0 $ ls /opt/aarch64/ -l

total 24

drwxr-xr-x 4 root root 4096 Apr 6 23:16 aarch64-linux-gnu

drwxr-xr-x 2 root root 4096 Apr 6 23:46 bin

drwxr-xr-x 2 root root 4096 Apr 6 23:46 include

drwxr-xr-x 3 root root 4096 Apr 6 23:46 lib

drwxr-xr-x 3 root root 4096 Apr 6 23:46 libexec

drwxr-xr-x 5 root root 4096 Apr 6 23:16 share

And the actual C compiler is copied in the bin directory.

kasi@Vostro ~/crosstool/gcc-6.3.0 $ ls /opt/aarch64/bin -l

total 111512

-rwxr-xr-x 1 root root 5542128 Apr 6 23:16 aarch64-linux-gnu-addr2line

-rwxr-xr-x 2 root root 5722432 Apr 6 23:16 aarch64-linux-gnu-ar

-rwxr-xr-x 2 root root 8000064 Apr 6 23:16 aarch64-linux-gnu-as

-rwxr-xr-x 1 root root 5497472 Apr 6 23:16 aarch64-linux-gnu-c++filt

-rwxr-xr-x 1 root root 4834080 Apr 6 23:46 aarch64-linux-gnu-cpp

-rwxr-xr-x 1 root root 105440 Apr 6 23:16 aarch64-linux-gnu-elfedit

-rwxr-xr-x 2 root root 4818496 Apr 6 23:46 aarch64-linux-gnu-gcc

-rwxr-xr-x 2 root root 4818496 Apr 6 23:46 aarch64-linux-gnu-gcc-6.3.0

-rwxr-xr-x 1 root root 148128 Apr 6 23:46 aarch64-linux-gnu-gcc-ar

-rwxr-xr-x 1 root root 148064 Apr 6 23:46 aarch64-linux-gnu-gcc-nm

-rwxr-xr-x 1 root root 148080 Apr 6 23:46 aarch64-linux-gnu-gcc-ranlib

-rwxr-xr-x 1 root root 2577248 Apr 6 23:46 aarch64-linux-gnu-gcov

-rwxr-xr-x 1 root root 2438376 Apr 6 23:46 aarch64-linux-gnu-gcov-tool

-rwxr-xr-x 1 root root 6125848 Apr 6 23:16 aarch64-linux-gnu-gprof

-rwxr-xr-x 4 root root 8811544 Apr 6 23:16 aarch64-linux-gnu-ld

-rwxr-xr-x 4 root root 8811544 Apr 6 23:16 aarch64-linux-gnu-ld.bfd

-rwxr-xr-x 2 root root 5585992 Apr 6 23:16 aarch64-linux-gnu-nm

-rwxr-xr-x 2 root root 6588800 Apr 6 23:16 aarch64-linux-gnu-objcopy

-rwxr-xr-x 2 root root 8323088 Apr 6 23:16 aarch64-linux-gnu-objdump

-rwxr-xr-x 2 root root 5722432 Apr 6 23:16 aarch64-linux-gnu-ranlib

-rwxr-xr-x 2 root root 1696480 Apr 6 23:16 aarch64-linux-gnu-readelf

-rwxr-xr-x 1 root root 5535400 Apr 6 23:16 aarch64-linux-gnu-size

-rwxr-xr-x 1 root root 5529816 Apr 6 23:16 aarch64-linux-gnu-strings

-rwxr-xr-x 2 root root 6588792 Apr 6 23:16 aarch64-linux-gnu-strip

kasi@Vostro ~/crosstool/gcc-6.3.0 $

There we have it. We have successfully created a C compiler which will be able to generate 64-bit binaries which can be run on 64-bit ARM based platforms.

Pls note that with this compiler you cant compile user space/user land code and create binaries which execute with the help of C library as we have disabled that option. The main reason for doing that is to give more options for selecting the C libary.

On Why it wont compile User land code

To compile user space code we need the C library (glibc or uclibc ) and the corresponding header files to successfully compile the C code. As I have told above, since there a few options available for choosing the C library (depending upon use case) i have kept it open so that in the future we can compile the desired C library and make that part of the croos toolchain which we have created.  I shall share a more detailed blog on this one in the near future.

But the good thing and important thing is you can compile linux kernel.

Procedure to configure binutils and GCC for 32-bit ARM

To compile the same packages for 32 bit ARM machines pls follow the below configuration for binutils and C compiler respectively.

To configure binutils for 32-bit ARM machine:
./configure –prefix=/opt/arm –target=arm-linux-gnueabihf

To configure GCC to compile code that runs on 32-bit ARM machine:
./configure –prefix=/opt/arm –target=arm-linux-gnueabihf –with-newlib –without-headers –disable-shared –enable-languages=c

Pls note i have changed the prefix location

Rest of the procedures are the same for both 32-bit and 64-bit compilation.

Again user space code cant be compiled using the 32-bit cross tool if compiled using the above procedure.

Why Linux kernel Alone

The reason why we can compile linux kernel using this tool chain is that linux kernel doesn’t not depend on any c libraries. But user space tools depend on C libraries for function definitions, reference and linking.

In the next blog i am going to use this toolchain to compile linux kernel for 64-bit ARM machine.To be more clear i am going to compile my own 64-bit kernel for Raspberry PI 3 platform for reasons which i have explained there. This was the main motivation for this blog in the first place.

Advertisements

One thought on “Create your own cross toolchain for 64-bit & 32-bit ARM Machines

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s