PROGRAM CONTROL INSTRUCTIONS:PROCEDURES.

PROCEDURES

The procedure (subroutine, method, or function) is an important part of any computer system’s architecture. A procedure is a group of instructions that usually performs one task. A procedure is a reusable section of the software that is stored in memory once, but used as often as necessary. This saves memory space and makes it easier to develop software. The only disadvantage of a procedure is that it takes the computer a small amount of time to link to the procedure and return from it. The CALL instruction links to the procedure, and the RET (return) instruction returns from the procedure.

The stack stores the return address whenever a procedure is called during the execution of a program. The CALL instruction pushes the address of the instruction following the CALL (return address) on the stack. The RET instruction removes an address from the stack so the program returns to the instruction following the CALL.

With the assembler, there are specific rules for storing procedures. A procedure begins with the PROC directive and ends with the ENDP directive. Each directive appears with the name of the procedure. This programming structure makes it easy to locate the procedure in a program listing. The PROC directive is followed by the type of procedure: NEAR or FAR. Example 6–16 shows how the assembler uses the definition of both a near (intrasegment) and far (intersegment) procedure. In MASM version 6.x, the NEAR or FAR type can be followed by the USES statement. The USES statement allows any number of registers to be automatically pushed to the stack and popped from the stack within the procedure. The USES statement is also illustrated in Example 6–14.

Program Control InstructionsA-0226

When these first two procedures are compared, the only difference is the opcode of the return instruction. The near return instruction uses opcode C3H and the far return uses opcode CBH. A near return removes a 16-bit number from the stack and places it into the instruction pointer to return from the procedure in the current code segment. A far return removes a 32-bit number from the stack and places it into both IP and CS to return from the procedure to any memory location.

Procedures that are to be used by all software (global) should be written as far procedures. Procedures that are used by a given task (local) are normally defined as near procedures. Most procedures are near procedures.

FIGURE 6–6 The effect of a near CALL on the stack and the instruction pointer.

Program Control InstructionsA-0227

CALL

The CALL instruction transfers the flow of the program to the procedure. The CALL instruction differs from the jump instruction because a CALL saves a return address on the stack. The return address returns control to the instruction that immediately follows the CALL in a program when a RET instruction executes.

Near CALL. The near CALL instruction is 3 bytes long; the first byte contains the opcode, and the second and third bytes contain the displacement, or distance of ±32K in the 8086 through the 80286 processors. This is identical to the form of the near jump instruction. The 80386 and above use a 32- bit displacement, when operating in the protected mode, that allows a distance of ±2G bytes. When the near CALL executes, it first pushes the offset address of the next instruction onto the stack. The offset address of the next instruction appears in the instruction pointer (IP or EIP). After saving this return address, it then adds the displacement from bytes 2 and 3 to the IP to transfer control to the procedure. There is no short CALL instruction. A variation on the opcode exists as CALLN, but this should be avoided in favor of using the PROC statement to define the CALL as near.

Why save the IP or EIP on the stack? The instruction pointer always points to the next instruction in the program. For the CALL instruction, the contents of IP/EIP are pushed onto the stack, so program control passes to the instruction following the CALL after a procedure ends. Figure 6–6 shows the return address (IP) stored on the stack and the call to the procedure.

Far CALL. The far CALL instruction is like a far jump because it can call a procedure stored in any memory location in the system. The far CALL is a 5-byte instruction that contains an opcode followed by the next value for the IP and CS registers. Bytes 2 and 3 contain the new contents of the IP, and bytes 4 and 5 contain the new contents for CS.

The far CALL instruction places the contents of both IP and CS on the stack before jumping to the address indicated by bytes 2 through 5 of the instruction. This allows the far CALL to call a procedure located anywhere in the memory and return from that procedure.

Program Control InstructionsA-0228

Figure 6–7 shows how the far CALL instruction calls a far procedure. Here, the contents of IP and CS are pushed onto the stack. Next, the program branches to the procedure. A variant of the far call exists as CALLF, but this should be avoided in favor of defining the type of call instruction with the PROC statement.

