Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум разработчиков электроники 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. Вызвать функцию с этой локальной переменной. (опционально)Скопировать значение назад. Это и есть пуленепробиваемое решение которое работает везде, независимо от типов и версий компиляторов и языка.

Ваш совет - один из лидеров среди самых вредных и опасных советов 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 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) *
Ваш совет - один из лидеров среди самых вредных и опасных советов cranky.gif
Кстати, memcpy - очень коварный костыль!

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

Гы! biggrin.gif

Автор: Forger Sep 13 2018, 15:15

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

Вы правы - это бесполезный пруф из разряда: почему нужно мыть руки перед едой или чистить зубы. Это знают даже дети biggrin.gif
Во многих уважающих себя конторах это "наследие" вообще http://electronix.ru/redirect.php?https://unspecified.wordpress.com/2009/05/16/microsoft-bans-memcpy/.
Хотя в примитивном коде, который ни за что не отвечает или служит чисто образовательным целям (ардуины), memcpy в целом беды не несет, разве что кроме впустую потраченных нервов и времени smile3046.gif

Автор: 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 по вредности "советов"? wink.gif

Автор: Kabdim Sep 14 2018, 08:56

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

Потому что пруфы для мытья рук есть и если не заниматься демагогией их несложно найти.
Цитата(Forger @ Sep 13 2018, 18:15) *
Во многих уважающих себя конторах это "наследие" вообще http://electronix.ru/redirect.php?https://unspecified.wordpress.com/2009/05/16/microsoft-bans-memcpy/.

И видимо что бы запретить совсем уж всю идею копирования памяти в другое место они придумали 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 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 спасает мир biggrin.gif

Автор: Forger Sep 14 2018, 09:15

Цитата(Kabdim @ Sep 14 2018, 11:56) *
Не переживайте

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

Цитата
Ну и к чему эти намеки...
Не стоить лукавать, вы все прекрасно поняли - ведь вон как активно оправдываетесь sm.gif

Автор: 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) *
Не стоить лукавать, вы все прекрасно поняли - ведь вон как активно оправдываетесь sm.gif

Ох уж эти школьные подколки.

Автор: Forger Sep 14 2018, 10:14

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

Автор: 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 готовите? Довольно редкий кейс, компилятор (и я rolleyes.gif ) естественно такого не ожидает. Вы как @мантех только регистры или что-то стороннее реалтаймовое используете?

Цитата(aaarrr @ Sep 14 2018, 16:59) *
Но и за компилятором есть грех - он предполагает, что невыровненный доступ разрешен, хотя это не обязательно так.

Выбор у него небогатый. Если не считать выравнивание и другие наиболее применимые найстройки нормой, то в других 99% случаев не получится сделать оптимизации. Именно поэтому все нестандартные вопросы с выравниванием и со всем остальными нюансами железа С/++ скинули на программиста. Хотя в 99% случаев об этом позволительно не думать. Но задача сериализации это тот самый 1%, в котором знать язык и железо нужно чуть лучше чем в среднем.

Автор: aaarrr Sep 16 2018, 11:03

Цитата(Kabdim @ Sep 16 2018, 12:27) *
Получается вы без линукса А8 готовите? Довольно редкий кейс, компилятор (и я rolleyes.gif ) естественно такого не ожидает. Вы как @мантех только регистры или что-то стороннее реалтаймовое используете?

Нет, это просто пример. Готовлю под 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й версии он несколько порезанный), и потому обратно уже не хочется sm.gif

Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)