#include <stdio.h>
int f(int a, int b, int c)
{
return a * b + c;
}
int main()
{
printf("%d\n", f(1, 2, 3)); // 5
return 0;
}
#if 0
调用方(caller)函数通过栈向被调用方(callee)函数传递参数。
/*
* x86
*/
/*
* x64
*/
能够使用寄存器传递(前4个或前6个)参数。
LEA 的效率比 ADD 的效率高,向寄存器赋值的速度也比MOV快。
比较意外的是,原本位于寄存器的3个参数都被推送到了栈里。这种现象叫作"阴影空间/shadow space"。
每个win64程序都可以(但非必须)把4个寄存器的值保存到阴影空间里。使用阴影空间有两个优点:
1.通过栈传递参数,可避免浪费寄存器资源(有时可能会占用4个寄存器)。
2.便于调试器在程序中断时找到函数参数。
大型函数可能会把输入参数保存在阴影空间里,但是小型函数可能就不会使用阴影空间了。
在使用阴影空间时,由调用方函数分配栈空间,由被调用方函数根据需要将寄存器参数转储到它们阴影空间中。
/*
* gcc
*/
阴影空间只是微软的概念,system V*nix里没有这种规范或约定。
GCC只在在寄存器数量容纳不下所有参数的情况下,才会使用栈传递参数。
#endif
#if 0
/*
* intel
*/
0000000000001149 <f>:
1149: f3 0f 1e fa endbr64
114d: 55 push %rbp
114e: 48 89 e5 mov %rsp,%rbp
1151: 89 7d fc mov %edi,-0x4(%rbp) // 1
1154: 89 75 f8 mov %esi,-0x8(%rbp) // 2
1157: 89 55 f4 mov %edx,-0xc(%rbp) // 3
115a: 8b 45 fc mov -0x4(%rbp),%eax // eax=a
115d: 0f af 45 f8 imul -0x8(%rbp),%eax // eax=a*b
1161: 89 c2 mov %eax,%edx // edx=eax
1163: 8b 45 f4 mov -0xc(%rbp),%eax // eax=c
1166: 01 d0 add %edx,%eax // eax=a*b+c
1168: 5d pop %rbp
1169: c3 retq
000000000000116a <main>:
116a: f3 0f 1e fa endbr64
116e: 55 push %rbp
116f: 48 89 e5 mov %rsp,%rbp
1172: ba 03 00 00 00 mov $0x3,%edx // edx=3
1177: be 02 00 00 00 mov $0x2,%esi // esi=2
117c: bf 01 00 00 00 mov $0x1,%edi // edi=1
1181: e8 c3 ff ff ff callq 1149 <f>
1186: 89 c6 mov %eax,%esi
1188: 48 8d 3d 75 0e 00 00 lea 0xe75(%rip),%rdi # 2004 <_IO_stdin_used+0x4>
118f: b8 00 00 00 00 mov $0x0,%eax
1194: e8 b7 fe ff ff callq 1050 <printf@plt>
1199: b8 00 00 00 00 mov $0x0,%eax
119e: 5d pop %rbp
119f: c3 retq
/*
* arm
*/
000000000040055c <f>:
40055c: d10043ff sub sp, sp, #0x10
400560: b9000fe0 str w0, [sp, #12] // 1
400564: b9000be1 str w1, [sp, #8] // 2
400568: b90007e2 str w2, [sp, #4] // 3
40056c: b9400fe1 ldr w1, [sp, #12] // w1=1
400570: b9400be0 ldr w0, [sp, #8] // w0=2
400574: 1b007c21 mul w1, w1, w0 // w1=1*2
400578: b94007e0 ldr w0, [sp, #4] // w0=3
40057c: 0b000020 add w0, w1, w0 // w0=1*2+3
400580: 910043ff add sp, sp, #0x10
400584: d65f03c0 ret
0000000000400588 <main>:
400588: a9bf7bfd stp x29, x30, [sp, #-16]!
40058c: 910003fd mov x29, sp
400590: 52800062 mov w2, #0x3 // #3
400594: 52800041 mov w1, #0x2 // #2
400598: 52800020 mov w0, #0x1 // #1
40059c: 97fffff0 bl 40055c <f>
4005a0: 2a0003e1 mov w1, w0
4005a4: 90000000 adrp x0, 400000 <_init-0x3e8>
4005a8: 9119c000 add x0, x0, #0x670
4005ac: 97ffffa9 bl 400450 <printf@plt>
4005b0: 52800000 mov w0, #0x0 // #0
4005b4: a8c17bfd ldp x29, x30, [sp], #16
4005b8: d65f03c0 ret
4005bc: 00000000 .inst 0x00000000 ; undefined
#endif