; #include <stdlib.h>
;
; void leaf_call(int b, int c, int d, int e, int f, int g, int h)
; {
; }
;
; void nonleaf_call(int a, int b, int c, int d, int e, int f, int g, int h)
; {
; /* use some local data */
; *(char*)alloca(220) = 'L';
; leaf_call(b, c, d, e, f, g, h);
; }
;
; int main()
; {
; nonleaf_call(0, 1, 2, 3, 4, 5, 6, 7);
; return 0;
; }
; output from godbolt compiler explorer w/ msvc 19.0 (/Gr for fastcall)
_b$ = -8
_c$ = -4
@leaf_call@28 PROC
push ebp
mov ebp, esp
sub esp, 8
mov DWORD PTR _c$[ebp], edx
mov DWORD PTR _b$[ebp], ecx
mov esp, ebp
pop ebp
ret 20
@leaf_call@28 ENDP
_a$ = -8
_b$ = -4
_c$ = 8
_d$ = 12
_e$ = 16
_f$ = 20
_g$ = 24
_h$ = 28
@nonleaf_call@32 PROC
push ebp ; |
mov ebp, esp ; | prolog
sub esp, 8 ; |
mov DWORD PTR _b$[ebp], edx ; in arg 1 -> local area on stack
mov DWORD PTR _a$[ebp], ecx ; in arg 0 -> local area on stack
mov ecx, 220 ; |
call @alloca@4 ; | call alloca(220) (ecx = arg)
mov BYTE PTR [eax], 76 ; 'L' -> alloca()'d space (pointed to by alloca's retval in eax)
mov eax, DWORD PTR _h$[ebp] ; |
push eax ; |
mov ecx, DWORD PTR _g$[ebp] ; |
push ecx ; |
mov edx, DWORD PTR _f$[ebp] ; | read in args 3-7 from prev frame's param area, and ...
push edx ; | ... "push" onto stack as arg 2-6
mov eax, DWORD PTR _e$[ebp] ; |
push eax ; |
mov ecx, DWORD PTR _d$[ebp] ; |
push ecx ; |
mov edx, DWORD PTR _c$[ebp] ; arg 1 | read from prev frame's param
mov ecx, DWORD PTR _b$[ebp] ; arg 0 | area and put in regs
call @leaf_call@28 ; push return address and call
mov esp, ebp ; |
pop ebp ; | epilog
ret 24 ; |
@nonleaf_call@32 ENDP
_main PROC
push ebp ; | prolog
mov ebp, esp ; |
push 7 ; arg 7
push 6 ; arg 6
push 5 ; arg 5
push 4 ; arg 4
push 3 ; arg 3
push 2 ; arg 2
mov edx, 1 ; arg 1 (via reg)
xor ecx, ecx ; arg 0 (via reg)
call @nonleaf_call@32 ; push return address and call
xor eax, eax ; return value
pop ebp ; |
ret 0 ; | epilog
_main ENDP
; ---------- structs by value (arg and return value), struct arg not fitting in regs ---------->
;
; struct A { int x; short y; char z; long long t; };
;
; struct A leaf_call(struct A a, short b, long long c, char d, int e, int f, int g, long long h)
; {
; a.x += 1;
; return a;
; }
;
; int main()
; {
; struct A a ={9, 99, 23, 12LL};
; leaf_call(a, 1, 2, 3, 4, 5, 6, 7LL);
; return 0;
; }
; output from godbolt compiler explorer w/ msvc 19.0 (/Gr for fastcall)
_b$ = -8
_d$ = -4
$T1 = 8
_a$ = 12
_c$ = 28
_e$ = 36
_f$ = 40
_g$ = 44
_h$ = 48
@leaf_call@52 PROC
push ebp ; |
mov ebp, esp ; | prolog
sub esp, 8 ; |
mov BYTE PTR _d$[ebp], dl ; in arg 3 -> local area on stack
mov WORD PTR _b$[ebp], cx ; in arg 1 -> local area on stack
mov eax, DWORD PTR _a$[ebp] ; \
add eax, 1 ; | get struct's x (from stack args), add 1 and write back
mov DWORD PTR _a$[ebp], eax ; /
mov ecx, DWORD PTR $T1[ebp] ; get ptr to retval struct passed as hidden arg (+8 to skip retval and saved ebp)
mov edx, DWORD PTR _a$[ebp] ; |
mov DWORD PTR [ecx], edx ; |
mov eax, DWORD PTR _a$[ebp+4] ; |
mov DWORD PTR [ecx+4], eax ; | copy modified (b/c of x+=1) struct arg to space of retval
mov edx, DWORD PTR _a$[ebp+8] ; |
mov DWORD PTR [ecx+8], edx ; |
mov eax, DWORD PTR _a$[ebp+12] ; |
mov DWORD PTR [ecx+12], eax ; |
mov eax, DWORD PTR $T1[ebp] ; return value (= ptr to struct that was passed-in as hidden arg)
mov esp, ebp ; |
pop ebp ; | epilog
ret 48 ; |
@leaf_call@52 ENDP
$T1 = -32
_a$ = -16
_main PROC
push ebp ; |
mov ebp, esp ; | prolog
sub esp, 32 ; / 32 = 16b local area for struct + 16b space used for retval struct
mov DWORD PTR _a$[ebp], 9 ; \ int x
mov eax, 99 ; | |
mov WORD PTR _a$[ebp+4], ax ; | struct values (local area) | short y
mov BYTE PTR _a$[ebp+6], 23 ; | char z
mov DWORD PTR _a$[ebp+8], 12 ; | |
mov DWORD PTR _a$[ebp+12], 0 ; / | long long t
push 0 ; \
push 7 ; | arg 7
push 6 ; arg 6
push 5 ; arg 5
push 4 ; arg 4
push 0 ; |
push 2 ; / arg 2 (via stack b/c not first arg and > 32 bits)
sub esp, 16 ; \
mov ecx, esp ; |
mov edx, DWORD PTR _a$[ebp] ; |
mov DWORD PTR [ecx], edx ; |
mov eax, DWORD PTR _a$[ebp+4] ; |
mov DWORD PTR [ecx+4], eax ; | arg 0 (struct), "pushed" onto stack (fetched from local area)
mov edx, DWORD PTR _a$[ebp+8] ; |
mov DWORD PTR [ecx+8], edx ; |
mov eax, DWORD PTR _a$[ebp+12] ; |
mov DWORD PTR [ecx+12], eax ; /
lea ecx, DWORD PTR $T1[ebp] ; \ ptr to space used for struct retval (pushed as hidden first arg)
push ecx ; |
mov dl, 3 ; arg 3 (via reg)
mov ecx, 1 ; arg 1 (via reg)
call @leaf_call@52 ; push return address and call
xor eax, eax ; return value
mov esp, ebp ; |
pop ebp ; | epilog
ret 0 ; |
_main ENDP
; ---------- C++ trivial and non-trivial aggrs passed to C funcs ---------->
;
; struct Trivial { int a; };
; struct NonTrivial {
; int a;
; NonTrivial() : a(0) {}
; NonTrivial(const NonTrivial& rhs) : a(rhs.a) { }
; };
;
; extern "C" {
;
; void f1(struct Trivial s) { }
; void f2(struct NonTrivial s) { }
;
; void f()
; {
; struct Trivial t;
; struct NonTrivial n;
; int a=1;
; a += 123;
; f1(t);
; a -= 123;
; f2(n);
; a -= 12;
; }
; }
; output from godbolt compiler explorer w/ msvc 19.31 (/Gr for fastcall)
_this$ = -4
NonTrivial::NonTrivial(void) PROC
push ebp
mov ebp, esp
push ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov DWORD PTR [eax], 0
mov eax, DWORD PTR _this$[ebp]
mov esp, ebp
pop ebp
ret 0
NonTrivial::NonTrivial(void) ENDP
_this$ = -4
_rhs$ = 8
NonTrivial::NonTrivial(NonTrivial const &) PROC
push ebp
mov ebp, esp
push ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov ecx, DWORD PTR _rhs$[ebp]
mov edx, DWORD PTR [ecx]
mov DWORD PTR [eax], edx
mov eax, DWORD PTR _this$[ebp]
mov esp, ebp
pop ebp
ret 4
NonTrivial::NonTrivial(NonTrivial const &) ENDP
_s$ = 8
@f1@4 PROC
push ebp
mov ebp, esp
pop ebp
ret 4
@f1@4 ENDP
_s$ = 8
@f2@4 PROC
push ebp
mov ebp, esp
pop ebp
ret 4
@f2@4 ENDP
_t$ = -12
_n$ = -8
_a$ = -4
@f@0 PROC
push ebp ;
mov ebp, esp ;
sub esp, 12 ;
lea ecx, DWORD PTR _n$[ebp] ;
call NonTrivial::NonTrivial(void) ;
mov DWORD PTR _a$[ebp], 1 ;
mov eax, DWORD PTR _a$[ebp] ;
add eax, 123 ;
mov DWORD PTR _a$[ebp], eax ;
mov ecx, DWORD PTR _t$[ebp] ;
push ecx ;
call @f1@4 ;
mov edx, DWORD PTR _a$[ebp] ;
sub edx, 123 ;
mov DWORD PTR _a$[ebp], edx ;
push ecx ;
mov ecx, esp ;
lea eax, DWORD PTR _n$[ebp] ;
push eax ;
call NonTrivial::NonTrivial(NonTrivial const &) ;
call @f2@4 ;
mov ecx, DWORD PTR _a$[ebp] ;
sub ecx, 12 ;
mov DWORD PTR _a$[ebp], ecx ;
mov esp, ebp ;
pop ebp ;
ret 0 ;
@f@0 ENDP
; ---------- C++ trivial and non-trivial aggrs as return values ---------->
;
; struct Trivial { int a; };
; struct NonTrivial {
; int a;
; NonTrivial() : a(0) {}
; NonTrivial(const NonTrivial& rhs) : a(rhs.a) { }
; };
;
; extern "C" {
; struct Trivial f1() { return Trivial(); }
; }
;
; struct NonTrivial f2() { return NonTrivial(); }
;
; extern "C" {
; void f()
; {
; int a=1;
; a += 123;
; struct Trivial t = f1();
; a -= 123;
; struct NonTrivial n = f2();
; a -= 12;
; }
; }
; output from godbolt compiler explorer w/ msvc 19.31 (/Gr for fastcall)
_this$ = -4
NonTrivial::NonTrivial(void) PROC
push ebp
mov ebp, esp
push ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov DWORD PTR [eax], 0
mov eax, DWORD PTR _this$[ebp]
mov esp, ebp
pop ebp
ret 0
NonTrivial::NonTrivial(void) ENDP
$T1 = -4
@f1@0 PROC
push ebp
mov ebp, esp
push ecx
xor eax, eax
mov DWORD PTR $T1[ebp], eax
mov eax, DWORD PTR $T1[ebp]
mov esp, ebp
pop ebp
ret 0
@f1@0 ENDP
___$ReturnUdt$ = -4
NonTrivial f2(void) PROC
push ebp ;
mov ebp, esp ;
push ecx ; ptr to hidden retval space as first arg (fastcall, in ecx)
mov DWORD PTR ___$ReturnUdt$[ebp], ecx ; |
mov ecx, DWORD PTR ___$ReturnUdt$[ebp] ; | a bit pointless
call NonTrivial::NonTrivial(void) ;
mov eax, DWORD PTR ___$ReturnUdt$[ebp] ; return passed-in ptr ptr to hidden retval space in eax
mov esp, ebp ;
pop ebp ;
ret 0 ;
NonTrivial f2(void) ENDP
_n$ = -16
_t$ = -12
$T1 = -8
_a$ = -4
@f@0 PROC
push ebp ;
mov ebp, esp ;
sub esp, 16 ;
mov DWORD PTR _a$[ebp], 1 ; a = 1
mov eax, DWORD PTR _a$[ebp] ; |
add eax, 123 ; | a += 123
mov DWORD PTR _a$[ebp], eax ; |
call @f1@0 ; call f1()
mov DWORD PTR $T1[ebp], eax ; retval (trivial struct <= 32bits, returned via eax)
mov ecx, DWORD PTR $T1[ebp] ; | copy of retval from stack to stack
mov DWORD PTR _t$[ebp], ecx ; /
mov edx, DWORD PTR _a$[ebp] ; \
sub edx, 123 ; | a -= 123
mov DWORD PTR _a$[ebp], edx ; |
lea ecx, DWORD PTR _n$[ebp] ; hidden first arg: ptr to space for (non-trivial) retval
call NonTrivial f2(void) ; call f2()
mov eax, DWORD PTR _a$[ebp] ; |
sub eax, 12 ; | a -= 12
mov DWORD PTR _a$[ebp], eax ; |
mov esp, ebp ;
pop ebp ;
ret 0 ;
@f@0 ENDP
; vim: ft=asm