相关疑难解决方法(0)

堆栈分配,填充和对齐

我一直在努力深入了解编译器如何生成机器代码,更具体地说是GCC如何处理堆栈.在这样做的过程中,我一直在编写简单的C程序,将它们编译成汇编并尽力理解结果.这是一个简单的程序及其生成的输出:

asmtest.c:

void main() {
    char buffer[5];
}
Run Code Online (Sandbox Code Playgroud)

asmtest.s:

pushl   %ebp
movl    %esp, %ebp
subl    $24, %esp
leave
ret
Run Code Online (Sandbox Code Playgroud)

让我感到困惑的是为什么要为堆栈分配24个字节.我知道由于处理器如何寻址内存,堆栈必须以4为增量进行分配,但如果是这种情况,我们应该只将堆栈指针移动8个字节而不是24个.作为参考,缓冲区为17 bytes产生一个移动40个字节的堆栈指针,并且根本没有缓冲区移动堆栈指针8. 1到16个字节之间的缓冲区移动ESP24个字节.

现在假设8个字节是必要的常量(它需要什么?),这意味着我们分配16个字节的块.为什么编译器会以这种方式对齐?我正在使用x86_64处理器,但即使是64位字也只需要8字节对齐.为什么会出现差异?

作为参考,我正在使用gcc 4.0.1运行10.5的Mac上进行编译,并且未启用任何优化.

c x86 assembly stack gcc

45
推荐指数
2
解决办法
2万
查看次数

什么是"堆栈对齐"?

什么是堆栈对齐?为什么用它?可以通过编译器设置来控制吗?

这个问题的细节来自于尝试将ffmpeg库与msvc一起使用时遇到的问题,但我真正感兴趣的是对"堆栈对齐"的解释.

细节:

  • 当runnig我的msvc编译程序链接到avcodec我得到以下错误:"编译器没有对齐堆栈变量.Libavcodec已被错误编译",随后avcodec.dll崩溃.
  • avcodec.dll没有用msvc编译,所以我无法看到里面发生了什么.
  • 运行ffmpeg.exe并使用相同的avcodec.dll时一切正常.
  • ffmpeg.exe没有用msvc编译,它符合gcc/mingw(与avcodec.dll相同)

谢谢,

c++ compiler-construction mingw visual-c++ data-structures

44
推荐指数
3
解决办法
2万
查看次数

为什么Mac ABI需要x86-32的16字节堆栈对齐?

我可以理解旧PPC RISC系统的这个要求,甚至是x86-64,但是对于旧的,经过验证的x86?在这种情况下,堆栈只需要在4字节边界上对齐.是的,某些MMX/SSE指令需要16字节对齐,但如果这是被调用者的要求,则应确保对齐正确.为什么要为每个来电者增加这项额外要求?这实际上可能会导致性能下降,因为每个呼叫站点都必须管理此要求.我错过了什么吗?

更新:在对此进行一些调查并与一些内部同事进行一些咨询后,我对此有一些理论:

  1. PPC,x86和x64版操作系统之间的一致性
  2. 似乎GCC codegen现在始终执行子esp,xxx然后将数据"移动"到堆栈而不是简单地执行"推送"指令.在某些硬件上,这实际上可能更快.
  3. 虽然这确实使调用站点变得复杂,但是当使用默认的"cdecl"约定时,调用者清理堆栈时几乎没有额外的开销.

我对最后一项的问题是,对于依赖于被调用者清理堆栈的调用约定,上述要求实际上 "uglify"了codegen.例如,某些编译器决定为自己的内部使用实现更快的基于寄存器的调用样式(即任何不打算从其他语言或源调用的代码)?这种堆栈对齐可能会通过在寄存器中传递一些参数来抵消一些性能提升.

更新:到目前为止,唯一真正的答案是一致性,但对我来说,答案有点太容易了.我有超过20年的x86架构经验,如果一致性,而不是性能,或其他具体的东西,那么我真的是因为我恭敬地建议开发人员要求它有点天真.他们忽略了近三十年的工具和支持.特别是如果他们期望工具供应商能够快速轻松地为他们的平台调整他们的工具(可能不是......这 Apple ......),而不必跳过几个看似不必要的箍.

我会在另一天左右给出这个话题,然后关闭它......

有关

macos stack alignment abi calling-convention

31
推荐指数
3
解决办法
6714
查看次数