Calling Global Constructors: Difference between revisions

Change community recommendation from i586-elf to i686-elf (about time too).
[unchecked revision][unchecked revision]
m (This wiki has no AT&T assembly syntax high-lighting)
(Change community recommendation from i586-elf to i686-elf (about time too).)
Line 5:
= GNU Compiler Collection - System V ABI =
 
The System V ABI (as used by <tt>i586i686-elf-gcc</tt>, <tt>x86_64-elf-gcc</tt>, and other ELF platforms) specifies use of five different object files that together handle program initialization. These are traditionally called <tt>crt0.o</tt>, <tt>crti.o</tt>, <tt>crtbegin.o</tt>, <tt>crtend.o</tt>, and <tt>crtn.o</tt>. Together these object files implement two special functions: <tt>_init</tt> which runs the global constructors and other initialization tasks, and <tt>_fini</tt> that runs the global destructors and other termination tasks.
 
This scheme allows the compiler great control in program initialization and makes things easy for you, but you have to cooperate with the compiler or bad things will happen. Your cross-compiler will provide you with <tt>crtbegin.o</tt> and <tt>crtend.o</tt>. These files contain the internals that the compiler wish to hide from you, but wants you to use. To get access to this information, you will need to provide your own implementation of <tt>crti.o</tt> and <tt>crtn.o</tt>. Fortunately, this is easy and described in detail in this tutorial. The fifth file <tt>crt0.o</tt> contains the program entry point (normally <tt>_start</tt>) and calls the special <tt>_init</tt> function that runs the "program initialization tasks" that <tt>crti.o</tt>, <tt>crtbegin.o</tt>, <tt>crtend.o</tt>, and <tt>crtn.o</tt> together form, and your exit function will normally call the <tt>_fini</tt> function made by these objects. However, <tt>crt0</tt>.o is out of scope of this article. (Note that the object file that contains <tt>_start</tt> acts as <tt>crt0.o</tt> in a kernel.)
Line 36:
== Using crti.o, crtbegin.o, crtend.o, and crtn.o in a Kernel ==
 
In a kernel, you are not using a user-space C library. You may be using a special kernel "C library", or none at all. The compiler always supplies <tt>crtbegin.o</tt> and <tt>crtend.o</tt>, but normally the C library supplies <tt>crti.o</tt> and <tt>crtn.o</tt>, but not in this case. The kernel should supply its own <tt>crti.o</tt> and <tt>crtn.o</tt> implementation (even if it would be otherwise identical to the user-space libc version). A kernel is linked with <tt>-nostdlib</tt> (which is the same as passing <tt>-nodefaultlibs</tt> and <tt>-nostartfiles</tt>) which disables the "start files" <tt>crt*.o</tt> that is normally automatically added to the link command line. By passing <tt>-nostartfiles</tt>, we promise to the compiler that we take on the responsibility ourselves to call the "program initialization tasks" in the <tt>crtbegin.o</tt> and <tt>crtend.o</tt> files. This means as we need to manually add <tt>crti.o</tt>, <tt>crtbegin.o</tt>, <tt>crtend.o</tt>, and <tt>crtn.o</tt> to the command line. Since we provide <tt>crti.o</tt> and <tt>crtn.o</tt> ourselves, that is trivial to add to the kernel command line. However, <tt>crtbegin.o</tt> and <tt>crtend.o</tt> is installed inside a compiler-specific directory we'll need to figure out the path. Luckily, gcc offers an option just to do this. If <tt>i586i686-elf-gcc</tt> is your cross-compiler and <tt>$CFLAGS</tt> is the flags you would normally provide to your compiler, then
 
<source lang="bash">i586i686-elf-gcc $CFLAGS -print-file-name=crtbegin.o</source>
 
will make the compiler print the path to the correct <tt>crtbegin.o</tt> file (that is ABI compatible with the $CFLAGS options) to the standard output. The same works with <tt>crtend.o</tt>. If you are using GNU Make, you can do it easily in your makefile assuming <tt>$(CC)</tt> is your cross-compiler and <tt>$(CFLAGS)</tt> is the flags you would normally pass it:
Anonymous user