Friday, November 23, 2012



INTRODUCTION TO PROCEDURES

·         A procedure is a unit of code designed to perform a particular sub-task of some main task. It is written out only once in some module, but can be used many times.

·         The advantages of using procedures are:

·         Improves code readability because the code does not need to be laid out as one long sequence.

·                     Allows code to be reused because it can be written once and called from more than one place in the code.

·          Allows tasks to be broken down into simpler components because procedures can be written for certain tasks (procedures can also call other procedures).

·         Modular code facilitates modification.

·         A procedure is always enclosed within some code segment.
·         A procedure is defined as:

PROCEDURE_NAME   PROC
.
.
.
PROCEDURE_NAME   ENDP

where PROCEDURE_NAME is any valid identifier.
·         The PROC directive usually includes one of the operands NEAR or FAR. Example:

PROCEDURE_NAME   PROC   FAR
.
.
.
PROCEDURE_NAME   ENDP

A NEAR procedure is defined in the same code segment from which it is called, and a FAR procedure is ordinarily defined in a separate code segment. Note if none of the operands NEAR or FAR follows the PROC directive, then the procedure is by default a NEAR procedure.

CALLING A NEAR PROCEDURE

·         A procedure is invoked by a CALL instruction that can be direct or indirect. A direct procedure call has the format:
                CALL     PROCEDURE_NAME
·         In an indirect near procedure call, the operand for the CALL instruction is either a 16-bit general-purpose register or a memory word containing the offset address of the procedure.

Example: An indirect procedure call using a register operand.
                .  .  .
                                MOV  SI ,  OFFSET  COMP
                                CALL  SI
                                .  .  .
                COMP  PROC  NEAR
                                .  .  .
                                RET
                COMP  ENDP

·         A procedure may be invoked by a JMP instruction if it does not return control to the caller:

JMP   PROCEDURE_NAME

Executing a near CALL
·         The return address to the calling program (the current value of the IP) is saved on the stack
·         IP get the offset address of the first instruction of the procedure (this transfers control to the procedure)

RETURNING FROM A PROCEDURE

The RET instruction returns control to the caller of a procedure. There are two formats for the RET instruction:
                RET
and
                RET  UnsignedInteger
The second form is used to discard parameters passed to the procedure through the stack. (This is discussed in another lecture )

Note: A procedure may have zero, one, or more RET instructions. A procedure will have no RET instruction in those programming situations where we don’t want to return control to the caller.

Executing a near RET
RET causes word at the top of the stack to be popped into IP  (Since this value is the offset address of the statement after the CALL statement, control is transferred to that statement.)

THE GENERAL STRUCTURE OF AN EXE-FORMAT PROGRAM CONTAINING PROCEDURES

                .MODEL SMALL
                .STACK  0400H
                .DATA 
                                .  .  .
                .CODE 
                MAIN  PROC
                                MOV  AX ,  @DATA          ; Initialize DS
                                MOV  DS ,  AX                     ;
                                .  .  .
                                CALL  SUB1
                                .  .  .
                                CALL  SUB2
                                .  .  .
                                MOV  AX ,  4C00H              ; Return to DOS
                                INT  21H
                MAIN  ENDP
                SUB1  PROC
                                .  .  .
                                RET
                SUB1  ENDP
                SUB2  PROC
                                .  .  .
                                CALL  SUB3
                                .  .  .
                                RET
                SUB2  ENDP
                SUB3  PROC
                                .  .  .
                                RET
                SUB3  ENDP
                END  MAIN


THE GENERAL STRUCTURES OF A COM-FORMAT PROGRAM CONTAINING PROCEDURES

.MODEL TINY
.CODE 
                ORG 100H
    MAIN  PROC
                .  .  .
            CALL  SUB1
                .  .  .
            CALL  SUB2
                .  .  .
            MOV  AX ,  4C00H   ; Return to DOS
            INT  21H
    MAIN  ENDP
    SUB1  PROC
         .  .  .
         RET
    SUB1  ENDP
    SUB2  PROC
         .  .  .
        CALL  SUB3
         .  .  .
         RET
     SUB2  ENDP
     SUB3  PROC
          .  .  .
          RET
     SUB3  ENDP
           .  .  .
          ; Data definitions, if any
           .  .  .
    END  MAIN
