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

    

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

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

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

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

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

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

Что делать?

img.jpg

 

P.S

Keil V5.23.0.0

 

 

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


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

 

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

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

 

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

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

 

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


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

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

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

 

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


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

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

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


Ссылка на сообщение
Поделиться на другие сайты
Скопировать значение в выравненную переменную с помощью 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

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


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

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

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

 

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

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

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


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

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

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


Ссылка на сообщение
Поделиться на другие сайты
2) Показать объявление этого буфера.

+1.

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

 

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

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

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


Ссылка на сообщение
Поделиться на другие сайты
Костыль в виде 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

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


Ссылка на сообщение
Поделиться на другие сайты
Ваш совет - один из лидеров среди самых вредных и опасных советов :cranky:

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

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

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

Гы! :biggrin:

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


Ссылка на сообщение
Поделиться на другие сайты
Пруфов, я так понимаю, дождаться нереально?

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

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

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

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


Ссылка на сообщение
Поделиться на другие сайты
Ну-ну, попробуйте объявить массив для стека какой-нить задачи RTOS, НЕ применив к нему обязательный "костыль" aligned. ...

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

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


Ссылка на сообщение
Поделиться на другие сайты
Скажем, lwip делает это легко и непринуждённо.

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

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

 

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

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

 

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

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

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


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

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

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

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

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

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

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

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

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


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

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

 

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

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти