C++: Difference between revisions

3,859 bytes removed ,  26 days ago
m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
mNo edit summary
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(34 intermediate revisions by 15 users not shown)
Line 1:
:''For a quick tutorial on getting a bare bones C++ kernel running see [[C++Bare bare bonesBones]]''
One thing up front: you can do a kernel in C++. It has been done before. This page will not discuss the pros and cons, just tell you about the things you have to be aware of when doing it.
 
A kernel can be programmed in C++, it is very similar to making a kernel in C, except that there are a few pitfalls you must take into account (runtime support, constructors, ...). This page will not list any (dis)advantages of this approach, but rather what you need to do to get things fired up.
For an article on linkage between C++ and ASM (please ''do'' read this, so that we don't have forum topic repetition), see [[C++ to ASM linkage in GCC]].
 
MostA featureslot of features C++ comeoffers "forcan free",be i.e.used on-the-fly; they require no additional supportingsupport or workcode to beuse usedthem inproperly kernel space(e.g. Templatestemplates, for example, do not require any additional logic; neither do classes, even when inheritance and, virtual functions). There are involved.however Otherother thingsparts of C++ that do require runtime support., This documentwhich will firstbe explaindiscussed howin to turn these features off, and then, gradually, how to implement the required support so you can turn them onthis againarticle.
 
== Introduction ==
==Features requiring run time support==
===Startup code===
By default, G++ attempts to link in startup code - the stuff usually done before <tt>main()</tt> is called, and after it exits / returns. This is all fine in a hosted environment, but you don't want to have it in your kernel (and it would not compile, either). Disable this by setting <tt>-nostartfiles</tt>.
 
If you have created a C++ kernel as documented in the [[Bare Bones]] article, then many C++ features are already available and work out the box. However, your kernel does not yet satisfy the ABI and you cannot be confident that the compiler will not emit problematic code, even if you stick to the intersection of C and C++. In particular, you may need to initialize further CPU state to enable the floating-point registers and instructions, as the compiler has every reason to think floating point registers and instructions are available by default.
====Why?====
It's for the very same reason of C. The startup code needed for C is OS-specific, and some times compiler specific. In a freestanding environment, you'll need to implement your own startup code to configure the stack and other language specific features. Then, your boot loader has to know where this startup code begins and jump to that address if it hopes to successfully run your kernel.
 
However, the compiler will assume that all the C++ runtime support is available by default, however you are not linking in libsupc++ into your C++ kernel, which implements the necessary run-time support. This is why you are passing -fno-rtti and -fno-exceptions to your cross-compiler to let these runtime features are unavailable. Going further, you should link in libsupc++ into your kernel, but at the moment it's known to not be readily accessible to those starting out with operating systems development and the GCC build process doesn't cross-compile it properly for the bare -elf platforms by default.
There is a bit more work to do than in C before calling main. For more information see [[C++ Bare Bones]].
 
You also need to call the global constructors as documented in [[Calling Global Constructors]] to satisfy the ABI requirement that the program initialization tasks are properly called.
===Pure virtual functions===
If you want to use pure virtual functions, your compiler needs one support function. It is only called in case a pure virtual function call cannot be made (e.g. if you have overridden the virtual function table of an object). But nonetheless your linker will complain about unresolved symbols, if you use pure virtual functions and don't provide that support routine.
 
== Pure virtual functions ==
====Why?====
It is a requirement of C++ to provide a backup function to call when a virtual function cannot be called.
 
If you want to use pure virtual functions, your compiler needs a single support function. It is only called in case a pure virtual function call cannot be made (e.g. if you have overridden the virtual function table of an object). But nonetheless your linker will complain about unresolved symbols, if you use pure virtual functions and don't provide this support routine.
====Enabling pure virtual functions====
To enable the use of virtual functions in GCC, you simply need the following function in one of your .cpp files. You do not need to place a prototype or anything in any of your headers. The contents of the function itself does not need to print an error message or do anything at all, since most implementations simply do nothing if the pure virtual function call cannot be made.
 
Enabling pure virtual functions in GCC is fairly straightforward. All you need to do is add the function below to one of your C++ source files (and make sure it is linked in). It is not necessary to declare this function first, the definition alone is good enough for GCC. The function itself doesn't even need to do anything (and it doesn't in most implementations), it just needs to be "there" just in case.
 