.MODEL TINY
.CODE 
                ORG 100H
 START: JMP MAIN
           .  .  .
          ; Data definitions, if any
           .  .  .
    MAIN  PROC
                .  .  .
            CALL  SUB1
                .  .  .
            CALL  SUB2
                .  .  .
            MOV  AX ,  4C00H   ; Return to DOS
            INT  21H
    MAIN  ENDP
    SUB1  PROC
         .  .  .
         RET
    SUB1  ENDP
    SUB2  PROC
         .  .  .
        CALL  SUB3
         .  .  .
         RET
     SUB2  ENDP
     SUB3  PROC
          .  .  .
          RET
     SUB3  ENDP
    END  START

Note: If the entry point is specified in the END directive, the procedures may appear in any order.

PRESERVING THE VALUES OF REGISTERS IN PROCEDURES

It is good programming practice to preserve the values of all the registers modified by a procedure, except if a register is used by the procedure to return a value to the calling program. This is done by PUSHing (i.e., saving) the values of those registers in the stack at the beginning of the procedure, and then POPing (i.e., retrieving) them from the stack, in the reverse order, before the RET instruction.

Example: MYPROC   PROC
                                                PUSH  AX
                                                PUSH  DX
                                                .  .  .                         ;  statements that modify AX and DX
                                                .  .  .                         ;
                                                POP  DX
                                                POP  AX
                                                RET
                                MYPROC  ENDP


·         Syntax of PUSH:
                   PUSH   source
Where source is either imm8, imm16, imm32, segment register, 16- or 32-bit general purpose register. If source is imm8, then the value is zero or sign extended to 16-bits.

·         Syntax of POP:
                POP  destination
Where destination is either mem16, mem32, segment register, 16- or 32-bit general purpose register.

Thus only words or double-words are pushed or popped from the stack. An 8-bit immediate value pushed in the stack is zero- or sign- extended to 16-bits.

Note:  (a) Since the stack is used by the system to store addresses during procedure calls, and to store addresses and the values of the flags during interrupts, it is necessary that to every PUSH instruction in your program there is a corresponding POP instruction.

 (b) To preserve the FLAGS register the instructions PUSHF and POPF are used.
       To preserve the EFLAGS register the instructions PUSHFD and POPFD are used.

(c) PUSHA    pushes the 16-bit general purpose registers in the order AX, CX, DX, BX, SP, BP, SI, and DI. POPA                     pops the 16-bit general purpose registers in the reverse order of PUSHA.
      PUSHAD  pushes the 32-bit general purpose registers in the order EAX, ECX, EDX, EBX, ESP, EBP, ESI,
                             EDI.
      POPAD         pops the 32-bit general-purpose registers in the reverse order of PUSHAD.

(d) USES directive: The PROC directive may have the form:
               procedure_name   PROC   USES  RegisterList
                    where:
RegisterList is a list of registers that are used by the procedure and which must be preserved. The registers in the list are separated by spaces. Including a register in this list will cause the assembler to automatically generate the necessary PUSH instruction to save the register value, and then to generate the necessary POP instruction to restore the value of that register before control is returned to the caller.

Example:  
      DISPLAY   PROC  USES   AX   BX   CX
                                         .   .   .
                                         RET
                         DISPLAY   ENDP


EXAMPLES

·         Procedures should normally be general and not specific, i.e., a procedure must be written such that it can be used by passing to it different parameters.

·         One way of passing parameters to procedures is to use registers.

·         Example1:       DISPLAY_STRING  PROC
                                                PUSH  AX
                                                MOV  AH ,  09H
                                                INT  21H
                                                POP  AX
                                                RET
                                DISPLAY_STRING  ENDP

This procedure will be invoked by a call of the form:
                                .   .   .
                                MOV  DX ,  OFFSET  STRING_NAME
                                CALL  DISPLAY_STRING
                                .   .   .
Note: If the previous procedure were coded as:
DISPLAY_STRING  PROC
                                                PUSH  AX
                                                PUSH  DX
                                                MOV  AH ,  09H
                                                MOV  DX , OFFSET  STRING1
                                                INT  21H
                                                POP  DX
                                                POP  AX
                                                RET
                                DISPLAY_STRING  ENDP

