Library Calls: Difference between revisions

Jump to navigation Jump to search
Markup fixes, categorisation, removed PFR
[unchecked revision][unchecked revision]
No edit summary
(Markup fixes, categorisation, removed PFR)
Line 1:
{{Convert}}
 
== Introduction ==
 
Line 31 ⟶ 29:
=== Linker ===
 
The '''linker''' is a different story. When the compiler is done compiling your source file into object files, it is up to the linker to '''link''' all object files together into an executable. It also '''resolves symbols'''. For the above code, the object code refers to a function ''<tt>printf()''</tt> which is, however, '''not defined''' in the object code itself.
 
It is defined in the '''system libraries'''. Luckily the linker knows that these exist, and where to find them. Any symbols not resolved in your own code it tries to resolve using the system libraries. It also links in the '''startup code''', since someone has to set up the environment and call your ''int main()'', right?
 
=== [[GCC Cross-Compiler]] ===
 
If you did follow the [[GCC Cross-Compiler]] how-to, your cross-compiler does not know about ''<stdio.h>'', and your cross-linker does not know about any system libraries. Which is just as well, since they don't exist.
Line 45 ⟶ 43:
=== Userspace ''printf()'' ===
 
Well, the usual userspace process for a library call is already explained above, is it? Well, yes, but only at a high level. What actually '''happens''' when you call ''<tt>printf()''</tt> like that?
 
Your userland =<tt>printf()=</tt> does not have a string to print, yet - only a parameter that happens to be an integer, and a manual on how to make a string of it. It then proceeds to construct that very string, "The answer is 42!\n". In some way. Doesn't matter.
 
'''Then''' comes the funny part. The function that does the actual '''printing''' (see "At the Bottom" above) is in '''kernel space'''. You can't just execute kernel functions like that, only the kernel can.
 
So let's say your standard library implementation of ''<tt>printf()''</tt>, after assembling the string to be printed, calls a function named ''<tt>write()''</tt>, passing it a pointer to the readily-assembled string and the information that it is to be printed to stdout - like, the integer 1.
 
''<tt>write()''</tt> now does something special: It places a special code into one register, the ''char *'' and the integer in some others, and calls an '''interrupt'''.
 
=== Enter the kernel ===
 
An interrupt ends userspace processing, and wakes up the kernel - more specifically, the interrupt handler registered by the kernel. Since it was the interrupt reserved for '''system calls''', it knows what to do: The special code tells it that it was ''<tt>write()''</tt> calling the interrupt. That means that there is a ''char *'' in '''this''' register, and an ''int'' in '''that'''... oh, it's a 1, so this goes to stdout (instead of, say, a file).
 
So the interrupt handler passes the ''char *'' to the printing function we mentioned in "At the Bottom" above, then returns control to the caller.
Line 63 ⟶ 61:
=== Done ===
 
The interrupt handler ends, ''<tt>write()''</tt> is back in control, which returns to ''printf()'' which returns to your application. You successfully completed a call to ''<tt>printf()''</tt>.
 
=== Kernel is Different ===
 
If you are in kernel space anyway, you don't want that hassle with the registers and the interrupt. After all, you '''can''' call the print function directly as you '''are''' in kernel space. You also never want to write to a file. The ''<tt>write()''</tt> function and the interrupt handler become unnecessary baggage.
 
'''And''' you probably don't want all the code necessary for e.g. floating point conversions or unicode output linked into your kernel binary, either. The userspace ''<tt>printf()''</tt> is much too heavy for your tastes.
 
So what do you do? The answer is easy. Just tell the linker that the _system libraries_ are to be found in a different directory than for userspace. (Your ''Makefile'' is already loaded with funny options for compiler and linker, one more wouldn't make a difference. Bad pun warning.)
 
So you provide a lightweight ''<tt>printf()''</tt> for kernel space. You don't even have to bother to call it ''<tt>kprintf()''</tt> or something as your kernel binary will never be '''linked''' with userspace code. Using some preprocessor ''#ifdef'' magic, you can even use the very same ''<stdio.h>'' header file as for userspace code, reducing redundancy and potential error sources: The preprocessor symbol STDC_HOSTED<tt>__STDC_HOSTED__</tt> (with two leading and trailing underscores that the Wiki stubbornly interprets as boldface markup) is undefined when you set ''-ffreestanding''...
 
<pre>
Line 82 ⟶ 80:
#endif
</pre>
 
[[Category:FAQ]]
1,490

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu