Компилятор делает неправильное предположение об выравнивании стека
Похоже, это была ошибка GCC, которая была исправлена в GCC 4.5. Если у вас возникла эта проблема, пожалуйста, обновите GCC до версии 4.5 и сообщите нам, чтобы мы могли обновить эту страницу.
Это проблема, с которой мы, до сих пор, столкнулись только с GCC на Windows: например, MinGW и TDM-GCC.
По умолчанию, в функции такого вида,
void foo() { Eigen::Quaternionf q; //... }
GCC предполагает, что стек уже выровнен на 16 байт, так что объект q будет создан в позиции, выровненной на 16 байт. По этой причине он не принимает никаких специальных мер для явного выравнивания объекта q, как требует Eigen.
Проблема заключается в том, что в некоторых особых случаях это предположение может быть ошибочным на Windows, где выравнивание стека гарантируется только на 4 байта. Действительно, даже если GCC позаботится о выравнивании стека в основной функции и сделает всё возможное, чтобы сохранить его выровненным, когда функция вызывается из другого потока или из двоичного файла, скомпилированного другим компилятором, выравнивание стека может быть нарушено. Это приводит к созданию объекта 'q' в невыровненной позиции, что приводит к сбою программы с утверждением о невыровненных массивах. До сих пор мы нашли три следующих решения.
Местное решение
Местным решением является пометка такой функции этим атрибутом:
__attribute__((force_align_arg_pointer)) void foo() { Eigen::Quaternionf q; //... }
Прочитайте эту документацию GCC, чтобы понять, что это делает. Конечно, это следует делать только для GCC на Windows, поэтому для обеспечения переносимости вам придётся заключить это в макрос, который останется пустым на других платформах. Преимущество этого решения заключается в том, что вы можете точно выбрать, какие функции могут иметь нарушенное выравнивание стека. Конечно, с другой стороны, это необходимо делать для каждой такой функции, поэтому вы можете предпочесть одно из следующих двух глобальных решений.
Глобальные решения
Глобальным решением является редактирование проекта таким образом, чтобы при компиляции с GCC на Windows вы передавали этот параметр GCC:
-mincoming-stack-boundary=2
Объяснение: это сообщает GCC, что выравнивание стека требуется только на 22=4 байта, чтобы GCC теперь знал, что он действительно должен позаботиться о соблюдении 16-байтового выравнивания типов Eigen с фиксированным размером и возможности векторизации при необходимости.
Другим глобальным решением является передача этого параметра gcc:
-mstackrealign
что имеет тот же эффект, что и добавление атрибута force_align_arg_pointer ко всем функциям.
Эти глобальные решения просты в использовании, но обратите внимание, что они могут замедлить вашу программу, потому что они приводят к дополнительным инструкциям пролога/эпилога для каждой функции.
© Eigen.
Licensed under the MPL2 License.
https://eigen.tuxfamily.org/dox/group__TopicWrongStackAlignment.html