Below you will find an example of an implementation in respectively GCC.
The following code applies to GCC:
 
<source lang="cpp">
<syntaxhighlight lang="cpp">
extern "C" void __cxa_pure_virtual()
{
// Do nothing or print an error message.
}
</syntaxhighlight>
</source>
 
Or, if you happen to use Visual Studio:
 
<syntaxhighlight lang="cpp">
The following code applies to Visual C++:
<source lang="cpp">
int __cdecl _purecall()
{
// Do nothing or print an error message.
}
</syntaxhighlight>
</source>
 
If, during runtime, your kernel detects that a call to a pure virtual function couldn't be made, it calls the above functions. These functions should actually never be called, because without hacks, (or through undefined behaviour of your kernel), it is not possible to instantiate a class that doesn't define all pure virtual functions. But nonetheless you have to define these functions or your linker will complain about unresolved symbols.
 
== Global objects ==
 
{{In_Progress}}
===Global objects===
Global objects must have their constructors called before they are used... and they would usually be called by the startup code you just disabled. So, stay away from global objects until you have set up your own kernel startup code.
 
TODO: Please unify this information with the newer [[Calling_Global_Constructors]] article.
====Why?====
All objects have constructor and deconstructor code. When an executable code is loaded into memory, and the program jumps straight into main, the constructor code for each global object has not be run. You could do this manually, by calling in the top of <tt>main()</tt>:
<source lang="cpp">
object1.object1();
object2.object2();
object3.object3();
// etc
</source>
 
Global objects must have their constructors called before they are used. Usually, they are called by the start-up code (which you just disabled). So, in order to be able to use them, you have to write your own start-up code for them. All objects have a constructor and a destructor. When an executable is loaded into memory and the program jumps straight to the entry point, the constructors of global objects will not have been called. One solution is to do this manually. You could put this code first when your C++ entry point is called:
====Enabling global objects====
Global or static objects have to be constructed by the environment before they are available for C++ code. Care should be taken if global/static objects need new and delete in their constructors. In this case it is best to construct global/static objects only after your kernel heap is ready for use. Not doing so can cause an object to attempt to allocate memory via the non-working new operator. This also simplifies the storing of the destructor functions in <tt>__cxa_atexit</tt>, because you don't have to use a static and fixed-size structure.
 
<syntaxhighlight lang="cpp">
According to the [http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/baselib---cxa-atexit.html Itanium C++ Application Binary Interface], which G++ follows, (and MSVC does not, so see further down for the MSVC example) the function <tt>__cxa_atexit</tt> is used to register a destructor to be called when a shared library is to be unloaded. This function should insert a function pointer, with (max) one accompanying argument, and the handle of the object or shared resource to be destroyed, into a table. In the source example for an implementation of <tt>__cxa_atexit</tt>, the <tt>__atexit_funcs[ATEXIT_MAX_FUNCS];
object1.object1();
</tt> array acts as the table.
object2.object2();
object3.object3();
// ...
</syntaxhighlight>
 
Global or static objects have to be constructed by the environment before they are available to C++. Care should be taken if global/static objects need '''new''' and '''delete''' in their constructors. In this case it is best to construct these objects only after your kernel heap is ready for use (and you have access to dynamic memory allocation). Not doing so can cause an object to attempt to allocate memory via the non-working '''new''' operator. This also simplifies the storing of the destructor functions in '''__cxa_atexit''', because you don't have to use a static and fixed-size structure.
This is why, below, the function <tt>__cxa_atexit</tt> is defined as:
<source lang="cpp">
int __cxa_atexit(void (*destructor_func)(void *), void *arg, void *__dso_handle);
</source>
Such that, as explained above, <tt>'destructor_func'</tt> is the handle for a destructor function, <tt>'arg'</tt> as defined by the ABI is the single argument it may take, and <tt>__dso_handle</tt> is a handle for the DSO (Dynamic Shared Object).
 
