Skip to content

Latest commit

 

History

History
114 lines (99 loc) · 4.91 KB

building-an-x86-64-gcc-cross-compiler.md

File metadata and controls

114 lines (99 loc) · 4.91 KB

Building an x86_64 Cross-Compiler

The OSDev wiki gives an in-depth tutorial but it is not complete for a complete C++ freestanding implementation. The modifications listed under https://wiki.osdev.org/Libgcc_without_red_zone need to be followed as well to support x86_64, and some changes below are made to add the freestanding C++ headers.

Instructions

The articles in the above links are detailed enough to follow, but the steps are also listed below here for posterity. The following steps were tested on Ubuntu using GCC version 11.3.0 and binutils version 2.38, the versions that come pre-installed on Ubuntu 22.04.1 LTS.

  1. Create a build source directory (e.g. $HOME/gcc-cross) to hold the GCC source files.

  2. Download and extract the GCC source files corresponding to your installed GCC version (use gcc --version to check) to the build source directory.

  3. Download and extract the binutils source files corresponding to your installed binutils version (use ld --version to check) to the build source directory.

  4. Install dependencies.

    Linux

    Install the depndencies listed here using the following command:

    sudo apt install bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo
    

    MacOS

    Install the dependencies using the following command:

    brew install gmp mpfr libmpc
    
  5. Export the following environnment variables (configured to your liking)

    # directory to install the compiler (under $PREFIX/bin)
    export PREFIX="$HOME/opt/cross" 
    export TARGET=x86_64-elf
    export PATH="$PREFIX/bin:$PATH" 
  6. Build binutils:

    cd $HOME/gcc-cross # your build source directory
    
    mkdir build-binutils
    cd build-binutils
    ../binutils-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror # replace x.y.z with your binutils version
    make
    make install # this may require a sudo if the install directory $PREFIX is protected
  7. Run the following to check that binutils was properly installed from the above steps:

    # was the assembler built and installed at the expected path?
    which -- $TARGET-as || echo $TARGET-as is not in the PATH
  8. Modify the GCC source files to exclude redzone from libgcc:

    1. Create a file with the following contents under gcc-x.y.z/gcc/config/i386/t-x86_64-elf (where gcc-x.y.z are the downloaded GCC sources)
      # Add libgcc multilib variant without red-zone requirement
      
      MULTILIB_OPTIONS += mno-red-zone
      MULTILIB_DIRNAMES += no-red-zone
    2. Modify the x86_64-elf configuration located in the gcc-x.y.z/gcc/config.gcc file:
       x86_64-*-elf*)
          tmake_file="${tmake_file} i386/t-x86_64-elf" # <-- add this line
          tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h"
          ;;
  9. Build gcc:

    Linux

    cd $HOME/gcc-cross # your build source directory
    
    mkdir build-gcc
    cd build-gcc
    ../gcc-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers --disable-hosted-libstdcxx # replace x.y.z with your binutils version
    make all-gcc
    make all-target-libgcc
    make all-target-libstdc++-v3
    make install-gcc
    make install-target-libgcc
    make install-target-libstdc++-v3

    MacOS

    Identical to the Linux steps, but we also need to specify where to find the installed dependencies when creating the Makefile with configure:

    ../gcc-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers --disable-hosted-libstdcxx -\
        --with-gmp=/opt/homebrew/Cellar/gmp/x.y.z \
        --with-mpfr=/opt/homebrew/Cellar/mpfr/x.y.z \
        --with-mpc=/opt/homebrew/Cellar/libmpc/x.y.z 
    
  10. Append the following to ~/.profile to add the built compilers and linkers to the path:

        export PATH="<PREFIX>/bin:$PATH"

    where <PREFIX> is the value of the chosen install directory (the value of $PREFIX).

  11. If using clangd, set the STL_PATHS in the root directory Makefile to point to the location of the compilers includes and system specific includes.

Verification

You can verify that both the C and C++ compiilers were properly built with

$PREFIX/bin/$TARGET-gcc --version

and

$PREFIX/bin/$TARGET-g++ --version

Check also that there are two versions of libgcc (one with red-zone and one without) with

find $PREFIX/lib -name 'libgcc.a'

which should output

./gcc/x86_64-pc-elf/x.y.z/libgcc.a
./gcc/x86_64-pc-elf/x.y.z/no-red-zone/libgcc.a