Clang 填充数组

Clang padding array

我正在尝试了解函数调用在机器级别的工作原理。为此,我创建了一个像这样的虚拟 C++ 函数:

int func(int a[], int n) {
    char arr[n];
    arr[n - 99] = 100; //to prevent compiler from optimizing my function to noop
    return arr[12]; //to prevent compiler from optimizing my function to noop
}

而且,我在使用 x86-64 clang 13.0.1 编译时得到了以下程序集

push    rbp
mov     rbp, rsp
mov     eax, esi
mov     rcx, rsp
add     rax, 15 // Instruction 1
and     rax, -16 // Instruction. 2
mov     rdx, rcx
sub     rdx, rax
mov     rsp, rdx
movsxd  rsi, esi
mov     byte ptr [rsi + rdx - 99], 100
neg     rax
movsx   eax, byte ptr [rcx + rax + 12]
mov     rsp, rbp
pop     rbp
ret

指令 1 和 2 正在根据变量 n 计算数组 arr 的大小。计算出的大小是 16 的下一个最大倍数,而不是 n。例如,即使 n = 1,clang 也会分配 16 字节的内存。我很困惑为什么 clang 会尝试将数组大小设置为 16 字节的倍数?

我检查了 arr 的不同数据类型,但它们都有相同的行为。所以,我不认为这是为了对齐目的,因为不同的数据类型会有不同的对齐大小。

我也检查了不同的编译器。所有人都在分配大小为 16 的倍数的数组。我缺少一些基本的东西。

Here是link作为参考。

x86-64 的 System V psABI 需要足够大的数组,并且 variable-length 数组至少要对齐到 16 个字节,以便它们正确对齐以进行 SSE 操作。

正如@PeterCordes 在此答案下解释的那样,还有其他原因使堆栈对齐到 16,尽管这对于您作为示例给出的特定函数并不重要。

但是请注意,variable-length 数组首先仅在 C++ 中作为 compiler-specific 扩展受支持。它们在标准 ISO C++ 中是不允许的,但在 C99 之后的 C 中受支持。

作为参考,您可以找到 ABI 规范(草案)here 的链接。该要求在第 3.1.2 节的“聚合和联合”标题下给出。