C++源代码:
#include<stdio.h> void __stdcall Show1(int m); void __cdecl Show2(int n); int main() { Show1(1); Show2(2); return 0; } void __stdcall Show1(int m) { printf("%d\n",m); } void _cdecl Show2(int n) { printf("%d\n",n); }生成的汇编代码:
Dump of assembler code for function main: 0x004012f0 <main+0>: push %ebp 0x004012f1 <main+1>: mov %esp,%ebp 0x004012f3 <main+3>: sub $0x8,%esp 0x004012f6 <main+6>: and $0xfffffff0,%esp 0x004012f9 <main+9>: mov $0x0,%eax 0x004012fe <main+14>: add $0xf,%eax 0x00401301 <main+17>: add $0xf,%eax 0x00401304 <main+20>: shr $0x4,%eax 0x00401307 <main+23>: shl $0x4,%eax 0x0040130a <main+26>: mov %eax,-0x4(%ebp) 0x0040130d <main+29>: mov -0x4(%ebp),%eax 0x00401310 <main+32>: call 0x401888 <_alloca> 0x00401315 <main+37>: call 0x401408 <__main> 0x0040131a <main+42>: movl $0x1,(%esp) 0x00401321 <main+49>: call 0x40133c <_Z5Show1i> 0x00401326 <main+54>: sub $0x4,%esp 0x00401329 <main+57>: movl $0x2,(%esp) 0x00401330 <main+64>: call 0x40135a <_Z5Show2i> 0x00401335 <main+69>: mov $0x0,%eax 0x0040133a <main+74>: leave 0x0040133b <main+75>: ret End of assembler dump. (gdb)
Dump of assembler code for function _Z5Show1i: 0x0040133c <_Z5Show1i+0>: push %ebp 0x0040133d <_Z5Show1i+1>: mov %esp,%ebp 0x0040133f <_Z5Show1i+3>: sub $0x8,%esp 0x00401342 <_Z5Show1i+6>: mov 0x8(%ebp),%eax 0x00401345 <_Z5Show1i+9>: mov %eax,0x4(%esp) 0x00401349 <_Z5Show1i+13>: movl $0x403000,(%esp) 0x00401350 <_Z5Show1i+20>: call 0x4018e8 <printf> 0x00401355 <_Z5Show1i+25>: leave 0x00401356 <_Z5Show1i+26>: ret $0x4 End of assembler dump. (gdb)
Dump of assembler code for function _Z5Show2i: 0x0040135a <_Z5Show2i+0>: push %ebp 0x0040135b <_Z5Show2i+1>: mov %esp,%ebp 0x0040135d <_Z5Show2i+3>: sub $0x8,%esp 0x00401360 <_Z5Show2i+6>: mov 0x8(%ebp),%eax 0x00401363 <_Z5Show2i+9>: mov %eax,0x4(%esp) 0x00401367 <_Z5Show2i+13>: movl $0x403000,(%esp) 0x0040136e <_Z5Show2i+20>: call 0x4018e8 <printf> 0x00401373 <_Z5Show2i+25>: leave 0x00401374 <_Z5Show2i+26>: ret End of assembler dump. (gdb)main函数和被它调用的函数一样,进入函数后第一件事都是保存栈底指针ebp,调整当前栈底指针位置到栈顶,抬高栈顶esp,此时开辟栈空间作为局部变量的存储空间。
push %ebp mov %esp,%ebp sub $0x8,%esp_cdecl(show2)是C++的默认调用方式,调用方平衡栈,不定参数的函数可以使用;
__stdcall(show1)则是由被调用方平衡栈,不定参数的函数无法使用。
在调用方"自作主张"平衡栈后,main函数中又减了回来,保证最终的结果平衡。