AArch64 ILP32 Toolchain

From LEAP Wiki
Jump to: navigation, search

Introduction

This page describes the details about using and building ILP32 AArch64 toolchain.

Requirements

Using ILP32 toolchain

1. Run LEAP on ARM64 platform: Installation instructions

2. Become root in order to run Docker

sudo -i

3. Install the latest LEAP kernel (4.3+) and Docker

yum update kernel 
yum install docker

4. Since Docker is not yet functioning as a systemd service, start it manually:

# Only have to run it for the first time to create image pool for docker
systemctl start docker-storage-setup
 
screen -dm docker daemon \
  $(grep -Po "(?<=OPTIONS=).*" /etc/sysconfig/docker | sed "s/'//g") \
  $(grep -Po "(?<=DOCKER_STORAGE_OPTIONS=).*" /etc/sysconfig/docker-storage)
Idea.png
Docker-storage-setup fails to start?
Just run 'screen -dm docker daemon'. Docker will be running in loop device mode.

5. Fetch our AArch64 ILP32 docker image from DockerHub

docker pull leapproject/leap-aarch64_ilp32-toolchain

6. Start a Docker container with Bash shell running

docker run -it docker.io/leapproject/leap-aarch64_ilp32-toolchain

7. Try compiling your sources and run it!

### Attached to the container
# C
aarch64_ilp32-linux-gnu-gcc helloworld.c
./a.out
 
# C++
aarch64_ilp32-linux-gnu-g++ helloworld.cpp
./a.out

All toolchain files are located under /opt/ilp32.

Sources and Patches

GCC

Source: Linaro GCC 4.9.4

Patches:

Licenses: GNU GPLv2, GNU GPLv3

Description: This is Linaro's 4.9.4 GCC release from June 2015. The above two patches are there to allow building for the aarch64_ilp32 target.

Binutils

Source: Binutils (commit 9fde51ed303ea3ecbaa7c0084ea417e775a5db29)

Patches:

Licenses: GNU GPLv2, GNU GPLv3

Description: This is Binutils from the master branch. The above patch allows building for the aarch64_ilp32 target.

GLIBC

Source: GLIBC thunderx-ilp32-32timetoff_t branch (commit 574af3313a602be1197bbc3b5ea9b88b58063244)

Patches:

Licenses: GNU GPLv2

Description: This is a WIP GLIBC with the ilp32 patches applied. The above patch allows building for the aarch64_ilp32 target.

Kernel

Kernel 4.3 with ILP32 patches (from Cavium via LKML 2015-11). Refer to the Kernel source RPM for details.

Building ILP32 toolchain manually

Overview

The overall process to build the ILP32 toolchain is a two part process. The toolchain is that is found normally on LEAP isn't capable of emitting ILP32. Thus we will have to build one that does. Using the above sources that have the ILP32 support, we will build a intermediary which is capable of then building what we really want, an ILP32 capable toolchain. The methodology used will resemble building a cross compiler but instead of building for a different platform/architecture, we are building starting with LP64 and going towards ILP32.

To summarize what we'll be doing: LEAP LP64 toolchain -> LP64 toolchain capable of emitting ILP32 -> ILP32 capable toolchain

Build Script

The following is a guideline showing snippets of a script which will build the ILP32 toolchain natively on LEAP. This is meant to show the methodology we used to build the toolchain. The script in full can be found here.

The script will assume that:

  • You have obtained the sources above and have applied their respective patches.
  • You are running LEAP with a 4.3 or higher kernel.
  • You have sudo access.
  • The source directories are all in the current directory and have the names gcc, glibc and binutils-gdb respectively.


1. Firstly we will set up some variables that will be used to build both the middleman LP64 and ILP32 toolchains. Mainly these are paths and flags which can be adjusted to your needs and preferences.

# Set up the variables
INSTALL_PATH_LP64=/opt/lp64
INSTALL_PATH_ILP32=/opt/ilp32
TARGET_LP64=aarch64-lp64-linux-gnu
TARGET_ILP32=aarch64_ilp32-linux-gnu
GCC_CONFIG_LP64="--enable-languages=c,c++,fortran"
GCC_CONFIG_ILP32="${GCC_CONFIG_LP64} --with-multilib-list=ilp32"
 
GLIBC_COMMON="--disable-multilib --disable-profile --disable-debug \
              --disable-werror --without-gd --enable-shared \
              --enable-static-nss --enable-obsolete-rpc libc_cv_forced_unwind=yes"
 
