Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Переменная по адресу не кратному 4 байт.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > Keil
maxntf
Всем привет, наткнулся на такой баг - объявил буфер в глобальных переменных.
Передаю его адрес в аргументе функции. И когда обращаюсь в функции к этой переменной через указатель сразу вылетаю в HardFault_Handler.
Пол дня парился, и в конце концов выяснил, что линковщик расположил ее по адресу не кратному 4.
Проверил, действительно если передать в функцию указатель не кратный 4, то при чтении по этому адресу вылетаем в HardFault_Handler.
И теперь не могу добиться, чтоб этот буфер разместился по корректному адресу. Добавляю перед ним или после него новые переменные, адреса смещаются, и у него все равно адрес не корректный.
Что делать?


P.S
Keil V5.23.0.0

Forger
Цитата(maxntf @ Sep 12 2018, 18:29) *
линковщик расположил ее по адресу не кратному 4


Сейчас принято делать так: http://www.keil.com/support/man/docs/armcc...59124981436.htm
но раньше делали так: http://www.keil.com/support/man/docs/armcc...59124966304.htm

И укажите версию компилятора.
Keil умеет работать с разными компиляторами, в комплекте к нему нынче идут ДВА встроенных РАЗНЫХ, и даже можно подключить внешний (GNU например)
Сергей Борщ
QUOTE (maxntf @ Sep 12 2018, 18:29) *
Что делать?

1) Уменьшить картинку, чтобы страница форума не расползалась.
2) Показать объявление этого буфера.
Kabdim
Скопировать значение в выравненную переменную с помощью memcpy. Вызвать функцию с этой локальной переменной. (опционально)Скопировать значение назад. Это и есть пуленепробиваемое решение которое работает везде, независимо от типов и версий компиляторов и языка.
Forger
Цитата(Kabdim @ Sep 13 2018, 11:10) *
Скопировать значение в выравненную переменную с помощью memcpy. Вызвать функцию с этой локальной переменной. (опционально)Скопировать значение назад. Это и есть пуленепробиваемое решение которое работает везде, независимо от типов и версий компиляторов и языка.

Ваш совет - один из лидеров среди самых вредных и опасных советов cranky.gif
Кстати, 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
Цитата(Forger @ Sep 12 2018, 18:33) *
Сейчас принято делать так: http://www.keil.com/support/man/docs/armcc...59124981436.htm

Спасибо, понял в чем тут дело.
Просто раньше работал только с 8 битными МК, там таких проблем нет.

А у меня получилось, что буфер char - выравнивание у него по одному байту (без атрибута, начинаться может с любого адреса), а в качестве аргумента функции я передаю указатель на этот буфер с приведением типа до uint32.
ViKo
union спасает выравнивание при любых компиляторах.
scifi
Цитата(Сергей Борщ @ Sep 12 2018, 18:35) *
2) Показать объявление этого буфера.

+1.
Сначала надо не костылями подпирать, а разобраться, в чём первопричина проблемы.

Цитата(maxntf @ Sep 13 2018, 11:55) *
А у меня получилось, что буфер char - выравнивание у него по одному байту (без атрибута, начинаться может с любого адреса), а в качестве аргумента функции я передаю указатель на этот буфер с приведением типа до uint32.

