堆栈框架上的gcc函数参数对齐

mawenbao

我在Ubuntu14.04 x86_64系统上有这个test.c。

void foo(int a, long b, int c) {
}

int main() {
    foo(0x1, 0x2, 0x3);
}

我用编译gcc --no-stack-protector -g test.c -o test并获得了汇编代码objdump -dS test -j .text

00000000004004ed <_Z3fooili>:
void foo(int a, long b, int c) {
  4004ed:       55                      push   %rbp
  4004ee:       48 89 e5                mov    %rsp,%rbp
  4004f1:       89 7d fc                mov    %edi,-0x4(%rbp)
  4004f4:       48 89 75 f0             mov    %rsi,-0x10(%rbp)
  4004f8:       89 55 f8                mov    %edx,-0x8(%rbp) // !!Attention here!!
}
  4004fb:       5d                      pop    %rbp
  4004fc:       c3                      retq   

00000000004004fd <main>:

int main() {
  4004fd:       55                      push   %rbp
  4004fe:       48 89 e5                mov    %rsp,%rbp
    foo(0x1, 0x2, 0x3);
  400501:       ba 03 00 00 00          mov    $0x3,%edx
  400506:       be 02 00 00 00          mov    $0x2,%esi
  40050b:       bf 01 00 00 00          mov    $0x1,%edi
  400510:       e8 d8 ff ff ff          callq  4004ed <_Z3fooili>
}
  400515:       b8 00 00 00 00          mov    $0x0,%eax
  40051a:       5d                      pop    %rbp
  40051b:       c3                      retq   
  40051c:       0f 1f 40 00             nopl   0x0(%rax)

我知道应该按顺序从右到左将函数参数推入堆栈。所以我期待着这个

void foo(int a, long b, int c) {
      push   %rbp
      mov    %rsp,%rbp
      mov    %edi,-0x4(%rbp)
      mov    %rsi,-0x10(%rbp)
      mov    %edx,-0x14(%rbp) // c should be push on stack after b, not after a

但是gcc似乎足够聪明,可以将参数c(0x3)紧跟在a(0x1)之后,以保存应为b(0x2)的数据对齐保留的四个字节。有人可以解释一下,并告诉我一些有关为什么gcc这样做的文档吗?

伊尔卡

这些参数在寄存器中传递- ,ediesiedx那么rcxr8r9然后才推向堆栈) -正是在Linux的AMD64调用约定任务。

您在函数中看到的只是使用进行编译时,编译器在输入时如何保存它们-O0,因此它们位于内存中,调试器可以对其进行修改。它可以按照自己想要的任何方式自由进行操作,并且可以巧妙地进行空间优化。

这样做的唯一原因是,gcc -O0 总是在C语句之间溢出/重新加载所有C变量,以支持修改变量和使用调试器在函数中的各行之间跳转。

最后,所有这些都将在发布版本中进行优化。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章