Code Monkey home page Code Monkey logo

libsupcxx's Introduction

libsupcxx

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

Building instructions

libsupcxx can be built with CMake or dbt. The two build systems produce the same results.

Building with CMake

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 an x86_64-elf toolchain
  • linux-x86_64 - requires an x86_64-elf toolchain
  • raspi3 - requires an aarch64-elf toolchain

Building with DBT

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

Running and debugging

Baremetal targets

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"

RaspberryPi 3

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

Linux-x86_64 target

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

Notes

Running Elf64 bit kernels with qemu

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.

libsupcxx's People

Contributors

jfrohnhofen avatar ljanyst avatar ptia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libsupcxx's Issues

Shell status code not always correctly set. (Test08 fails)

Test08 fails, in that it returns a non-zero shell status code (1 on my machine).

The main() function calls std::exit(0), so the status code should be 0. (Just as a note -- the call to std::exit(0) is redundant in the test, since dropping off the end of main is the same as returning 0, which is the same as exit(0)).

dbt run "//libsupcxx/tests/Test08" cc-toolchain=linux-x86_64-libsupcxx

Running libsupcxx/tests/Test08:
Constructing global object
glibcxx datestamp: 20180726
glibcxx release: 8
sizeof(std::size_t): 8
float eval method: 0
ULLONG_MAX: 18446744073709551615
__alignas_is_defined: 1
printArgs(5, 1, 2, 3, 4, 5)
__bool_true_false_are_defined: 1
sizeof(std::uint8_t): 1
At exit function called
Destructing global object
FAILED: libsupcxx/tests/Test08#run

io/ is a hidden dependency of boot/

boot/raspi3 and boot/linux-x86_64 use io/string.hh/cc for standard C string functions. This dependency shouldn't exist, as at the moment io is not automatically linked, and it's probably best to keep standard C string functions in libsupcxx, which is always linked.

Return code from main ignored

The return code from main using libsupcxx is not the same as calling exit, at least in linux-x86_64-libsupcxx . Specifically, sys::exit(1) (which calls the C function exit(1)) causes a shell exit status of 1, whereas "return 1;" from an initial call to main leads to a shell exit status of 0.

Note, the C standard says:
5.1.2.2.3 Program termination

  1. If the return type of the main function is a type compatible with int, a return from the
    initial call to the main function is equivalent to calling the exit function with the value
    returned by the main function as its argument.

Test05 is flawed

Test05 currently fails with a crash.

The comments and print statement suggest that the expected behavior is as it is, but the behavior (as the comments also suggest) is undefined behavior.

There's several problems with this test:

  1. The test fails, even though the behavior is as expected.
  2. It's undefined behavior, so there is no guarantee what the test does.
  3. Even if the runtime is supposed to support specific behavior when one tries to recursively init a local static, any code that contains this construct exhibits undefined behavior and is therefore already faulty.

Here's an example running the test:

$ dbt run "//libsupcxx/tests/Test05" cc-toolchain=linux-x86_64-libsupcxx

Running libsupcxx/tests/Test05:
Getting the meaning of life!
Computing the meaning of life!
Answer to the Ultimate Question of Life, the Universe, and Everything: 42
Getting the meaning of life!
Answer to the Ultimate Question of Life, the Universe, and Everything: 42
recursiveInit(0)!
recursiveInit(1)!
FAILED: libsupcxx/tests/Test05#run

x86_64 toolchain has ArchName "i386"

It's probably not a big deal, but the toolchain registered by x86_64-elf-gcc has the field ArchName set to "i386".

I would expect it should be "x86_64".

Unwind stack on failure

A basic version could just return the raw return addresses. It can be expanded by reading the symbol table and printing the function names.

gcc toolchain BUILD.go served from a .tar.gz on storage.googleapis.com

We serve x86_64-elf-gcc from storage.googleapis.com. That's fine for the binaries (and I guess something like this is necessary to avoid the push limits of github).

But we also have BUILD.go in there, which specifies the toolchain.

I feel like that file should be in version control (ie: github). It's unlikely we want to edit gcc source files, but we do want to occasionally edit the BUILD.go. Right now apart from being a bit of a pain, the process for changing BUILD.go is very unclear.

Could we have a github repo per toolchain with just the BUILD.go file, and a dependency on the binaries on storage.googleapis?
This would also make specifying a version of the toolchain easier as we can depend on git branches and tags like for other versioned things.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.