C++ exceptions and runtime support

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
yr
Member
Member
Posts: 31
Joined: Sat Mar 28, 2015 12:50 pm

C++ exceptions and runtime support

Post by yr »

Over time, through a combination of googling, reading ABI docs, browsing libsupc++ source, and generally mucking around, I've figured out a few things around C++ development in a freestanding environment. I have some notes on this stuff (e.g., building libsupc++) that I'm happy to share if anyone would find it useful. So please let me know if that's the case.

Not claiming to be an authority on any of it, of course, as the learning process is ongoing...
Techel
Member
Member
Posts: 215
Joined: Fri Jan 30, 2015 4:57 pm
Location: Germany
Contact:

Re: C++ exceptions and runtime support

Post by Techel »

Nice. Could you explain how to build libsupc++ or generally how to integrate exceptions into a freestanding kernel? I'm also currently fiddling around with this.
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: C++ exceptions and runtime support

Post by xenos »

I would also be interested in this. You might also consider putting it into the wiki. Actually there already exists some information, so you could extend that instead of starting from 0:

C++
Libsupcxx
C++_Exception_Support
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
yr
Member
Member
Posts: 31
Joined: Sat Mar 28, 2015 12:50 pm

Re: C++ exceptions and runtime support

Post by yr »

I'll look into merging with the wiki later when I have a bit more time, but for now below is a copy-paste of my notes on getting libsupc++ to work. Hope you guys find it useful. Happy to answer any questions.

libsupc++
Unfortunately, the gcc build system (at least up to v4.9.2) seems to be incapable of configuring a cross-compiler build for libsupc++, so we have to handle that ourselves. The only prerequisite is to have a few standard library pieces implemented already: some functions from stdlib.h (e.g., malloc, free, abort), and some functions from string.h (e.g., strcmp).

The actual steps to build are straightforward:
  • Copy the source for libsupc++ to wherever we'll be building.
  • Copy the file "unwind-pe.h" from the libgcc source directory to our libsupc++ source directory.
  • Write a makefile to compile all the source files and link the resulting object files into a static library.
  • Try to build, see what the errors are, resolve them, and try again.
Most of the compile errors will be caused by the compiler looking for bits/... and ext/... headers. The easiest way to resolve these is to search the gcc source tree for the required header, and copy it to libsupc++/bits/... or libsupc++/ext/... as needed. Note that some of the bits/... headers can in fact be found in the libsupc++ source directory itself (e.g., exception_defines.h), so for those we can just change the #include <bits/...> directive to remove the "bits/" prefix.

We'll likely also need to edit the bits/c++config.h header to set _GLIBCXX_HOSTED and _GLIBCXX_HAVE_TLS to 0, since we're building for a freestanding environment and there's no thread-local storage support unless we implement it.

Note that this can be a bit restrictive. For thread safety, exception support relies on thread-local variables (e.g., each thread is supposed to have an object of type __cxa_eh_globals to hold thrown exceptions). If there are no thread-local variables, then the library falls back on a global static buffer. This is fine so long as we are dealing with just one thread, but if there are multiple threads and any of them can throw exceptions, then things might get messed up. If we set _GLIBCXX_HAVE_TLS to 1, then the library will still compile. However, in that case we will have to set up the thread-local storage correctly at runtime (which has a standard, architecture-dependent handling for ELF binaries).

And the fun doesn't stop there. In case we do add TLS support, any thread-local variable with a non-trivial destructor will need that destructor called when the thread exits. The compiler handles this by registering thread-local destructors with __cxa_thread_atexit. In our freestanding world, the library implementation falls back on a single-threaded implementation, which can only lead to wonderful things once there are multiple threads. A possible way to deal with this might be to define _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL as 1 in bits/c++config.h, and provide our own implementation of __cxa_thread_atexit_impl (see atexit_thread.cc for reference). Or we can just avoid having non-trivial destructors for thread-locals.

There is an additional potential concern around exceptions. The ABI functions to allocate/deallocate memory when an exception is thrown (__cxa_allocate_exception and __cxa_deallocate_exception) use malloc/free by default. But if malloc fails, the allocation falls back on an emergency static global buffer, and access to this buffer is protected via a mutex. In our freestanding setup, the mutex implementation is trivial, so the buffer access is unprotected. So, in the event that malloc fails and multiple threads are throwing exceptions, there is a race condition. But, of course, malloc would never fail...

