Examples Using the __stdcall Calling Convention

The following examples are included for purposes of illustration only. They have not been optimized. The examples assume that you are familiar with programming in assembler. Note that, in the examples, the stack grows toward the bottom of the page, and ESP always points to the top of the stack.

For the call

   m = func(a,b,c);

a, b, and c are 32-bit integers and func has two local variables, x and y (both 32-bit integers).

The stack for the call to func would look like this:

 

The instructions used to create this activation record on the stack look like this on the calling side:


   PUSH    c
   PUSH    b
   PUSH    a
   CALL    func@12
       .
       .
   MOV     m, EAX
       .
       .

For the callee, the code looks like this:

_func@12 PROC
   PUSH    EBP
   MOV     EBP, ESP       ;  Allocating 8 bytes of storage
   SUB     ESP, 8         ;   for two local variables.
   PUSH    EDI            ; These would only be
   PUSH    ESI            ;  pushed if they were used
   PUSH    EBX            ;  in this function.
   .
   .
   MOV     EAX, [EBP - 8]    ; Load y into EAX
   MOV     EBX, [EBP + 12]   ; Load b into EBX
   .
   .
   XOR     EAX, EAX           ; Zero the return value
   POP     EBX                ; Restore the saved registers
   POP     ESI
   POP     EDI
   LEAVE                      ; Equivalent to  MOV   ESP, EBP
                              ;                POP   EBP
   RET     0CH
_func@12 ENDP

The saved register set is EBX, ESI, and EDI.

Structures are not returned on the stack. The caller pushes the address where the returned structure is to be placed as a lexically first hidden parameter. A function that returns a structure must be aware that all parameters are 4 bytes farther away from EBP than they would be if no structure return were involved. The address of the returned structure is returned in EAX.

In the most common case, where the return from a function is simply assigned to a variable, the compiler merely pushes the address of the variable as the hidden parameter. For example:

    struct test_tag {
             int a;
             int some_array[100];
             } test_struct;

   struct test_tag test_function@404(struct test_tag test_parm)
   {
      test_parm.a = 42;
      return test_parm;
   }

   int main(void)
   {
      test_struct = test_function@404(test_struct);
      return test_struct.a;
   }

The code generated for the above example would be:


test_function@404 PROC
   PUSH    EBP
   MOV     EBP, ESP
   PUSH    ESI
   PUSH    EDI
   MOV     DWORD PTR [ESP+0cH], 02aH   ; test_parm.a
   MOV     EAX, [EBP+08H]              ; Get the target of the return value
   MOV     EDI, EAX                    ; Value
   LEA     ESI, [EBP+0cH]              ; test_parm
   MOV     ECX, 065H
   REP MOVSD
   POP     EDI
   POP     ESI
   LEAVE
   RET     198H
test_function@404  ENDP

   PUBLIC  main
main  PROC
   PUSH    EBP
   MOV     EBP, ESP
   PUSH    ESI
   PUSH    EDI

   SUB     ESP, 0194H                  ; Adjust the stack pointer
   MOV     EDI, ESP
   MOV     ESI, OFFSET FLAT: test_struct
   MOV     ECX, 065H
   REP MOVSD                           ; Copy the parameter
   PUSH    OFFSET FLAT: test_struct    ; Push the address of the target
   CALL    TEST_FUNCTION&404

   MOV     EAX, DWORD PTR test_struct  ; Take care of the return
   POP     EDI                         ;  from main
   POP     ESI
   LEAVE
   RET
main   ENDP




Calling Conventions


_stdcall Calling Convention