Calling C++ Constructors From C++: Difference between revisions
Jump to navigation
Jump to search
[unchecked revision] | [unchecked revision] |
Content added Content deleted
m (Loop through destructors in opposite order of the constructors) |
m (Bot: Mark uncategorized redirects) |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
#REDIRECT [[Calling Global Constructors]] |
|||
{{Rating|2}}{{Template:Kernel designs}} |
|||
{{Redirect page}} |
|||
:''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="c"> |
|||
/** 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="c"> |
|||
/** 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. |
|||
u32int numberOfConstructors = (end_ctors - start_ctors); |
|||
// Loop though all the constructors, |
|||
// loading and executing them one at a time. |
|||
for(u32int x = 0; x < numberOfConstructors; x++) |
|||
{ |
|||
function_pointer constructor = start_ctors[x]; |
|||
constructor(); |
|||
} |
|||
} |
|||
</source> |
|||
Similar code can be produced for the destructors; |
|||
<source lang="c"> |
|||
/** 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. |
|||
u32int numberOfDestructors = (end_dtors - start_dtors); |
|||
// Loop though all the destructors backwards, |
|||
// loading and executing them one at a time. |
|||
for(u32int 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="c"> |
|||
extern "C" void func(void) |
|||
{ |
|||
print("extern "C" void func(void) CALLED"); |
|||
} |
|||
</source> |
|||
* 2. Finding the address |
|||
<source lang="c"> |
|||
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++]] |
Latest revision as of 09:33, 22 June 2024
Redirect to:
This page is a redirect.
This redirect is categorized in following manner:
- This redirect is not yet categorized.