There is also another thing to be aware of. Local static variables are initialized the first time the code is executed, and the C++ standard requires this to be thread-safe. The ABI handles this by putting guards around the initialization (__cxa_guard_acquire and __cxa_guard_release) to ensure that it happens only once. Since our freestanding build does not have thread support, it falls back on a single threaded implementation. So, once again, there's a potential issue there, but it's relatively straightforward to avoid (either don't use local statics or ensure that the initialization runs before multiple threads are active).
Techel
Member
Member
Posts: 215
Joined: Fri Jan 30, 2015 4:57 pm
Location: Germany
Contact:

Re: C++ exceptions and runtime support

Post by Techel »

I'll look at it later, but thanks in advance!
User avatar
max
Member
Member
Posts: 616
Joined: Mon Mar 05, 2012 11:23 am
Libera.chat IRC: maxdev
Location: Germany
Contact:

Re: C++ exceptions and runtime support

Post by max »

That sounds a little hacky. Why bother having that in kernel, why not just in userspace with a proper OS-specific toolchain? Building libsupc++ should be straightforward then.
yr
Member
Member
Posts: 31
Joined: Sat Mar 28, 2015 12:50 pm

Re: C++ exceptions and runtime support

Post by yr »

That's a reasonable question, with a couple of answers. One serious, and the other less so (though both are honest).

Let's start with the serious. One of the things I'm interested in is the usefulness of higher level language abstractions in a kernel context. They generally require more runtime support (which, as kernel developers, we have to provide ourselves), but then make it easier to control complexity. At the end of the day, the conclusion might well be that the cost/benefit is not worth it. But one has to know enough to make that call. I don't think I'm there yet, but am certainly interested in learning from those who might be.

As an example, probably the single most useful idiom in C++ is RAII (closing brace = magic). It's powerful and makes many things clean and easy to reason about (e.g., std::lock_guard is awesome). However, RAII without exceptions is problematic because constructors can't signal errors. It's possible to work around this, but the workarounds are considerably less elegant.

Finally, on a less serious note... because hacking is fun. :D
User avatar
max
Member
Member
Posts: 616
Joined: Mon Mar 05, 2012 11:23 am
Libera.chat IRC: maxdev
Location: Germany
Contact:

Re: C++ exceptions and runtime support

Post by max »

yr wrote:Finally, on a less serious note... because hacking is fun. :D
I let that one count :mrgreen:

Yes it might make sense to have that in the kernel - but it can also make debugging it a lot more complicated, keep that in mind. All that fancy stuff that comes with newer C++ is more about making it easier to program more in less time, but you have to be careful with that stuff in kernel land. Faster is not always more efficient, because it sometimes leads to bugs that eat the time that you saved in the first place.
You should try to get libsupc++ compile a "standard way", that should be possible with a proper cross toolchain I think.
Anyways, good luck :)
dschatz
Member
Member
Posts: 61
Joined: Wed Nov 10, 2010 10:55 pm

Re: C++ exceptions and runtime support

Post by dschatz »

I had no issues getting libsupc++ to build for my cross compiler. The article on the wiki http://wiki.osdev.org/Libsupcxx#Full_C. ... supc.2B.2B is pretty good. One of the tricky parts is providing functions for threading (though you need this for C++ even without exceptions) to libgcc.
yr
Member
Member
Posts: 31
Joined: Sat Mar 28, 2015 12:50 pm

Re: C++ exceptions and runtime support

Post by yr »

dschatz wrote:I had no issues getting libsupc++ to build for my cross compiler. The article on the wiki http://wiki.osdev.org/Libsupcxx#Full_C. ... supc.2B.2B is pretty good. One of the tricky parts is providing functions for threading (though you need this for C++ even without exceptions) to libgcc.
Which version of gcc are you using? The article seems to refer to some rather dated versions. At least with version 4.9.2 (which I'm currently using), libsupc++ does not compile with those instructions. And it seems like other people have had the same experience: http://wiki.osdev.org/Talk:Libsupcxx.

I would really like to be able to build without the hacking, so if there's something I'm missing, please let me know.
yr
Member
Member
Posts: 31
Joined: Sat Mar 28, 2015 12:50 pm

Re: C++ exceptions and runtime support

Post by yr »

max wrote: You should try to get libsupc++ compile a "standard way", that should be possible with a proper cross toolchain I think.
Anyways, good luck :)
Thanks. I'm hoping to get there with some more work, but in the meantime figured I'd share whatever I've learned in case others are encountering similar issues.
Post Reply