A bare-metal x86-cross-compiler on Mountain Lion

I wanted to create a bare-metal program for an Intel-x86 processor. The program is used in a chapter called The Bare Metal in the book Into Embedded.

On an Ubuntu Linux host I could use gcc, together with a linker script, to accomplish the task. I could then run the program using Bochs.

On a Mac Mountain Lion host, the above method did not work out of the box, due to ld not being the GNU linker.

In addition, gcc was not GNU gcc either.

I searched the net and found this interesting page by M3 Operating System Development where it was described how to build an i386 cross-compiler. I thought that this could be a way to create a compiler for bare-metal programs with no OS-dependencies – which was desirable since the bare-metal program was to be evolved into an OS by itself.

Problem arose, however, since the pre-installed gcc on my Mac could not build the i386-cross-gcc.

I searched again, and found this eminent page by Solarian Programmer where it is described how to build a GNU gcc compiler.

I downloaded the gcc 4.7.2 sources from the GNU ftp repository.

Then, following the instructions, however leaving out the choice of building a compiler for Fortran and also changing the gcc version from 4.7.1 to gcc 4.7.2, I was able to build a native GNU gcc compiler.

The newly built native gcc could then be set to the default gcc by issuing the command

export PATH=/usr/gcc-4.7.2/bin:$PATH

Then, returning to the instructions for building an i386-cross-gcc, I started with downloading


from the GNU binutils repository.

I created a destination directory for the cross compiler, by doing

sudo mkdir /usr/local/i386elfgcc/

The binutils could then be unpacked, configured, and built, using the commands

tar zxvf binutils-2.23.tar.gz
mkdir build-binutils
cd build-binutils/
../binutils-2.23/configure --target=i386-elf --prefix=/usr/local/i386elfgcc
sudo make install

I then built gcc, using inspiration also from this OS development wiki, by issuing the commands

tar xvjf gcc-4.7.2.tar.bz2
mkdir build-gcc
cd build-gcc
../gcc-4.7.2/configure --target=i386-elf --prefix=/usr/local/i386elfgcc --with-gnu-as --with-gnu-ld --disable-libssp --enable-languages=c --without-headers
make all-gcc
sudo make install-gcc

After having added /usr/local/i386elfgcc/bin to the PATH environment variable I was able to compile and link a bare metal program.

The program consists of three C-files, which I could compile using the commands

i386-elf-gcc -Wall -c screen_output.c
i386-elf-gcc -c -Wall -DBUILD_X86_FD_TARGET src/bare_metal.c -o obj/bare_metal_x86_fd_target.o
i386-elf-gcc -c -Wall -DBUILD_X86_FD_TARGET src/console.c -o obj/console_x86_fd_target.o

The program could then be linked, using a command where also startup code, written in assembly and assembled using NASM resulting in the object file start_code.o, as

i386-elf-ld -T arch/x86_fd_target/link.ld --oformat=elf32-i386 -melf_i386 arch/x86_fd_target/start_code.o arch/x86_fd_target/screen_output.o -o prog_x86_fd_target.elf obj/console_x86_fd_target.o obj/bare_metal_x86_fd_target.o

Finally, the file prog_x86_fd_target.elf needs to be converted from ELF format to raw binary format. This can be done using the command

i386-elf-objcopy -O binary prog_x86_fd_target.elf prog_x86_fd_target.bin

As a last step, a binary bootable image for a floppy-disc drive can be created, by concatenating a FAT12 boot sector, a defined number of empty FAT12-sectors, and the binary file created by the i386-elf-objcopy command.

The concatenation is done as

cat arch/x86_fd_target/boot.bin arch/x86_fd_target/b_32_512.bin prog_x86_fd_target.bin > arch/x86_fd_target/a.img

The program can now be run, using Bochs, by giving the command

bochs -f arch/x86_fd_target/bochsrc.txt -q