我正在尝试了解堆栈机制。
从我所看到的理论来看,在调用函数之前,它的参数被推到堆栈上。
但是,在下面的代码中调用 printf 时,它们都不会被推送:
#include<stdio.h>
int main(){
char *s = " test string";
printf("Print this: %s and this %s n", s, s);
return 1;
}
我在 gdb 中对 printf 指令进行了中断,并且在显示堆栈时,3 个参数都没有被推到堆栈上。
唯一推送到堆栈的是字符串地址 s,如下面的反汇编代码所示:
0x000000000040052c <+0>: push %rbp
0x000000000040052d <+1>: mov %rsp,%rbp
0x0000000000400530 <+4>: sub $0x10,%rsp
0x0000000000400534 <+8>: movq $0x400604,-0x8(%rbp) // variable pushed on the stack
0x000000000040053c <+16>: mov -0x8(%rbp),%rdx
0x0000000000400540 <+20>: mov -0x8(%rbp),%rax
0x0000000000400544 <+24>: mov %rax,%rsi
0x0000000000400547 <+27>: mov $0x400611,%edi
0x000000000040054c <+32>: mov $0x0,%eax
0x0000000000400551 <+37>: callq 0x400410 <printf@plt>
0x0000000000400556 <+42>: mov $0x1,%eax
0x000000000040055b <+47>: leaveq
实际上,到目前为止,在反汇编代码中出现的唯一参数是当"打印这个:%s和这个%s "被放入%edi...
0x0000000000400547 <+27>: mov $0x400611,%edi
所以我的问题是:为什么我没有看到我的三个参数中的每一个的 3 条推送指令?
uname -a:3.8.0-31-通用 #46-Ubuntu SMP 星期二 九月 10 20:03:44 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
ABI(x86-64 应用程序二进制接口)不会在堆栈上推送参数,而是使用一些寄存器(此调用约定略快)。
如果您传递许多参数 - 例如十几个 - 其中一些会被推到堆栈上。
也许在阅读 x86-64 ABI 规范之前,先阅读有关 x86 调用约定的维基页面。
对于像printf
这样的可变参数函数,细节有点吓人。
根据您的编译器,您需要在堆上为指针's'分配空间。而不是 char *s;
用 char s[300];
分配 300 字节的房间否则,"s"只是指向堆栈 - 这可能是随机的
这可能是您看不到 PUSH 指令的部分原因。
另外,我不明白为什么应该为 printf 中所需的指针提供 PUSH 指令?汇编程序只是复制(MOV)指针的值