为__m256i分配内存

时间:2016-10-12 03:32:05

标签: c ubuntu gcc x86 avx

我遇到了这种神秘的分段错误。

#include <stdio.h>
#include <immintrin.h>
struct Box{
    __m256i L;
};
int main()
{
    struct Box *result=NULL;
    result=(struct Box *)malloc(sizeof(struct Box));
    (*result).L=(*result).L;
}

使用标记-msse4.2 -march=corei7-avx

编译

它在我的Mac上运行完全正常(OS X EI Caption 10.11.6,GCC 4.8.4)。 但它在Amazon EC2机器上给出了Segmentation故障(Ubuntu 14.04,GCC 4.8.4)。

当我稍作修改时:

#include <stdio.h>
#include <immintrin.h>
struct Box{
    __m256i L;
};
int main()
{
    struct Box result[1];
    (*result).L=(*result).L;
}

它将能够在Ubuntu机器上运行。

有没有人对此有任何解释?

1 个答案:

答案 0 :(得分:4)

对齐,Malloc行为和堆栈分配

@Peter Cordes的评论解决了部分问题。

特别是在你的OSX机器上,你总是&#34;总是&#34;获得正确对齐的内存,该内存满足为__m256i数据类型supposed to be 32 byte aligned生成的程序集的对齐需求。 (我把&#34;总是&#34;在引文中因为malloc没有保证。你可能只是幸运得到了OSX的malloc。相同的代码倾向于获得相同的对齐,不像在一个程序中重复调用malloc。实际上,请看下面:OS X上的编译器生成不同的asm)

在Ubuntu上,你没有在malloc返回的内存地址中得到合适的对齐方式。 (有关原因的详细信息,请参见下文。)

您将第二个代码段称为slight change

int main()
{
    struct Box result[1];
    (*result).L=(*result).L;
}

它实际上与使用malloc的第一个代码段完全不同,因为编译器(此处为gcc)知道数据类型Box的对齐要求(以及扩展名{{1}另外)在堆栈上分配内存时。因此,在这种情况下不存在segfaulting的风险,因为编译器提供了正确的对齐。

您可以按照https://stackoverflow.com/a/227900/3516034中的说明操作__m256i返回的基指针。我会让你看看那里的细节,但简而言之,你可以做点像

malloc

其中struct Box *result=NULL; void *mem = malloc(2 * sizeof(struct Box)); result = (struct Box *)((uintptr_t)mem + offset); 允许您探索对齐和段错误。打印出最终用于offset result的指针地址(同样来自该帖子)可能会很有用。

指令差异

最后,我可以在Ubuntu和OSX上重现这一点。我实际上看到我的OSX printf("0x%08" PRIXPTR "\n", (uintptr_t)result);调用给出 16字节对齐而不是32字节对齐。我在Ubuntu上看到16字节对齐(在同一硬件上的VM中) 导致段错误。当我手动对齐到32个字节时,段错误就会消失。

因此,问题的根本原因是系统没有生成相同的汇编指令。我使用malloc选项获得了gcc的程序集。在OSX上,我看到-S使用XMM操作数4次,而使用YMM操作数使用Ubuntu vmovaps两次,以移动vmovdqa

vmovdqavmovaps要求其内存操作数自然对齐(即YMM为32B,XMM为16B)。因此,即使__m256i为32B,OSX上生成的程序集也只需要16B对齐。

相关问题