【问题标题】:EXC_BAD_ACCESS signal when trying to initialize __m128 class member variable尝试初始化 __m128 类成员变量时的 EXC_BAD_ACCESS 信号
【发布时间】:2023-12-18 14:34:01
【问题描述】:

我正在使用 Apple GCC 4.2.1,我偶然发现了以下代码的一个奇怪问题...我在尝试初始化 __m128 类成员变量。不幸的是,下面的简化代码在测试应用程序中工作,但也许你仍然可以帮助我找到这个问题的根源?

我不明白 EXC_BAD_ACCESS 异常背后的原因 - __m128 类型不是指针,所有其他 MyClass 成员都在没有的情况下初始化和访问任何问题,没有堆栈/堆损坏的迹象,如果我使用局部变量,一切正常,并且在 MSVC 下没有问题......也许对齐有问题?

请帮忙!

class MyClass
{
    public:
    // lots of members
    __m128 vect;

    MyClass()
    {
        vect = _mm_setr_ps (0.f, 0.f, 0.f, 10.0f); // Program received signal: “EXC_BAD_ACCESS”.
    }

    void iniialize()
    {
        __m128 localVector = _mm_setr_ps (0.f, 0.f, 0.f, 10.0f); // No problems
        vect = localVector; // Program received signal: “EXC_BAD_ACCESS”.
    }
};

【问题讨论】:

  • 谢谢你,Sehe 和 Paul!但是,指定 16 字节对齐并没有解决任何问题 :( 请告诉我,还有什么可能导致这个问题?
  • 您是在堆栈上还是通过new 创建类的实例?如果您使用的是new,那么您是否覆盖它以使用例如posix_memalign ?在每个 vect 分配处设置一个断点并检查对齐方式(vect 成员应该有一个以 0 结尾的十六进制地址)。

标签: c++ visual-c++ gcc exc-bad-access sse


【解决方案1】:

我的想法是:我会说对齐问题

尤其是“很多成员”的部分

__attribute__aligned

【讨论】:

  • Sehe,你正在确认我最糟糕的噩梦......在 MSVC 项目中,16 字节对齐是强制的,但我无法在 GCC 中找到这样做的方法,恐怕我会因手动将对齐属性添加到数千个源文件中的所有 __m128 成员及其包装器而死……也许我遗漏了一些东西,也许还有其他方法?
  • 您可以将相同的 gcc 属性应用于 __m128 类型。我怀疑这涉及编辑 Windows 头文件,但它应该可以工作。
  • 我相信 Google gcc +"__m128" 会在这里发现比我更好的提示。现在我认为你可以 typedef 说aligned_m128,如果你关心命名空间的话。您不应重载 保留标识符 __m128,因此您需要使用预处理器宏来避免更改代码
  • 我通过将 属性 应用到整个类来解决了这个问题,因为仅将它用于 __m128 成员并没有正确对齐它们。
【解决方案2】:

如果对象是在堆栈上创建的,gcc 将自动正确对齐 __m128 成员,但对于通过 new 分配的对象,您将受内存分配器的支配,在 Linux 上通常只有 8 字节对齐。您可能需要为您的类覆盖运算符 new 以便它调用 posix_memalign 以便您始终获得 16 字节对齐的对象。

话虽如此,如果您要进行 SSE 代码优化,那么您可能需要重新评估您的编码方式 - 因为性能通常是 SIMD 优化的动力,您可能希望在比C++ 类 - 通常您只想对大块连续数据(即 1D 或 2D 数组)进行同构操作。

【讨论】:

    【解决方案3】:

    如果堆栈未对齐是问题所在,您应该检查-mstackrealign 命令行选项,请参阅GCC documentation。这解决了我在 MinGW 目标上的问题。另请参阅stack alignment 上的讨论。最后,您可能希望将 GCC 更新到较新的版本。

    另一方面,如果您动态分配对象,则必须确保内存对齐,正如 Paul 指出的那样。有像 _mm_malloc_mm_free 这样的方法可以帮助你。

    【讨论】: