have little in common with the rest of C. The C preprocessor is often (but not always) a separate
program. If the code generator (also known as the "back end") is written as a stand-alone program, it
can probably be shared by other languages. The trade-off is that running several smaller programs will
take longer than running one big program (because of the overhead of initiating a process and sending
information between the phases). You can look at the individual phases of compilation by using the -#
option. The -V option will provide version information.
You can pass options to each phase, by giving the compiler-driver a special -W option that says "pass
this option to that phase." The "W" will be followed by a character indicating the phase, a comma, and
then the option. The characters that represent each phase are shown in Figure 5-1.
So to pass any option through the compiler driver to the linker, you have to prefix it by "-Wl," to tell
the compiler driver that this option is intended for the link editor, not the preprocessor, compiler,
assembler, or another compilation phase. The command
cc -Wl,-m main.c > main.linker.map
will give ld the "-m" option, telling it to produce a linker map. You should try this once
or twice to see the kind of information that is produced.
An object file isn't directly executable; it needs to be fed into a linker first. The linker identifies the
main routine as the initial entry point (place to start executing), binds symbolic references to memory
addresses, unites all the object files, and joins them with the libraries to produce an executable.
There's a big difference between the linking facilities available on PC's and those on bigger systems.
PC's typically provide only a small number of elementary I/O services, known as the BIOS routines.
These exist in a fixed location in memory, and are not part of each executable. If a PC program or
suite of programs requires more sophisticated services, they can be provided in a library, but the
implementor must link the library into each executable. There's no provision in MS-DOS for
"factoring out" a library common to several programs and installing it just once on the PC.
UNIX systems used to be the same. When you linked a program, a copy of each library routine that
you used went into the executable. In recent years, a more modern and superior paradigm known as
dynamic linking has been adopted. Dynamic linking allows a system to provide a big collection of
libraries with many useful services, but the program will look for these at runtime rather than having
the library binaries bound in as part of the executable. IBM's OS/2 operating system has dynamic
linking, as does Microsoft's new flagship NT operating system. In recent years, Microsoft Windows®
has introduced this ability for the windowing part of PC applications.
If a copy of the libraries is physically part of the executable, then we say the executable has been
statically linked; if the executable merely contains filenames that enable the loader to find the
program's library references at runtime, then we say it has been dynamically linked. The canonical
names for the three phases of collecting modules together and preparing them for execution are link-
editing, loading, and runtime linking. Statically linked modules are link edited and then loaded to run
them. Dynamically linked modules are link-edited and then loaded and runtime-linked to run them. At
execution, before main() is called, the runtime loader brings the shared data objects into the process
address space. It doesn't resolve external function calls until the call is actually made, so there's no
penalty to linking against a library that you may not call. The two linking methods are compared in
Figure 5-2.
Figure 5-2. Static Linking versus Dynamic Linking