32 位 x86 汇编中堆栈对齐的职责

2024-11-04 08:43:00
admin
原创
66
摘要:问题描述:我试图弄清楚谁(调用者或被调用者)负责堆栈对齐。64 位汇编的情况相当清楚,它由调用者负责。参照 System V AMD64 ABI,第 3.2.2 节“堆栈框架”:输入参数区域的末尾应与 16(如果 __m256 在堆栈上传递,则为 32)字节边界对齐。换句话说,可以安全地假设,对于被调用函数的...

问题描述:

我试图弄清楚谁(调用者或被调用者)负责堆栈对齐。64 位汇编的情况相当清楚,它由调用者负责。

参照 System V AMD64 ABI,第 3.2.2 节“堆栈框架”

输入参数区域的末尾应与 16(如果 __m256 在堆栈上传递,则为 32)字节边界对齐。

换句话说,可以安全地假设,对于被调用函数的每个入口点:

16 | (%rsp + 8)

保持(额外的八个是因为call隐式地将返回地址推送到堆栈上)。


在 32 位世界中看起来如何(假设是 cdecl)?我注意到gcc将对齐放在调用函数内部,其结构如下:

and esp, -16

这似乎表明,这是被调用者的责任。

为了更清楚起见,请考虑以下 NASM 代码:

global main
extern printf
extern scanf
section .rodata
    s_fmt   db "%d %d", 0
    s_res   db `%d with remainder %d
`, 0
section .text
main:
    start   0, 0
    sub     esp, 8
    mov     DWORD [ebp-4], 0 ; dividend
    mov     DWORD [ebp-8], 0 ; divisor

    lea     eax, [ebp-8]
    push    eax
    lea     eax, [ebp-4]
    push    eax
    push    s_fmt
    call    scanf
    add     esp, 12

    mov     eax, [ebp-4]
    cdq
    idiv    DWORD [ebp-8]

    push    edx
    push    eax
    push    s_res
    call    printf

    xor     eax, eax
    leave
    ret

在调用之前是否需要对齐堆栈?如果是这样,那么在将这两个参数推送到之前,scanf需要减少四个字节:%esp`scanf`

4 bytes (return address)
4 bytes (%ebp of previous stack frame)
8 bytes (for two variables)
12 bytes (three arguments for scanf)
= 28

解决方案 1:

GCC在 中进行额外的堆栈对齐main;该函数很特殊。 如果您查看任何其他函数的代码生成,您将看不到它,除非您有本地的 withalignas(32)或类似的东西。

GCC 只是采取了一种防御性的方法-m32,不假设main使用正确 16B 对齐的堆栈调用。或者这种特殊处理是从-mpreferred-stack-boundary=4一个好主意而不是法律1遗留下来的。

多年来,i386 System V ABI 一直保证/要求 ESP+4 在进入函数时是 16B 对齐的。(即,ESP在 CALL 指令之前必须是 16B 对齐的,因此堆栈上的参数从 16B 边界开始。这与 x86-64 System V 相同。) ESP % 16 == 0在调用之前、ESP % 16 == 12在函数进入时、在调用之后。

ABI 还保证新的 32 位进程以在 16B 边界上对齐的 ESP 启动(例如_start,在 ELF 入口点,其中 ESP 指向 argc,而不是返回地址),并且 glibc CRT 代码保持该对齐。

就调用约定而言,EBP 只是另一个调用保留寄存器。但是,是的,编译器输出-fno-omit-frame-pointer确实会在其他调用保留寄存器(如 EBX)之前进行处理push ebp,因此保存的 EBP 值会形成一个链接列表。(因为它还负责mov ebp, esp在推送之后设置帧指针。)


也许 gcc 是防御性的,因为非常古老的 Linux 内核(从 i386 ABI 修订版之前开始,当时所需的对齐只有 4B)可能会违反该假设,并且它只是在进程的生命周期中运行一次的额外几个指令(假设程序不递归main调用)。


与 gcc 不同,clang 假定堆栈在进入主函数时正确对齐。(clang 还假定窄参数已被符号或零扩展为 32 位,即使当前 ABI 修订版尚未指定该行为。gcc 和 clang 都发出在调用方执行的代码,但只有 clang 在被调用方依赖于它。这发生在 64 位代码中,但我没有检查 32 位。)

