Gcc 关于序言/调用函数的一些问题英特尔x86

Gcc 关于序言/调用函数的一些问题英特尔x86,gcc,assembly,x86,Gcc,Assembly,X86,我不太明白gcc的开场白,尤其是对于main。 为什么会有指令和esp,0xfffffff0?我知道它的作用,但为什么它是必要的 当我们调用函数时,首先必须推送参数,但是为什么gcc不使用推送指令而使用MOV呢?此外,使用这些MOV,它会创建一个空的填充。这看起来像是在浪费记忆,为什么 最后,gcc首先使用esp的sub指令为堆栈“保留”内存,但如何确保其他程序不使用该内存呢 我想我很理解这个理论,但是我找不到一个文档能在实践中解释更多关于内存的内容(几个程序的内存如何不重叠,…)。谢谢你的回答

我不太明白gcc的开场白,尤其是对于main。 为什么会有指令
和esp,0xfffffff0
?我知道它的作用,但为什么它是必要的

当我们调用函数时,首先必须推送参数,但是为什么gcc不使用推送指令而使用MOV呢?此外,使用这些MOV,它会创建一个空的填充。这看起来像是在浪费记忆,为什么

最后,gcc首先使用esp的sub指令为堆栈“保留”内存,但如何确保其他程序不使用该内存呢

我想我很理解这个理论,但是我找不到一个文档能在实践中解释更多关于内存的内容(几个程序的内存如何不重叠,…)。谢谢你的回答

PS:我添加了汇编代码和cpp代码:

    Dump of assembler code for function main(int, char**):
0x08048657 <+0>:     push   ebp
   0x08048658 <+1>:     mov    ebp,esp
   0x0804865a <+3>:     and    esp,0xfffffff0
   0x0804865d <+6>:     sub    esp,0x20
   0x08048660 <+9>:     mov    DWORD PTR [esp+0x1c],0x3
   0x08048668 <+17>:    mov    BYTE PTR [esp+0x1b],0x61
=> 0x0804866d <+22>:    mov    DWORD PTR [esp],0x8048771
   0x08048674 <+29>:    call   0x804863c <p(char*)>
   0x08048679 <+34>:    mov    eax,0x0
   0x0804867e <+39>:    leave  
   0x0804867f <+40>:    ret    
End of assembler dump.


 int main(int argc, char *argv[]) {
  int b = 3;
  char c = 'a';
  p("hello woooooooooorld !!");}
函数main的汇编程序代码转储(int,char**): 0x08048657:推动ebp 0x08048658:mov ebp,esp 0x0804865a:和esp,0xFFFFF0 0x0804865d:子esp,0x20 0x08048660:mov DWORD PTR[esp+0x1c],0x3 0x08048668:mov字节PTR[esp+0x1b],0x61 =>0x0804866d:mov DWORD PTR[esp],0x8048771 0x08048674:调用0x804863c 0x08048679:mov eax,0x0 0x0804867e:离开 0x0804867f:ret 汇编程序转储结束。 int main(int argc,char*argv[]){ int b=3; 字符c='a'; p(“你好,Wooorld!!”);}
堆栈对齐仅针对
main
完成,其余函数仅保持ABI所需的对齐

编译器对局部变量使用
mov
指令,因此可以随机访问它们。对于传出函数参数,您可以使用
-mpush args
编译器选项请求
push
指令,该选项可能会生成较小的代码

至于浪费的内存,您可能没有在启用优化的情况下编译(这当然会完全消除
b
c
,因为它们没有被使用;)


每个进程都有自己的虚拟内存地址空间,因此其他任何人都不可能使用从堆栈分配的内存。

“浪费内存”:我想他说的是每个arg在堆栈上占用4B的事实,即使是较窄的类型@x4rkz:这是ABI所要求的。原因包括:保持堆栈对齐,以及将参数发送到同一位置,而不管其类型如何。不过,您的示例并没有说明这一点。或者他说的是局部变量存储位置和函数arg的位置之间的差距。这是为了保持堆栈对齐。谢谢,我理解了其中的大部分内容,我理解了为什么需要对齐,这要感谢这个链接,很显然,它与硬件相关。我只是不明白你说的购买“它们可以随机访问”是什么意思@Peter谢谢你的评论,当我理解堆栈对齐的目的时,我就明白了。我需要一个实际的原因,我有一个。@x4rkz:“随机访问”:您最初可以
局部变量推到堆栈上。一旦它们到了那里,您就可以通过它们从
esp
的偏移量来访问它们,而不是使用
pop
。推送它们将是一种特殊情况下的微观优化,这在
-O0
中是无法实现的。此外,
push
将使下一个
mov eax、[esp+1c]
变慢,因为堆栈引擎必须插入额外的uop以与堆栈引擎的内部偏移同步
esp
。(). 由于
main
已经在
esp
中使用了
and
指令,该价格已经支付,因此
push
的成本很低。
gcc-O0
甚至没有使用
xor eax,eax
作为调零习惯用法:/