Почему в GCC 6 предполагается, что данные выровнены по 16 байтов?

(Заранее извините за то, что мне не удалось свести мою проблему к простому неудачному тестовому кейсу …)

Я столкнулся с проблемами при обновлении до GCC 6.3.0 для создания нашей кодовой базы (соответствующие флаги: -O3 -m32).

В частности, мое приложение вызывает ошибки в вызове struct ctor из-за оптимизации GCC.

В этом ctor используется GCC movaps :

movaps %xmm0,0x30a0(%ebx)

movaps требует операнд быть 16-байтовое выравнивание. Но на данный момент, %ebx указывает на мой объект, который не обязательно 16-байтовый. Из glibc:

«Адрес блока, возвращаемого malloc или realloc в системах GNU, всегда кратен восьми (или шестнадцати в 64-битных системах)».

Следовательно segfault (когда построен с -O3 -m32).

Почему GCC полагает, что выделенный объект будет выровнен по 16 байтов? Я что-то неправильно понимаю?

Заметки:

  • Никаких советов или атрибутов выравнивания в этой структуре
  • Объект был инициализирован по умолчанию new оператор
  • Зависит от уровня оптимизации:
    • ПРОХОДИТЬ: -m32 -O2
    • ПОТЕРПЕТЬ ПОРАЖЕНИЕ: -m32 -O2 -ftree-slp-vectorize
    • ПРОХОДИТЬ: -m32 -O3 -fno-tree-slp-vectorize
    • ПОТЕРПЕТЬ ПОРАЖЕНИЕ: -m32 -O3

Этот другой проект, похоже, столкнулся с похожими проблемами: https://github.com/godotengine/godot/issues/4623

Их расследование указывает на -fvect-cost-model=dynamic, Расследование на моей кодовой базе скорее указывает на -ftree-slp-vectorize,

9

Решение

Возможно, у компилятора есть основания полагать, что объект имеет выравнивание ≥ 16 байт. Можно узнать, что компилятор считает выравниванием, используя alignof() оператор в C ++ 11. GCC имеет расширение __alignof__ это доступно в C и более ранних версиях C ++.

Выравнивание структуры является наивысшим выравниванием всего, что есть в ней, рекурсивно. Там может быть что-то с более высоким выравниванием, чем ожидалось.

В то время как стандарт C ++ 11 гарантирует, что память возвращается new выравнивается по значению, требуемому «фундаментальным требованием выравнивания» любого объекта, это относится только к стандартным типам и объектам из них. Использование C ++ 11 alignas() или __attribute__((aligned(x))) Расширение GCC для запроса более высокого выравнивания может превышать то, что new обеспечивает.

Решением этого было бы использовать std::aligned_alloc() (C ++ 11 или более поздняя версия) или posix_memalign() (Только для POSIX, но < C ++ 11) для выравнивания памяти. Это может быть связано с формой размещения new оператор для создания объекта в этой памяти или класс перегрузки оператора конкретного класса new а также delete,

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]