Running Linux, 5th Edition - Matthias Kalle Dalheimer [380]
First, the gcc compiler must generate an object file from this source code . The object file is essentially the machine-code equivalent of the C source. It contains code to set up the main() calling stack, a call to the printf() function, and code to return the value of 0.
The next step is to link the object file to produce an executable. As you might guess, this is done by the linker. The job of the linker is to take object files , merge them with code from libraries , and spit out an executable. The object code from the previous source does not make a complete executable. First and foremost, the code for printf() must be linked in. Also, various initialization routines, invisible to the mortal programmer, must be appended to the executable.
Where does the code for printf() come from? Answer: the libraries. It is impossible to talk for long about gcc without mentioning them. A library is essentially a collection of many object files, including an index. When searching for the code for printf(), the linker looks at the index for each library it's been told to link against. It finds the object file containing the printf() function and extracts that object file (the entire object file, which may contain much more than just the printf() function) and links it to the executable.
In reality, things are more complicated than this. Linux supports two kinds of libraries: static and shared. What we have described in this example are static libraries : libraries where the actual code for called subroutines is appended to the executable. However, the code for subroutines such as printf() can be quite lengthy. Because many programs use common subroutines from the libraries, it doesn't make sense for each executable to contain its own copy of the library code. That's where shared libraries come in.[*]
With shared libraries, all the common subroutine code is contained in a single library "image file" on disk. When a program is linked with a shared library, stub code is appended to the executable, instead of actual subroutine code. This stub code tells the program loader where to find the library code on disk, in the image file, at runtime. Therefore, when our friendly "Hello, World!" program is executed, the program loader notices that the program has been linked against a shared library. It then finds the shared library image and loads code for library routines, such as printf(), along with the code for the program itself. The stub code tells the loader where to find the code for printf() in the image file.
Even this is an oversimplification of what's really going on. Linux shared libraries use jump tables that allow the libraries to be upgraded and their contents to be jumbled around, without requiring the executables using these libraries to be relinked. The stub code in the executable actually looks up another reference in the library itself—in the jump table. In this way, the library contents and the corresponding jump tables can be changed, but the executable stub code can remain the same.
Shared libraries also have another advantage: their ability to be upgraded. When someone fixes a bug in printf() (or worse, a security hole), you only need to upgrade the one library. You don't have to relink every single program on your system.
But don't allow yourself to be befuddled by all this abstract information. In time, we'll approach a real-life example and show you how to compile, link, and debug your programs. It's actually very simple; the gcc compiler takes care of most of the details for you. However, it helps to understand what's going on behind the scenes.
gcc Features
gcc has more features than we could possibly enumerate here. The gcc manual page and Info document give an eyeful of interesting information about this compiler. Later in this section, we give you a comprehensive overview of the most useful gcc features to get you started. With this in hand, you should be able to figure out for yourself how to get the many other facilities to work to your advantage.
For starters, gcc supports the standard C syntax