#include <stdio.h>
This first line of the program is a preprocessing directive, #include. This causes the preprocessorâthe first tool to examine source code when it is compiledâto substitute for that line the entire text of the file or other entity to which it refers. In this case, the header file stdio.hâwhich contains the definitions of standard input and output functionsâwill replace that line. The angle brackets surrounding stdio.h indicate that the file can be found within one of the locations given to the preprocessor through the search path for header files.
Linker:
A linker takes the object code generated by the compiler / assembler, and links it against the C library (and / or libgcc.a or whatever link library you provide). This can be done in two ways: static, and dynamic.
Static Linking
When linking statically, the linker is invoked during the build process, just after the compiler / assembler run. It takes the object code, checks it for unresolved references, and checks if it can resolve these references from the available libraries. It then adds the binary code from these libraries to the executable; after this process, the executable is complete, i.e. when running it does not require anything but the kernel to be present.
On the downside, the executable can become quite large, and code from the libraries is duplicated over and over, both on disk and in memory.
Dynamic Linking
When linking dynamically, the linker is invoked during the loading of an executable. The unresolved references in the object code are resolved against the libraries currently present in the system. This makes the on-disk executable much smaller, and allows for in-memory space-saving strategies such as shared libraries (see below).
On the downside, the executable becomes dependent on the presence of the libraries it references; if a system does not have those libraries, the executable cannot run.
Shared Libraries
A popular strategy is to share dynamically linked libraries across multiple executables. This means that, instead of attaching the binary of the library to the executable image, the references in the executable are tweaked, so that all executables refer to the same in-memory representation of the required library.
This requires some trickery. For one, the library must either not have any state (static or global data) at all, or it must provide a seperate state for each executable. This gets even trickier with multithreaded systems, where one executable might have more than one simultaneous control flow.
Second, in a virtual memory environment, it is usually impossible to provide a library to all executables in the system at the same virtual memory address. To access library code at an arbitrary virtual address requires the library code to be position independent (which can be achieved e.g. by setting the -PIC command line option for the GCC compiler). This requires support of the feature by the binary format (relocation tables), and can result in slightly less efficient code on some architectures.
Regards,
Paramesh.
"Don't walk behind me; I may not lead.
Don't walk in front of me; I may not follow.
Just walk beside me and be my friend."
|