Jump to content

    

Переменная по адресу не кратному 4 байт.

Всем привет, наткнулся на такой баг - объявил буфер в глобальных переменных.

Передаю его адрес в аргументе функции. И когда обращаюсь в функции к этой переменной через указатель сразу вылетаю в HardFault_Handler.

Пол дня парился, и в конце концов выяснил, что линковщик расположил ее по адресу не кратному 4.

Проверил, действительно если передать в функцию указатель не кратный 4, то при чтении по этому адресу вылетаем в HardFault_Handler.

И теперь не могу добиться, чтоб этот буфер разместился по корректному адресу. Добавляю перед ним или после него новые переменные, адреса смещаются, и у него все равно адрес не корректный.

Что делать?

img.jpg

 

P.S

Keil V5.23.0.0

 

 

Share this post


Link to post
Share on other sites
линковщик расположил ее по адресу не кратному 4

 

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

но раньше делали так: http://www.keil.com/support/man/docs/armcc...59124966304.htm

 

И укажите версию компилятора.

Keil умеет работать с разными компиляторами, в комплекте к нему нынче идут ДВА встроенных РАЗНЫХ, и даже можно подключить внешний (GNU например)

 

Share this post


Link to post
Share on other sites
Что делать?

1) Уменьшить картинку, чтобы страница форума не расползалась.

2) Показать объявление этого буфера.

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
Скопировать значение в выравненную переменную с помощью memcpy. Вызвать функцию с этой локальной переменной. (опционально)Скопировать значение назад. Это и есть пуленепробиваемое решение которое работает везде, независимо от типов и версий компиляторов и языка.

Ваш совет - один из лидеров среди самых вредных и опасных советов :cranky:

Кстати, 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

Share this post


Link to post
Share on other sites
Сейчас принято делать так: http://www.keil.com/support/man/docs/armcc...59124981436.htm

Спасибо, понял в чем тут дело.

Просто раньше работал только с 8 битными МК, там таких проблем нет.

 

А у меня получилось, что буфер char - выравнивание у него по одному байту (без атрибута, начинаться может с любого адреса), а в качестве аргумента функции я передаю указатель на этот буфер с приведением типа до uint32.

Edited by maxntf

Share this post


Link to post
Share on other sites

union спасает выравнивание при любых компиляторах.

Share this post


Link to post
Share on other sites
2) Показать объявление этого буфера.

+1.

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

 

А у меня получилось, что буфер char - выравнивание у него по одному байту (без атрибута, начинаться может с любого адреса), а в качестве аргумента функции я передаю указатель на этот буфер с приведением типа до uint32.

Это ужасно. Костыль в виде aligned вылечит, но ужас никуда не денется.

Share this post


Link to post
Share on other sites
Костыль в виде 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

Share this post


Link to post
Share on other sites
Ваш совет - один из лидеров среди самых вредных и опасных советов :cranky:

Кстати, memcpy - очень коварный костыль!

Пруфов, я так понимаю, дождаться нереально?

Пример реально пуленепробиваемого решения:

Гы! :biggrin:

Share this post


Link to post
Share on other sites
Пруфов, я так понимаю, дождаться нереально?

Вы правы - это бесполезный пруф из разряда: почему нужно мыть руки перед едой или чистить зубы. Это знают даже дети :biggrin:

Во многих уважающих себя конторах это "наследие" вообще давно запрещено к применению.

Хотя в примитивном коде, который ни за что не отвечает или служит чисто образовательным целям (ардуины), memcpy в целом беды не несет, разве что кроме впустую потраченных нервов и времени :smile3046:

Share this post


Link to post
Share on other sites
Ну-ну, попробуйте объявить массив для стека какой-нить задачи RTOS, НЕ применив к нему обязательный "костыль" aligned. ...

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

Share this post


Link to post
Share on other sites
Скажем, lwip делает это легко и непринуждённо.

Не пойму, при чем тут lwip?

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

 

Не вижу никакой сложности использовать встроенное расширение компилятора, которое полностью устраняет эту "проблему".

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

 

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

Соревнуетесь с Kabdim по вредности "советов"? ;)

Share this post


Link to post
Share on other sites
Вы правы - это бесполезный пруф из разряда: почему нужно мыть руки перед едой или чистить зубы. Это знают даже дети :biggrin:

Потому что пруфы для мытья рук есть и если не заниматься демагогией их несложно найти.

Во многих уважающих себя конторах это "наследие" вообще давно запрещено к применению.

И видимо что бы запретить совсем уж всю идею копирования памяти в другое место они придумали memcpy_s... :biggrin:

Хотя в примитивном коде, который ни за что не отвечает или служит чисто образовательным целям (ардуины), memcpy в целом беды не несет, разве что кроме впустую потраченных нервов и времени :smile3046:

Ну и к чему эти намеки, если вдруг вы не догадывались, то с Ардуиной я никогда не работал и к образованию кого-либо отношения не имею. Вы мешаете в один чан два разных применения. С буферами переменной длинны где для использования memcpy нужно много проверок и всё зло от того что индусы о ни забывают, а их отсутствие не обеспечивает падение сразу. А с другой стороны копирование переменной фиксированной длинны, где единственная задача убедится что на входе есть данные нужного размера. Если вы тратите на второй вариант использования memcpy нервы и время, могу только посочувствовать.

Соревнуетесь с Kabdim по вредности "советов"? ;)

Не переживайте, в этом вопросе вы непревзойденный идеал. :biggrin:

Share this post


Link to post
Share on other sites
Потому что пруфы для мытья рук есть и если не заниматься демагогией их несложно найти.

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

 

Ну и обратный пруф - memcpy спасает мир :biggrin:

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now