Clang 填充数组

发布于 2025-01-16 21:14:33 字数 2195 浏览 2 评论 0原文

我试图了解函数调用在机器级别是如何工作的。为此,我创建了一个像这样的虚拟 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 的倍数。我缺少一些基本的东西。

<一href="https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(文件名:%271%27,fontScale:14,fontUsePx:%270% 27,j:1,lang:c%2B%2B,选择:(endColumn:2,endL ineNumber:5,positionColumn:2,positionLineNumber:5,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),来源:%27int+fun c(int+a%5B%5D,+int+n)+%7B%0A%09char+arr%5Bn%5D%3B%0A++++arr%5Bn+-+99%5D+%3D +100%3B%0A++++返回+arr%5B12%5D%3B%0A%7D%27),l:%275%27,n:%270%27,o:%27C%2B %2B+来源+%231%27,t:%270%27)),k:50,l:%274%27,n:%270%27,o:%27%27,s:0,t:% 270 %27),(g:!((h:编译器,i:(编译器:clang1301,过滤器:(b:%270%27,二进制:%271%2 7、仅注释:%270%27、分解:%270%27、指令:%270%27、执行:%271%27、英特尔:%270%27、库代码:%270%27、修剪:%271%27 ),flagsViewOpen:%271%27,fontSc ale:14,fontUsePx:%270%27,j:1,lang:c%2B%2B,库:!(),选项:%27-O3%27,选择:(endColumn:1,endLineNumber:1,positionColumn :1,位置行号:1,选择ctionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),源:1,树:%271%27),l:%275%27,n:%270%27,o:%27x86-64+铿锵+13.0.1+(C% 2B%2B,+编辑器+%231,+编译器+%231)%27,t:%270%27)),k:50,l:%274%27,n:%270%27, o:%27%27,s:0,t:%270%27)),l:%272%27,n:%270%27,o:%27%27,t:%270%27)),版本:4" rel="nofollow noreferrer">这里是作为参考的链接。

I am trying to understand how function calling works at machine level. For that I created a dummy C++ function like this :

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
}

And, I got following assembly when compiling with 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

Instructions 1 and 2 are calculating size of array arr from variable n. The calculated size is next largest multiple of 16 than n. For example, even if n = 1, clang is allocating 16 bytes of memory. I am confused as to why would clang try to make array sizes as multiple of 16 bytes?

I checked with different data types for arr but all have same behavior. So, I don't think this is for alignment purposes as different data type would have different alignment size.

I checked with different compilers as well. All are allocating arrays of sizes multiple of 16. There is something fundamental that I am missing.

Here is the link as reference.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

み零 2025-01-23 21:14:33

x86-64 的 System V psABI 需要足够大的数组和可变长度数组来对齐到至少 16 个字节,以便它们能够正确对齐以进行 SSE 操作。

正如 @PeterCordes 在这个答案中解释的那样,还有进一步的原因将堆栈保持为 16,尽管这对于您作为示例给出的特定函数并不重要。

但请注意,可变长度数组首先仅在 C++ 中作为编译器特定的扩展来支持。它们在标准 ISO C++ 中是不允许的,但自 C99 起在 C 中受支持。

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

The System V psABI for x86-64 requires sufficiently large arrays and variable-length arrays to be aligned to at least 16 bytes so that they are correctly aligned for SSE operations.

As @PeterCordes explains under this answer, there are also further reasons to keep the stack aligned to 16, although that wouldn't matter for the specific function you are giving as an example.

Note however that variable-length arrays are only supported in C++ as compiler-specific extension in the first place. They are not allowed in standard ISO C++, but are supported in C since C99.

For reference you can find links to the ABI specification (draft) here. The requirement is given in section 3.1.2 under the heading "Aggregates and Unions".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文