Назначение структуры в Linux терпит неудачу в ARM, но успешно в x86

Я заметил кое-что действительно странное. скажем, у меня определена следующая структура

typedef struct
{
  uint32_t a;
  uint16_t b;
  uint32_t c;
} foo;

Эта структура содержится в большом буфере, который я получаю из сети.

Следующий код работает в x86, но я получаю SIGBUS на ARM.

extern void * buffer;
foo my_foo;
my_foo = (( foo * ) buffer)[0];

замена разыменования указателя на memcpy решила проблему.

Поиск по SIGBUS в ARM показал мне, что это связано с выравниванием памяти.

Может кто-нибудь объяснить, что происходит?

4 ответа

Решение

Вы сами сказали: существуют ограничения на выравнивание памяти для вашего конкретного процессора, и buffer не выровнен вправо, чтобы разрешить чтение больше, чем байт от него. Задание, вероятно, скомпилировано в три хода более крупных объектов.

С memcpy()нет ограничений на выравнивание, он должен иметь возможность копировать между любыми двумя адресами, поэтому он делает все, что нужно для реализации этого. Вероятно, копирование побайтово, пока адреса не выровнены, это обычная картина.

Кроме того, я считаю более понятным написать ваш код без индексации массива:

extern const void *buffer;
const foo my_foo = *(const foo *) buffer;

Стандарт C [ISO/IEC 9899:2011] - 6.3.2.3, параграф 7:

Указатель на объект или неполный тип может быть преобразован в указатель на другой объект или неполный тип. Если результирующий указатель не правильно выровнен для указанного типа, поведение не определено.

Источник: CERT Стандарты безопасного кодирования

Системы на основе ARM ожидают, что структуры будут выровнены по границе слова. Если это не тот случай, вы можете иметь другое поведение (например, в ядре Linux, это поведение описано в /proc/cpu/alignement и один из них это отправить SIGBUS).

Что вы сделали с memcpy() в том, что вы принудительно выровняли структуру данных.

Я разрабатывал какое-то приложение для загрузки на freescale imx некоторое время назад.... там была проблема с выравниванием памяти (требовалось, чтобы исполняемый файл был кратным 512 байтам)... Принципиальное различие между arm и x86... Но дело в с помощью memcpy помните, что он выполняет побайтовое копирование... Итак, это может сработать, но, пожалуйста, не забудьте проверить наличие проблем во время выполнения... Не надо одурачить memcpy... Всегда хорошая идея иметь память выровненная структура для вашей конкретной платформы.

Другие вопросы по тегам