Skip to main content
  1. All Posts/

i686-elf-tools

Tools Shell

i686-elf-tools

Cross compiling an i386- or i686-elf Win32 toolchain is an outstandingly complicated and painful process. Both Binutils and GCC fail to properly articulate the extent of software dependencies required to build them, resulting in a litany of spurious and confusing error messages being emitted during compilation. Even once you do have the required software dependencies in place, you will still run into roadblocks due to anomalies in how GCC performs cross compilation.
This repo provides a set of precompiled binaries to those who want to use get what they came for and move on (an i686-elf toolchain that, unlike others on the internet, includes cc1 and GDB), as well as a set of instructions for those that would like to build these things themselves. Also featured are a set of instructions for those that wish to install these tools on Mac OS X or Linux.
Pre-compiled binaries can be found here!
Information on using i686-elf-tools in Visual Studio can be found here!

Win32

Tutorial

By default, i686-elf-tools.sh will download

  • GCC 7.1.0
  • Binutils 2.28
  • GDB 8.0

If you would like to change these versions, specify the -gv, -bv and -dv parameters when invoking the script (for overriding the Binutils, GCC and Debugger versions, respectively). Instead of using MinGW32 or MinGW64, MXE is used, providing us with an awesome Win32 toolchain that always produces statically linked binaries that just work (and don’t need random MinGW DLLs).
Note: if you already have MXE installed, i686-elf-tools.sh won’t attempt to make MXE’s version of GCC. Please ensure that MXE’s gcc has been built (run make gcc in your MXE install directory), else you will experience issues during compilation.

Docker

The following command will compile all Linux/Windows binaries, placing the results under the current user’s profile. Substitute /home/admin in this command for whatever your home directory is.

docker run -it -v "/home/admin:/root" --rm lordmilko/i686-elf-tools

Any arguments (see below) specified after the image name (lordmilko/i686-elf-tools) will be passed as arguments to i686-elf-tools.sh within the container. In the above example, build results will be stored in /home/admin/build-i686-elf.
Note that absolute paths must be used when when specifying Docker volumes, as such specifying ~ for the local user’s home directory will not work.
To avoid making a mess on your system, the container will automatically self delete itself after it has run (--rm) leaving only the build results in your home directory.

# Compile GCC 9.2.0, Binutils 2.34 and GDB 9.1
docker run -it -v "/home/admin:/root" --rm lordmilko/i686-elf-tools -gv 9.2.0 -bv 2.34 -dv 9.1

