【问题标题】:gcc 4.7.2 in Debian wheezy doesn't always properly align stack pointer. Is this a bug?Debian wheezy 中的 gcc 4.7.2 并不总是正确对齐堆栈指针。这是一个错误吗?
【发布时间】:2014-04-08 15:24:38
【问题描述】:

偶然地,在阅读示例 C 程序的汇编程序列表时,我注意到在调用函数 foo 之前堆栈指针不是 16 位对齐的:

void foo() { }
int func(int p) { foo(); return p; }  
int main() { return func(1); }

func:  
  pushq %rbp
  movq  %rsp, %rbp
  subq  $8, %rsp          ; See here
  movl  %edi, -4(%rbp)
  movl  $0, %eax
  call  foo
  movl  -4(%rbp), %eax
  leave
  ret

subq $8, %rsp 指令使 RSP 在调用 foo 之前未对齐(它应该是“subq $16, %rsp”)。
在 System V ABI 中,par。 3.2.2,我读到:“当控制转移到函数入口点时,值 (%rsp - 8) 始终是 16 的倍数”。
有人可以帮我理解为什么 gcc 不放 subq $16, %rsp 吗?
提前谢谢你。

编辑: 我忘了提及我的操作系统和编译器版本:
Debian wheezy,gcc 4.7.2

【问题讨论】:

  • 也许是因为让你到达那里的call func 指令已经将一些东西压入了堆栈,pushq %rbp 也是如此。在call 之前可能还有其他指令推送参数等...
  • 也许它应该是 16 位?如,16 位的倍数,表示按字对齐(两个字节)。根据我的经验,这就是堆栈指针必须......甚至。奇数就出来了!
  • @lornix。编号对齐以字节为单位。您可以为编译器指定首选值(请参阅:msdn.microsoft.com/en-us/library/83ythb65.aspxgcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html)。如果您尝试反汇编其他代码,您会注意到堆栈指针始终是 16 字节的倍数。我不明白为什么在我发布的简单示例中这是不正确的。
  • @twalberg。不。 main() 的汇编程序列表显示堆栈指针在调用 func() 之前是 16 字节对齐的:“pushq %rbp”、“movq %rsp, %rbp”、“movl $1, %edi”、“call func” .我假设 main() 启动时 rsp 正确(16 字节)对齐。

标签: c gcc calling-convention


【解决方案1】:

假设进入func时栈指针是16字节对齐的,那么

的组合
pushq %rbp              ; <- 8 bytes
movq  %rsp, %rbp
subq  $8, %rsp          ; <- 8 bytes

将保持 16 字节对齐,以便后续调用 foo()

似乎因为编译器知道foo() 的实现并且它是一个noop,所以它不会打扰堆栈对齐。如果foo() 仅被视为编译func() 的翻译单元中的声明或原型,您将看到预期的堆栈对齐。

【讨论】:

  • @Burr。否:“call func”指令将 rip(8 字节)推入堆栈,然后“pushq %rbp”使 rsp 16 字节对齐。但是下一个 "subq $8, %rsp" 使得 rsp 没有正确对齐。尝试添加“putchar('A');”在 foo() 和 func() 中将更正为“subq $16, %rsp”
  • 我现在明白了。我认为发生的事情是,由于编译器知道foo() 的实现并且它是一个noop,它不会打扰堆栈对齐。如果foo() 在另一个翻译单元中实现,您将看到预期的堆栈对齐。我不确定为什么即使在“非优化”代码中也会发生这种情况。
猜你喜欢
  • 2021-12-16
  • 2016-01-21
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 2013-06-16
  • 2013-05-04
  • 2017-01-04
相关资源
最近更新 更多