Перейти к содержанию
    

GCC arm-none-eabi обращения к невыровненным данным

50 minutes ago, Сергей Борщ said:

Явные приведения типов никто не отменял. operator T() вполне позволяет неявно приводить к целому, над которым все эти операции определены ("я так думаю!"). И ругань идет не на мой класс, а на ваши макросы. Что они делают - мне, на первый взгляд, не совсем понятно, но вот этот ужасный WORDn(x,n) я бы записал так:

 

Макросы тоже не мои. Это выхлоп декомпилятора Hex-rays от IDA Pro.  Декомпилятор порождает псевдо-код : он очень похож на Си, но чтоб его запустить, нужно многое пофиксить.

Оригинальные макросы были такие - они нарушали правило строгого алиасинга и не учитывали доступ к невыровненным данным:

#define BYTEn(x, n)   (*((u8*)&(x)+n))
#define WORDn(x, n)   (*((u16*)&(x)+n))
#define DWORDn(x, n)  (*((u32*)&(x)+n))

 

После как объявил тип с перегрузками, исправил на такие:

#define BYTEn(x, n)  (*(UA<u8 >*)( (u8* )&(x)+(n) ))
#define WORDn(x, n)  (*(UA<u16>*)( (u16*)&(x)+(n) ))
#define DWORDn(x,n)  (*(UA<u32>*)( (u32*)&(x)+(n) ))

 

Стало уже веселее.  Можно даже делать операции, наподобие:

BYTEn(x,1)++;

--BYTEn(x,1);

BYTEn(x,1)+= BYTEn(y,0);

BYTEn(x,1)>>=4;

BYTEn(y,1)=0;

 

Ну и в финале - обращения к невыровненным данным и операции с ними:

*(UA<int>*)p++;

--*(UA<int>*)p;

*(UA<int>*)p = *(UA<int>*)q ++;

*(UA<int>*)p = 15;

*((UA<int>*)(UA<uintptr_t>)p+1)=2;

 

50 minutes ago, Сергей Борщ said:

А  в целом не игрался бы с приведением в макросах, а сразу исходные vXXX объявлял бы как unaligned<нужный тип>

 

Иногда приходится работать с чужим кодом или с машинными выхлопами.  Вручную править такое - руки отсохнут.  Вот и приходится искать системные подходы.

Претензий к вашему варианту не имею.  Изначально, я полагал, что в GCC и в TI CC есть специальные директивы, допускающие объявления указателей на невыровненные данные.  наподобие как в IAR и Keil.  Оказалось, нет.  Пришлось самостоятельно делать.

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 часов назад, repstosw сказал:

Оригинальные макросы были такие - они нарушали правило строгого алиасинга и не учитывали доступ к невыровненным данным:


#define BYTEn(x, n)   (*((u8*)&(x)+n))
#define WORDn(x, n)   (*((u16*)&(x)+n))
#define DWORDn(x, n)  (*((u32*)&(x)+n))

 

После как объявил тип с перегрузками, исправил на такие:


#define BYTEn(x, n)  (*(UA<u8 >*)( (u8* )&(x)+(n) ))
#define WORDn(x, n)  (*(UA<u16>*)( (u16*)&(x)+(n) ))
#define DWORDn(x,n)  (*(UA<u32>*)( (u32*)&(x)+(n) ))

Но зачем вы оставили приведение к выровненным типам (u8*)? Достаточно было его заменить на (UA<u8>*) и компилятор бы скушал это молча.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 hours ago, Сергей Борщ said:

Но зачем вы оставили приведение к выровненным типам (u8*)? Достаточно было его заменить на (UA<u8>*) и компилятор бы скушал это молча.

 Чтобы были правильно посчитаны смещения +(n).

Есть альтернативный вариант, но с ним код получается больше размером:

#define BYTEn(x, n)  (*(UA<u8 >*)(((uintptr_t)&(x))+ (n)   ))
#define WORDn(x, n)  (*(UA<u16>*)(((uintptr_t)&(x))+((n)*2)))
#define DWORDn(x,n)  (*(UA<u32>*)(((uintptr_t)&(x))+((n)*4)))

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 часов назад, repstosw сказал:

Чтобы были правильно посчитаны смещения +(n).

Но они же и так будут правильно рассчитаны. Они считаются исходя из размера данных, на которые указывает указатель. Что u16 *, что UA<u16>* указывают на 2 байта, и 

#define WORDn(x, n)  ((*(UA<u16>*)&(x))+(n))

будет точно так же смещаться по 2 байта, но поскольку UA<u16>* указывает на невыровненные данные, компилятор не будет ругаться на приведение типа.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 hours ago, Сергей Борщ said:

#define WORDn(x, n)  ((*(UA<u16>*)&(x))+(n))

будет точно так же смещаться по 2 байта, но поскольку UA<u16>* указывает на невыровненные данные, компилятор не будет ругаться на приведение типа.

 

Так не работает, потому что (n) должен входить в состав адреса, не не как добавка к разыменованному значению.

Возможно, вы имели в виду вот так:

#define BYTEn(x, n) *((UA<u8 >*)&(x)+(n))
#define WORDn(x, n) *((UA<u16>*)&(x)+(n))
#define DWORDn(x,n) *((UA<u32>*)&(x)+(n))

 Так работает правильно и без предупреждений.

 

P.S. Проверил на ARM - в обоих случаях код одинаковый по размеру с точностью до байта:

так:

#define BYTEn(x, n)  (*(UA<u8 >*)( (u8* )&(x)+(n) ))

и так:

#define BYTEn(x, n) *((UA<u8 >*)&(x)+(n))

 

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, repstosw сказал:

Возможно, вы имели в виду вот так:

Да, конечно. Запутался в скобках. Поэтому и предлагал шаблонную фунуцию вместо всех трех макросов в самом первом ответе.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В CMSIS есть макросы __UNALIGNED_UINT32_WRITE, __UNALIGNED_UINT16_WRITE, __UNALIGNED_UINT32_READ и __UNALIGNED_UINT16_READ. Можно использовать, это будет компиляторонезависимо. Ну и просто подсмотреть как "взрослые дяди" это делают.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...