GLIBC_CONFIG_LP64="--build=$MACHTYPE --host=${TARGET_LP64} --target=${TARGET_LP64} \
                   --with-headers=${INSTALL_PATH_LP64}/${TARGET_LP64}/include/ \
                   ${GLIBC_COMMON}"
 
GLIBC_CONFIG_ILP32="--build=$MACHTYPE --host=${TARGET_ILP32} --target=${TARGET_ILP32} \
                    --with-headers=${INSTALL_PATH_ILP32}/${TARGET_ILP32}/include/ \ 
                    ${GLIBC_COMMON}"
PMAKE=-j10

2. Here we'll set up the directory structure we'll be building in as well as setting up the necessary PATH for the build and grabbing some build dependencies. There are two sets of build directories as we'll be building two toolchains during this process.

# Build directory prefixes
B_LP64=build-lp64
B_ILP32=build-ilp32
 
# Set up build directories
mkdir ${B_LP64}-{binutils-gdb,gcc,glibc}
mkdir ${B_ILP32}-{binutils-gdb,gcc,glibc}
 
export PATH=${INSTALL_PATH_ILP32}/bin:${INSTALL_PATH_LP64}/bin:$PATH
 
# Grab the necessary dependencies and tools from the LEAP repo
yum install gcc gcc-c++ bison flex gperf texinfo automake

3. Now we start the build process. We first build our binutils-gdb and install it into our install path. We will be subsequently using the pieces from this binutils to build the next toolchain.

cd ${B_LP64}-binutils-gdb
../binutils-gdb/configure --prefix=$INSTALL_PATH_LP64 --target=$TARGET_LP64
make $PMAKE
make install
cd ..

4. Install the kernel headers from the system's headers to our install path.

cp -r /usr/include ${INSTALL_PATH_ILP64}/${TARGET_ILP64}

5. We start building some parts of gcc mainly the compilers and the portions related to isl. We again install them into the install path. From this point onward we will begin using the compilers built in this step.

cd ${B_LP64}-gcc
../gcc/configure --prefix=${INSTALL_PATH_LP64} --target=${TARGET_LP64} ${GCC_CONFIG_LP64}
make $PMAKE all-isl
make $PMAKE all-gcc
make install-gcc
cd ..

6. Here we install the standard C library headers, build and install the C runtimes and other start up files.

cd ${B_LP64}-glibc
../glibc/configure --prefix=${INSTALL_PATH_LP64}/${TARGET_LP64} ${GLIBC_CONFIG_LP64} CC="${TARGET_LP64}-gcc -O2"
make install-bootstrap-headers=yes install-headers
make $PMAKE csu/subdir_lib
install csu/crt1.o csu/crti.o csu/crtn.o ${INSTALL_PATH_LP64}/${TARGET_LP64}/lib
${TARGET_LP64}-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o ${INSTALL_PATH_LP64}/${TARGET_LP64}/lib/libc.so
touch ${INSTALL_PATH_LP64}/${TARGET_LP64}/include/gnu/stubs.h
cd ..

7. Build and install the compiler support libraries / libgcc.

cd ${B_LP64}-gcc
make $PMAKE all-target-libgcc
make install-target-libgcc
cd ..

8. Build and install the standard C library.

cd ${B_LP64}-glibc
make $PMAKE
make install
cd ..

9. Lastly we finish off by building the standard C++ library

cd ${B_LP64}-gcc
make $PMAKE all-libcpp
make $PMAKE
make install
cd ..

10. At this point we've finished building our middleman toolchain. Now that we have it, we can proceed to building the ILP32 toolchain. The steps to do so will mirror what we have done above with just differences in the install path and build flags. Refer to the full script for a reference.

11. The last thing the script does is set up the library paths and create a link to the interpreter.

ln -s ${INSTALL_PATH_ILP32}/${TARGET_ILP32}/lib/ld-2.21.90.so /lib/ld-linux-aarch64_ilp32.so.1
touch ${INSTALL_PATH_ILP32}/${TARGET_ILP32}/etc/ld.so.conf
${INSTALL_PATH_ILP32}/${TARGET_ILP32}/sbin/ldconfig

12. Now the toolchain is ready to be used. Just remember to export the PATH. At this point you may discard the middleman toolchain if desired as well as the various build directories that were created by the script.

export PATH=/opt/ilp32/bin:$PATH

Extra links