Это ужасно. Костыль в виде aligned вылечит, но ужас никуда не денется.
Forger
Цитата(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
Цитата(Forger @ Sep 13 2018, 11:21) *
Ваш совет - один из лидеров среди самых вредных и опасных советов cranky.gif
Кстати, memcpy - очень коварный костыль!

Пруфов, я так понимаю, дождаться нереально?
Цитата(Forger @ Sep 13 2018, 11:21) *
Пример реально пуленепробиваемого решения:

Гы! biggrin.gif
Forger
Цитата(Kabdim @ Sep 13 2018, 17:55) *
Пруфов, я так понимаю, дождаться нереально?

Вы правы - это бесполезный пруф из разряда: почему нужно мыть руки перед едой или чистить зубы. Это знают даже дети biggrin.gif
Во многих уважающих себя конторах это "наследие" вообще давно запрещено к применению.
Хотя в примитивном коде, который ни за что не отвечает или служит чисто образовательным целям (ардуины), memcpy в целом беды не несет, разве что кроме впустую потраченных нервов и времени smile3046.gif
scifi
Цитата(Forger @ Sep 13 2018, 13:17) *
Ну-ну, попробуйте объявить массив для стека какой-нить задачи RTOS, НЕ применив к нему обязательный "костыль" aligned. ...

Скажем, lwip делает это легко и непринуждённо. Нужно выравнивать по 4 байта? Прибавь к размеру массива 3 байта, а указатель отрихтуй до ровного.
Forger
Цитата(scifi @ Sep 14 2018, 09:40) *
Скажем, lwip делает это легко и непринуждённо.

Не пойму, при чем тут lwip?
Ядро ARM требуют выравнивание стеков по границе 8 байт, иначе вылетаем в HF.

Не вижу никакой сложности использовать встроенное расширение компилятора, которое полностью устраняет эту "проблему".
Тем более компилятор v6 от ARM практически полностью поддерживает расширения GCC (в отличие от v5, который в целом устарел и поэтому лишь частично умеет это делать).

Цитата
Нужно выравнивать по 4 байта? Прибавь к размеру массива 3 байта, а указатель отрихтуй до ровного.

Соревнуетесь с Kabdim по вредности "советов"? wink.gif
Kabdim
Цитата(Forger @ Sep 13 2018, 18:15) *
Вы правы - это бесполезный пруф из разряда: почему нужно мыть руки перед едой или чистить зубы. Это знают даже дети biggrin.gif

Потому что пруфы для мытья рук есть и если не заниматься демагогией их несложно найти.
Цитата(Forger @ Sep 13 2018, 18:15) *
Во многих уважающих себя конторах это "наследие" вообще давно запрещено к применению.

И видимо что бы запретить совсем уж всю идею копирования памяти в другое место они придумали memcpy_s... biggrin.gif
Цитата(Forger @ Sep 13 2018, 18:15) *
Хотя в примитивном коде, который ни за что не отвечает или служит чисто образовательным целям (ардуины), memcpy в целом беды не несет, разве что кроме впустую потраченных нервов и времени smile3046.gif

Ну и к чему эти намеки, если вдруг вы не догадывались, то с Ардуиной я никогда не работал и к образованию кого-либо отношения не имею. Вы мешаете в один чан два разных применения. С буферами переменной длинны где для использования memcpy нужно много проверок и всё зло от того что индусы о ни забывают, а их отсутствие не обеспечивает падение сразу. А с другой стороны копирование переменной фиксированной длинны, где единственная задача убедится что на входе есть данные нужного размера. Если вы тратите на второй вариант использования memcpy нервы и время, могу только посочувствовать.
Цитата(Forger @ Sep 14 2018, 10:47) *
Соревнуетесь с Kabdim по вредности "советов"? wink.gif

Не переживайте, в этом вопросе вы непревзойденный идеал. biggrin.gif
aaarrr
Цитата(Kabdim @ Sep 14 2018, 11:56) *
Потому что пруфы для мытья рук есть и если не заниматься демагогией их несложно найти.

Пруф. Нельзя вызывать memcpy абы как.

Ну и обратный пруф - memcpy спасает мир biggrin.gif
Forger
Цитата(Kabdim @ Sep 14 2018, 11:56) *
Не переживайте

Я-то как раз и не переживаю, поскольку использую то, что дает компилятор, как это указано в мануале на компилятор.
По мне - пусть проблемы размещения объектов решает тот, кто их обязан решать - компилятор с линкером. Для этого они и созданы. Иначе писал бы на ассемблере.
Достаточно лишь разумно использовать встроенные штатные инструменты, вместо того, чтобы заниматься "самодеятельностью".
Впрочем, тут каждый сам решает: бороться с "ветряной мельницей" или обойти ее стороной, не связываясь wink.gif

Цитата
Ну и к чему эти намеки...
Не стоить лукавать, вы все прекрасно поняли - ведь вон как активно оправдываетесь sm.gif
Kabdim
Цитата(aaarrr @ Sep 14 2018, 12:04) *
Пруф. Нельзя вызывать memcpy абы как.

Ну вообще там говорится что оптимизатор верят в то что программист знает язык, на котором программирует, не более того. Рекомендаций по неиспользованию memcpy там не дается.
Цитата(Forger @ Sep 14 2018, 12:15) *
Не стоить лукавать, вы все прекрасно поняли - ведь вон как активно оправдываетесь sm.gif

Ох уж эти школьные подколки.
Forger
Цитата(Kabdim @ Sep 14 2018, 12:59) *
Ох уж эти школьные подколки.
Все верно: для каждого случая - "подколка" соответствующего "уровня сложности" wink.gif
aaarrr
Цитата(Kabdim @ Sep 14 2018, 12:59) *
Ну вообще там говорится что оптимизатор верят в то что программист знает язык, на котором программирует, не более того.

Где же это там такое говорится?
Kabdim
Цитата(aaarrr @ Sep 14 2018, 13:20) *
Где же это там такое говорится?

Расписывание про натруальное выравнивание и использование его в оптимизации оно и есть кмк.
aaarrr
Цитата(Kabdim @ Sep 14 2018, 13:27) *
Расписывание про натруальное выравнивание и использование его в оптимизации оно и есть кмк.

В данном случае это как раз отклонение от стандарта - у библиотечной memcpy нет ограничений по выравниванию.
Kabdim
Цитата(aaarrr @ Sep 14 2018, 13:32) *
В данном случае это как раз отклонение от стандарта - у библиотечной memcpy нет ограничений по выравниванию.

Нет тут никакого отклонения от стандарта. Считается что в невыровненной памяти не может быть объекта, а значит компилятор имеет право рассчитывать что указатель указывает на выровненную память и соответственно оптимизировать. Для того что бы memcpy принимал невыравненный буфер, достаточно самому не стрелять себе в ногу , т.е. не делать ненужные преобразования из типа элемента буфера в тип требующий более строгого выравнивания.
aaarrr
Цитата(Kabdim @ Sep 14 2018, 14:27) *
Нет тут никакого отклонения от стандарта. Считается что в невыровненной памяти не может быть объекта...

Каким типом данных по стандарту оперирует memcpy?
Kabdim
Цитата(aaarrr @ Sep 14 2018, 14:35) *
Каким типом данных по стандарту оперирует memcpy?

В данном случае это не имеет значения. В вашей программе появился указатель на (условно)int - он уже считается выровненным, а если он не выравнен, то ваша программа уже ill-formed и всё что происходит после этого факта уже не важно.
aaarrr
Цитата(Kabdim @ Sep 14 2018, 14:40) *
В данном случае это не имеет значения.

Имеет. memcpy() принимает на вход указатель типа void и оперирует типом char. Очевидно, что ограничений на выравнивание тут нет.
И происхождение указателя на поведение функции влиять не должно.
scifi
Цитата(aaarrr @ Sep 14 2018, 14:35) *
Каким типом данных по стандарту оперирует memcpy?

Так неинтересно. Для начала приведите пример, в котором вот эта лихая оптимизация memcpy приводит к сбою, а я приведу цитату из стандарта, которая пояснит, почему в примере содержится косяк.
aaarrr
Цитата(scifi @ Sep 14 2018, 15:03) *
Так неинтересно. Для начала приведите пример, в котором вот эта лихая оптимизация memcpy приводит к сбою, а я приведу цитату из стандарта, которая пояснит, почему в примере содержится косяк.

Пожалуйста, пример по ссылке в сообщении #15.
scifi
Цитата(aaarrr @ Sep 14 2018, 15:08) *
Пожалуйста, пример по ссылке в сообщении #15.

Вот это что ли?
Код
#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
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
Всё тоже самое нарушено, но на А8 оно по идее работает? И на х86 не выравненные обращения работают. Программы с ЮБ иногда работают так как задумал создатель, в этом и есть смысл ЮБ - никаких гарантий, даже гарантий неработоспособности. Конкретно тут наверняка страдает производительность.
aaarrr
Цитата(Kabdim @ Sep 14 2018, 16:18) *
Всё тоже самое нарушено, но на А8 оно по идее работает?

Нет, я привожу 123 к типу void * - тут все корректно.

Падает в fault, что и требовалось.
Kabdim
С А8 может выйти гадание на кисиле, сложный чип, много деталей которые могут повлиять. В норме он разрешает невыравненный доступ и этим пользуется компилятор. Но так будет даже веселей, первое предположение: используете ММУ и у вас в районе нулевого адреса область памяти с нестандартными правами доступа?
Этот пример кстати с операционкой? Если да, то с какой?

У меня нет по рукой А8, проверьте вот такой вариант, пожалуйста:
Код
unsigned int dst[4];
char src[16];
  
  int main(void)
  {
      memcpy(dst, (int*)(&src[1]), 8);
  }
aaarrr
Нет, все же плохой пример. Но и за компилятором есть грех - он предполагает, что невыровненный доступ разрешен, хотя это не обязательно так.

Для выровненного источника код такой:
Код
; 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
И как падает или нет?
aaarrr
Цитата(Kabdim @ Sep 14 2018, 17:02) *
И как падает или нет?

Ваш пример? Падает.

Извиняюсь за задержку, хотел все проверить. На Cortex-A8 невыровненный доступ возможен только
при включенном MMU, а в тесте у меня он не был задействован.
Kabdim
Получается вы без линукса А8 готовите? Довольно редкий кейс, компилятор (и я rolleyes.gif ) естественно такого не ожидает. Вы как @мантех только регистры или что-то стороннее реалтаймовое используете?
Цитата(aaarrr @ Sep 14 2018, 16:59) *
Но и за компилятором есть грех - он предполагает, что невыровненный доступ разрешен, хотя это не обязательно так.

Выбор у него небогатый. Если не считать выравнивание и другие наиболее применимые найстройки нормой, то в других 99% случаев не получится сделать оптимизации. Именно поэтому все нестандартные вопросы с выравниванием и со всем остальными нюансами железа С/++ скинули на программиста. Хотя в 99% случаев об этом позволительно не думать. Но задача сериализации это тот самый 1%, в котором знать язык и железо нужно чуть лучше чем в среднем.
aaarrr
Цитата(Kabdim @ Sep 16 2018, 12:27) *
Получается вы без линукса А8 готовите? Довольно редкий кейс, компилятор (и я rolleyes.gif ) естественно такого не ожидает. Вы как @мантех только регистры или что-то стороннее реалтаймовое используете?

Нет, это просто пример. Готовлю под Linux, но драйверы и загрузчики ведь тоже приходится пилить.

Цитата(Kabdim @ Sep 16 2018, 12:27) *
Выбор у него небогатый. Если не считать выравнивание и другие наиболее применимые найстройки нормой, то в других 99% случаев не получится сделать оптимизации.

Беда в том, что это не отключается. А со стороны языка пример вполне корректный, тут надо именно приколы компилятора знать.
Kabdim
Я бы скорее странным назвал решение АРМ сделавшей невыравненное чтение/запись только при использовании MMU. Хотя и у них наверняка были свои резоны.
aaarrr
Цитата(Kabdim @ Sep 16 2018, 16:34) *
Я бы скорее странным назвал решение АРМ сделавшей невыравненное чтение/запись только при использовании MMU. Хотя и у них наверняка были свои резоны.

Это в любом случае решение ARM, т.к. компилятор тоже их.
Kabdim
Afaik там clang и если много приходится писать без MMU наверное имеет смысл сделать форк, в котором отключить это умолчание.
aaarrr
Цитата(Kabdim @ Sep 16 2018, 16:41) *
Afaik там clang

Вы что-то путаете: armcc существовал задолго до clang'а и проприетарен до мозга костей.
Kabdim
Они ж его вроде бросили, с 5 что ли версии, если мне изменяет память.
aaarrr
Тут не скажу - это четвертый, а дальше я его судьбой не интересовался. Жаль, если бросили.
Forger
Цитата(aaarrr @ Sep 16 2018, 17:10) *
Жаль, если бросили.

Вроде как полностью переключились на 6й
5й пока еще поддерживается, но не обновлялся практически год. Вангую, что скоро он перейдет в разряд т.н. "legacy" ...

Мне как однажды пришлось перейти с 5го на 6й, но освоил, привык к полноценному C++11 (в 5й версии он несколько порезанный), и потому обратно уже не хочется sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.