Calling Global Constructors: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
m (Bot: Replace deprecated source tag with syntaxhighlight)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
Line 209:
Another way to execute the global constructors / destructors is to execute the .ctors / .dtors symbols manually (assuming you have your own ELF loader, see [[ELF_Tutorial]]). Once you have loaded each ELF file into memory, and all of the symbols have been resolved and relocated you can use .ctors / .dtors to execute the global constructors / destructors manually (apparently, the same applies to .init_array and .fini_array). To do this, you must first locate the .ctors / .dtors section headers:
 
<sourcesyntaxhighlight lang="c">
for (i = 0; i < ef->ehdr->e_shnum; i++)
{
Line 235:
}
}
</syntaxhighlight>
</source>
 
Now that you have the .ctors / .dtors section headers, you can resolve each constructor using the following. Note that .ctors / .dtors is a table of pointers (32bit for ELF32 and 64bit for ELF64). Each pointer is a function that must be executed.
 
<sourcesyntaxhighlight lang="c">
typedef void(*ctor_func)(void);
 
Line 254:
/* elf->exec is the char * that stores the location in memory that the ELF file have been loaded to, and and reloacted */
}
</syntaxhighlight>
</source>
 
Don't be surprised if you only have one entry in .ctors / .dtors. At least on x86_64, GCC appears to add a single entry to a set of functions called _GLOBAL__sub_I_XXX and _GLOBAL__sub_D_XXX which call _Z41__static_initialization_and_destruction_0ii that actually call each constructor for you. Adding more globally defined constructors / destructors will cause this function to grow, and not .ctors / .dtors.
Line 262:
If you don't call the constructors / destructors that GCC provides, GCC will generate code that will segfault under certain conditions with x86_64. Take this for example:
 
<sourcesyntaxhighlight lang="cpp">
class A
{
Line 276:
p_a->anything(); // <---- segfault
}
</syntaxhighlight>
</source>
 
It appears that GCC is using the constructor / destructor initialization routines to do more than simply call the constructors / destructors of each globally defined class. Executing the functions defined in .ctors / .dtors not only initializes all of the constructors / destructors, but resolves these types of segfaults (the above is only one example of many that are resolved). From what I can tell, when globally defined objects exist, GCC might also create ".data.rel.ro" which is another relocation table that GCC needs to process. It is marked as PROGBITS and not REL/RELA, which means that the ELF loader will not do the relocations for you. Instead, executing the functions defined in .ctors will execute _Z41__static_initialization_and_destruction_0ii which appears to perform the relocations for us. See the following for more info: [https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68738]