使用带有自定义对齐分配器实现的最新 g++ 使用 SSE 和 -O3 选项编译时出现非法指令(核心转储)

Posted

技术标签:

【中文标题】使用带有自定义对齐分配器实现的最新 g++ 使用 SSE 和 -O3 选项编译时出现非法指令(核心转储)【英文标题】:Illegal instruction (core dumped) upon compiling with SSE and -O3 options using latest g++ with a custom alignment allocator implementation 【发布时间】:2014-11-13 06:51:20 【问题描述】:

使用 g++ (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7) 编译以下代码时使用编译命令“g++ -g -fno-omit-frame-pointer -msse2 -mssse3 - O3 Memory.cpp”,可执行文件在执行时引发“非法指令(核心转储)”。

它使用相同的编译器标志使用旧的 g++ 版本编译和运行没有问题。当编译器标志“-mssse3 -O3”被删除或替换为较低的优化级别(例如“-O2”)时,它也可以毫无问题地编译和运行。

如果同时使用旧的和新的 g++ 编译器,具有编译器标志“-msse2 -mssse3 -O3”,并且具有可移植的对齐内存分配器是必需的,存在哪些选项?以下代码中是否存在可以轻松修复的简单错误?最后,为什么会出现这个错误?

使用 gdb 时,触发此错误的行是:“memory[i] = (unsigned char)i;”。

非常感谢。

#include <iostream>
using std::cerr;
using std::cout;
using std::endl;
using std::flush;
#include <stdlib.h>

void *aligned_alloc(int alignment, int size)
  const int pointer_size = sizeof(unsigned char *);
  const int requested_size = size + alignment - 1 + pointer_size;
  unsigned char *base = (unsigned char *)malloc(requested_size);
  if (base == NULL)  return NULL;
  unsigned char *start = base + pointer_size;
  const int trim_offset = (int)(((unsigned long long)(start+alignment-1)) & (alignment-1));
  unsigned char *aligned = start + alignment - 1 - trim_offset;
  *(unsigned char **)(aligned-pointer_size) = base;
  return aligned;

void aligned_free(void **aligned)
  if (*aligned == NULL)  return;
  unsigned char *base = *(unsigned char **)((unsigned char *)(*aligned) - sizeof(unsigned char *));
  free(base);
  *aligned = NULL;


int main()
  unsigned char *memory = (unsigned char *)aligned_alloc(16, 120);
  if (memory == NULL)
    cout<<"ERROR: Unable to allocate memory."<<endl;
    exit(1);
  

  for (int i=0; i<120; i++)
    memory[i] = (unsigned char)i;
  

  aligned_free((void **)&memory);

  return 0;

【问题讨论】:

aligned_alloc 是最新版本的 glibc 中的标准函数 - 我想知道您是否正在链接它而不是您自己的函数,或者类似的东西 - 也许尝试将您的函数重命名为my_aligned_alloc/my_aligned_free 只是作为测试? 你用的是什么CPU?在 GDB 中,什么指令(不是行)以及在哪里导致陷阱(尝试(gdb) bt(gdb) disas)?那时 insn 使用的寄存器的值是多少?此外,您可以通过将aligned 转换为unsigned char** 并将base 访问为unsigned char* base = ((unsigned char**)aligned)[-1]; 来对您的ptr 算法进行一些deuglify @PaulR 我也这么认为,但转念一想我打了折扣,因为至少在我的机器上aligned_alloc 没有被破坏,它的参数是size_t,而这里我们谈论的是 C++ 和参数int 类型。尽管如此,还是值得一试重命名。 你用的是什么CPU? 哇。我从来没有想过我仍然会遇到不支持 SSSE3 指令集的 Intel CPU。我做了一个 cat /proc/cpuinfo ,它清楚地报告该标志丢失。为了完整起见,我在比较 1) 编译器 = "g++ (GCC) 4.4.4 20100630 (Red Hat 4.4.4-10)" on CPU = "Intel(R) Core(TM) i3-4010U CPU @ 1.70GHz" vs 2) 编译器 = "g++ (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)" on CPU = "Intel(R) Pentium(R) 4 CPU 3.00GHz"。我的印象是,我的代码肯定是罪魁祸首,而不是编译器。我想它也可能是硬件!谢谢! 【参考方案1】:

这是由不支持 SSSE3(Supplemental Streaming SIMD Extensions 3)指令子集(特别是某种 3GHZ P4)的 CPU 试图运行为支持该指令子集的 CPU 编译的代码引起的;只需从 GCC 命令行中删除 -mssse3 标志就足以使违规指令消失。

【讨论】:

以上是关于使用带有自定义对齐分配器实现的最新 g++ 使用 SSE 和 -O3 选项编译时出现非法指令(核心转储)的主要内容,如果未能解决你的问题,请参考以下文章

如何将最新数据附加到android中的自定义基本适配器列表视图?

使用自定义适配器实现 Expandable ListView

带有由 LoaderManager 管理的自定义适配器的 AlphabetIndexer

深度剖析结构体@自定义类型1---结构体的声明,自引用,变量定义和初始化 + 结构体内存对齐 + 结构体传参 + 结构体实现位段

模板typedef与std :: vector有自定义分配器

使用带有文本和图像的自定义适配器在列表视图中搜索