是否所有函数都有一个 "function prologue" 来减少局部变量的堆栈指针?

do all functions have a "function prologue" that decrements the stack pointer for locals?

我有几个关于组装的基本问题。

在汇编中编写函数时,是否所有函数都有一个"function prologue"?我在网上看到一些功能,但他们没有,这让我很困惑。我认为您总是需要通过递减堆栈来获取新的基指针和局部变量?

另外,是否每条入栈指令都需要栈指针的减法指令,因为我们总是希望栈指针位于栈顶,如果不是,为什么?所以如果

 push %eax
 sub , %esp

我的最后一个问题是,是否有任何资源可以通俗易懂地解释装配?

制作您自己的示例相当简单,只需要在函数的堆栈上有一些东西(不会优化掉)。

unsigned int more_fun ( unsigned int );
void fun_too ( unsigned int *);
void fun ( void )
{
    unsigned int ra;
    unsigned int ray[64];
    for(ra=0;ra<64;ra++) ray[ra]=more_fun(ra);
    fun_too(ray);
}



0000000000000000 <fun>:
   0:   53                      push   %rbx
   1:   31 db                   xor    %ebx,%ebx
   3:   48 81 ec 10 01 00 00    sub    [=10=]x110,%rsp
   a:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  11:   00 00 
  13:   48 89 84 24 08 01 00    mov    %rax,0x108(%rsp)
  1a:   00 
  1b:   31 c0                   xor    %eax,%eax
  1d:   0f 1f 00                nopl   (%rax)
  20:   89 df                   mov    %ebx,%edi
  22:   e8 00 00 00 00          callq  27 <fun+0x27>
  27:   89 04 9c                mov    %eax,(%rsp,%rbx,4)
  2a:   48 83 c3 01             add    [=10=]x1,%rbx
  2e:   48 83 fb 40             cmp    [=10=]x40,%rbx
  32:   75 ec                   jne    20 <fun+0x20>
  34:   48 89 e7                mov    %rsp,%rdi
  37:   e8 00 00 00 00          callq  3c <fun+0x3c>
  3c:   48 8b 84 24 08 01 00    mov    0x108(%rsp),%rax
  43:   00 
  44:   64 48 33 04 25 28 00    xor    %fs:0x28,%rax
  4b:   00 00 
  4d:   75 09                   jne    58 <fun+0x58>
  4f:   48 81 c4 10 01 00 00    add    [=10=]x110,%rsp
  56:   5b                      pop    %rbx
  57:   c3                      retq   

(它没有链接所以调用中的立即数是零所以链接器可以填充它们)

正如 Jester 在评论中指出的那样,您可以代替向 rsp 减去或添加常量,而是放置一长串推送和弹出。这只是浪费代码 space 和执行时间,加法和减法更有意义。

现在有人可能会争辩说,您可以实现此代码,以便每次通过循环推送 more_fun(); 的结果;仅在函数需要时增加堆栈,并根据需要使用推送而不是从 rsp 中减去。但是在 return 上,您希望在一条指令中添加到 rsp,而不是浪费时间和 space 在单个 pops 或 pops 循环上。作为编译器作者,此解决方案更难调试,并且更难理解为编译器输出的 user/reader。 (如果你想在堆栈上保持 64 位对齐并说这里的 unsigned int 是 32 位,那么你将需要更多的指令来解决这个问题)