libsupcxx
is an implementation of the freestanding C++ runtime on top
of bare metal. Most of it, is derived from the GNU standard C++ library and is,
therefore distributed under the terms of the GNU GPLv3 with the
runtime exception. The GNU library has been cleaned-up from all
the code that was not compatible with C++14 and all the code supporting the
previous versions of the standard has been converted to the form idiomatic to
C++14. All the code meant specifically for compilers other than GCC or for the
platforms we do not want to support has been removed as well.
The directory structure is as follows:
- boot - bootup code for the supported architectures including program startup and linker scripts
- cmake - CMake utility scripts
- io - printing utilities (
printf
) and other IO-related code - libruncxx - parts of the runtime that were either not provided (dependent on the OS or libc) or that had to be rewritten because of the target platform considerations
- libsupcxx - refactored and cleaned-up version of GCC's libsupc++
- tests - a bunch of simple tests kernels that test some of the functionality provided by the library
libsupcxx
can be built with CMake or dbt. The two build systems produce the same results.
First of all, you will need a cross-compiler targeting bare metal. To build one, you will need a couple of utilities and libraries. These may be installed on Ubuntu using the following command:
sudo apt-get install build-essential libgmp-dev libmpc-dev libmpfr-dev
This distribution provides a convenience shell script that can help with the building and installation process of the cross-compiler itself. Run something like the command below to build it for the desired architecture.
./build-cross-compiler.sh <installation-path> <architecture>
Currently supported architectures are:
x86_64-elf
aarch64-elf
After the installation process is complete, you will need to add the installation binary path to your shell's search path:
export PATH=<installation-path>/bin:$PATH
Finally, you can build the whole thing using CMake:
mkdir build
cd build
cmake .. -DPLATFORM_NAME=<platform>
make
where platform is one of the names below:
x86_64
- requires anx86_64-elf
toolchainlinux-x86_64
- requires anx86_64-elf
toolchainraspi3
- requires anaarch64-elf
toolchain
You will only need to have dbt installed. The cross-compiler dependency is automatically resolved by dbt. To fetch the dependencies run:
dbt sync
To build the whole thing run:
dbt build "//libsupcxx/.*" cc-toolchain=<toolchain>
where toolchain is one of
x86_64-libsupcxx
raspi3-libsupcxx
linux-x86_64-libsupcxx
The binaries built for x86_64
and raspi3
are meant for bare metal and thus are not runnuble
under an operating system. They are however, multiboot compatible kernels and,
therefore, can be run using qemu
. To install qemu
on Ubuntu, type:
sudo apt-get install qemu-system-x86
To run the tests, type:
qemu-system-i386 -serial stdio -kernel tests/test-07-throw-clean-up-rethrow.elf
The binaries are built in debug mode by default and may be debugged using GDB.
Run qemu
in one terminal window:
qemu-system-i386 -serial stdio -S -s -kernel tests/test-07-throw-clean-up-rethrow.elf
The -s
parameter is a shorthand for -gdb tcp::1234
and will start a GDB
server at localhost:1234
, -S
tells qemu
to not start the virtual CPU,
but to wait for the monitor (GDB) to start it. You can then run gdb in another
terminal window:
gdb tests/test-07-throw-clean-up-rethrow.elf
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000fff0 in ?? ()
(gdb) b main
Breakpoint 1 at 0x10057a: file /home/lj/Project/libsupcxx/tests/test-07-throw-clean-up-rethrow.cc, line 62.
(gdb) c
Continuing.
Breakpoint 1, main (cmdline=0x100043 <_start+40> "tests/test-07-throw-clean-up-rethrow.elf") at /home/lj/Project/libsupcxx/tests/test-07-throw-clean-up-rethrow.cc:62
62 int test = one();
(gdb) p cmdline
$1 = 0x100043 <_start+40> "tests/test-07-throw-clean-up-rethrow.elf"
At the time of writing this file, the released aarch64
version of qemu
does
not support the RaspberryPi3. However, the support has been included in the head
of the git repo. If you want to run the examples with the debugger in qemu
,
you will need to get the sources from here and compile them
yourself.
Furthermore, qemu
's bootloader won't load ELF binaries. Therefore, you will
need to use tha raw equivalent (the .hex
instead of the .elf
files). Note
that, regardless of what the bootloader accepts, gdb
will still need .elf
.
We also print to UART not to the frambuffer, so you need to tell qemu
to
forward the MiniUART to standard output.
qemu-system-aarch64 -M raspi3 \
-kernel tests/test-07-throw-clean-up-rethrow.hex \
-append "Kernel commandline params go here" \
-serial null -serial stdio
These binaries can be run as normal ELF executables. Optionally it is possible to
specify the size of the heap, by setting the environment variable LIBSUPCXX_HEAPLEN
.
If the variable is not set, it will default to 64 MiB.
LIBSUPCXX_HEAPLEN=100000 tests/test-07-throw-clean-up-rethrow.elf
Qemu checks if the kernel being loaded is an Elf 64 binary and, if it is, qemu
will refuse to load it for no good reason whatsoever. The qemu team decided long
ago to add this check to make the project feature compatible with GRUB. Even
though the feature worked perfectly fine in the first place and both GRUB and
syslinux can now load 64 bit kernels, this check has not yet been removed in any
released version. The patches
directory contains a fix should you wish to
rebuild qemu from source. See this launchpad ticket.