# HG changeset patch # User Tassilo Philipp # Date 1644270092 -3600 # Node ID 79e76734bb5c8ccd2aeb33d002d8467528589022 # Parent 984e6652b975021247cbe8d674a3957c773b7c35 " diff -r 984e6652b975 -r 79e76734bb5c doc/disas_examples/x86.fastcall_gnu.disas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/disas_examples/x86.fastcall_gnu.disas Mon Feb 07 22:41:32 2022 +0100 @@ -0,0 +1,283 @@ +; #include +; +; void __attribute__((fastcall)) leaf_call(int b, int c, int d, int e, int f, int g, int h) +; { +; } +; +; void __attribute__((fastcall)) 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 alpine_linux-3.11.3-x86 w/ gcc 9.2.0 (w/ flags to simplify: -fno-stack-protector -fno-pic) + +00001205 : + 1205: 55 push %ebp ; | + 1206: 89 e5 mov %esp,%ebp ; | prolog + 1208: 83 ec 08 sub $0x8,%esp ; | + 120b: 89 4d fc mov %ecx,-0x4(%ebp) ; + 120e: 89 55 f8 mov %edx,-0x8(%ebp) ; + 1211: 90 nop ; + 1212: c9 leave ; | + 1213: c2 14 00 ret $0x14 ; | epilog + +00001216 : + 1216: 55 push %ebp ; | + 1217: 89 e5 mov %esp,%ebp ; | prolog + 1219: 83 ec 18 sub $0x18,%esp ; / + 121c: 89 4d f4 mov %ecx,-0xc(%ebp) ; in arg 0 -> local area on stack + 121f: 89 55 f0 mov %edx,-0x10(%ebp) ; in arg 1 -> local area on stack + 1222: b8 10 00 00 00 mov $0x10,%eax ; | + 1227: 83 e8 01 sub $0x1,%eax ; | + 122a: 05 e8 00 00 00 add $0xe8,%eax ; | + 122f: b9 10 00 00 00 mov $0x10,%ecx ; | alloca (seems like 220 is rounded up for stack alignment purposes) + 1234: ba 00 00 00 00 mov $0x0,%edx ; | + 1239: f7 f1 div %ecx ; | + 123b: 6b c0 10 imul $0x10,%eax,%eax ; | + 123e: 29 c4 sub %eax,%esp ; / + 1240: 89 e0 mov %esp,%eax ; \ + 1242: 83 c0 0f add $0xf,%eax ; | + 1245: c1 e8 04 shr $0x4,%eax ; | align alloca'd space + 1248: c1 e0 04 shl $0x4,%eax ; | + 124b: c6 00 4c movb $0x4c,(%eax) ; write 'L' to alloca'd space + 124e: 8b 45 f0 mov -0x10(%ebp),%eax ; in arg 1 (from local area) -> eax (then copied to ecx/arg0, below, could be done directly) + 1251: 83 ec 0c sub $0xc,%esp ; @@@ unsure why, alignment? + 1254: ff 75 1c pushl 0x1c(%ebp) ; | + 1257: ff 75 18 pushl 0x18(%ebp) ; | + 125a: ff 75 14 pushl 0x14(%ebp) ; | read in args 3-7 from prev frame's param area, and ... + 125d: ff 75 10 pushl 0x10(%ebp) ; | ... push onto stack as arg 2-6 + 1260: ff 75 0c pushl 0xc(%ebp) ; | + 1263: 8b 55 08 mov 0x8(%ebp),%edx ; arg 1 (via reg, read in arg 2 from prev frame's param area) + 1266: 89 c1 mov %eax,%ecx ; arg 0 (via reg) + 1268: e8 98 ff ff ff call 1205 ; push return address and call + 126d: 83 c4 0c add $0xc,%esp ; @@@ restore esp to what it was before pushing args + 1270: 90 nop ; + 1271: c9 leave ; | + 1272: c2 18 00 ret $0x18 ; | epilog + +00001275
: + 1275: 8d 4c 24 04 lea 0x4(%esp),%ecx ; | + 1279: 83 e4 f0 and $0xfffffff0,%esp ; | @@@? alignment? + 127c: ff 71 fc pushl -0x4(%ecx) ; | prolog + 127f: 55 push %ebp ; | + 1280: 89 e5 mov %esp,%ebp ; | + 1282: 51 push %ecx ; preserve ecx (so it can be used for passing arg 0) + 1283: 83 ec 04 sub $0x4,%esp ; @@@ unsure why, alignment? + 1286: 83 ec 08 sub $0x8,%esp ; @@@ unsure why, alignment? pointless + 1289: 6a 07 push $0x7 ; arg 7 + 128b: 6a 06 push $0x6 ; arg 6 + 128d: 6a 05 push $0x5 ; arg 5 + 128f: 6a 04 push $0x4 ; arg 4 + 1291: 6a 03 push $0x3 ; arg 3 + 1293: 6a 02 push $0x2 ; arg 2 + 1295: ba 01 00 00 00 mov $0x1,%edx ; arg 1 (via reg) + 129a: b9 00 00 00 00 mov $0x0,%ecx ; arg 0 (via reg) + 129f: e8 72 ff ff ff call 1216 ; push return address and call + 12a4: 83 c4 08 add $0x8,%esp ; @@@ restore one of the two "sub...esp"s above + 12a7: b8 00 00 00 00 mov $0x0,%eax ; return value + 12ac: 8b 4d fc mov -0x4(%ebp),%ecx ; restore ecx + 12af: c9 leave ; | + 12b0: 8d 61 fc lea -0x4(%ecx),%esp ; | epilog + 12b3: c3 ret ; | + + + +; ---------- vararg call (shows that all args are pushed) ----------> + +; void __attribute__((fastcall)) leaf_call(int a, short b, char c, ...) +; { +; } +; +; int main() +; { +; leaf_call(0, 1, 2, 3, 4, 5, 6, 7LL); +; return 0; +; } + + + +; output from alpine_linux-3.11.3-x86 w/ gcc 9.2.0 (w/ flags to simplify: -fno-stack-protector -fno-pic) + +00001205 : + 1205: 55 push %ebp + 1206: 89 e5 mov %esp,%ebp + 1208: 90 nop + 1209: 5d pop %ebp + 120a: c3 ret + +0000120b
: + 120b: 55 push %ebp + 120c: 89 e5 mov %esp,%ebp + 120e: 6a 00 push $0x0 + 1210: 6a 07 push $0x7 + 1212: 6a 06 push $0x6 + 1214: 6a 05 push $0x5 + 1216: 6a 04 push $0x4 + 1218: 6a 03 push $0x3 + 121a: 6a 02 push $0x2 + 121c: 6a 01 push $0x1 + 121e: 6a 00 push $0x0 + 1220: e8 e0 ff ff ff call 1205 + 1225: 83 c4 24 add $0x24,%esp + 1228: b8 00 00 00 00 mov $0x0,%eax + 122d: c9 leave + 122e: c3 ret + + + +; ---------- 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 __attribute__((fastcall)) 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 alpine_linux-3.11.3-x86 w/ gcc 9.2.0 (w/ flags to simplify: -fno-stack-protector -fno-pic) + +00001205 : + 1205: 55 push %ebp ; | + 1206: 89 e5 mov %esp,%ebp ; | prolog + 1208: 83 ec 20 sub $0x20,%esp ; | + 120b: 89 4d fc mov %ecx,-0x4(%ebp) ; ptr to retval space for struct (hidden first arg) -> local area + 120e: 8b 45 18 mov 0x18(%ebp),%eax ; + 1211: 8b 55 24 mov 0x24(%ebp),%edx ; + 1214: 66 89 45 f8 mov %ax,-0x8(%ebp) ; + 1218: 8b 45 1c mov 0x1c(%ebp),%eax ; + 121b: 89 45 f0 mov %eax,-0x10(%ebp) ; + 121e: 8b 45 20 mov 0x20(%ebp),%eax ; + 1221: 89 45 f4 mov %eax,-0xc(%ebp) ; + 1224: 89 d0 mov %edx,%eax ; + 1226: 88 45 ec mov %al,-0x14(%ebp) ; + 1229: 8b 45 34 mov 0x34(%ebp),%eax ; + 122c: 89 45 e0 mov %eax,-0x20(%ebp) ; + 122f: 8b 45 38 mov 0x38(%ebp),%eax ; + 1232: 89 45 e4 mov %eax,-0x1c(%ebp) ; + 1235: 8b 45 08 mov 0x8(%ebp),%eax ; | + 1238: 83 c0 01 add $0x1,%eax ; | a.x += 1 (written to param area of prev frame) + 123b: 89 45 08 mov %eax,0x8(%ebp) ; / + 123e: 8b 45 fc mov -0x4(%ebp),%eax ; \ ptr to retval space + 1241: 8b 55 08 mov 0x8(%ebp),%edx ; | + 1244: 89 10 mov %edx,(%eax) ; | + 1246: 8b 55 0c mov 0xc(%ebp),%edx ; | + 1249: 89 50 04 mov %edx,0x4(%eax) ; | copy struct from param area in prev frame to retval space + 124c: 8b 55 10 mov 0x10(%ebp),%edx ; | + 124f: 89 50 08 mov %edx,0x8(%eax) ; | + 1252: 8b 55 14 mov 0x14(%ebp),%edx ; | + 1255: 89 50 0c mov %edx,0xc(%eax) ; | + 1258: 8b 45 fc mov -0x4(%ebp),%eax ; return value (passed-in hidden ptr) + 125b: c9 leave ; | + 125c: c2 34 00 ret $0x34 ; | epilog + +0000125f
: + 125f: 8d 4c 24 04 lea 0x4(%esp),%ecx ; | + 1263: 83 e4 f0 and $0xfffffff0,%esp ; | + 1266: ff 71 fc pushl -0x4(%ecx) ; | prolog + 1269: 55 push %ebp ; | + 126a: 89 e5 mov %esp,%ebp ; | + 126c: 51 push %ecx ; preserve ecx (so it can be used for passing arg 0) + 126d: 83 ec 24 sub $0x24,%esp ; reserve stack space for struct (local area) + 1270: c7 45 e8 09 00 00 00 movl $0x9,-0x18(%ebp) ; | int x + 1277: 66 c7 45 ec 63 00 movw $0x63,-0x14(%ebp) ; | short y + 127d: c6 45 ee 17 movb $0x17,-0x12(%ebp) ; | struct values (local area) char z + 1281: c7 45 f0 0c 00 00 00 movl $0xc,-0x10(%ebp) ; | | + 1288: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%ebp) ; | | long long t + 128f: 8d 45 d8 lea -0x28(%ebp),%eax ; ptr to space used for struct retval (passed as hidden first arg) -> eax + 1292: 83 ec 04 sub $0x4,%esp ; @@@ unsure why, alignment? (also needed so what's in eax doesn't point below esp) + 1295: 6a 00 push $0x0 ; | + 1297: 6a 07 push $0x7 ; | arg 7 + 1299: 6a 06 push $0x6 ; arg 6 + 129b: 6a 05 push $0x5 ; arg 5 + 129d: 6a 04 push $0x4 ; arg 4 + 129f: 6a 03 push $0x3 ; arg 3 + 12a1: 6a 00 push $0x0 ; | + 12a3: 6a 02 push $0x2 ; | arg 2 (via stack b/c not first arg and > 32 bits) + 12a5: 6a 01 push $0x1 ; arg 1 + 12a7: ff 75 f4 pushl -0xc(%ebp) ; | + 12aa: ff 75 f0 pushl -0x10(%ebp) ; | arg 0 (struct by value, pushed onto stack) + 12ad: ff 75 ec pushl -0x14(%ebp) ; | + 12b0: ff 75 e8 pushl -0x18(%ebp) ; | + 12b3: 89 c1 mov %eax,%ecx ; ptr to free space for call's retval (struct), hidden first arg + 12b5: e8 4b ff ff ff call 1205 ; push return address and call + 12ba: 83 c4 04 add $0x4,%esp ; @@@ restore esp to what it was before pushing args + 12bd: b8 00 00 00 00 mov $0x0,%eax ; return value + 12c2: 8b 4d fc mov -0x4(%ebp),%ecx ; restore ecx + 12c5: c9 leave ; | + 12c6: 8d 61 fc lea -0x4(%ecx),%esp ; | epilog + 12c9: c3 ret ; | + + + +; ---------- small struct returned by value (shows it's never returned via regs) ----------> + +; struct A { short x; short y; }; +; +; struct A __attribute__((fastcall)) leaf_call(int a, int b) +; { +; struct A r = { 13, 15 }; +; return r; +; } +; +; int main() +; { +; leaf_call(99, 2); +; return 0; +; } + + + +; output from alpine_linux-3.11.3-x86 w/ gcc 9.2.0 (w/ flags to simplify: -fno-stack-protector -fno-pic) + +00001205 : + 1205: 55 push %ebp ; | + 1206: 89 e5 mov %esp,%ebp ; | prolog + 1208: 83 ec 18 sub $0x18,%esp ; | + 120b: 89 4d ec mov %ecx,-0x14(%ebp) ; ptr to retval space for struct (hidden first arg) -> local area + 120e: 89 55 e8 mov %edx,-0x18(%ebp) ; in arg 0 -> local area + 1211: 66 c7 45 fc 0d 00 movw $0xd,-0x4(%ebp) ; | + 1217: 66 c7 45 fe 0f 00 movw $0xf,-0x2(%ebp) ; | struct values (local area) + 121d: 8b 45 ec mov -0x14(%ebp),%eax ; ptr to retval space for struct (fetched from local area) -> eax + 1220: 8b 55 fc mov -0x4(%ebp),%edx ; | + 1223: 89 10 mov %edx,(%eax) ; | copy struct in local area to retval space + 1225: 8b 45 ec mov -0x14(%ebp),%eax ; return value (passed-in hidden ptr) + 1228: c9 leave ; | + 1229: c2 04 00 ret $0x4 ; | epilog + +0000122c
: + 122c: 55 push %ebp ; | + 122d: 89 e5 mov %esp,%ebp ; | prolog + 122f: 83 ec 04 sub $0x4,%esp ; | + 1232: 8d 45 fc lea -0x4(%ebp),%eax ; ptr to space used for struct retval (passed as hidden first arg) + 1235: 6a 02 push $0x2 ; arg 1 + 1237: ba 63 00 00 00 mov $0x63,%edx ; arg 0 (via reg) + 123c: 89 c1 mov %eax,%ecx ; ptr to free space for call's retval (struct), hidden first arg + 123e: e8 c2 ff ff ff call 1205 ; push return address and call + 1243: b8 00 00 00 00 mov $0x0,%eax ; return value + 1248: c9 leave ; | + 1249: c3 ret ; | epilog + + + +; vim: ft=asm + diff -r 984e6652b975 -r 79e76734bb5c doc/disas_examples/x86.fastcall_ms.disas --- a/doc/disas_examples/x86.fastcall_ms.disas Mon Feb 07 13:15:49 2022 +0100 +++ b/doc/disas_examples/x86.fastcall_ms.disas Mon Feb 07 22:41:32 2022 +0100 @@ -88,7 +88,7 @@ -; ---------- structs by value, struct in first call on reg arg boundary ----------> +; ---------- structs by value (arg and return value), struct arg not fitting in regs ----------> ; ; struct A { int x; short y; char z; long long t; }; ; @@ -154,7 +154,7 @@ 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 0 ; \ push 7 ; | arg 7 push 6 ; arg 6 push 5 ; arg 5