Creating a C Library: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
(update the notes for NO_IMPLICIT_EXTERN_C for GCC 9 and above.)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(6 intermediate revisions by 3 users not shown)
Line 5:
== Building ==
 
Now that you have an OS-specific freestanding toolchain that can build your kernel, there is a problem of bootstrapping. To build aan OS-specific toolchain that supports a hosted environment, you need the headers of your standard C library installed. To build your libc you need a compiler that supports a hosted environment (building a user-space libc as in a freestanding environment is a logical mistake). The solution is to create a make target that installs your C library and kernel headers into your sysroot's include directory without needing a compiler. Then you can simply build your cross-compiler with --with-sysroot="$SYSROOT" (and not giving the --without-headers option), and you should get a cross-compiler that offers a freestanding environmment for your kernel, and a hosted environment for your user-space. Note that [[libgcc]] may depend on a few things from your C library: if you get errors during building libgcc, then simply add the declarations to your header files. You will get undeclared symbols if GCC deems it appropriate to call a libgcc function that needs a libc symbol, so it is a good idea to implement what libgcc needs early on. Note that [[libgcc]] is <em>not</em> optional, and gcc <em>will</em> emit calls to it if it thinks it is a good idea.
 
Then you can simply build your C library source files using:
 
<sourcesyntaxhighlight lang="bash">
x86_64-myos-gcc -c strfoo.c -o strfoo.o
x86_64-myos-as x86_64/crt0.s -o x86_64/crt0.o
x86_64-myos-ar rcs libc.a strfoo.o x86_64/crt0.o
</syntaxhighlight>
</source>
 
Note that unlike the kernel, you don't need to add extra special options that disable standard include directories and libraries. After all, this is the C library meant for user-space. You don't need to add -I options to the compiler if you already have installed your libc and kernel headers into your sysroot. Otherwise, simply add the appropriate -I options to the above commands. It may be useful to use the same libc for both user-space and the kernel, in that case don't make the mistake of thinking that user-space-libc and kernel-libcs are the same thing. First of all many user-space things don't make sense (or even work) in the kernel. Secondly, a kernel-usable libc must be built differently than the user-space libc because it is <em>freestanding</em>. A kernel libc must have all the special options that a kernel binary is passed. For instance, don't forget to add -mno-red-zone on x86_64 to both your kernel and libc, or interrupts may corrupt the stack.
Line 20:
:''See also: [[Calling Global Constructors]]''
 
The first and most important thing to implement in a C library is the _start function, to which control is passed from your program loader. It'sIts task is to initialize and run the process. Normally this is done by initializing the C library (if needed), then calling the global constructors, and finally calling exit(main(argc, argv)). You can change the name of the default program entry point by adding ENTRY=_my_start_name in your OS-specific binutils emulparams script (binutils/ld/emulparams). You can change which start files are used by modifying gcc/gcc/config/myos.h in your OS-specific GCC. The macros STARTFILE_SPEC and ENDFILE_SPEC define the object files to use in the GCC spec language. See gcc/gcc/config/gnu-user.h for examples on how to use this. If you decide to use the conventional (GNU-like) names and semantics for these initialization files, the following information applies:
 
=== crt0.o ===
Line 125:
C library headers conventionally use include guards to prevent multiple declarations. It may be wise to use the same format as GNU's libc as some programs (and GCC fixincludes) may erroneously rely on these macros to detect whether a given header has been included. GNU libc's headers usually follow this simple scheme:
 
<sourcesyntaxhighlight lang="c">
#ifndef _STDIO_H
#define _STDIO_H 1
Line 132:
 
#endif
</syntaxhighlight>
</source>
 
== Repeated Declarations ==
Line 146:
'''For GCC versions < 9''', telling GCC that your headers understand C++ is done by having the following in your OS-specific gcc/gcc/config/myos.h:
 
<sourcesyntaxhighlight lang="c">
/* Don't assume anything about the header files. */
#undef NO_IMPLICIT_EXTERN_C
#define NO_IMPLICIT_EXTERN_C 1
</syntaxhighlight>
</source>
 
'''For GCC versions >= 9''', [https://patchwork.ozlabs.org/patch/934478/ this patch] changed the behaviour; they have made <tt>NO_IMPLICIT_EXTERN_C</tt> a so-called "poisoned identifier", so compiling your OS-specific toolchain will fail. If you read the linked patch above, you will realise that they decided to invert the behaviour, such that system headers are assumed to understand C++ by default. So, in theory, you do not need those two lines above at all, and it should Just Work (tm).
Line 158:
Adding support for C++ in your C header files (such as stdio.h) is very simple. Previously GCC automatically added extern "C" around all headers if compiling C++, but now we'll need to do it ourselves. The key feature is that we don't need to do this on C++-only headers, meaning that C++ headers will now actually work, instead of GCC assuming they have C-linkage. For instance, you can change your stdio.h to be of this form:
 
<sourcesyntaxhighlight lang="c">
#ifndef _STDIO_H
#define _STDIO_H 1
Line 173:
 
#endif
</syntaxhighlight>
</source>
 
[[Category:C]]
[[Category:Standard Libraries]]
[[Category:Porting]]
[[Category:Tutorials]]