c - gcc 函数参数在堆栈帧上的对齐方式

标签 c gcc assembly callstack

我的 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(然后是 rcx r8r9 然后才压入堆栈) - 正是 Linux amd64 calling convention授权。

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

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

所有这些最终都会在发布版本中得到优化。

关于c - gcc 函数参数在堆栈帧上的对齐方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23513196/

相关文章:

assembly - 如何检测 x86 组件中的核心数量?

c - 如何链接同名的 .c 和 .h 文件?

c - 从文件读取 getc 后,C 中出现奇怪的字符串

c++ - 在代码块链接器错误中混合使用 C 和 C++

c - 强制编译器为某个变量使用某个寄存器

c - 汇编中的指针

c - C语言中如何存储负 float

c - 如何在 Windows 中构建 ctags 5.8

c - GCC C vector 扩展 : How to check if result of ANY element-wise comparison is true, 和哪个?

c++ - 使用汇编代码在 OpenGL 中呈现视频时出错