Accessing Parameters

Once you have established the frame pointer, allocated local storage (if required), and pushed any registers that need to be preserved, you can write the main body of the procedure. Figure 11.4 shows how functions that observe the C calling convention use the stack frame.

The stack frame for the assembly-language procedure shown in Figure 11.4 is established by the following:

1.The calling program pushes each of the parameters onto the stack, after which SP points to the last parameter pushed.

2.The calling program issues a CALL instruction, which causes the return address (the place in the calling program to which control will ultimately return) to be placed on the stack. This address can be either two bytes long (for near calls) or four bytes long (for far calls). SP now points to this address.

3.The first instruction of the called procedure saves the old value of BP, with the instruction push bp. SP now points to the saved copy of BP.

4.BP is used to hold the current value of SP, with the instruction mov bp,sp. BP therefore now points to the old value of BP (saved on the stack).

5.While BP remains constant throughout the procedure, SP is often decreased to provide room on the stack for local data or saved registers.

In general, the displacement (from BP) for a parameter x is equal to the size of return address plus 2 plus the total size of parameters between x and BP.

To calculate the size of parameters between x and BP, you must start with the rightmost parameter because C pushes parameters from right to left. For example, consider a FAR procedure that has one argument of type int (two bytes). The displacement of the parameter is

Argument's displacement = size of far return address + 2

= 4 + 2

= 6

The argument can thus be loaded into BP with the following instruction:

mov bx,[bp+6]

Once you determine the displacement of each parameter, you can use EQU directives or structures to refer to the parameter with a single identifier name in your assembly source code. For example, you can use a more readable name to reference the parameter at BP+6 if you put the following statement at the beginning of the assembly source file:

Arg1 EQU [bp+6]

You can then refer to the first parameter in your source as Arg1 in any instruction. Use of this feature is optional.

For far (segmented) addresses, Microsoft C pushes the segment address before pushing the offset address. When pushing arguments larger than two bytes, high-order words are always pushed before low-order words, and parameters larger than two bytes are stored on the stack in most-significant, least-significant order.

This standard for pushing segment addresses before pushing offset addresses facilitates the use of the assembly-language instructions LDS (load data segment) and LES (load extra segment).