Anonymous user
C++: Difference between revisions
Jump to navigation
Jump to search
no edit summary
[unchecked revision] | [unchecked revision] |
No edit summary |
No edit summary |
||
Line 6:
==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>.
===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
===Global objects===
Line 16:
===new and delete===
Before you can use new and delete, you have to implement some memory management, and the operator <tt>new()</tt> and operator <tt>delete()</tt> functions (including their array counterparts).
===Builtins===
GCC provides several standard library functions as builtins, which you most likely do not want in your kernel binary either. Disable them with -nostdlib
Note: the option <tt>-ffreestanding</tt>, usually recommended in kernel tutorials, cannot be used with G++.
===RTTI===
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>.
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.
===Exceptions===
Another feature that requires run-time support. Disable them with <tt>-fno-exceptions</tt>.
Line 56:
===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.
GCC (version < 3.2)
Line 64:
====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.
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
Line 70:
int __cxa_atexit(void (* f)(void *), void *p, void *d);
<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
void __cxa_finalize(void *d);
with d = 0 in order to destroy all with <tt>__cxa_atexit</tt> registered objects. Objects, which were registered first with <tt>__cxa_atexit</tt>, must be destroyed last by <tt>__cxa_finalize</tt>. You must provide the symbol <tt>__dso_handle</tt> in your executable. Only the address of this symbol is needed, because GCC calls <tt>__cxa_atexit</tt> with <tt>&__dso_handle</tt>.
<pre>
Line 117:
====Visual C====
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.
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.
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.
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.
<pre>
Line 225:
===new and delete===
<pre>
Line 253:
</pre>
Note that new should actually use <tt>kcalloc</tt> (allocate and zero) otherwise the variables will be filled with garbage which you will then need to clear manually
Note the use of the "operator" keyword. A nice option is that <tt>new()</tt> can be overloaded (non-standard but potentially useful).
GCC sometimes emits code that calls operator delete even when you haven't used delete yourself. It seems to sometimes emit a "normal" version of a destructor and a separate version for delete. So you might need to define operator delete even before you have <tt>kmalloc</tt>:
<pre>
Line 266:
</pre>
This won't be called until you use <tt>new</tt>/<tt>delete</tt>, but it might be needed for linking. This problem seems to appear when classes with pure virtual functions are used.
===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 an example, say you wanted to create an APIC object at address <tt>0x09fff0000</tt>. This snippet of code will use placement new to do the trick:
void* apic_address = reinterpret_cast<void*>(0x09fff0000);
|