Calling C++ Constructors From C++: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
m (Oops, typo.)
(The information in this article is wrong! Refer to my correct article instead.)
Line 1: Line 1:
#REDIRECT [[Calling Global Constructors]]
{{Rating|2}}{{Template:Kernel designs}}

:''In this tutorial we will learn, how to move the code for calling static object con-/de-structors from assembly into C++. This tutorial is a followup on [[C++ Bare Bones]]''

==Preface==
Currently we have some assembly code, that takes care of calling the static
objects constructors and destructors namely;
<source lang="asm">
mov ebx, start_ctors ; call the constructors
jmp .ctors_until_end
.call_constructor:
call [ebx]
add ebx,4
.ctors_until_end:
cmp ebx, end_ctors
jb .call_constructor
</source>
for constructors, and;
<source lang="asm">
mov ebx, end_dtors ; call the destructors
jmp .dtors_until_end
.call_destructor:
sub ebx, 4
call [ebx]
.dtors_until_end:
cmp ebx, start_dtors
ja .call_destructor
</source>
for destructors.

==Porting to C++==
Actually porting the above code to C++ is rather simple, we'll start off by
defining a function pointer typedef, and the declare some externs to the linker symbols.
<source lang="cpp">
/** A typedef for the default constructor function pointer type */
typedef void (*function_pointer) (void);
/** Externs to the linker symbols */
/** Constructors */
extern function_pointer start_ctors[];
extern function_pointer end_ctors[];
/** Destructors */
extern function_pointer start_dtors[];
extern function_pointer end_dtors[];
</source>

The only thing left to do, is simply to load and execute all the function pointers
within the range, below is a snippet that does exactly this;
<source lang="cpp">
/** Executes all the constructors found in the ctor section */
void executeConstructors()
{
// We don't need to divide by 4 (bytes per function pointer), as the
// compiler figures this from the typedef.
uint32_t numberOfConstructors = (end_ctors - start_ctors);

// Loop though all the constructors,
// loading and executing them one at a time.
for(uint32_t x = 0; x < numberOfConstructors; x++)
{
function_pointer constructor = start_ctors[x];
constructor();
}
}
</source>
Similar code can be produced for the destructors;
<source lang="cpp">
/** Executes all the destructors found in the dtor section */
void executeDestructors()
{
// We don't need to divide by 4 (bytes per function pointer), as the
// compiler figures this from the typedef.
uint32_t numberOfDestructors = (end_dtors - start_dtors);

// Loop though all the destructors backwards,
// loading and executing them one at a time.
for(uint32_t x = numberOfDestructors - 1; x >= 0; x--)
{
function_pointer destructor = start_dtors[x];
destructor();
}
}
</source>
This will effectively execute the constructors and destructors.

==Testing==
A crude hack, which can be used to check whether the above code is actually working
can be produced by the following method;

* 1. Create a function with the correct prototype ('void func(void)')
* 2. Find the address of this function ('print_hex(&func);')
* 3. Hardcode the found function address into the ctor list in the linker script.

Below is a concrete example of this;

* 1. Example function;
<source lang="cpp">
extern "C" void func(void)
{
print("extern "C" void func(void) CALLED");
}
</source>
* 2. Finding the address
<source lang="cpp">
print_hex(&func);
</source>
Say this returns '0x00100990'
* 3. Hardcoding into the linker script;
<pre>
ENTRY (loader)

SECTIONS
{
...
.rodata ALIGN (0x1000) :
{
start_ctors = .;
*(SORT(.ctors.*)) /* Note the "SORT" */
LONG(0x00100990) /* The hardcoded function address */
end_ctors = .;

...
}
...
}
</pre>
When the static object constructor calling code is run, it will then call the
'func()' function.


==See Also==
===Articles===
*[[C++]]
*[[Bare Bones]]
*[[C++ Bare Bones]]

[[Category:Bare bones tutorials]]
[[Category:C++]]

Revision as of 11:58, 24 May 2013