所有功能都有一个"功能序言"减少本地人的堆栈指针?

时间:2018-05-01 23:16:52

标签: assembly x86 nasm att

我有一些关于装配的基本问题。

在汇编中编写函数时,所有函数都有一个"函数序言"?我看到一些在线写的功能,而且他们没有这个让我感到困惑的功能。我认为你总是需要通过减少堆栈来获得新的基本指针和局部变量吗?

每个push指令都需要一个stackpointer的减法指令,因为我们总是希望堆栈指针位于堆栈的顶部,如果不是为什么?所以,如果

 push %eax
 sub $4, %esp

我的最后一个问题是,是否有任何资源用于解释外行人的装配?

1 个答案:

答案 0 :(得分:2)

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

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    $0x110,%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    $0x1,%rbx
  2e:   48 83 fb 40             cmp    $0x40,%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    $0x110,%rsp
  56:   5b                      pop    %rbx
  57:   c3                      retq   

(它没有链接,因此调用中的立即数为零,因此链接器可以填充它们)

而不是向rsp中减去或添加常量,而是可以像Jester在注释中指出的那样添加一长串推送和弹出。这只是浪费代码空间和执行时间,加减法更有意义。

现在有人可能会争辩说你可以实现这个代码,这样每次循环都可以推送more_fun();仅在函数需要时增加堆栈,并根据需要使用推送而不是从rsp中减去。但是在返回时你需要在一条指令中添加rsp,而不是浪费时间和空间在单个弹出或一个流行音乐循环。作为编译器作者,此解决方案更难以调试,并且更难理解为编译器输出的用户/读取器。 (如果你想在堆栈上保持说64位对齐并说这里的unsigned int是32位,如图所示那么你就会烧掉一些更多的指令来解决这个问题)