我遇到了这种神秘的分段错误。
#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机器上运行。
有没有人对此有任何解释?
答案 0 :(得分:4)
@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
。
vmovdqa
和vmovaps
要求其内存操作数自然对齐(即YMM为32B,XMM为16B)。因此,即使__m256i
为32B,OSX上生成的程序集也只需要16B对齐。