=== GCC ===
 
Note: This appears to be specific to the Itanium platform. For IA-32/x86/i386 and amd64/x86_64, please check out [[Calling_Global_Constructors]] instead.
In summary: the Itanium C++ ABI requires that you define two functions, and one symbol:
<source lang="cpp">
int __cxa_atexit(void (*f)(void *), void *objptr, void *dso);
void __cxa_finalize(void *f);
void *__dso_handle
</source>
 
According to the [http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/baselib---cxa-atexit.html Itanium C++ Application Binary Interface] (which '''g++''' follows and VC++ does not) the function '''__cxa_atexit''' is used to register a destructor that should be called when a shared library needs to be unloaded. It should insert a function pointer with maximum 1 accompanying argument and the handle of the object or shared resource to be destroyed into a table.
Before you can define global objects in your C++ files.
=====GCC (version < 3.2)=====
 
In the example implementation of '''__cxa_atexit''', the '''__atexit_funcs[ATEXIT_MAX_FUNCS]''' array acts as the table. This is why the '''__cxa_atexit''' function is defined as:
GCC inserts an array of pointers into the object file: Look for the ELF sections called "ctors*". Each pointer indicates the constructor of a global / static object. Your ASM startup code should call them in turn before passing control to your C++ kernel code.
 
<syntaxhighlight lang="cpp">
There also is a "dtors*" list of destructors; if your kernel returns, the exit / cleanup code should also call them in turn. Remember to destruct your objects in the opposite order you have constructed them.
int __cxa_atexit(void (*destructor) (void *), void *arg, void *__dso_handle);
</syntaxhighlight>
 
So that the '''destructor''' function pointer is the handle for a destructor function and '''arg''' is the single argument it may take. Finally, '''__dso_handle''' is a handle for the DSO (Dynamic Shared Object).
=====GCC >= 3.2=====
:GCC 4.0.2 seems to follow the same convention as GCC versions below 3.2. This seems to be independent of what is given with <tt>-fabi-version</tt>. I do get a dtors section.
 
So summarized, you are required to define two functions and one symbol in order to use global objects in your C++ files:
The construction of global/static objects is the same as of older versions of GCC. After you have called the objects constructor GCC automatically calls the function
 
<sourcesyntaxhighlight lang="cpp">
void *__dso_handle;
int __cxa_atexit(void (* f)(void *), void *p, void *d);
</source>
 
int __cxa_atexit(void (*destructor) (void *), void *arg, void *dso);
<tt>f</tt> is a function-pointer to the destructor, <tt>p</tt> is the parameter for the destructor and <tt>d</tt> is the "home DSO" (DSO = dynamic shared object). This function should save all three parameters and if successful return zero, on failure nonzero. When your kernel exits you should call <tt>__cxa_finalize(0)</tt>. According to the ABI specification, calling this with (int) 0 as the parameter instead of the address of a function to be called and removed from the list causes <em>all</em> destructors in the list to be called and removed from the list.
void __cxa_finalize(void *f);
</syntaxhighlight>
 
After you have called the objects constructor GCC automatically calls the function
Since you will be calling this function from your assembly source, right after your kernel exits, you could use the following code to do so:
 
<sourcesyntaxhighlight lang="asmcpp">
int __cxa_atexit(void (*destructor) (void *), void *arg, void *dso);
</syntaxhighlight>
 
This function should save all three parameters and if successful return zero, on failure non-zero. When your kernel exits you should call '''__cxa_finalize(0)'''. According to the ABI specification, calling this with 0 as the parameter instead of the address of a function (to be called and removed from the list) causes ''all'' destructors in the list to be called and removed from the list.
 
Since you will be calling this function from your Assembly source right after your kernel exits, you could use the following code:
 
