Mercurial > pub > dyncall > dyncall
view doc/disas_examples/x86.stdcall.disas @ 619:c754150fe87f
- x64 win disas example fix and addition
author | Tassilo Philipp |
---|---|
date | Mon, 03 Oct 2022 13:49:19 +0200 |
parents | fc614cb865c6 |
children |
line wrap: on
line source
; #include <stdlib.h> ; ; void __stdcall leaf_call(int b, int c, int d, int e, int f, int g, int h) ; { ; } ; ; void __stdcall 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.14 (w/ /GS- for simplicity) _leaf_call@28 PROC push ebp mov ebp, esp pop ebp ret 28 _leaf_call@28 ENDP _b$ = 12 _c$ = 16 _d$ = 20 _e$ = 24 _f$ = 28 _g$ = 32 _h$ = 36 _nonleaf_call@32 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@28 pop ebp ret 32 _nonleaf_call@32 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@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 __stdcall 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.14 (w/ /GS- for simplicity) $T1 = 8 _a$ = 12 _leaf_call@52 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 56 ; | epilog (56 = stack cleanup of stdcall) _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 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@52 ; push return address and call ; (note: cdecl would clean up stack, here) 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; ; __attribute__((stdcall)) NonTrivial() : a(0) {} ; __attribute__((stdcall)) NonTrivial(const NonTrivial& rhs) : a(rhs.a) { } ; }; ; ; extern "C" { ; ; void __attribute__((stdcall)) f1(struct Trivial s) { } ; void __attribute__((stdcall)) f2(struct NonTrivial s) { } ; ; void __attribute__((stdcall)) f() ; { ; struct Trivial t; ; struct NonTrivial n; ; int a=1; ; a += 123; ; f1(t); ; a -= 123; ; f2(n); ; a -= 12; ; } ; } ; output from alpine_linux-3.11.3-x86 w/ gcc 9.2.0 00001215 <f1>: 1215: 55 push %ebp 1216: 89 e5 mov %esp,%ebp 1218: e8 f0 ff ff ff call 120d <__x86.get_pc_thunk.ax> 121d: 05 af 2d 00 00 add $0x2daf,%eax 1222: 90 nop 1223: 5d pop %ebp 1224: c2 04 00 ret $0x4 00001227 <f2>: 1227: 55 push %ebp 1228: 89 e5 mov %esp,%ebp 122a: e8 de ff ff ff call 120d <__x86.get_pc_thunk.ax> 122f: 05 9d 2d 00 00 add $0x2d9d,%eax 1234: 90 nop 1235: 5d pop %ebp 1236: c2 04 00 ret $0x4 00001239 <f>: 1239: 55 push %ebp ; 123a: 89 e5 mov %esp,%ebp ; 123c: 83 ec 28 sub $0x28,%esp ; 123f: e8 c9 ff ff ff call 120d <__x86.get_pc_thunk.ax> ; 1244: 05 88 2d 00 00 add $0x2d88,%eax ; 1249: 65 a1 14 00 00 00 mov %gs:0x14,%eax ; 124f: 89 45 f4 mov %eax,-0xc(%ebp) ; 1252: 31 c0 xor %eax,%eax ; 1254: 83 ec 0c sub $0xc,%esp ; 1257: 8d 45 e8 lea -0x18(%ebp),%eax ; 125a: 50 push %eax ; 125b: e8 6e 00 00 00 call 12ce <_ZN10NonTrivialC1Ev> ; NonTrivial::NonTrivial() / ctor 1260: 83 c4 0c add $0xc,%esp ; 1263: c7 45 f0 01 00 00 00 movl $0x1,-0x10(%ebp) ; 126a: 83 45 f0 7b addl $0x7b,-0x10(%ebp) ; 126e: 83 ec 0c sub $0xc,%esp ; 1271: ff 75 e4 pushl -0x1c(%ebp) ; 1274: e8 9c ff ff ff call 1215 <f1> ; call f1(struct Trivial) 1279: 83 c4 0c add $0xc,%esp ; 127c: 83 6d f0 7b subl $0x7b,-0x10(%ebp) ; 1280: 83 ec 08 sub $0x8,%esp ; 1283: 8d 45 e8 lea -0x18(%ebp),%eax ; | | ptr to n 1286: 50 push %eax ; | / 1287: 8d 45 ec lea -0x14(%ebp),%eax ; | \ 128a: 50 push %eax ; | copy n | ptr to dest of copy of n 128b: e8 5a 00 00 00 call 12ea <_ZN10NonTrivialC1ERKS_> ; | NonTrivial::NonTrivial(const NonTrivial&) / copy ctor 1290: 83 c4 08 add $0x8,%esp ; 1293: 83 ec 0c sub $0xc,%esp ; 1296: 8d 45 ec lea -0x14(%ebp),%eax ; | 1299: 50 push %eax ; | f2 arg 0 (ptr to copy of struct NonTrivial), via ptr as non-trivial 129a: e8 88 ff ff ff call 1227 <f2> ; call f2(struct NonTrivial) 129f: 83 c4 0c add $0xc,%esp ; 12a2: 83 6d f0 0c subl $0xc,-0x10(%ebp) ; 12a6: 90 nop ; 12a7: 8b 45 f4 mov -0xc(%ebp),%eax ; 12aa: 65 33 05 14 00 00 00 xor %gs:0x14,%eax ; 12b1: 74 05 je 12b8 <f+0x7f> ; 12b3: e8 4e 00 00 00 call 1306 <__stack_chk_fail_local> ; 12b8: c9 leave ; 12b9: c3 ret ; ; ... snip, removed code of ctor and copy ctor ... ; ---------- C++ trivial and non-trivial aggrs as return values ----------> ; ; struct Trivial { int a; }; ; struct NonTrivial { ; int a; ; __attribute__((stdcall)) NonTrivial() : a(0) {} ; __attribute__((stdcall)) NonTrivial(const NonTrivial& rhs) : a(rhs.a) { } ; }; ; ; extern "C" { ; struct Trivial __attribute__((stdcall)) f1() { return Trivial(); } ; } ; ; struct NonTrivial __attribute__((stdcall)) f2() { return NonTrivial(); } ; ; extern "C" { ; void __attribute__((stdcall)) f() ; { ; int a=1; ; a += 123; ; struct Trivial t = f1(); ; a -= 123; ; struct NonTrivial n = f2(); ; a -= 12; ; } ; } ; output from alpine_linux-3.11.3-x86 w/ gcc 9.2.0 (w/ -O0 --no-stack-protector for simplicity) 00001205 <f1>: 1205: 55 push %ebp ; | prolog 1206: 89 e5 mov %esp,%ebp ; | 1208: e8 f0 ff ff ff call 11fd <__x86.get_pc_thunk.ax> ; 120d: 05 c3 2d 00 00 add $0x2dc3,%eax ; 1212: 8b 45 08 mov 0x8(%ebp),%eax ; fetch ptr to retval space -> eax 1215: c7 00 00 00 00 00 movl $0x0,(%eax) ; write retval 121b: 8b 45 08 mov 0x8(%ebp),%eax ; re-fetch ptr to retval space -> eax, to return it in eax (a bit pointless) 121e: 5d pop %ebp ; | 121f: c2 04 00 ret $0x4 ; | epilog 00001222 <_Z2f2v>: 1222: 55 push %ebp 1223: 89 e5 mov %esp,%ebp 1225: 83 ec 08 sub $0x8,%esp 1228: e8 d0 ff ff ff call 11fd <__x86.get_pc_thunk.ax> 122d: 05 a3 2d 00 00 add $0x2da3,%eax 1232: 83 ec 0c sub $0xc,%esp 1235: ff 75 08 pushl 0x8(%ebp) 1238: e8 65 00 00 00 call 12a2 <_ZN10NonTrivialC1Ev> 123d: 83 c4 0c add $0xc,%esp 1240: 8b 45 08 mov 0x8(%ebp),%eax 1243: c9 leave 1244: c2 04 00 ret $0x4 00001247 <f>: 1247: 55 push %ebp ; 1248: 89 e5 mov %esp,%ebp ; 124a: 83 ec 18 sub $0x18,%esp ; 124d: e8 ab ff ff ff call 11fd <__x86.get_pc_thunk.ax> ; 1252: 05 7e 2d 00 00 add $0x2d7e,%eax ; 1257: c7 45 f4 01 00 00 00 movl $0x1,-0xc(%ebp) ; a = 1 125e: 83 45 f4 7b addl $0x7b,-0xc(%ebp) ; a += 123 1262: 8d 45 f0 lea -0x10(%ebp),%eax ; ptr to space (top of stack) to hold aggr retval -> eax ... 1265: 50 push %eax ; ... as hidden first arg 1266: e8 9a ff ff ff call 1205 <f1> ; call f1() 126b: 83 6d f4 7b subl $0x7b,-0xc(%ebp) ; a -= 123 126f: 8d 45 ec lea -0x14(%ebp),%eax ; ptr to space to hold aggr retval -> eax ... 1272: 83 ec 0c sub $0xc,%esp ; grow stack by 12 1275: 50 push %eax ; ... as hidden first arg 1276: e8 a7 ff ff ff call 1222 <_Z2f2v> ; call f2() 127b: 83 c4 0c add $0xc,%esp ; shrink stack back by 12 127e: 83 6d f4 0c subl $0xc,-0xc(%ebp) ; a -= 12 1282: 90 nop ; 1283: c9 leave ; 1284: c3 ret ; ; vim: ft=asm