Linux Kernel Architecture

(Jacob Rumans) #1
Mauerer app03.tex V1 - 09/04/2008 6:11pm Page 1180

Appendix C: Notes on C


The size of the additional macro and C files is similar to that of the actual instruction patterns (IA-32:
12,000 lines; Alpha: 9,000 lines; and Sparc: 12,000 lines). They constitute an important part of the CPU
definition and are essential for the generation of efficient code.

C.1.2 Assembly and Linking


At the end of the actual compilation process, the original C program has been translated into assembler
code, and the final steps along the path to binary code require little compiler effort because the assembler
and linker (often referred to as the ‘‘binder‘‘) do the rest of the work.

As compared to the task of the compiler, the work of the assembler is very simple. The individual assem-
bler statements (and their arguments) are translated into a special binary format that differs according
to processor type (each assembler command has itsown binary code notation; on some systems, such as
IA-32, different binary forms may be available fora command depending on the argument types used). A
further task of the assembler is to accommodate constant data (such as fixed strings or numeric constants)
in the binary code. Usually the ELF format (described at length in Appendix E) is employed to arrange
the program and data in a binary file.

The linker must (among other things) adjust the branch addresses in the assembler code. Although
the assembler source text can still reference symbolic names (for example, the preceding assembler
code uses calls to theprintffunction defined in the standard library), the binary variant must
specifyrelativeorabsolutebranch addresses; for instance, ‘‘skip the next 5 bytes‘‘ or ‘‘branch to
positionx‘‘).

C.1.3 Procedure Calls


An interesting aspect in C not specifically associated with the use of the GNU compiler^4 is the implemen-
tation of procedure and function calls. Because, at certain points, the kernel is responsible for ensuring
the interoperability of assembler and C code (in other words, C functions are called from within assem-
bler code), it is important to know the mechanisms behind function calls. This section describes these
mechanisms by reference to the IA-32 architecture, although the approach is generally similar on other
architectures.^5

Let’s discuss the basic terms involved in procedure calls by reference to Figure C-1. The system
stack is a memory area at the end of the address space of a process. It grows from top to bottom
when elements are pushed on to it — this is contrary to the expected direction associated with the
word ‘‘grow‘‘. It is used to provide memory for the local variables of the function. It also supports
parameter-passing when functions are invoked.If nested procedures are called, the stack grows
from top to bottom and accepts newactivation recordsthat hold all data needed foroneprocedure.
The activation record of the procedure currently executing is delimited at the top by theframe
pointerand at the bottom by thestack pointer. While the upper boundary stays the same throughout
procedure execution, the lower boundary can beextended downward if necessary in order to create
more space.

(^4) The call conventions of other compilers may differ in their details, but the underlying principle is always the same.
(^5) A major exception is the IA-64 architecture, which adopts the concept ofregister windowsto persuade programs that the size of the
register set is unlimited, a fact that can be exploited when implementing function calls. The resulting mechanism differs substantially
from the variant discussed here. Detailed information can be found in the processor-specific documentation on IA-64.

Free download pdf