Passing and Returning Aggregates by Value to a Prototyped Routine

If an aggregate is passed by value, the following code sequences are produced for the caller and callee:

'C' Source:

   struct s_tag {
             long  a;
             float b;
             long  c;
             } x, y;
   long  z;
   double q;

   /* Prototype */
   struct s_tag bar(long lvar, struct s_tag aggr, float fvar);
    ·

   /* Actual Call */
   y = bar(z, x, q);
    ·

   /* callee */
   struct s_tag bar(long lvar, struct s_tag aggr, float fvar)
   {
      struct s_tag temp;

      temp.a = lvar + aggr.a + 23;
      temp.b = fvar - aggr.b;
      temp.c = aggr.c;

      return temp;
   }

Caller's code up until call:


   FLD     QWORD_PTR q          ; Load lexically first floating-point
                                ;  parameter to be converted
   FSTP    DWORD_PTR [EBP - T1] ; Convert to formal parameter type by
   FLD     DWORD_PTR [EBP - T1] ; Storing and loading from a temp (T1)
   SUB     ESP, 4               ; Allocate space for the floating-point
                                ;  register parameter
   PUSH    x.c                  ; Push nonconforming parameters on
   PUSH    x.b                  ;  stack
   PUSH    x.a                  ;
   MOV     EAX, Z               ; Load lexically first conforming
                                ;  parameter into EAX
   SUB     ESP, 4               ; Allocate stack space for the first
                                ;  general-purpose register parameter.
   PUSH    addr y               ; Push hidden first parameter (address of
                                ;  return space)
   CALL    BAR


Callee's prolog code:

   PUSH     EBP          ; Save caller's EBP
   MOV      EBP, ESP     ; Set up callee's EBP
   SUB      ESP, 12      ; Allocate callee's Local
                         ;  = sizeof(struct s_tag)
   PUSH     EBX          ; Save preserved registers -
   PUSH     EDI          ;  will optimize to save
   PUSH     ESI          ;  only registers callee uses

Note: the term undefined in registers ECX and EDX refers to the fact that they can be safely overwritten by the code in bar.

   temp.a = lvar + aggr.a + 23;
   temp.b = fvar - aggr.b;
   temp.c = aggr.c

   return temp;

   ADD       EAX, 23               ;
   ADD       EAX, [EBP + 16]       ; Calculate temp.a
   MOV       [EBP - 12], EAX       ;

   FSUB      DWORD_PTR [EBP + 20]  ; Calculate temp.b
   FSTP      DWORD_PTR [EBP - 8]   ;

   MOV       EAX, [EBP + 24]       ; Calculate temp.c
   MOV       [EBP - 4], EAX        ;

   MOV       EAX, [EBP + 8]        ; Load hidden parameter (address
                                   ;  of return value storage). Useful
                                   ;  both for setting return value
                                   ;  and for returning address in EAX.

   MOV       EBX, [EBP - 12]       ; Return temp by copying its contents
   MOV       [EAX], EBX            ;  to the return value storage
   MOV       EBX, [EBP - 8]        ;  addressed by the hidden parameter.
   MOV       [EAX + 4], EBX        ;  String move instructions would be
   MOV       EBX, [EBP - 4]        ;  faster above a certain threshold
   MOV       [EAX + 8], EBX        ;  size of returned aggregate.

   POP       ESI                   ; Begin Epilog by restoring
   POP       EDI                   ;  preserved registers.
   POP       EBX
   MOV       ESP, EBP              ; Deallocate callee's local
   POP       EBP                   ; Restore caller's EBP
   RET                             ; Return to caller


 

 

Caller's code just after call:


   ADD    ESP, 24       ; Remove parameters from stack
    ...                 ; Because address of y was given as the
                        ;  hidden parameter, the assignment of the
                        ;  return value has already been performed.

If a y.a = bar(x).b construct is used instead of the more common y = bar(x) construct, the address of the return value is available in EAX. In this case, the address of the return value (hidden parameter) would point to a temporary variable allocated by the compiler in the automatic storage of the caller.



Calling Conventions


Examples of Passing Parameters Using _Optlink