7.3.2 Passing Arguments on the Stack

Each time you call a procedure, you may want it to operate on different data. This data, called “arguments,” can be passed in various ways. For example, arguments can be passed to a procedure in registers or in variables. However, the most common method of passing arguments is to use the stack. Microsoft languages have specific conventions for passing arguments. Chapter 20, “Mixed-Language Programming,” explains these conventions for assembly-language modules shared with modules from high-level languages.

This section describes how a procedure accesses the arguments passed to it on the stack. Each argument is accessed as an offset from BP. However, if you use the PROC directive to declare parameters, the assembler calculates these offsets for you and lets you refer to parameters by name. The next section, “Declaring Parameters with the PROC Directive,” explains how to use PROC this way.

This example shows how to pass arguments to a procedure. The procedure expects to find those arguments on the stack. As this example shows, arguments must be accessed as offsets of BP.

; C-style procedure call and definition

mov ax, 10 ; Load and

push ax ; push constant as third argument

push arg2 ; Push memory as second argument

push cx ; Push register as first argument

call addup ; Call the procedure

add sp, 6 ; Destroy the pushed arguments

. ; (equivalent to three pops)

.

.

addup PROC NEAR ; Return address for near call

; takes two bytes

push bp ; Save base pointer - takes two bytes

; so arguments start at fourth byte

mov bp, sp ; Load stack into base pointer

mov ax, [bp+4] ; Get first argument from

; fourth byte above pointer

add ax, [bp+6] ; Add second argument from

; sixth byte above pointer

add ax, [bp+8] ; Add third argument from

; eighth byte above pointer

mov sp, bp

pop bp ; Restore BP

ret ; Return result in AX

addup ENDP

Figure 7.1 shows the stack condition at key points in the process.

Starting with the 80186 processor, the ENTER and LEAVE instructions simplify the stack setup and restore instructions at the beginning and end of procedures.

However, ENTER uses a lot of time. It is necessary only with nested, statically scoped procedures. Thus, a Pascal compiler may sometimes generate ENTER. The LEAVE instruction, on the other hand, is an efficient way to do the stack cleanup. LEAVE reverses the effect of the last ENTER instruction by restoring BP and SP to their values before the procedure call.