Версия для печати темы
Форум разработчиков электроники ELECTRONIX.ru _ Keil _ Переменная по адресу не кратному 4 байт.
Автор: maxntf Sep 12 2018, 15:29
Всем привет, наткнулся на такой баг - объявил буфер в глобальных переменных.
Передаю его адрес в аргументе функции. И когда обращаюсь в функции к этой переменной через указатель сразу вылетаю в HardFault_Handler.
Пол дня парился, и в конце концов выяснил, что линковщик расположил ее по адресу не кратному 4.
Проверил, действительно если передать в функцию указатель не кратный 4, то при чтении по этому адресу вылетаем в HardFault_Handler.
И теперь не могу добиться, чтоб этот буфер разместился по корректному адресу. Добавляю перед ним или после него новые переменные, адреса смещаются, и у него все равно адрес не корректный.
Что делать?
http://electronix.ru/redirect.php?https://postimg.cc/image/ck5x0raln/
P.S
Keil V5.23.0.0
Автор: Forger Sep 12 2018, 15:33
Цитата(maxntf @ Sep 12 2018, 18:29)
линковщик расположил ее по адресу не кратному 4
Сейчас принято делать так: http://electronix.ru/redirect.php?http://www.keil.com/support/man/docs/armcc/armcc_chr1359124981436.htm
но раньше делали так: http://electronix.ru/redirect.php?http://www.keil.com/support/man/docs/armcc/armcc_chr1359124966304.htm
И укажите версию компилятора.
Keil умеет работать с разными компиляторами, в комплекте к нему нынче идут ДВА встроенных РАЗНЫХ, и даже можно подключить внешний (GNU например)
Автор: Сергей Борщ Sep 12 2018, 15:35
QUOTE (maxntf @ Sep 12 2018, 18:29)
Что делать?
1) Уменьшить картинку, чтобы страница форума не расползалась.
2) Показать объявление этого буфера.
Автор: Kabdim Sep 13 2018, 08:10
Скопировать значение в выравненную переменную с помощью memcpy. Вызвать функцию с этой локальной переменной. (опционально)Скопировать значение назад. Это и есть пуленепробиваемое решение которое работает везде, независимо от типов и версий компиляторов и языка.
Автор: Forger Sep 13 2018, 08:21
Цитата(Kabdim @ Sep 13 2018, 11:10)
Скопировать значение в выравненную переменную с помощью memcpy. Вызвать функцию с этой локальной переменной. (опционально)Скопировать значение назад. Это и есть пуленепробиваемое решение которое работает везде, независимо от типов и версий компиляторов и языка.
Ваш совет - один из лидеров среди самых
вредных и опасных советов
Кстати, memcpy - очень коварный костыль!
Любой компилятор умеет "говорить" о том, какой он и даже "назвать" свою версию.
Ничто не мешает использовать эту информацию в своем коде для учета особенностей разных компиляторов, если есть нужда в поддержки разных компиляторов.
Пример реально пуленепробиваемого решения:
Код
// Arm Compiler v5
#if defined ( __CC_ARM )
#pragma import(__use_no_heap)
#pragma import(__ARM_use_no_argv)
#pragma import(__use_two_region_memory)
// Arm Compiler v6
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
__asm(".global __use_no_heap \n\t");
__asm(".global __ARM_use_no_argv \n\t");
__asm(".global __use_two_region_memory \n\t");
#endif
Автор: maxntf Sep 13 2018, 08:55
Цитата(Forger @ Sep 12 2018, 18:33)
Сейчас принято делать так: http://electronix.ru/redirect.php?http://www.keil.com/support/man/docs/armcc/armcc_chr1359124981436.htm
Спасибо, понял в чем тут дело.
Просто раньше работал только с 8 битными МК, там таких проблем нет.
А у меня получилось, что буфер char - выравнивание у него по одному байту (без атрибута, начинаться может с любого адреса), а в качестве аргумента функции я передаю указатель на этот буфер с приведением типа до uint32.
Автор: ViKo Sep 13 2018, 09:01
union спасает выравнивание при любых компиляторах.
Автор: scifi Sep 13 2018, 09:03
Цитата(Сергей Борщ @ Sep 12 2018, 18:35)
2) Показать объявление этого буфера.
+1.
Сначала надо не костылями подпирать, а разобраться, в чём первопричина проблемы.
Цитата(maxntf @ Sep 13 2018, 11:55)
А у меня получилось, что буфер char - выравнивание у него по одному байту (без атрибута, начинаться может с любого адреса), а в качестве аргумента функции я передаю указатель на этот буфер с приведением типа до uint32.
Это ужасно. Костыль в виде aligned вылечит, но ужас никуда не денется.
Автор: Forger Sep 13 2018, 10:17
Цитата(scifi @ Sep 13 2018, 12:03)
Костыль в виде aligned вылечит, но ужас никуда не денется.
Ну-ну, попробуйте объявить массив для стека какой-нить задачи RTOS, НЕ применив к нему обязательный "костыль" aligned. ...
"Ужас" убирается объявлением вместо банальных байтовых массивов с разношерстными данными ("протокольные" дела) объявлением полноценных структур с полями нужных размеров и названий, даже с применением union, где это нужно.
Чтобы структура была одинакового размера на любых компиляторах, нужен атрибут packed. Это - норма.
После чего в соотв. функцию передается ссылка (&) на структуру (или указатель, если нельзя писать на плюсах).
В этом случае правильный доступ к полям структуры станет головной болью
компилятора, а не кодера.
Вот пример обяявления такой структуры (не самый лучший пример, но тем не менее):
Код
struct __PACKED Frame
{
uint8_t start;
uint8_t command;
uint8_t dataSize;
union
{
uint8_t payload[COMMUNICATION_MAX_FRAME_DATA_SIZE_IN_BYTES];
MasterToSlave masterToSlave;
SlaveToMaster slaveToMaster;
} data;
struct
{
union
{
struct
{
uint8_t low;
uint8_t high;
};
uint16_t value;
};
} crc16;
};
// SlaveToMaster и SlaveToMaster - структуры одинакового размера, но с разными полями
ps. из-за необходимости применения телепатии к стартовому посту эта тема рискует перейти в очередной холивар :D
Автор: Kabdim Sep 13 2018, 14:55
Цитата(Forger @ Sep 13 2018, 11:21)
Ваш совет - один из лидеров среди самых
вредных и опасных советов
Кстати, memcpy - очень коварный костыль!
Пруфов, я так понимаю, дождаться нереально?
Цитата(Forger @ Sep 13 2018, 11:21)
Пример реально пуленепробиваемого решения:
Гы!
Автор: Forger Sep 13 2018, 15:15
Цитата(Kabdim @ Sep 13 2018, 17:55)
Пруфов, я так понимаю, дождаться нереально?
Вы правы - это бесполезный пруф из разряда: почему нужно мыть руки перед едой или чистить зубы. Это знают даже дети
Во многих уважающих себя конторах это "наследие" вообще http://electronix.ru/redirect.php?https://unspecified.wordpress.com/2009/05/16/microsoft-bans-memcpy/.
Хотя в примитивном коде, который ни за что не отвечает или служит чисто образовательным целям (ардуины), memcpy в целом беды не несет, разве что кроме впустую потраченных нервов и времени
Автор: scifi Sep 14 2018, 06:40
Цитата(Forger @ Sep 13 2018, 13:17)
Ну-ну, попробуйте объявить массив для стека какой-нить задачи RTOS, НЕ применив к нему обязательный "костыль" aligned. ...
Скажем, lwip делает это легко и непринуждённо. Нужно выравнивать по 4 байта? Прибавь к размеру массива 3 байта, а указатель отрихтуй до ровного.
Автор: Forger Sep 14 2018, 07:47
Цитата(scifi @ Sep 14 2018, 09:40)
Скажем, lwip делает это легко и непринуждённо.
Не пойму, при чем тут lwip?
Ядро ARM требуют выравнивание стеков по границе 8 байт, иначе вылетаем в HF.
Не вижу никакой сложности использовать
встроенное расширение компилятора, которое полностью устраняет эту "проблему".
Тем более компилятор v6 от ARM практически полностью поддерживает расширения GCC (в отличие от v5, который в целом устарел и поэтому лишь частично умеет это делать).
Цитата
Нужно выравнивать по 4 байта? Прибавь к размеру массива 3 байта, а указатель отрихтуй до ровного.
Соревнуетесь с Kabdim по вредности "советов"?
Автор: Kabdim Sep 14 2018, 08:56
Цитата(Forger @ Sep 13 2018, 18:15)
Вы правы - это бесполезный пруф из разряда: почему нужно мыть руки перед едой или чистить зубы. Это знают даже дети
Потому что пруфы для мытья рук есть и если не заниматься демагогией их несложно найти.
Цитата(Forger @ Sep 13 2018, 18:15)
Во многих уважающих себя конторах это "наследие" вообще http://electronix.ru/redirect.php?https://unspecified.wordpress.com/2009/05/16/microsoft-bans-memcpy/.
И видимо что бы запретить совсем уж всю идею копирования памяти в другое место они придумали memcpy_s...
Цитата(Forger @ Sep 13 2018, 18:15)
Хотя в примитивном коде, который ни за что не отвечает или служит чисто образовательным целям (ардуины), memcpy в целом беды не несет, разве что кроме впустую потраченных нервов и времени
Ну и к чему эти намеки, если вдруг вы не догадывались, то с Ардуиной я никогда не работал и к образованию кого-либо отношения не имею. Вы мешаете в один чан два разных применения. С буферами переменной длинны где для использования memcpy нужно много проверок и всё зло от того что индусы о ни забывают, а их отсутствие не обеспечивает падение сразу. А с другой стороны копирование переменной фиксированной длинны, где единственная задача убедится что на входе есть данные нужного размера. Если вы тратите на второй вариант использования memcpy нервы и время, могу только посочувствовать.
Цитата(Forger @ Sep 14 2018, 10:47)
Соревнуетесь с Kabdim по вредности "советов"?
Не переживайте, в этом вопросе вы непревзойденный идеал.
Автор: aaarrr Sep 14 2018, 09:04
Цитата(Kabdim @ Sep 14 2018, 11:56)
Потому что пруфы для мытья рук есть и если не заниматься демагогией их несложно найти.
http://electronix.ru/redirect.php?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3934.html. Нельзя вызывать memcpy абы как.
Ну и http://electronix.ru/redirect.php?https://electronix.ru/forum/index.php?showtopic=148387&st=0 - memcpy спасает мир
Автор: Forger Sep 14 2018, 09:15
Цитата(Kabdim @ Sep 14 2018, 11:56)
Не переживайте
Я-то как раз и не переживаю, поскольку использую то, что дает компилятор, как это указано в мануале на компилятор.
По мне - пусть проблемы размещения объектов решает тот, кто их обязан решать - компилятор с линкером. Для этого они и созданы. Иначе писал бы на ассемблере.
Достаточно лишь разумно использовать
встроенные штатные инструменты, вместо того, чтобы заниматься "самодеятельностью".
Впрочем, тут каждый сам решает: бороться с "ветряной мельницей" или обойти ее стороной, не связываясь
Цитата
Ну и к чему эти намеки...
Не стоить лукавать, вы все прекрасно поняли - ведь вон как активно оправдываетесь
Автор: Kabdim Sep 14 2018, 09:59
Цитата(aaarrr @ Sep 14 2018, 12:04)
http://electronix.ru/redirect.php?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3934.html. Нельзя вызывать memcpy абы как.
Ну вообще там говорится что оптимизатор верят в то что программист знает язык, на котором программирует, не более того. Рекомендаций по неиспользованию memcpy там не дается.
Цитата(Forger @ Sep 14 2018, 12:15)
Не стоить лукавать, вы все прекрасно поняли - ведь вон как активно оправдываетесь
Ох уж эти школьные подколки.
Автор: Forger Sep 14 2018, 10:14
Цитата(Kabdim @ Sep 14 2018, 12:59)
Ох уж эти школьные подколки.
Все верно: для каждого случая - "подколка" соответствующего "уровня сложности"
Автор: aaarrr Sep 14 2018, 10:20
Цитата(Kabdim @ Sep 14 2018, 12:59)
Ну вообще там говорится что оптимизатор верят в то что программист знает язык, на котором программирует, не более того.
Где же это там такое говорится?
Автор: Kabdim Sep 14 2018, 10:27
Цитата(aaarrr @ Sep 14 2018, 13:20)
Где же это там такое говорится?
Расписывание про натруальное выравнивание и использование его в оптимизации оно и есть кмк.
Автор: aaarrr Sep 14 2018, 10:32
Цитата(Kabdim @ Sep 14 2018, 13:27)
Расписывание про натруальное выравнивание и использование его в оптимизации оно и есть кмк.
В данном случае это как раз отклонение от стандарта - у библиотечной memcpy нет ограничений по выравниванию.
Автор: Kabdim Sep 14 2018, 11:27
Цитата(aaarrr @ Sep 14 2018, 13:32)
В данном случае это как раз отклонение от стандарта - у библиотечной memcpy нет ограничений по выравниванию.
Нет тут никакого отклонения от стандарта. Считается что в невыровненной памяти не может быть объекта, а значит компилятор имеет право рассчитывать что указатель указывает на выровненную память и соответственно оптимизировать. Для того что бы memcpy принимал невыравненный буфер, достаточно самому не стрелять себе в ногу , т.е. не делать ненужные преобразования из типа элемента буфера в тип требующий более строгого выравнивания.
Автор: aaarrr Sep 14 2018, 11:35
Цитата(Kabdim @ Sep 14 2018, 14:27)
Нет тут никакого отклонения от стандарта. Считается что в невыровненной памяти не может быть объекта...
Каким типом данных по стандарту оперирует memcpy?
Автор: Kabdim Sep 14 2018, 11:40
Цитата(aaarrr @ Sep 14 2018, 14:35)
Каким типом данных по стандарту оперирует memcpy?
В данном случае это не имеет значения. В вашей программе появился указатель на (условно)int - он уже считается выровненным, а если он не выравнен, то ваша программа уже ill-formed и всё что происходит после этого факта уже не важно.
Автор: aaarrr Sep 14 2018, 11:51
Цитата(Kabdim @ Sep 14 2018, 14:40)
В данном случае это не имеет значения.
Имеет. memcpy() принимает на вход указатель типа void и оперирует типом char. Очевидно, что ограничений на выравнивание тут нет.
И происхождение указателя на поведение функции влиять не должно.
Автор: scifi Sep 14 2018, 12:03
Цитата(aaarrr @ Sep 14 2018, 14:35)
Каким типом данных по стандарту оперирует memcpy?
Так неинтересно. Для начала приведите пример, в котором вот эта лихая оптимизация memcpy приводит к сбою, а я приведу цитату из стандарта, которая пояснит, почему в примере содержится косяк.
Автор: aaarrr Sep 14 2018, 12:08
Цитата(scifi @ Sep 14 2018, 15:03)
Так неинтересно. Для начала приведите пример, в котором вот эта лихая оптимизация memcpy приводит к сбою, а я приведу цитату из стандарта, которая пояснит, почему в примере содержится косяк.
Пожалуйста, пример по ссылке в http://electronix.ru/redirect.php?https://electronix.ru/forum/index.php?s=&showtopic=148695&view=findpost&p=1582752.
Автор: scifi Sep 14 2018, 12:17
Цитата(aaarrr @ Sep 14 2018, 15:08)
Пожалуйста, пример по ссылке в http://electronix.ru/redirect.php?https://electronix.ru/forum/index.php?s=&showtopic=148695&view=findpost&p=1582752.
Вот это что ли?
Код
#include <string.h>
unsigned int * const dest;
void example (unsigned int * const unaligned_ptr)
{
__packed unsigned int * packed_ptr = unaligned_ptr;
char * temp_ptr = (char *)unaligned_ptr;
memcpy(dest, unaligned_ptr, 32); /* Unsafe */
memcpy(dest, (void *)packed_ptr, 32); /* Safe */
memcpy(dest, temp_ptr, 32); /* Safe */
}
Пожалуйста:
Цитата
A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined.
То есть где-то привели указатель на что-то (да хотя бы на char) к типу указатель на unsigned int, выравнивание не было соблюдено - бац! неопределённое поведение. А как вы хотели?
Автор: aaarrr Sep 14 2018, 13:00
del - Извиняюсь, кривой пример получился
Нет, все же правильный:
Код
unsigned int dst[4];
int main(void)
{
memcpy(dst, (void *)123, 8);
}
; generated by ARM C/C++ Compiler, 4.1 [Build 462]
; commandline armcc [--debug -c --asm -omain.o --cpu=Cortex-A8 --fpu=VFPv3 --diag_style=ide --depend_format=unix_escaped --no_depend_system_headers ..\main.c]
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
main PROC
MOV r1,#0x7b
LDR r0,|L1.24|
VLD1.64 {d0},[r1]
VST1.64 {d0},[r0]
MOV r0,#0
BX lr
ENDP
Автор: Kabdim Sep 14 2018, 13:18
Всё тоже самое нарушено, но на А8 оно по идее работает? И на х86 не выравненные обращения работают. Программы с ЮБ иногда работают так как задумал создатель, в этом и есть смысл ЮБ - никаких гарантий, даже гарантий неработоспособности. Конкретно тут наверняка страдает производительность.
Автор: aaarrr Sep 14 2018, 13:23
Цитата(Kabdim @ Sep 14 2018, 16:18)
Всё тоже самое нарушено, но на А8 оно по идее работает?
Нет, я привожу 123 к типу void * - тут все корректно.
Падает в fault, что и требовалось.
Автор: Kabdim Sep 14 2018, 13:36
С А8 может выйти гадание на кисиле, сложный чип, много деталей которые могут повлиять. В норме он разрешает невыравненный доступ и этим пользуется компилятор. Но так будет даже веселей, первое предположение: используете ММУ и у вас в районе нулевого адреса область памяти с нестандартными правами доступа?
Этот пример кстати с операционкой? Если да, то с какой?
У меня нет по рукой А8, проверьте вот такой вариант, пожалуйста:
Код
unsigned int dst[4];
char src[16];
int main(void)
{
memcpy(dst, (int*)(&src[1]), 8);
}
Автор: aaarrr Sep 14 2018, 13:59
Нет, все же плохой пример. Но и за компилятором есть грех - он предполагает, что невыровненный доступ разрешен, хотя это не обязательно так.
Для выровненного источника код такой:
Код
; generated by ARM C/C++ Compiler, 4.1 [Build 462]
; commandline armcc [--debug -c --asm -omain.o --cpu=Cortex-A8 --fpu=VFPv3 --diag_style=ide --depend_format=unix_escaped --no_depend_system_headers ..\main.c]
ARM
REQUIRE8
PRESERVE8
AREA ||.text||, CODE, READONLY, ALIGN=2
main PROC
LDR r0,|L1.24|
ADD r1,r0,#0x11
LDM r1,{r1,r2}
STM r0,{r1,r2}
MOV r0,#0
BX lr
ENDP
Автор: Kabdim Sep 14 2018, 14:02
И как падает или нет?
Автор: aaarrr Sep 14 2018, 15:10
Цитата(Kabdim @ Sep 14 2018, 17:02)
И как падает или нет?
Ваш пример? Падает.
Извиняюсь за задержку, хотел все проверить. На Cortex-A8 невыровненный доступ возможен только
при включенном MMU, а в тесте у меня он не был задействован.
Автор: Kabdim Sep 16 2018, 09:27
Получается вы без линукса А8 готовите? Довольно редкий кейс, компилятор (и я ) естественно такого не ожидает. Вы как @мантех только регистры или что-то стороннее реалтаймовое используете?
Цитата(aaarrr @ Sep 14 2018, 16:59)
Но и за компилятором есть грех - он предполагает, что невыровненный доступ разрешен, хотя это не обязательно так.
Выбор у него небогатый. Если не считать выравнивание и другие наиболее применимые найстройки нормой, то в других 99% случаев не получится сделать оптимизации. Именно поэтому все нестандартные вопросы с выравниванием и со всем остальными нюансами железа С/++ скинули на программиста. Хотя в 99% случаев об этом позволительно не думать. Но задача сериализации это тот самый 1%, в котором знать язык и железо нужно чуть лучше чем в среднем.
Автор: aaarrr Sep 16 2018, 11:03
Цитата(Kabdim @ Sep 16 2018, 12:27)
Получается вы без линукса А8 готовите? Довольно редкий кейс, компилятор (и я
) естественно такого не ожидает. Вы как @мантех только регистры или что-то стороннее реалтаймовое используете?
Нет, это просто пример. Готовлю под Linux, но драйверы и загрузчики ведь тоже приходится пилить.
Цитата(Kabdim @ Sep 16 2018, 12:27)
Выбор у него небогатый. Если не считать выравнивание и другие наиболее применимые найстройки нормой, то в других 99% случаев не получится сделать оптимизации.
Беда в том, что это не отключается. А со стороны языка пример вполне корректный, тут надо именно приколы компилятора знать.
Автор: Kabdim Sep 16 2018, 13:34
Я бы скорее странным назвал решение АРМ сделавшей невыравненное чтение/запись только при использовании MMU. Хотя и у них наверняка были свои резоны.
Автор: aaarrr Sep 16 2018, 13:35
Цитата(Kabdim @ Sep 16 2018, 16:34)
Я бы скорее странным назвал решение АРМ сделавшей невыравненное чтение/запись только при использовании MMU. Хотя и у них наверняка были свои резоны.
Это в любом случае решение ARM, т.к. компилятор тоже их.
Автор: Kabdim Sep 16 2018, 13:41
Afaik там clang и если много приходится писать без MMU наверное имеет смысл сделать форк, в котором отключить это умолчание.
Автор: aaarrr Sep 16 2018, 13:51
Цитата(Kabdim @ Sep 16 2018, 16:41)
Afaik там clang
Вы что-то путаете: armcc существовал задолго до clang'а и проприетарен до мозга костей.
Автор: Kabdim Sep 16 2018, 14:01
Они ж его вроде бросили, с 5 что ли версии, если мне изменяет память.
Автор: aaarrr Sep 16 2018, 14:10
Тут не скажу - это четвертый, а дальше я его судьбой не интересовался. Жаль, если бросили.
Автор: Forger Sep 16 2018, 14:28
Цитата(aaarrr @ Sep 16 2018, 17:10)
Жаль, если бросили.
Вроде как полностью http://electronix.ru/redirect.php?https://developer.arm.com/products/software-development-tools/compilers/arm-compiler/downloads/version-6
http://electronix.ru/redirect.php?https://developer.arm.com/products/software-development-tools/compilers/arm-compiler/downloads/version-5, но не обновлялся практически год. Вангую, что скоро он перейдет в разряд т.н. "legacy" ...
Мне как однажды пришлось перейти с 5го на 6й, но освоил, привык к полноценному C++11 (в 5й версии он несколько порезанный), и потому обратно уже не хочется
Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)