Tags

, , , , , ,

This is a worked example of cross-compiling gcc 4.8.3 for AArch64 port on Ubuntu 12.04.3 LTS.

NOTE:

(i) Cross-compiling GCC : Full credit to GRC-IITB Team for the GCC config & build guide. I followed the instructions in this guide and changed a few config & build options where necessary.

(ii) QEMU’s aarch64 system emulation mode : Full credit to Alex for his wonderful and easy to follow article on Running Linux in QEMU’s aarch64 system emulation mode

Building/Cross compiling gcc 4.8.3 for ARM64(AArch64) port on linux:

The outline of cross compiling gcc is:

1. crossgcc1 : Build a stage1 cross compiler with certain facilities disabled

2. Initial Library(EGLIBC): Configure the C library using crossgcc1. Build some
specified C run-time object files, but not rest of the library. Install the
library’s header files and run-time object file, and create dummy libc.so

3. crossgcc2: Build a stage2 cross-compiler, using the header files and object
files installed in step 2

4. Final Library: Configure, build and install fresh C library, using crossgcc2

5. crossgcc: Build a full & final cross compiler, based on the C library built in step 4

Pre-requisites:

Pre-requisites for configuring and building GCC : https://gcc.gnu.org/install/prerequisites.html
However, it is recommended to install the latest version of these important libraries in respective order : GMP, MPFR, MPC, ISL, CLooG

To enable C++ language in GCC toolchain, GMP library must be configured as below:

#GMP Library configure options
$ CPPFLAGS=-fexceptions ../configure --enable-cxx  --prefix=/usr/local --build=i686-pc-linux-gnu

Source Tarballs:

Tar File Name Download URL
gcc-4.8.3.tar.bz2 http://gcc.cybermirror.org/releases/gcc-4.8.3/gcc-4.8.3.tar.bz2
binutils-2.24.tar.bz2 http://ftp.gnu.org/gnu/binutils/binutils-2.24.tar.bz2
Latest revision of EGLIBC svn co svn://svn.eglibc.org/trunk eglibc
linux-3.14.6.tar.xz https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.14.6.tar.xz

 

Setting Up the Environment for Cross Compilation:


#parent directory for sources and binaries of cross-compiler
$ mkdir crossbuild 

$ cd crossbuild

#Downloaded source tarballs should be put in respective folders
$ mkdir gcc binutils eglibc

#cross-compiler toolchain will be installed in this dir
$ mkdir install

#complete EGLIBC, header files, library files and startup C files for target will be installed in this dir
$ mkdir sysroot

#My PC linux version info:
$ uname -a
Linux linux 3.8.0-29-generic #42~precise1-Ubuntu SMP Wed Aug 14 15:31:16 UTC 2013 i686 i686 i386 GNU/Linux

#Set the environment variables to generalize the later steps for cross build:

#<path to crossbuild>/install
$ export prefix=/home/user1/crossbuild/install/

#<path to crossbuild>/sysroot
$ export sysroot=/home/user1/crossbuild/sysroot/

# Refer https://www.gnu.org/software/autoconf/manual/autoconf-2.65/html_node/Specifying-Target-Triplets.html for more info.

#This is my host info. Specify your host info
$ export host=i686-pc-linux-gnu

#host = build in our case for cross compiling.
$ export build=i686-pc-linux-gnu

#target is same for us, since our goal is to cross compile for aarch64 target.
$ export target=aarch64-linux-gnu

#architecture target info required to build linux kernel.
$ export linuxarch=arm64

$ export PATH=$prefix/bin:$PATH

#Including '/usr/local/lib' in library search path since libraries GMP,MPFR,MPC etc., are installed here.
$ export LD_LIBRARY_PATH=/usr/local/lib

1.1> Building Binutils for AArch64 port


#Start at parent directory 'crossbuild'

crossbuild$ cd binutils

crossbuild/binutils$ tar -jxf binutils-2.24.tar.bz2

crossbuild/binutils$ mkdir build && cd build

crossbuild/binutils/build$ ../binutils-2.24/configure --target=$target --prefix=$prefix --with-sysroot=$sysroot

#parallel build --> make -j n --> Here, n is number of processor cores on your system
crossbuild/binutils/build$ make -j 2

crossbuild/binutils/build$ make install

#Move to parent directory 'crossbuild'
crossbuild/binutils/build$ cd ../../

1.2> cross compile – gcc stage1


crossbuild$ cd gcc

crossbuild/gcc$ tar -jxf gcc-4.8.3.tar.bz2

crossbuild/gcc$ mkdir build && cd build