In the 64-bit mode a far call is to any memory location and the information placed onto the stack is an 8-byte number. Likewise, the far return instruction also retrieves an 8-byte return address from the stack and places it into RIP.

CALLs with Register Operands. Like jump instructions, call instructions also may contain a register operand. An example is the CALL BX instruction, which pushes the contents of IP onto the stack. It then jumps to the offset address, located in register BX, in the current code segment. This type of CALL always uses a 16-bit offset address, stored in any 16-bit register except the segment registers.

Example 6–15 illustrates the use of the CALL register instruction to call a procedure that begins at offset address DISP. (This call could also directly call the procedure by using the CALL DISP instruction.) The OFFSET address DISP is placed into the BX register, and then the CALL BX instruction calls the procedure beginning at address DISP. This program displays an “OK” on the monitor screen.

Program Control InstructionsA-0229Program Control InstructionsA-0230

CALLs with Indirect Memory Addresses. A CALL with an indirect memory address is particularly useful whenever different subroutines need to be chosen in a program. This selection process is often keyed with a number that addresses a CALL address in a lookup table. This is essentially the same as the indirect jump that used a lookup table for a jump address earlier in this chapter.

Example 6–16 shows how to access a table of addresses using an indirect CALL instruction. This table illustrated in the example contains three separate subroutine addresses referenced by the numbers 0, 1, and 2. This example uses the scaled-index addressing mode to multiply the number in EBX by 2 so it properly accesses the correct entry in the lookup table.

Program Control InstructionsA-0231

The CALL instruction also can reference far pointers if the instruction appears as CALL FAR PTR [4*EBX] or as CALL TABLE [4*EBX], if the data in the table are defined as double- word data with the DD directive. These instructions retrieve a 32-bit address (4 bytes long) from the data segment memory location addressed by EBX and use it as the address of a far procedure.

RET

The return instruction (RET) removes a 16-bit number (near return) from the stack and places it into IP, or removes a 32-bit number (far return) and places it into IP and CS. The near and far return instructions are both defined in the procedure’s PROC directive, which automatically selects the proper return instruction. With the 80386 through the Pentium 4 processors operating in the protected mode, the far return removes 6 bytes from the stack. The first 4 bytes contain the new value for EIP and the last 2 contain the new value for CS. In the 80386 and above, a protected mode near return removes 4 bytes from the stack and places them into EIP.

When IP/EIP or IP/EIP and CS are changed, the address of the next instruction is at a new memory location. This new location is the address of the instruction that immediately follows the most recent CALL to a procedure. Figure 6–8 shows how the CALL instruction links to a procedure and how the RET instruction returns in the 8086–Core2 operating in the real mode.

There is one other form of the return instruction, which adds a number to the contents of the stack pointer (SP) after the return address is removed from the stack. A return that uses an immediate operand is ideal for use in a system that uses the C/C++ or PASCAL calling conventions. (This is true even though the C/C++ and PASCAL calling conventions require the caller to remove stack data for many functions.) These conventions push parameters on the stack before near return instruction on the stack and instruction pointer.

Program Control InstructionsA-0232

calling a procedure. If the parameters are to be discarded upon return, the return instruction contains a number that represents the number of bytes pushed to the stack as parameters.

Example 6–17 shows how this type of return erases the data placed on the stack by a few pushes. The RET 4 adds a 4 to SP after removing the return address from the stack. Because the PUSH AX and PUSH BX together place 4 bytes of data on the stack, this return effectively deletes AX and BX from the stack. This type of return rarely appears in assembly language programs, but it is used in high-level programs to clear stack data after a procedure. Notice how parameters are addressed on the stack by using the BP register, which by default addresses the stack segment. Parameter stacking is common in procedures written for C++ or PASCAL by using the C++ or PASCAL calling conventions.

Program Control InstructionsA-0233

As with the CALLN and CALLF instructions, there are also variants of the return instruction: RETN and RETF. As with the CALLN and CALLF instructions, these variants should also be avoided in favor of using the PROC statement to define the type of call and return.

Leave a comment

Your email address will not be published. Required fields are marked *