如果您好奇的话,请查看http://gcc.godbolt.org/上的 main 函数和除 main 之外的其他函数的编译器输出。


我刚刚更新了x86标签 wiki。http: //x86-64.org/仍然处于死机状态并且似乎不会回来,因此我更新了 System V 链接以指向 HJ Lu 的 github repo 中当前修订版的 PDF,以及他的带有链接的页面。

请注意,SCO 网站上的最新版本不是当前修订版,并且不包括 16B 堆栈对齐要求。


ABI 从 4 字节对齐变为 16 字节对齐的历史

脚注 1:向 i386 SysV ABI 添加 16 字节对齐要求纯属意外;GCC 出于性能原因维持了 16 字节对齐(例如,8 字节double永远不会跨越缓存行边界)。

另请参阅我的答案底部关于为什么 x86-64 / AMD64 System V ABI 要求 16 字节堆栈对齐?的部分以获取更多详细信息。

在某些 GCC 版本中,SSE/SSE2 代码生成开始使用movaps溢出/重新加载__m128变量到堆栈,而无需手动对齐传入的 ESP。这使调整选择成为一项要求,但直到带有此类代码的库在一些长期稳定的 Linux 发行版中广泛部署时才被发现。

面对这一选择,GCC 开发人员/ABI 维护人员选择了最不坏的路径,将其作为官方要求。这破坏了调用其他函数的现有手写 asm。

请参阅https://sourceforge.net/p/fbc/bugs/659/了解一些历史记录,以及我在https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40838#c91上的评论,尝试总结 i386 GNU/Linux + GCC 意外陷入这样一种境地的不幸历史:对 i386 System V ABI 进行向后不兼容的更改是两害相权取其轻。


大多数 BSD 版本和 i386 MacOS 未采用此 ABI 更改,并且仍然不需要16字节堆栈对齐。GCC 可能默认为-mpreferred-stack-boundary=4这些目标,但代码生成alignas(16) char buf[16];(或__m128从 regs 溢出的本地变量)需要手动对齐函数内的 ESP,以防它一开始就不是。

因此,从 4 字节对齐到 16 字节对齐的改变实际上针对的是 Linux,而不是其他操作系统。这可能是简化 GCC 源代码并始终为main32 位目标包含额外堆栈对齐代码的另一个原因。目前,Linux 的 32 位 x86 已经过时,现在不值得改变。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   681  
  在项目管理领域,集成产品开发(IPD)流程以其高效、协同的特点,被众多企业视为提升产品竞争力的关键。IPD流程强调跨部门、跨职能的紧密合作,以确保产品从概念到市场各个环节的无缝衔接。然而,实现这一目标并非易事,它需要企业深刻理解并掌握IPD流程中的跨部门协作艺术。本文将深入探讨IPD流程中跨部门协作的三个关键点,旨在为...
IPD项目管理咨询   9  
  掌握IPD流程图:提升团队协作的关键路径在当今快速变化的商业环境中,团队协作的效率与效果直接关系到项目的成功与否。集成产品开发(Integrated Product Development,简称IPD)作为一种先进的研发管理理念,通过跨部门、跨领域的协同工作,能够显著提升产品开发的速度与质量。而IPD流程图,则是这一理...
IPD流程阶段   9  
  IPD流程概述:理解其核心价值与实施背景集成产品开发(Integrated Product Development,简称IPD)是一种先进的产品开发管理理念,它强调跨部门协作、市场导向和快速响应变化的能力。IPD流程不仅关注产品本身的技术创新,更注重将市场、研发、生产、销售等各个环节紧密集成,以实现产品从概念到市场的高...
华为IPD是什么   7  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程以其跨部门协作、高效决策和快速响应市场变化的特点,被众多企业视为提升竞争力的关键。然而,实践IPD流程并非易事,项目管理中的种种错误往往阻碍了其效果的充分发挥。本文旨在深入探讨如何在实施IPD流程时避免这些常见错误,...
IPD框架   7  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用