# --with-gmp, --with-mpfr options etc., are required if the corresponding libraries are not in the library search path
# On my system, I have installed all these libraries in /usr/local. For more info, refer https://gcc.gnu.org/install/configure.html

#Enable 'C' language only in stage1
crossbuild/gcc/build$ ../gcc-4.8.3/configure --target=$target --prefix=$prefix --with-gmp=/usr/local --with-mpfr=/usr/local --with-mpc=/usr/local --with-isl=/usr/local --with-cloog=/usr/local --without-headers --with-newlib --disable-shared --disable-threads --disable-libssp --disable-libgomp --disable-libmudflap --disable-multilib --disable-libatomic --disable-libitm --disable-libsanitizer --disable-libquadmath --disable-target-libiberty --enable-languages=c

#Install gcc in the install folder:

crossbuild/gcc/build$ PATH=$prefix/bin:$PATH make all-gcc -j 2

crossbuild/gcc/build$ PATH=$prefix/bin:$PATH make install-gcc

#Move to parent directory 'crossbuild'
crossbuild/gcc/build$ cd ../../

2.1> Install Linux Kernel Headers


#Place 'linux-3.14.6.tar.xz' package in 'crossbuild' directory

crossbuild$ tar -xf linux-3.14.6.tar.xz

crossbuild$ cd linux-3.14.6

#Install Linux Kernel headers into sysroot directory
crossbuild/linux-3.14.6$ PATH=$prefix/bin:$PATH make headers_install CROSS_COMPILE=$target- INSTALL_HDR_PATH=$sysroot/usr ARCH=$linuxarch

#Move to parent directory 'crossbuild'
crossbuild/linux-3.14.6$ cd ../ 

2.2> Installing EGLIBC Headers and Preliminary Objects



crossbuild$ cd eglibc

#check out trunk from EGLIBC svn directory

crossbuild/eglibc$ svn co svn://svn.eglibc.org/trunk eglibc

crossbuild/eglibc$ mkdir build && cd build

# libc_cv_forced_unwind=yes, libc_cv_c_cleanup=yes, libc_cv_ctors_header=yes are passed to configure script so that the tests for force-unwind support is skipped,
# C cleanup handling support and gcc constructor support are configured respectively.

crossbuild/eglibc/build$ BUILD_CC=gcc CC=$prefix/bin/$target-gcc AR=$prefix/bin/$target-ar RANLIB=$prefix/bin/$target-ranlib ../eglibc/libc/configure --prefix=/usr --with-headers=$sysroot/usr/include --build=$build --host=$target --disable-profile --without-gd --without-cvs --enable-add-ons libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes  libc_cv_ctors_header=yes

crossbuild/eglibc/build$ make install-headers install_root=$sysroot install-bootstrap-headers=yes

#Install shared libraries manually

crossbuild/eglibc/build$ mkdir -p $sysroot/usr/lib

crossbuild/eglibc/build$ make csu/subdir_lib

crossbuild/eglibc/build$ cp csu/crt1.o csu/crti.o csu/crtn.o $sysroot/usr/lib

#creating a dummy libc.so to link with libgcc_s.so

crossbuild/eglibc/build$ $prefix/bin/$target-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o $sysroot/usr/lib/libc.so

#Move to parent directory 'crossbuild'

crossbuild/eglibc/build$ cd ../../

3> cross compile – gcc stage2

#Change the working directory to build directory inside gcc folder

crossbuild$ cd gcc/build

#Clean the build folder for stage2 build

crossbuild/gcc/build$ rm -rf *

crossbuild/gcc/build$ ../gcc-4.8.3/configure --target=$target --prefix=$prefix --with-sysroot=$sysroot --with-gmp=/usr/local --with-mpfr=/usr/local --with-mpc=/usr/local --with-isl=/usr/local --with-cloog=/usr/local --disable-libssp --disable-libgomp --disable-libmudflap --disable-multilib --disable-libatomic --disable-libitm --disable-libsanitizer --disable-libquadmath --disable-target-libiberty --enable-languages=c

#parallel build
crossbuild/gcc/build$ PATH=$prefix/bin:$PATH make -j 2

crossbuild/gcc/build$ PATH=$prefix/bin:$PATH make install

#Move to parent directory 'crossbuild'
crossbuild/gcc/build$ cd ../../ 

4> Building Complete EGLIBC

#Change the working directory to the build directory inside eglibc folder.

crossbuild$ cd eglibc/build

#Clean the build folder for building EGLIBC completely

crossbuild/eglibc/build$ rm -rf *