Native

  1. Install a Debian based operating system, ideally 32-bit (i386). This procedure has successfully been performed on Debian 9.5 i386 and Ubuntu 18.04 64-bit (amd64). If you wish to compile a x86_64-elf toolchain (via -64), you should probably use a 64-bit operating system.
  2. Remove the CD-ROM source from /etc/apt/sources.list (if applicable)
  3. If you are running Ubuntu, you may need to modify /etc/apt/sources.list to include universe and multiverse in addition to main. If you simply do the default Ubuntu install, these appear to be included by default.

    -deb http://archive.ubuntu.com/ubuntu bionic main
    +deb http://archive.ubuntu.com/ubuntu bionic main universe multiverse
    deb http://archive.ubuntu.com/ubuntu bionic-security main
    deb http://archive.ubuntu.com/ubuntu bionic-updates main
  4. Run the following commands. sudo -s is optional, however if you are not running as root you will get repeated password request prompts during the course of the execution.

    sudo -s
    wget https://raw.githubusercontent.com/lordmilko/i686-elf-tools/master/i686-elf-tools.sh
    chmod +x ./i686-elf-tools.sh
    ./i686-elf-tools.sh
    <p>
      A full run (including installing prerequisites and configuring MXE) takes approximately 1.5-2 hours on a 4xCPU virtual machine. </li> 
      
      <li>
        When the script completes you will have two zip files containing your i686-elf toolchain</p> <ul dir="auto">
          <li>
            <code>~/build-i686-elf/i686-elf-tools-windows.zip</code>
          </li>
          <li>
            <code>~/build-i686-elf/i686-elf-tools-linux.zip</code>
          </li>
        </ul>
      </li></ol> 
      
      <p>
        If you experience any issues, you can specify one or more command line arguments to only perform certain parts of the script. The following arguments are supported
      </p>
      
      <ul dir="auto">
        <li>
          <code>binutils</code>
        </li>
        <li>
          <code>gcc</code>
        </li>
        <li>
          <code>gdb</code>
        </li>
        <li>
          <code>zip</code> &#8211; zip it all up!
        </li>
        <li>
          <code>linux</code> &#8211; compile the linux toolchain only
        </li>
        <li>
          <code>win</code> &#8211; compile the windows toolchain only
        </li>
        <li>
          <code>env</code> &#8211; only install the prerequisite packages + MXE
        </li>
        <li>
          <code>-gv</code>/<code>--gcc-version</code> &#8211; specify the GCC version to build
        </li>
        <li>
          <code>-bv</code>/<code>--binutils-version</code> &#8211; specify the Binutils version to build
        </li>
        <li>
          <code>-dv</code>/<code>--gdb-version</code> &#8211; specify the GDB version to build
        </li>
        <li>
          <code>-64</code> &#8211; compile for x86_64-elf instead of i686-elf
        </li>
      </ul>
      
      <pre># Compile binutils and gcc only
    

    ./i686-elf-tools.sh binutils gcc

      <p>
        The <code>win</code> argument should only be used if the Linux toolchain has already been compiled and you&#8217;re experiencing issues with the Win32 part.<br /> Logs are stored for each stage of the process under ~/build-i686-elf/build-<strong>xyz</strong>/<strong>xyz</strong>_<strong>stage</strong>.log<br /> e.g. <strong>~/build-i686-elf/build-gcc-7.1.0/gcc_make.log</strong><br /> If you attempt to run <code>make</code> and <code>configure</code> commands manually that depend on components of the linux i686-elf toolchain, ensure <code>~/build-i686-elf/linux/output/bin</code> is on your path, else you may get errors about binaries being missing.
      </p>
      
      <h2 dir="auto">
        <a rel="nofollow noopener" target="_blank" id="user-content-mac-os-x" class="anchor" aria-hidden="true" href="#mac-os-x"></a>Mac OS X
      </h2>
      
      <p>
        Installing an i386-elf toolchain on Mac OS X is &#8211; theoretically &#8211; outstandingly simple process. Note that the following relies on a third party script and is not supported by me. It may be possible to run i686-elf-tools.sh on Mac OS X with a bit of tweaking (like not using <code>apt-get</code> to install packages) however this is not supported.
      </p>
      
      <ol dir="auto">
        <li>
          Install <a rel="nofollow noopener" target="_blank" href="http://brew.sh/">Brew</a>
        </li>
        <li>
          Download the i386-elf recipes
        </li>
        <li>
          Copy <code>i386-elf-binutils.rb</code>, <code>i386-elf-gcc.rb</code> and <code>i386-elf-gdb.rb</code> to <code>/usr/local/Library/Formula</code>. As these formulae depend on one another, attempting to execute these directly with <code>brew install i386-elf-gcc.rb</code>, etc will fail.
        </li>
        <li>
          Run <code>brew install i386-elf-binutils</code>, <code>brew install i386-elf-gcc</code> and <code>brew install i386-elf-gdb</code>
        </li>
      </ol>
      
      <h2 dir="auto">
        <a rel="nofollow noopener" target="_blank" id="user-content-linux" class="anchor" aria-hidden="true" href="#linux"></a>Linux
      </h2>
      
      <p>
        Extract the contents of <code>i686-elf-tools-linux.zip</code> somewhere. By default GCC installs them under <code>/usr/local/</code>.<br /> To compile a newer i686-elf toolchain, invoke <code>i686-elf-tools.sh</code> as follows
      </p>
      
      <pre>./i686-elf-tools.sh linux</pre>
      
      <h2 dir="auto">
        <a rel="nofollow noopener" target="_blank" id="user-content-faq" class="anchor" aria-hidden="true" href="#faq"></a>FAQ
      </h2>
      
      <h3 dir="auto">
        <a rel="nofollow noopener" target="_blank" id="user-content-why-would-i-want-to-use-this" class="anchor" aria-hidden="true" href="#why-would-i-want-to-use-this"></a>Why would I want to use this?
      </h3>
      
      <p>
        For building your own <a rel="nofollow noopener" target="_blank" href="http://wiki.osdev.org/Bare_Bones">Operating System</a>, of course!
      </p>
      
      <h3 dir="auto">
        <a rel="nofollow noopener" target="_blank" id="user-content-how-do-i-install-this-on-windows" class="anchor" aria-hidden="true" href="#how-do-i-install-this-on-windows"></a>How do I install this on Windows?
      </h3>
      
      <p>
        After copying <code>i686-elf-tools-windows.zip</code> to your PC, all necessary programs can be found in the <code>bin</code> folder. You can then put this folder in your <code>PATH</code>, or simply browse to the programs in this folder manually. When running these programs, it is important to make sure all of the subfolders are kept together, as files outside of the bin folder are required for certain programs (such as GCC).
      </p>
      
      <h3 dir="auto">
        <a rel="nofollow noopener" target="_blank" id="user-content-does-this-include-libgcc" class="anchor" aria-hidden="true" href="#does-this-include-libgcc"></a>Does this include libgcc?
      </h3>
      
      <p>
        Seems so! For more information see the section How on earth did you compile libgcc? below.
      </p>
      
      <h3 dir="auto">
        <a rel="nofollow noopener" target="_blank" id="user-content-can-i-use-msysmsys2mingwmingwmingw-w32mingw-w64cygwin-etc-to-do-this" class="anchor" aria-hidden="true" href="#can-i-use-msysmsys2mingwmingwmingw-w32mingw-w64cygwin-etc-to-do-this"></a>Can I use MSYS/MSYS2/MinGW/MinGW/MinGW-w32/MinGW-w64/Cygwin, etc to do this?
      </h3>
      
      <p>
        No. But you can try. I got all sorts of crazy errors I was simply unable to resolve when I was looking at solutions to compile these tools. I have successfully compiled on Windows in the past, however there have been two issues with this:
      </p>
      
      <ul dir="auto">
        <li>
          Executables had dependencies on MinGW/Cygwin libraries (most likely as I just didn&#8217;t know how to statically link)
        </li>
        <li>
          GDB would randomly quit whenever I tried to type a command
        </li>
      </ul>
      
      <p>
        YMMV.
      </p>
      
      <h3 dir="auto">
        <a rel="nofollow noopener" target="_blank" id="user-content-can-i-use-distro-instead-of-debian" class="anchor" aria-hidden="true" href="#can-i-use-distro-instead-of-debian"></a>Can I use <code>$DISTRO</code> instead of Debian?
      </h3>
      
      <p>
        I originally tried to use CentOS 7 64-bit, however along the way I encountered various issues potentially attributable to bitness, resulting in my switching to a 32-bit OS to simplify troubleshooting. CentOS 7 32-bit cannot be used, as all the packages required by MXE are not available on yum.<br /> If you are determined not to use Debian (or another Debian derivitive), please see the <a rel="nofollow noopener" target="_blank" href="http://mxe.cc/#requirements">prerequisites for MXE</a>. Note: you may need additional packages to these to successfully compile gcc, e.g. texinfo, readline-devel, etc. Google any error messages you get to reveal the appropriate package you need to install.
      </p>
      
      <h3 dir="auto">
        <a rel="nofollow noopener" target="_blank" id="user-content-when-running-these-steps-manually-and-running-make-for-binutils-i-get-an-error-gcc_no_executables" class="anchor" aria-hidden="true" href="#when-running-these-steps-manually-and-running-make-for-binutils-i-get-an-error-gcc_no_executables"></a>When running these steps manually and running <code>make</code> for&#8230;
      </h3>