C++: Difference between revisions

Jump to navigation Jump to search
416 bytes added ,  17 years ago
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 overridenoverridden 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.
 
===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===
 
EverytimeEvery 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>:
 
<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);
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu