5.11 Low Level Procedures and the CALL Instruction


5.11 Low Level Procedures and the CALL Instruction

The 80x86 call instruction does two things. First, it pushes the address of the instruction immediately following the call onto the stack; then it transfers control to the address of the specified procedure. The value that call pushes onto the stack is known as the return address. When the procedure wants to return to the caller and continue execution with the first statement following the call instruction, the procedure simply pops the return address off the stack and jumps (indirectly) to that address. Most procedures return to their caller by executing a ret (return) instruction. The ret instruction pops a return address off the stack and transfers control indirectly to the address it pops off the stack.

By default, the HLA compiler automatically places a ret instruction (along with a few other instructions) at the end of each HLA procedure you write. This is why you haven't had to explicitly use the ret instruction up to this point. To disable the default code generation in an HLA procedure, specify the following options when declaring your procedures:

 procedure ProcName; @noframe; @nodisplay; begin ProcName;      .      .      . end ProcName; 

The @noframe and @nodisplay clauses are examples of procedure options. HLA procedures support several such options, including @returns, @noframe, @nodisplay, and @noalignstack. You'll see the purpose of @noalignstack and a couple of other procedure options a little later in this chapter. These procedure options may appear in any order following the procedure name (and parameters, if any). Note that @noframe and @nodisplay (as well as @noalignstack) may only appear in an actual procedure declaration. You cannot specify these options in a forward declaration.

The @noframe option tells HLA that you don't want the compiler to automatically generate entry and exit code for the procedure. This tells HLA not to automatically generate the ret instruction (along with several other instructions).

The @nodisplay option tells HLA that it should not allocate storage in procedure's local variable area for a display. The display is a mechanism you use to access nonlocal var objects in a procedure. Therefore, a display is only necessary if you nest procedures in your programs. This book will not consider the display or nested procedures; for more details on the display and nested procedures see the appropriate chapter in the electronic edition appearing on the CD-ROM or check out the HLA Reference Manual. Until then, you can safely specify the @nodisplay option on all your procedures. Indeed, for all of the procedures appearing in this chapter up to this point specifying the @nodisplay option makes a lot of sense because none of those procedures actually use the display. Procedures that have the @nodisplay option are a tiny bit faster and a tiny bit shorter than those procedures that do not specify this option.

The following is an example of the minimal procedure:

 procedure minimal; @nodisplay; @noframe; @noalignstack; begin minimal;      ret(); end minimal; 

If you call this procedure with the call instruction, minimal will simply pop the return address off the stack and return back to the caller. You should note that a ret instruction is absolutely necessary when you specify the @noframe procedure option.[13] If you fail to put the ret instruction in the procedure, the program will not return to the caller upon encountering the "end minimal;" statement. Instead, the program will fall through to whatever code happens to follow the procedure in memory. The example program in Listing 5-10 demonstrates this problem.

Listing 5-10: Effect of Missing RET Instruction in a Procedure.

start example
 program missingRET; #include( "stdlib.hhf" );      // This first procedure has the NOFRAME      // option but does not have a RET instruction.      procedure firstProc; @noframe; @nodisplay;      begin firstProc;           stdout.put( "Inside firstProc" nl );      end firstProc;      // Because the procedure above does not have a      // RET instruction, it will "fall through" to      // the following instruction. Note that there      // is no call to this procedure anywhere in      // this program.      procedure secondProc; @noframe; @nodisplay;      begin secondProc;           stdout.put( "Inside secondProc" nl );           ret(); end secondProc; begin missingRET;      // Call the procedure that doesn't have      // a RET instruction.      call firstProc; end missingRET; 
end example

Although this behavior might be desirable in certain rare circumstances, it usually represents a defect in most programs. Therefore, if you specify the @noframe option, always remember to explicitly return from the procedure using the ret instruction.

[13]Strictly speaking, this isn't true. But some mechanism that pops the return address off the stack and jumps to the return address is necessary in the procedure's body.




The Art of Assembly Language
The Art of Assembly Language
ISBN: 1593272073
EAN: 2147483647
Year: 2005
Pages: 246
Authors: Randall Hyde

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