1. INTRODUCCIÓN
1.1. Historia de la Cirugía Cardíaca
1.1.2. Derivación cardiopulmonar y cirugía extracorpórea (15)
1.1.2.1. Componentes del circuito
The bp, or base pointer (also referred to as frame pointer) register is used to
hold the address of the beginning or base of the current frame. The purpose of this is so that a common reference point for all local stack variables can be
used. In other words, stack variables are referenced by the bp register plus an
offset. When working in a particular stack frame, the value of this register will
never change. Each stack frame has its own unique bp value.
The sp, or stack pointer register is used to hold the address of the end of
the stack. A program’s assembly instructions will modify its value when new
always the end of the stack, when a new frame is created, its value is used to
set the new frame’s bp value. The best way to understand exactly how these
two registers work is to examine the assembly instructions involved in starting a new function and allocating stack variables within it. Consider the following source code:
#include <stdio.h>
void function1( int param ) {
int localVar = 99; }
int main( void ) {
int stackVar = 3; function1( stackVar ); return 0;
}
Compiling this code with the -S switch will produce the following assembly
listing:
.file “stack4.c” .text
.globl function1
.type function1, @function function1:
pushl %ebp movl %esp, %ebp subl $4, %esp movl $99, -4(%ebp) leave
ret
.size function1, .-function1 .globl main
.type main, @function main:
pushl %ebp movl %esp, %ebp subl $8, %esp andl $-16, %esp movl $0, %eax subl %eax, %esp movl $3, -4(%ebp) subl $12, %esp pushl -4(%ebp) call function1
addl $16, %esp movl $0, %eax leave
ret
.size main, .-main
.ident “GCC: (GNU) 3.3.1 (SuSE Linux)”
Note: Because the source program was very simple, this assembly listing is also quite simple. Without any prior knowledge of or experience with assembly listings, you should be able to easily look at this listing
and pick out the beginning of the two functions, function1 and main.
In function1, the first instruction pushl %ebp saves the value of the base
pointer from the previous frame on the stack. The next instruction movl %esp,
%ebp copies the value of the stack pointer into the base pointer register. Recall
that the stack pointer, esp in this example, always points to the top of the
stack. The next instruction subl $4, %esp subtracts 4 from the current value
stored in the stack pointer register. This effectively opens up storage in the newly created stack frame for 4 bytes. This is the space needed for the local
variable localVar, which is indeed 4 bytes in size (an int). These three
instructions combined form what’s commonly referred to as the function prologue. The function prologue is code added to the beginning of every function that is compiled by gcc and most, if not all, compilers. It is responsible for defining and preparing a new stack frame for upcoming function execution.
Along with a function prologue is an associated function epilogue. In the
assembly code shown for the preceding function1(), the epilogue consists of
the leave and ret instructions. The epilogue is effectively the reverse of the
prologue. It is hard to tell this because those unfamiliar with the x86 instruction
set will not know that the leave instruction is actually a high-level instruction
equivalent to these instructions:
movl %ebp, %esp popl %ebp
Comparing these two instructions to the first two instructions in the prologue, we can see that they are in fact the mirror image of each other. The function
epilogue code is completed by the ret instruction, which transfers program
control to the address located at the end of the stack.
The function prologue and epilogue are extremely important contributors to the proper execution and isolation of individual function calls. They make
up what’s commonly referred to as the function or procedure calling conventions.
We will discuss the remaining details of the calling conventions, but first a special note is required regarding the prologue and epilogue.
5.5.1.1 Special Case: gcc’s -fomit-frame-pointer Compile Option
Some architectures support gcc’s -fomit-frame-pointer compile option, which
is used to avoid the need for the function prologue and epilogue, thus freeing up the frame pointer register to be used for other purposes. This optimization is done at the cost of the ability to debug the application because certain debugging tools and techniques rely on the frame pointer being present. SUSE 9.0 Professional and SLES 8 on the x86-64 architecture have been compiled
with the -fomit-frame-pointer option enabled, which could improve performance
in certain areas of the operating system. GDB is able to handle this properly, but other debugging techniques might have difficulties such as using a home- grown stack traceback function. It is also important to note that when using
gcc 3.3.x with the -O1 or greater optimization level, the -fomit-frame-pointer
flag is automatically turned on for the x86-64 architecture. If omitting the frame pointer is not desired but optimization is, be sure to compile your program with something like the following:
gcc -o myexe myexe.c -O1 -fno-omit-frame-pointer