# HG changeset patch # User Tassilo Philipp # Date 1644236149 -3600 # Node ID 984e6652b975021247cbe8d674a3957c773b7c35 # Parent 79b95db3d68fd7aeedf83405582198df009b5407 some x86 disas examples, for completion but also while researching struct by val passing on non-x64 diff -r 79b95db3d68f -r 984e6652b975 doc/disas_examples/x86.cdecl.disas --- a/doc/disas_examples/x86.cdecl.disas Sun Feb 06 17:22:59 2022 +0100 +++ b/doc/disas_examples/x86.cdecl.disas Mon Feb 07 13:15:49 2022 +0100 @@ -1,16 +1,16 @@ ; #include -; +; ; 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); @@ -484,7 +484,154 @@ -; @@@ windows missing +; output from godbolt compiler explorer w/ msvc 19.0 + +_leaf_call PROC + push ebp + mov ebp, esp + pop ebp + ret 0 +_leaf_call ENDP + +_b$ = 12 +_c$ = 16 +_d$ = 20 +_e$ = 24 +_f$ = 28 +_g$ = 32 +_h$ = 36 +_nonleaf_call PROC + push ebp + mov ebp, esp + push 220 + call _alloca + add esp, 4 + mov BYTE PTR [eax], 76 + mov eax, DWORD PTR _h$[ebp] + push eax + mov ecx, DWORD PTR _g$[ebp] + push ecx + mov edx, DWORD PTR _f$[ebp] + push edx + mov eax, DWORD PTR _e$[ebp] + push eax + mov ecx, DWORD PTR _d$[ebp] + push ecx + mov edx, DWORD PTR _c$[ebp] + push edx + mov eax, DWORD PTR _b$[ebp] + push eax + call _leaf_call + add esp, 28 + pop ebp + ret 0 +_nonleaf_call ENDP + +_main PROC + push ebp + mov ebp, esp + push 7 + push 6 + push 5 + push 4 + push 3 + push 2 + push 1 + push 0 + call _nonleaf_call + add esp, 32 + xor eax, eax + pop ebp + ret 0 +_main ENDP + + + +; ---------- structs by value, struct in first call on reg arg boundary ----------> +; +; 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 + +$T1 = 8 +_a$ = 12 +_leaf_call PROC + push ebp ; | prolog + mov ebp, esp ; / + 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) + pop ebp ; | + ret 0 ; | epilog +_leaf_call 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 3 ; arg 3 + push 0 ; | + push 2 ; arg 2 + push 1 ; arg 1 + 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 | + call _leaf_call ; push return address and call + add esp, 56 ; | + xor eax, eax ; : return value + mov esp, ebp ; | + pop ebp ; | epilog + ret 0 ; | +_main ENDP + + ; vim: ft=asm diff -r 79b95db3d68f -r 984e6652b975 doc/disas_examples/x86.fastcall_ms.disas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/disas_examples/x86.fastcall_ms.disas Mon Feb 07 13:15:49 2022 +0100 @@ -0,0 +1,188 @@ +; #include +; +; 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, struct in first call on reg arg boundary ----------> +; +; 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 + + + +; vim: ft=asm +