A generic stack


The diagram below illustrates a simplified view of a stack frame. The only data this sample frame holds is a pointer to the previous frame, the program counter from the previous routine, and the arguments that were passed to the new routine.

Figure 17-1. A generic stack frame

graphics/17fig01.gif

This simple frame layout is actually that used by the sun2 hardware architecture and probably other vendors ' system architectures as well.

When one routine calls another routine, the three pieces of information diagrammed above will need to be loaded into a new frame that is placed or " pushed " onto the current stack. How this data gets moved onto the stack is implementation-specific. Soon, we will see how this is done on SPARC systems. For now, we'll just trust that it gets done for us.

As shown in the previous figure, the address of the caller's frame is saved in fr_savfp of the new frame. This provides us with a way of returning to the caller's frame.

The address, or program counter, of the instruction that caused us to jump into the new routine is stored in fr_savpc . This is used when it's time for us to return to the calling routine.

Finally, the arguments or parameters passed to the new routine are stored in the frame starting at fr_arg .

Now, keeping this as generic as possible, let's watch our stack grow as the result of a call to a new routine.

Here is a little program that calls a little routine, passing it three parameters. The little routine, fred() , actually does nothing at all.

 main ()  {   fred (1, 2, 3);  }  int fred (a, b, c)  int a, b, c;  {} 

When we start running main() , an initial frame will be put on the stack. This is taken care of for us by the system. For now, we will demonstrate this initial frame as being filled with nulls or zeros. When we call fred() , a new frame will be put or "pushed" onto the stack for us. While we are actually in fred() , our stack will hold two frames , as shown in the next figure.

Figure 17-2. Stack frame example

graphics/17fig02.gif

When we are done executing fred() and need to return to main() , we will use the saved PC, the address of main+24 in this example, as our reference of where to return within the main routine. This is in the current frame in fr_savpc. In many machines, this is the address of the instruction following the call to fred() . On SPARC, this is the actual address of the calling instruction, usually some sort of jump to subroutine or call instruction. Since we've already executed the instruction at main+24 , we will not be executing the instruction referenced in the saved PC, but instead we will be using it as a reference for where to resume within the main routine.

As we return to main() , the original frame becomes our current frame. This is known as "popping" the stack. The area of memory that was used to store the stack frame we were using while in fred() is now considered free. If we were to call fred() a second time from main() , a brand-new frame would be constructed and pushed onto the stack.

Looking at the figure above, what may cause some confusion for you at this point is the direction in which the stack grows. Instead of starting at a low memory address and growing towards high memory, the stack starts in high memory and works its way down towards low memory.

Okay, that's the general concept. Now let's talk about SPARC frames in detail.



PANIC. UNIX System Crash Dump Analysis Handbook
PANIC! UNIX System Crash Dump Analysis Handbook (Bk/CD-ROM)
ISBN: 0131493868
EAN: 2147483647
Year: 1994
Pages: 289
Authors: Chris Drake

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net