在进行 C 到 Intel x86 程序集转换时,堆栈上的数组分配占用的空间超过了所需的空间 [重复]

Posted

技术标签:

【中文标题】在进行 C 到 Intel x86 程序集转换时,堆栈上的数组分配占用的空间超过了所需的空间 [重复]【英文标题】:Array allocation on stack taking more space than required while doing C to Intel x86 Assembly Conversion [duplicate] 【发布时间】:2021-08-04 16:00:57 【问题描述】:

我正在学习 C 和 intel x86 汇编。我使用了这个简单的 C 代码。

#include <stdio.h> 
void function()
 char c[1];

int main()
 function();
 return 0;

我用下面的命令编译它来获取程序集。

gcc -S -o code.s code.c

函数的预期输出汇编如下:

pushl %ebp
movl %esp, %ebp
subl $24, %esp

我的理解是 1 个字符是 1 个字节,intel x86 中的 1 个字大小是 4 个字节,因为我们以字长进行分配,所以应该在堆栈上为 char 分配总共 4 个字节的内存长度为 1 的数组。但是为什么上面的程序集显示 24 字节的分配。

在玩了之后我发现如果 char 数组长度保持在 1-12 范围内,则汇编代码显示 24 个字节的分配,但如果它超过 12,假设它是 13,那么它显示 40 个字节。

对我来说很困惑..

【问题讨论】:

在这种情况下,这只是因为您没有启用优化(然后会删除整个函数,所以...)。在一般情况下,这是因为堆栈指针和数据本身对齐。 您能否请我参考任何文章或链接,因为我仍然没有得到它 gcc.gnu.org/onlinedocs/gcc-5.5.0/gcc/… @Jester:GCC 的 16 个额外字节的堆栈分配并不总是随着优化而消失,例如Why does GCC allocate more space than necessary on the stack, beyond what's needed for alignment?。 godbolt.org/z/nhrdGv7zb 表明 GCC -O3 执行 sub $28, %esp (如果您创建数组 volatile 则它不会消失)。 -fstack-protector-strong 似乎是查询者默认 GCC 选项的一部分,因此在 Godbolt 上需要使用 -O0 重现 24 【参考方案1】:

用于 IA-32 (Intel386) 的原始 System V Unix ABI 要求堆栈指针在 4 字节边界上对齐。1 用于 IA-32 的(未发布的)Linux ABI 基于最初的 System V Unix ABI,但在 2015 年 2 月发布了更新的 Linux IA-32 ABI 1.0 版,要求在调用函数时堆栈指针对齐到 16(如果在堆栈上传递 __m256,则为 32)字节边界.2(此 ABI 已于 2015 年 12 月更新至 1.1 版,3据我所知是撰写本文时的最新版本。)

函数调用的编译器前导代码通常假定堆栈在入口处已经对齐。它假定%esp+4+4 代表堆栈上的返回地址)与 16(或 32)字节边界对齐,并确保堆栈指针减少 16 的倍数(并与32 的倍数)调用另一个函数时。即使被调用的函数没有调用另一个函数,它也会这样做。

对于下面的序言:

pushl %ebp
movl %esp, %ebp
subl $24, %esp

在第一条指令 (pushl %ebp) 之前,%esp+4 与 16 字节边界对齐。在第一条指令之后,%esp+4+4 与 16 字节边界对齐。在第三条指令(subl $24, %esp)之后,%esp+4+4+24 对齐到 16 字节边界,由于 4+4+24 是 16 的倍数,%esp 对齐到 16 字节边界。

编译器可能已将subl $24, %esp 替换为subl $8, %esp 并仍保持堆栈与16 字节边界对齐。我不知道分配额外 16 个字节的原因。

在修订 ABI 的 1.0 版发布之前,Linux 的 GCC 编译器已经假设堆栈已经与 16 字节边界对齐多年。这导致 GCC 4.4 破坏了几个二进制文件。 “修复”是更改 ABI,破坏现有的旧代码,而不是修复编译器以与现有代码兼容。4


脚注:

    System V Application Binary Interface, Intel386™ Architecture Processor Supplement Fourth Edition — 图 3-15:标准堆栈框架。 System V Application Binary Interface Intel386 Architecture Processor Supplement Version 1.0 — 2.2.2 堆栈框架。 System V Application Binary Interface Intel386 Architecture Processor Supplement Version 1.1 Bug 40838 - gcc shouldn't assume that the stack is aligned — Comment 86 by H.J.Lu (2011-01-18 21:07:26 UTC):

    我正在更新 i386 psABI 以指定 16 字节堆栈对齐。

【讨论】:

Why does GCC allocate more space than necessary on the stack, beyond what's needed for alignment? - 额外的 16 个字节是一个常见的 GCC 错误;有人应该报告它...请注意,这是一个叶函数,并且数组小于 16 字节,因此没有任何对齐要求。 (clang -O3volatile 来阻止数组优化实际上做了一个疯狂的sub $1, %esp;这可能不是一件好事。godbolt.org/z/Gcnqx8931)

以上是关于在进行 C 到 Intel x86 程序集转换时,堆栈上的数组分配占用的空间超过了所需的空间 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

cmp 不工作 - Intel x86 (IA32) 程序集

x86 AT&T 语法程序集的注释语法

Intel x86的架构模式

GCC 生成的程序集 - C 函数调用时的段错误

AT&T 语法中的 3 或 4 参数 x86 程序集[重复]

将 ISR 链接到向量中断 80x86 32 位 AT&T 程序集