Linux Kernel Architecture

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

Appendix C: Notes on C


A procedure call therefore consists of the following two steps:


  1. Build a parameter list in the stack. Thefirstargument to be passed to the called function is
    placedlaston the stack; this makes it possible to pass a varying number of arguments that
    can bepoppedfrom the stack one after the other.

  2. Invokecall, which causes the current value of the instruction pointer (pointing to the
    instruction thatfollowscall) to be pushed onto the stack and delegates code flow to the
    invoked function.


The procedure called is responsible for managing the frame pointer and performs the following steps:


  1. The previous frame pointer is pushed onto the stack, thus moving the stack pointer down.

  2. The frame pointer is assigned the current value of the stack pointer and now marks the start
    of the stack area for the function to be executed.

  3. The code of the function is executed.

  4. When the function terminates, the stored frame pointer is at the bottom of the stack. Its value
    ispoppedfrom the stack and saved in the frame pointer that now again points to the start of
    the stack area of the previous function. Thereturn address saved when the function was
    called is now located at the bottom end of the stack.

  5. Invokingreturncauses the return address to bepoppedfrom the stack. The pro-
    cessor branches to the return address, thus returning the code flow to the calling
    function.


At first glance, this approach may seem a little confusing. To dispel any confusion, let’s consider the
following simple C example:

#include<stdio.h>

int add (int a, int b) {
return a+b;
}

int main() {
int a,b;
a=3;
b=4;
int ret = add(a,b);
printf("Result: %u\n", ret);

exit(0);
}

The following assembler code is generated on IA-32 systems — albeit with compiler optimization
switched off (which would produce much improved code but complicate the explanation). This example
uses Intel representation because it is easier to read and explain than the AT&T variant preferred by
the GCC. Line numbers are not usually included in assembler syntax, but they have been added here to
simplify the code explanation.
Free download pdf