then a separate procedure will be required for every string to be displayed !
                               
·         Example2:       STRING_DISPLAY  PROC
                                                PUSH  AX
                                                PUSH  BX
                                                MOV  AH , 40H
                                                MOV  BX , 01H
                                                INT  21H
                                                POP  BX
                                                POP  AX
                                                RET
                                STRING_DISPLAY  ENDP

This procedure will be invoked by a call of the form:
                                .   .   .
                                MOV  CH , 00H
                                MOV  CL , string_length
                                LEA  DX ,  StringName
                                CALL  STRING_DISPLAY
                                .   .   .

·         Example3:
DISPLAY_CHAR   PROC
                                                PUSH  AX
                                                MOV  AH ,  02H
                                                INT  21H
                                                POP  AX
                                                RET
                                DISPLAY_CHAR  ENDP

This procedure will be invoked by a call of the form:
                                .   .   .
                                MOV  DL ,  character
                                CALL  DISPLAY_CHAR
                                .   .   .
·         Example4:
                                READ_CHAR   PROC
                                                ; Returns the character read in the AL register
                                                PUSH CX                               ; Preserve the CX register
                                                MOV CH, AH                       ; Preserve the AH register
                                                MOV  AH ,  01H
                                                INT  21H
                                                MOV AH, CH                       ; Restore the AH register
                                                POP CX                  ; Restore the CX register
                                                RET
                                READ_CHAR  ENDP

Note: In this procedure the AX register is not pushed and then popped (i.e., it is not preserved) because the procedure returns a value to the calling program in the AL register. This procedure will be invoked by a call of the form:
                                .   .   .
                                CALL  READ_CHAR                         
                                .   .   .



THE CALL AND RETURN MECHANISM FOR A NEAR PROCEDURE
Assume that a program defines a stack segment as:
                .STACK  200 
               
then the original state of this stack is:




high address




byte 200

¬ SP

byte 199



byte 198












.
stack segment

.



.






byte 1



byte 0

¬ SS            




low address

Notice that the SP register is initialized to point one byte beyond the stack. The reason is that when a PUSH instruction:
                                PUSH Operand16
 is executed the value in the SP register is automatically decremented by 2 and then the value of the word operand is pushed into the stack at the new word pointed to by SP:
                                (SP)  ¬   (SP) - 2
                                (Word at Top of Stack)  ¬   (Operand16)
 In the above example, the first word to be pushed into the stack will be stored at bytes 198 and 199. The state of the stack after pushing one word is then:




high address




byte 200



byte 199
XX


byte 198
XX
¬ SP          










.
stack segment

.



.






byte 1



byte 0

¬ SS          




low address

When a POP instruction:
                POP  Operand16
is executed, the value of the word at the current top of the stack (i.e., the word pointed to by SP) is copied to the operand of the POP instruction and then the value of the SP register is automatically incremented by 2:
                Operand16  ¬  (Word at top of stack)
                (SP)  ¬   (SP) + 2
Since the value of the popped word is no longer accessible in the stack it will be overwritten by a subsequent PUSH operation.


When a NEAR procedure is called the following sequence of events occurs:

·         (SP)  ¬  (SP)  -  2
·         (Word at top of Stack)  ¬   (IP)
i.e., the offset address of the statement after the CALL statement is stored in the stack.
·         (IP)  ¬ offset address of first executable statement in the called procedure.

Since the logical address CS:IP now refers to the first executable statement in the called NEAR procedure, program execution continues with the execution of the procedure statements.

When a RET instruction is executed in the procedure the following sequence of events occurs:

·         (IP)  ¬   (Word at top of Stack)
i.e.,  restore the offset address of the statement, in the calling program, after the CALL statement.
·         (SP)  ¬   (SP)  +  2

Since now the logical address CS:IP refers to the statement, in the calling program, after the CALL statement, program execution continues from that statement.

Note: For a NEAR procedure call the value of CS is not pushed in the stack, because both the calling program and the called procedure are in the same code segment; the value of CS does not change.

0 comments:

Post a Comment