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.
![]()
Examples of Passing Parameters Using
_Optlink