<syntaxhighlight lang="asm">
; This is NASM source, mind you.
sub esp, 4
Line 104 ⟶ 97:
 
add esp, 4
</syntaxhighlight>
</source>
 
The following is tested, working, fully commented source that gives a more detailed explanation than the source previously found here. It also hilights what improvements can be implemented on itself, where they can be inserted.
 
The following is tested, working, fully commented source that gives a more detailed explanation than the source previously found here. It also highlights what improvements can be implemented and where they can be inserted. To use it, just include '''icxxabi.h''' in any ONE'''one''' file of your C++ kernel source. Preferable(preferably the file where your kernel's main statements begin).
 
'''File: icxxabi.h'''
<sourcesyntaxhighlight lang="cpp">
#ifndef _ICXXABI_H
#define _ICXXABI_H
Line 142 ⟶ 133:
 
#endif
</syntaxhighlight>
</source>
 
 
'''File: icxxabi.cpp'''
<sourcesyntaxhighlight lang="cpp">
 
#include "./icxxabi.h"
Line 186 ⟶ 178:
//You may insert a prinf() here to tell you whether or not the function gets called. Testing
//is CRITICAL!
while (i--i)
{
if (__atexit_funcs[i].destructor_func)
Line 206 ⟶ 198:
};
 
forwhile ( ; i >= 0; --)
{
/*
Line 250 ⟶ 242:
};
#endif
</syntaxhighlight>
</source>
 
===== Visual C==++ ===
{{main|Visual Studio}}
Running constructors and destructors is covered in MSDN help and in the C runtime library sources. See '''#pragma init_seg''' on MSDN for more information.
 
Basically what happens is that pointers to functions are placed in '''.CRT$XIC, $XIL, $XIU''' based on the value of '''init_seg'''. The linker then merges everything together in the '''.CRT''' section, in the order of the letters after the '''$'''. The pointers between the XIA ('''xi_a''') and XIZ ('''xi_z''') are then called if non-zero. The '''.CRT''' section is merged with the '''.data''' section to avoid a completely separated section.
Running constructors and destructors is covered in MSDN help and in the C runtime library sources. See <tt>#pragma init_seg</tt> on MSDN for some more information.
 
One problem with C++ support is the horrible name-mangling that is impossible to read in the map file. A build script should be set up that runs the map file through the '''undname.exe''' tool, so that names like '''??2@YAPAXI@Z''' (operator new - I think...) and others are readable.
Basically what happens is that pointers to functions are placed in <tt>.CRT$XIC, $XIL, $XIU</tt> based on the value of <tt>init_seg</tt>. The linker then merges everything together in the <tt>.CRT</tt> section, in the order of the letters after the <tt>$.</tt> The pointers between the XIA (<tt>xi_a</tt>) and XIZ (<tt>xi_z</tt>) are then called if nonzero. The <tt>.CRT</tt> section is merged with the .data section to avoid a whole separate section.
 
Below you will find some example code. Simply call '''runInit()''' if you want to initialize any static objects and then call '''runTerm()''' if static object destructors are to be run.
One problem with C++ support is the horrible name-mangling that is impossible to read in the map file. A build script should be set up that runs the map file through the <tt>undname.exe</tt> tool, so that names like <tt>??2@YAPAXI@Z</tt> (operator new - I think...) and others are readable.
 
<syntaxhighlight lang="cpp">
Here is some code. Sorry for its length, but it is hard to explain any other way. Simply call <tt>runInit()</tt> when you want to initialize any static objects and then call <tt>runTerm()</tt> when static object destructors are to be run.
 
<source lang="cpp">
typedef void (*_PVFV)(void);
typedef int (*_PIFV)(void);
Line 356 ⟶ 348:
__declspec(allocate(".CRT$XIB")) static _PIFV pinit = onexitinit;
#pragma data_seg()
</syntaxhighlight>
</source>
 
=== Local staticStatic variablesVariables (GCC onlyOnly)= ==
When you declare a local static variable, at least GCC compiler, puts a guard around the variable's constructor call. This ensures that only one thread can call the constructor at the same time to initialize it.
 
''Note that these are only stubs to get the code compiled, and you should implement them yourself. Simply add a mutex-like guard with a test-and-set primitive.''
====Why?====
TODO: Fill this in.
 
<syntaxhighlight lang="cpp">
====Enabling local static variables====
 
Note, that these are only stubs to get the code compiled, and you should implement them yourself. Simply add a mutex like guard with test and set primitive.
 
<source lang="cpp">
namespace __cxxabiv1
{
Line 374 ⟶ 361:
 
/* The ABI requires a 64-bit type. */
__extension__ typedef int __guard __attribute__((mode (__DI__)));
 
extern "C" int __cxa_guard_acquire (__guard *);
Line 392 ⟶ 379:
extern "C" void __cxa_guard_abort (__guard *)
{
 
}
}
</syntaxhighlight>
</source>
 
ActualThe actual code, emitedemitted by GCC, to call a local static variable's constructor looks something like this:
 
<sourcesyntaxhighlight lang="cpp">
static <type> guard;
 
if (!guard.first_byte) {
if (__cxa_guard_acquire (&!guard.first_byte)) {
{
if (__cxa_guard_acquire (&guard))
{
bool flag = false;
 
try {
try
{
// Do initialization.
__cxa_guard_release (&guard);
 
flag = true;
// Register variable for destruction at end of program.
} catch {
 
if (!flag) {
catch
{
if (!flag)
{
__cxa_guard_abort (&guard);
}
Line 415 ⟶ 413:
}
}
</syntaxhighlight>
</source>
 
=== The Operators 'new' and 'delete=' ==
Before you can properly use '''new''' and '''delete''', you have to implement some sort of memory management,. andYou thealso operatorhave to implement both operators <tt>new(including their array counterparts)</tt>. '''new''' and operator'''delete''' respectively allocate and <tt>delete()</tt> functionsmemory (includingmuch theirlike array'''malloc''' counterpartsand '''free''' in C). Take a look at the [[Memory Management]] article if you would like to know more about this subject.
 
Every time you call one of the operators '''new''', '''new[]''', '''delete''', or '''delete[]''', the compiler inserts a call to them. The most simple implementation would be to map them to your kernel's '''malloc''' and '''free'''. For example:
 
<syntaxhighlight lang="cpp">
====Why?====
#include <stddef.h>
<tt>new()</tt> and <tt>delete()</tt> allocate memory and free memory, respectively. For your kernel to allocate memory, it must somehow store what part of memory is used and what part of memory is free to be divided and allocated.
 
void *operator new(size_t size)
 
====Enabling new and delete====
Every time you call one of the operators <tt>new()</tt>, <tt>new[]()</tt>, <tt>delete()</tt>, or <tt>delete[]()</tt>, the compiler inserts a call to them. The most simple implementation would be to map them to <tt>kmalloc()</tt> / <tt>kfree()</tt>: (or malloc() and free() depending on your implementation)
 
<source lang="cpp">
//overload the operator "new"
void * operator new (uint_t size)
{
return kmallocmalloc(size);
}
 
//overload thevoid *operator "new[]"(size_t size)
void * operator new[] (uint_t size)
{
return kmallocmalloc(size);
}
 
//overload thevoid operator "delete"(void *p)
void operator delete (void * p)
{
kfreefree(p);
}
 
//overload thevoid operator "delete[]"(void *p)
void operator delete[] (void * p)
{
kfreefree(p);
}
</syntaxhighlight>
</source>
 
You could also let '''new''' use '''calloc''' (allocate and zero). This way, newly allocated memory will always be zeroed (thus, not contain garbage). The standard '''new''' implementations do however not clear the returned memory.
An easy malloc implementation you can port to your OS is [[liballoc]]. It only requires basic page management (that is, store a list of used and free pages, and have a function to find the next free page) to work.
 
An easy malloc implementation you can port to your OS is [https://github.com/blanham/liballoc/ liballoc]. It only requires basic [[Paging]] (that is, store a list of used and free pages, and have a function to find the next free page) to work.
====Other things you can try: Allocate and initialise memory====
New can use <tt>kcalloc</tt> (allocate and zero) instead of <tt>kalloc</tt> to allocate memory and intialise it (that is, fill it with '\0's) otherwise the variables will be filled with garbage which you will then need to clear manually. (The standard implementations of <tt>operator new()</tt> and <tt>operator new[]()</tt> do not initialize the memory returned.)
 
=== Placement New ===
====Other things you can try: Placement new====
In C++, and (especially in OS code where structures can be found at fixed addresses,) it can be useful to construct an object in memory obtained elsewhere. This is accomplished through a technique known as 'placement new'. As anFor example, say you wanted to create an APIC object at address <tt>0x09fff0000</tt>.'''0x09FFF0000''', Thisthen this snippet of code will use placement new to do the trick:
 
<sourcesyntaxhighlight lang="cpp">
void* *apic_address = reinterpret_cast<void *>(0x09fff00000x09FFF0000);
APIC* *apic = new (apic_address) APIC;
</syntaxhighlight>
</source>
 
In order to use placement new, you need special overloads of the new and delete operators defined in scope. Fortunately, the required definitions are simple and can be inlined in a header file (the C++ standard puts them in a header called <'''new>''').
 
<sourcesyntaxhighlight lang="cpp">
inline void* *operator new(uint_tsize_t, void* *p) throw() { return p; }
inline void* *operator new[](uint_tsize_t, void* *p) throw() { return p; }
inline void operator delete (void *, void *) throw() { };
inline void operator delete[](void *, void *) throw() { };
</syntaxhighlight>
</source>
 
The above implementation can potentially be potentially unsafe for allocating memory, since your kernel does not mark the memory that was allocated as being used. Placement new is hardly ever used, and if you wish to read an object from a specified address in memory, it is usually easier to create a pointer to that address. [[liballoc]] does not support placement new.
 
You never call placement delete explicitly (it's only required for certain implementation detail reasons). Instead, you simply invoke your object's destructor explicitly.
 
<sourcesyntaxhighlight lang="cpp">
apic->~APIC();
</syntaxhighlight>
</source>
 
== RTTI (Run-Time Type Information) ==
===Builtins===
RTTI is used for '''typeid''' and '''dynamic_cast'''. It requires runtime support as well. Disable it with '''-fno-rtti'''. A kernel has no access to run-time features, which are most likely operating system-dependent. Note that virtual functions work without RTTI.
GCC provides several standard library functions as builtins, which you most likely do not want in your kernel binary either. Disable them with -nostdlib
 
== Exceptions ==
Note: the option <tt>-ffreestanding</tt>, usually recommended in kernel tutorials, cannot be used with G++.
Another feature that requires run-time support. Disable it with '''-fno-exceptions'''. Exceptions require code to unwind the stack while looking for an appropriate exception handler to handle the exception. Usually, this code is linked in with your C++ application, but in a freestanding kernel the code must be provided manually.
 
See [[C++ Exception Support]].
====Why?====
Library routines are almost always OS-dependent. You can't mix code for two operating systems in a single operating system — it wouldn't work.
 
== Standard Library ==
TODO: why -ffreestanding/--freestanding do not work.
Note that the C++ Standard Library (stdlib) is not the same as the C++ Standard Template Library (STL). The STL was designed in 1994 and largely influenced the C++ Standard Library, but it's not a part of the ISO C++ standard. The C++ Standard Library is part of the C++ ISO specification, however, and is what you're using when you use ''std::vector'', ''std::string'', etc. Be wary of misusing the term STL and, ideally, avoid it completely. Anyone using it almost certainly means the C++ stdlib.
 
You cannot use stdlib functions or classes without porting a stdlib implementation. A lot of existing code depending on the stdlib is OS-dependent, so you must port an stdlib implementation to your OS if you want to use them.
===Run-time type information===
Run-time type information is used for <tt>typeid</tt> and <tt>dynamic_cast</tt>, and requires run-time support as well. Disable it with <tt>-fno-rtti</tt>.
 
To gain access to the stdlib in your OS you can do either of the following:
Note that RTTI is required for some C++ features. If you disable it, you won't be able to use <tt>typeid</tt> or <tt>dynamic_cast</tt>. Virtual functions should work without RTTI, though.
* Write your own implementation of a few of the required class templates (std::string, std::list, std::cout, ...).
* Port a stdlib implementation to your OS (e.g. [[STLport]]).
 
A lot of the stdlib classes require '''new''' and '''delete''' to be implemented in your OS. File access requires your OS to support reading and wrapping. Console functions require your OS to already have working console I/O.
====Why?====
RTTI stands for Run-Time Type Identification. A kernel has no access to run-time features, which are most likely operating system-dependent.
 
Porting the C++ stdlib (like porting the [[C_Library|C Standard Library]]) does not automatically make your OS able to read from and write to the disk or get data straight from the keyboard. These are simply wrappers around your OS' functions, and must be implemented by in your kernel.
===Exceptions===
Another feature that requires run-time support. Disable them with <tt>-fno-exceptions</tt>.
 
Note that it is generally not a good idea to port the entire stdlib to your kernel, although it is reasonable to port a few class templates, such as <tt>std::vector</tt> and <tt>std::string</tt> if you wish to. As for your user applications: the more the merrier! :)
====Why?====
Exceptions require code to unwind the stack while looking for an appropriate exception handler to handle the exception. Usually, this code is linked in with your C++ application, but in a freestanding kernel the code must be provided manually.
 
Here is a list of a the most commonly used stdlib implementations:
====Enabling exceptions====
TODO: Fill this in, rather than just dump links.
 
* http://www.codesourcery.com/cxx-abi/abi-eh.html (sounds like being Itanium specific, but that's actually the base for the common C++ ABI)
* http://www.codeproject.com/cpp/exceptionhandler.asp (explaining the stuff, but for VC++. Note that, on x86, VC++ and most other PC compilers use a [[Stack#Unwinding the stack|stack-based unwinding]] and handling mechanism known as SEH, common to OS/2, Windows and Windows NT and described in detail in a famous MSJ article, http://www.microsoft.com/msj/0197/Exception/Exception.aspx. GCC and most other UNIX compilers, instead, use the same table-based mechanism that is the rule on RISC architectures on x86 too. Also note that any use of stack-based SEH may or may not be covered by USPTO patent #5,628,016, held by Borland International, Inc. SEH on RISC architectures is table-based, thus unaffected by the patent)
* http://www.kuzbass.ru:8086/docs/isocpp/except.html
 
Note that there is a standard header <exception>, declaring several support functions.
 
 
===Standard Template Library===
You cannot use [[Standard Template Library]] (or STL for short) functions and classes without porting a Standard Template Library implementation. These include <tt>std::vector</tt>, <tt>std::list</tt>, <tt>std::cin</tt>, <tt>std::cout</tt>, etc.
 
====Why?====
C++ classes and templates such as <tt>std::vector</tt>, <tt>std::list</tt>, <tt>std::cout</tt>, <tt>std::string</tt>, to name a few, are not actually part of the C++ language. They are part of a library called the Standard Template Library. A lot of the code depending on STL is OS-dependent, so you must port an STL implementation to your OS.
 
====Porting a Standard Template Library====
TODO: Create an article on porting STLport.
 
To gain access to the STL in your OS you can do either of the following:
- Write your own implementation of a few of the required templates classes (std::string, std::list, std::cout, etc).
- Port an STL implementation to your OS (e.g. [[STLport]]).
 
A lot of the STD classes require <tt>new</tt> and <tt>delete</tt> implemented in your OS. File access requires your OS to support reading and wrapping. Console functions require your OS to already have working console input/output.
 
Porting STL, the same with the [[C Standard Library]], do not automatically make your OS to be able to read from and write to the disk, or to get data straight from the keyboard. These are simply wrappers around your OS's functions, and must be implemented by you.
 
Note that it is generally not a good idea to port the entire STL to your kernel, although it is reasonable to port a few classes, such as <tt>std::list</tt> and <tt>std::string</tt> if you wish to. As for your user applications; the more the merrier! :)
 
=====Standard Template Library Implementations=====
Here is a list of a the most commonly used STL implementations:
 
* [http://incubator.apache.org/stdcxx/ STDCXX] (a.k.a Apache C++ Standard Library, formally Rogue Wave C++ Standard Library)
* [https://www.dinkumware.com/cpp.aspx Dinkumware C++ Standard Library]
* [http://msdn2.microsoft.com/en-us/library/cscc687y%28VS.80%29.aspx Microsoft C++ Standard Library] (closed source)
* [http://gcc.gnu.org/libstdc++/ libstdc++] (a.k.a. GNU Standard C++ Library)
* [http://www.stlport.org/ STLport]
* [http://ustl.sourceforge.net/ uSTL]
* [http://libcxx.llvm.org/ libc++] (LLVM C++ Standard library)
 
== Full C++ Runtime supportSupport withUsing libgcc andAnd libsupc++ ==
{{Main|Libsupcxx#Full C++ Runtime Support Using libgcc And libsupc++}}
The following description is true for i386, gcc 3.2 and libgcc/libsupc++ compiled for Linux/glibc (you can use the static gcc/supc++ libraries compiled for your Linux for your kernel).
 
If you want Exceptions, RTTI, nice new and delete operators altogether, you also couldshould use [[libgcc]] and libsupc++. libgcc contains the unwinder (for exceptions), while libsupc++ contains the C++ support.
 
You may run into problems with libsupc++, but there are [[GCC_and_Libc++|alternative libraries]].
These functions look very complex (gcc_sources/gcc/unwind*, gcc_sources/libstdc++-v3/libsupc++/*), so maybe you shouldn't try to write an own unwinder or such, since there would be no benefit...
 
== Optimizations ==
To get full C++ support, you only have to do the following:
There are [[C#Things_you_should_know_about_optimizations|things you should know about optimizations]] that also affect C++ because it is an extension of the [[C]] language. You should know about them even if you don't plan to to use the optimizer of your C++ compiler in the near future.
 
== Links ==
* provide some libc functions like abort, malloc, free (and some more, maybe). libsupc++ needs them. There are even more functions you could support, like pthread_*, but since these are weak symbols, you don't need to define them.
=== Wiki ===
* there's also a strange function dl_iterate_phdrs; you don't need this, let it simply return -1. It's normally used to find exception frames for dynamical linked objects... You also could compile libsupc++ in such a way, that this function isn't called anymore.
* [[Bare Bones]]
* To make use of exception handling, you also have to tell libsupc++ where the .eh_frames section begins, before you throw any exception: <verbatim> __register_frame(address_of_eh_frames); </verbatim>.
* [[Volatile_(keyword)|Use of the volatile keyword]]
* Terminate the .eh_frame section with 4 bytes of zeros, somehow. If you forget this, libsupc++ will never find the end of .eh_frame and generate stupid pagefaults.
* [[C++ to ASM linkage in GCC|Linking C++ and Assembly (GCC-specific)]]
 
That's all. Please note that you still have to call the constructors/destructors by yourself.
 
Additionally, this sadly enlarges your kernel by ca. 50K (or even more).
 
You could also cross compile [[libsupcxx|libsupc++]] for your kernel.
 
 
== Things you should know about optimizations ==
 
There are [[C#Things_you_should_know_about_optimizations|things you should know about optimizations]] that also affect C++ because it is an extension of the [[C]] language. You should know about them even if you don't plan to to use the optimizer of your C++ compiler in the near future.
 
[[Category:Languages]]
[[Category:C++]]
[[de:C++]]