crossbuild/eglibc/build$ BUILD_CC=gcc CC=$prefix/bin/$target-gcc AR=$prefix/bin/$target-ar RANLIB=$prefix/bin/$target-ranlib ../eglibc/libc/configure --prefix=/usr --with-headers=$sysroot/usr/include --build=$build --host=$target --disable-profile --without-gd --without-cvs --enable-add-ons libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes  libc_cv_ctors_header=yes

crossbuild/eglibc/build$ PATH=$prefix/bin:$PATH make -j 2

#Install the libraries in sysroot

crossbuild/eglibc/build$ PATH=$prefix/bin:$PATH make install install_root=$sysroot

#Move to parent directory 'crossbuild'
crossbuild/eglibc/build$ cd ../../ 

5> Building fully Cross-compiled GCC – stage3

#Change the working directory to build directory inside gcc folder

crossbuild$ cd gcc/build

#Clean the build folder for stage3/final build

crossbuild/gcc/build$ rm -rf *

#Enable languages 'C','C++' in stage3
crossbuild/gcc/build$ ../gcc-4.8.3/configure --target=$target --prefix=$prefix --with-sysroot=$sysroot --with-gmp=/usr/local --with-mpfr=/usr/local --with-mpc=/usr/local --with-isl=/usr/local --with-cloog=/usr/local --disable-nls --disable-static --disable-multilib --enable-shared --enable-__cxa_atexit --enable-c99 --enable-long-long --enable-threads=posix  --enable-checking=release --enable-libstdcxx-time --enable-languages=c,c++

crossbuild/gcc/build$ PATH=$prefix/bin:$PATH make -j 2

#Install the final gcc in the install folder:

crossbuild/gcc/build$ PATH=$prefix/bin:$PATH make install

#Move to parent directory 'crossbuild'
crossbuild/gcc/build$ cd ../../ 

6> Maintaining $sysroot Folder

#Manually copy a few libraries into sysroot. If c++ is enabled, copy the libstdc++.so* files also

crossbuild$ cp -d $prefix/$target/lib64/libgcc_s.so* $sysroot/lib64  

crossbuild$ cp -d $prefix/$target/lib64/libstdc++.so* $sysroot/usr/lib64

DONE!!! We now have a cross-compiled toolchain for AArch64 in $prefix. Also, EGLIBC installation in $sysroot.

In $prefix/bin, we should have aarch64-linux-gnu-gcc, aarch64-linux-gnu-as, aarch64-linux-gnu-ld etc.,

BuildStat Info

crossbuild$ ./config.guess
i686-pc-linux-gnu

crossbuild$ ./install/bin/aarch64-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=../../install/bin/aarch64-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/home/user1/aarch64-crossbuild-gcc4.8.3/install/libexec/gcc/aarch64-linux-gnu/4.8.3/lto-wrapper
Target: aarch64-linux-gnu
Configured with: ../gcc-4.8.3/configure --target=aarch64-linux-gnu --prefix=/home/user1/aarch64-crossbuild-gcc4.8.3/install/ --with-sysroot=/home/user1/aarch64-crossbuild-gcc4.8.3/sysroot/ --with-gmp=/usr/local --with-mpfr=/usr/local --with-mpc=/usr/local --disable-libssp --disable-libgomp --disable-libmudflap --disable-multilib --disable-libatomic --disable-libitm --disable-libsanitizer --disable-libquadmath --disable-target-libiberty --enable-languages=c
Thread model: posix
gcc version 4.8.3 (GCC)

crossbuild$ uname -a 
Linux linux 3.8.0-29-generic #42~precise1-Ubuntu SMP Wed Aug 14 15:31:16 UTC 2013 i686 i686 i386 GNU/Linux 

crossbuild$ dpkg -l libc6
 Name           Version        Description
==============-==============-============================================
 libc6          2.15-0ubuntu10 Embedded GNU C Library: Shared libraries

Testing:


$ cd ..
$ mkdir aarch64-examples && cd aarch64-examples

aarch64-examples$ vi hello.c

hello.c
~~~~~~~

#include <stdio.h>

int main(void)
{
  printf("I successfully built GCC 4.8.3 for ARM 64 port. Welcome All. \n");
  
  return 0;
}

#Build an ELF output file

aarch64-examples$ ../crossbuild/install/bin/aarch64-linux-gnu-gcc -o hello hello.c

#Verify - Use readelf to verify whether the executable is indeed for aarch64:

aarch64-examples$ ../crossbuild/install/bin/aarch64-linux-gnu-readelf -hl hello

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           AArch64
  Version:                           0x1
  ...
Program Headers:
  ...
     [Requesting program interpreter: /lib/ld-linux-aarch64.so.1]

  ...
Advertisements