......
| 局部变量n |
......
| 局部变量1 |
......
| ESI |
......
| EDI |
......
---------------------<--函数的栈的偏移地址 rsp
低地址
下面是centos 64位下的实验:
#t.c
int t(int i,int j,int k){
int sum;
sum = i+j+k;
return sum;
}
int main(int argc,char *argv[]){
int i,j,sum;
i=1;
j=2;
sum = t(i,j,3);
return sum;
}
gcc -g t.c
gdb ./a.out
(gdb) disass main
Dump of assembler code for function main:
0x0000000000400466 <main+0>: push %rbp //函数调用时,首先是保存前一个栈的基址,
0x0000000000400467 <main+1>: mov %rsp,%rbp //接着把之前的栈偏移地址作为新的栈基址,
//这个过程与最后的 leaveq和retq对应。
0x000000000040046a <main+4>: sub $0x20,%rsp //为什么是申请32个字节呢?函数里声明的变量共加起来也就只有4字节*3=12字节,
//加上一些存寄存器的,也到不了32字节啊,这里猜想,编译器为函数调用
//预分配的内存空间应该是某个长度的倍数,我用的centos64位的gcc,
0x000000000040046e <main+8>: mov %edi,-0x14(%rbp) //调用函数的时候,如果参数少的话,会使用寄存器edi,rsi之类的
//寄存器来传参数,所以这里会保存原来寄存器的值。
0x0000000000400471 <main+11>: mov %rsi,-0x20(%rbp)
0x0000000000400475 <main+15>: movl $0x1,-0xc(%rbp)
0x000000000040047c <main+22>: movl $0x2,-0x8(%rbp)
0x0000000000400483 <main+29>: mov -0x8(%rbp),%esi
0x0000000000400486 <main+32>: mov -0xc(%rbp),%edi
0x0000000000400489 <main+35>: mov $0x3,%edx
0x000000000040048e <main+40>: callq 0x400448 <t>
0x0000000000400493 <main+45>: mov %eax,-0x4(%rbp)
0x0000000000400496 <main+48>: mov -0x4(%rbp),%eax //函数调用后的结果是放在EAX中的,这点非常重要!
0x0000000000400499 <main+51>: leaveq //leaveq首先会把现在的栈基址赋值给rsp,也就是恢复原来的栈的
//偏移地址,然后pop rbp,恢复原来的栈基址。
0x000000000040049a <main+52>: retq //返回调用函数前的下一条指令的地址。
End of assembler dump.
(gdb) disassemble t
Dump of assembler code for function t: //下面这段代码与main类似
0x0000000000400448 <t+0>: push %rbp
0x0000000000400449 <t+1>: mov %rsp,%rbp
0x000000000040044c <t+4>: mov %edi,-0x14(%rbp)
0x000000000040044f <t+7>: mov %esi,-0x18(%rbp)
0x0000000000400452 <t+10>: mov %edx,-0x1c(%rbp)
0x0000000000400455 <t+13>: mov -0x18(%rbp),%eax
0x0000000000400458 <t+16>: add -0x14(%rbp),%eax
0x000000000040045b <t+19>: add -0x1c(%rbp),%eax
0x000000000040045e <t+22>: mov %eax,-0x4(%rbp)
0x0000000000400461 <t+25>: mov -0x4(%rbp),%eax
0x0000000000400464 <t+28>: leaveq
0x0000000000400465 <t+29>: retq
End of assembler dump.
下面把上面的代码改改,把函数的参数改为9个:
int t(int i,int j,int k,int l,int n,int m,int o,int p,int q){
int sum;
sum = i+j+k;
return sum;
}
int main(int argc,char *argv[]){
int i,sum,j;
long k;
i=1;
j=2;
sum = t(i,j,3,4,5,6,7,8,9);
return sum;
}
(gdb) disass main
Dump of assembler code for function main:
0x0000000000400471 <main+0>: push %rbp
0x0000000000400472 <main+1>: mov %rsp,%rbp
0x0000000000400475 <main+4>: sub $0x48,%rsp
0x0000000000400479 <main+8>: mov %edi,-0x24(%rbp)
0x000000000040047c <main+11>: mov %rsi,-0x30(%rbp)
0x0000000000400480 <main+15>: movl $0x1,-0x14(%rbp)
0x0000000000400487 <main+22>: movl $0x2,-0xc(%rbp)
0x000000000040048e <main+29>: mov -0xc(%rbp),%esi
0x0000000000400491 <main+32>: mov -0x14(%rbp),%edi
0x0000000000400494 <main+35>: movl $0x9,0x10(%rsp)
0x000000000040049c <main+43>: movl $0x8,0x8(%rsp)
0x00000000004004a4 <main+51>: movl $0x7,(%rsp)
0x00000000004004ab <main+58>: mov $0x6,%r9d //看到这里,我服了,去查了下,
//竟然64位下还多了N个通用寄存器,直接看下一段实验吧...
0x00000000004004b1 <main+64>: mov $0x5,%r8d
0x00000000004004b7 <main+70>: mov $0x4,%ecx
0x00000000004004bc <main+75>: mov $0x3,%edx
0x00000000004004c1 <main+80>: callq 0x400448 <t>
0x00000000004004c6 <main+85>: mov %eax,-0x10(%rbp)
0x00000000004004c9 <main+88>: mov -0x10(%rbp),%eax
0x00000000004004cc <main+91>: leaveq
0x00000000004004cd <main+92>: retq
End of assembler dump.
(gdb) disass t
Dump of assembler code for function t:
0x0000000000400448 <t+0>: push %rbp
0x0000000000400449 <t+1>: mov %rsp,%rbp
0x000000000040044c <t+4>: mov %edi,-0x14(%rbp)
0x000000000040044f <t+7>: mov %esi,-0x18(%rbp)
0x0000000000400452 <t+10>: mov %edx,-0x1c(%rbp)
0x0000000000400455 <t+13>: mov %ecx,-0x20(%rbp)
0x0000000000400458 <t+16>: mov %r8d,-0x24(%rbp)
0x000000000040045c <t+20>: mov %r9d,-0x28(%rbp)
0x0000000000400460 <t+24>: mov -0x18(%rbp),%eax
0x0000000000400463 <t+27>: add -0x14(%rbp),%eax
0x0000000000400466 <t+30>: add -0x1c(%rbp),%eax
0x0000000000400469 <t+33>: mov %eax,-0x4(%rbp)
0x000000000040046c <t+36>: mov -0x4(%rbp),%eax
0x000000000040046f <t+39>: leaveq
0x0000000000400470 <t+40>: retq
End of assembler dump.
实在不服!我把参数搞为20个试试!
int t(int i,int j,int k,int l,int n,int m,int o,int p,int q,int qa,int qb,int qc,
int qd,int qe,int qf,int qg,int qh,int qi,int qj,int qk){
int sum;
sum = i+j+k+l+n+m+o+p+q+qa+qb+qc+qd+qe+qf+qg+qh+qi+qj+qk;
return sum;
}
int main(int argc,char *argv[]){
int i,sum,j;
long k;
i=1;
j=2;
sum = t(i,j,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);
return sum;
}
(gdb) disass main
Dump of assembler code for function main:
0x00000000004004a4 <main+0>: push %rbp
0x00000000004004a5 <main+1>: mov %rsp,%rbp
0x00000000004004a8 <main+4>: sub $0xa0,%rsp
0x00000000004004af <main+11>: mov %edi,-0x24(%rbp)
0x00000000004004b2 <main+14>: mov %rsi,-0x30(%rbp)
0x00000000004004b6 <main+18>: movl $0x1,-0x14(%rbp)
0x00000000004004bd <main+25>: movl $0x2,-0xc(%rbp)
0x00000000004004c4 <main+32>: mov -0xc(%rbp),%esi
0x00000000004004c7 <main+35>: mov -0x14(%rbp),%edi
0x00000000004004ca <main+38>: movl $0x14,0x68(%rsp) //哈哈,系统终于寄存器不够用了,果然是放到内存里去了!
//不过貌似%esi和%edi寄存器就是死活要拿来用啊,想想也对,寄存器快嘛!
0x00000000004004d2 <main+46>: movl $0x13,0x60(%rsp)
0x00000000004004da <main+54>: movl $0x12,0x58(%rsp)
0x00000000004004e2 <main+62>: movl $0x11,0x50(%rsp)
0x00000000004004ea <main+70>: movl $0x10,0x48(%rsp)
0x00000000004004f2 <main+78>: movl $0xf,0x40(%rsp)
0x00000000004004fa <main+86>: movl $0xe,0x38(%rsp)
0x0000000000400502 <main+94>: movl $0xd,0x30(%rsp)
0x000000000040050a <main+102>: movl $0xc,0x28(%rsp)
0x0000000000400512 <main+110>: movl $0xb,0x20(%rsp)
0x000000000040051a <main+118>: movl $0xa,0x18(%rsp)
0x0000000000400522 <main+126>: movl $0x9,0x10(%rsp)
0x000000000040052a <main+134>: movl $0x8,0x8(%rsp)
0x0000000000400532 <main+142>: movl $0x7,(%rsp)
0x0000000000400539 <main+149>: mov $0x6,%r9d
0x000000000040053f <main+155>: mov $0x5,%r8d
0x0000000000400545 <main+161>: mov $0x4,%ecx
0x000000000040054a <main+166>: mov $0x3,%edx
0x000000000040054f <main+171>: callq 0x400448 <t>
0x0000000000400554 <main+176>: mov %eax,-0x10(%rbp)
0x0000000000400557 <main+179>: mov -0x10(%rbp),%eax
0x000000000040055a <main+182>: leaveq
0x000000000040055b <main+183>: retq
End of assembler dump.
(gdb) disass t
Dump of assembler code for function t:
0x0000000000400448 <t+0>: push %rbp
0x0000000000400449 <t+1>: mov %rsp,%rbp
0x000000000040044c <t+4>: mov %edi,-0x14(%rbp)
0x000000000040044f <t+7>: mov %esi,-0x18(%rbp)
0x0000000000400452 <t+10>: mov %edx,-0x1c(%rbp)
0x0000000000400455 <t+13>: mov %ecx,-0x20(%rbp)
0x0000000000400458 <t+16>: mov %r8d,-0x24(%rbp)
0x000000000040045c <t+20>: mov %r9d,-0x28(%rbp)
0x0000000000400460 <t+24>: mov -0x18(%rbp),%eax
0x0000000000400463 <t+27>: add -0x14(%rbp),%eax
0x0000000000400466 <t+30>: add -0x1c(%rbp),%eax
0x0000000000400469 <t+33>: add -0x20(%rbp),%eax
0x000000000040046c <t+36>: add -0x24(%rbp),%eax
0x000000000040046f <t+39>: add -0x28(%rbp),%eax
0x0000000000400472 <t+42>: add 0x10(%rbp),%eax //回头去取数据
0x0000000000400475 <t+45>: add 0x18(%rbp),%eax
0x0000000000400478 <t+48>: add 0x20(%rbp),%eax
0x000000000040047b <t+51>: add 0x28(%rbp),%eax
0x000000000040047e <t+54>: add 0x30(%rbp),%eax
0x0000000000400481 <t+57>: add 0x38(%rbp),%eax
0x0000000000400484 <t+60>: add 0x40(%rbp),%eax
0x0000000000400487 <t+63>: add 0x48(%rbp),%eax
0x000000000040048a <t+66>: add 0x50(%rbp),%eax
0x000000000040048d <t+69>: add 0x58(%rbp),%eax
0x0000000000400490 <t+72>: add 0x60(%rbp),%eax
0x0000000000400493 <t+75>: add 0x68(%rbp),%eax
0x0000000000400496 <t+78>: add 0x70(%rbp),%eax
0x0000000000400499 <t+81>: add 0x78(%rbp),%eax
0x000000000040049c <t+84>: mov %eax,-0x4(%rbp)
0x000000000040049f <t+87>: mov -0x4(%rbp),%eax
0x00000000004004a2 <t+90>: leaveq
0x00000000004004a3 <t+91>: retq
End of assembler dump.