Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Выравнивание в gcc
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
xelax
Есть задача перенести код с avr на arm (компилятор gcc). Люди, которые писали программу на avr активно использовали атрибут packed для структур, затем передавали данные структуры по сериальному интерфейсу.

При переходе на arm вот с чем столкнулся. Компилятор с дериктивой packed честно пакует данные без выравнивания, а далее при попытки записать и прочитать 16, 32 - разрядные переменные, запакованные по нечётным адресам вызывает переходя ядра arm в abort mode.

Есть ли какая возможность обойти данную особенность архитектуры с помощью компилятора. Например деректива какая-нибудь. Что бы он например при обращении по нечётным адресам, делал вычитывание побайтно, а затем собирал из них short или long.

Вообще кто-нибудь сталкивался с такой проблемой? И как решал её? help.gif
Puzan
Директивами не исправить.
Попробуй сделать битовыми полями.
xelax
Цитата(Puzan @ Sep 7 2007, 10:36) *
Директивами не исправить.
Попробуй сделать битовыми полями.


около ста файлов в проекте, очень не хочется отыскивать структуры и править их руками.

Вот нашёл в старых разделах форума
Цитата
1. Все memory allocator'ы выделяют "выровненные" блоки памяти. Можешь у себя это проверить выделив два блока памяти размером в байт и посмотреть на адреса соответствующих pointer'ов.
2. Если уж очень надо читать с невыровненного адреса существует специальный модификатор (по крайней мере в EVC++) - __unaligned, например - WORD __unaligned *pwD. Он нормально (только медленнее) читает с любого адреса.

Насчет Keil и прочих - не в курсе, но наверное есть что-то похожее


но такой или похожей фичи для gnu-gcc на их сайте найти не могу в упор.
amw
Цитата(xelax @ Sep 7 2007, 09:21) *
Есть задача перенести код с avr на arm (компилятор gcc). Люди, которые писали программу на avr активно использовали атрибут packed для структур, затем передавали данные структуры по сериальному интерфейсу.

При переходе на arm вот с чем столкнулся. Компилятор с дериктивой packed честно пакует данные без выравнивания, а далее при попытки записать и прочитать 16, 32 - разрядные переменные, запакованные по нечётным адресам вызывает переходя ядра arm в abort mode.

Есть ли какая возможность обойти данную особенность архитектуры с помощью компилятора. Например деректива какая-нибудь. Что бы он например при обращении по нечётным адресам, делал вычитывание побайтно, а затем собирал из них short или long.

Вообще кто-нибудь сталкивался с такой проблемой? И как решал её? help.gif

Код
typedef struct _ustr {
char c;
int i;
} __attribute__ ((packed)) ustr_t;

int x;
ustr_t str;
str.i = 5;
x = str.i;

GCC 3.4.5 AT91SAM7S256 - все работает.


В догонку дизассемблируем прведенный выше код
Код
    str.i = 5;
    8180:    e59f2060     ldr    r2, [pc, #96]; 81e8 <.text+0x1cc>
    8184:    e3a03000     mov    r3, #0; 0x0
    8188:    e3833005     orr    r3, r3, #5; 0x5
    818c:    e5c23001     strb    r3, [r2, #1]
    8190:    e3a03000     mov    r3, #0; 0x0
    8194:    e5c23002     strb    r3, [r2, #2]
    8198:    e3a03000     mov    r3, #0; 0x0
    819c:    e5c23003     strb    r3, [r2, #3]
    81a0:    e3a03000     mov    r3, #0; 0x0
    81a4:    e5c23004     strb    r3, [r2, #4]
    x = str.i;
    81a8:    e59f003c     ldr    r0, [pc, #60]; 81ec <.text+0x1d0>
    81ac:    e59f2034     ldr    r2, [pc, #52]; 81e8 <.text+0x1cc>
    81b0:    e5d21001     ldrb    r1, [r2, #1]
    81b4:    e5d23002     ldrb    r3, [r2, #2]
    81b8:    e1a03403     mov    r3, r3, lsl #8
    81bc:    e1831001     orr    r1, r3, r1
    81c0:    e5d23003     ldrb    r3, [r2, #3]
    81c4:    e1a03803     mov    r3, r3, lsl #16
    81c8:    e1831001     orr    r1, r3, r1
    81cc:    e5d23004     ldrb    r3, [r2, #4]
    81d0:    e1a03c03     mov    r3, r3, lsl #24
    81d4:    e1833001     orr    r3, r3, r1
    81d8:    e5803000     str    r3, [r0]

Как видим - доступ побайтный и OR со сдвигом.
Все в порядке.
xelax
Код
#define PACK __attribute__ ((__packed__))

typedef struct
{
  uint8_t  a;
  uint16_t b;
  uint32_t d;
  uint8_t  c;
} PACK my_packed_struct;      

void test(void)
{
  my_packed_struct  str;
  my_packed_struct* pstr;
  uint8_t*  pa;
  uint16_t*  pb;
  uint32_t*  pd;
  uint8_t*  pc;    
  uint16_t q = 1;
  
  pstr = &str;
  pa = &(pstr->a);
  pb = &(pstr->b);
  pd = &(pstr->d);
  pc = &(pstr->c);  
  *pb = q;
}


Пухнет и дохнет. uint32_t и uint16_t. Расположенны по нечётным адресам. Смотрел дебагером.

А ваш пример действительно работает, так как он начало структуры кладёт по нечётному адресу.

GCC-4.1.1 sam7x256

З.Ы.

Только что проверил такой код
Код
pstr = &str;
  pa = &(pstr->a);
  pstr->b = q;
  pb = &(pstr->b);
  pd = &(pstr->d);
  pc = &(pstr->c);  
  *pb = q;


pstr->b = q; ---- работает, хотя pb после присваивания указывает на нечётный адрес.
вот дизасм кода.
Код
pstr->b = q;
  100d80:    e51b0024     ldr    r0, [fp, #-36]
  100d84:    e55b100e     ldrb    r1, [fp, #-14]
  100d88:    e3a03000     mov    r3, #0; 0x0
  100d8c:    e1a02003     mov    r2, r3
  100d90:    e1a03001     mov    r3, r1
  100d94:    e1823003     orr    r3, r2, r3
  100d98:    e5c03001     strb    r3, [r0, #1]
  100d9c:    e55b100d     ldrb    r1, [fp, #-13]
  100da0:    e3a03000     mov    r3, #0; 0x0
  100da4:    e1a02003     mov    r2, r3
  100da8:    e1a03001     mov    r3, r1
  100dac:    e1823003     orr    r3, r2, r3
  100db0:    e5c03002     strb    r3, [r0, #2]


Отрадно конечно, но всё равно половина присваиваний в коде идёт через разыменование указателей.
crying.gif
abcdefg
Цитата(Puzan @ Sep 7 2007, 10:36) *
Директивами не исправить.
Попробуй сделать битовыми полями.


Наверно имелось ввиду байтовые?!

имел похожу проблему в keil'е, пришлось менять на массивы байтов...
amw
Цитата
А ваш пример действительно работает, так как он начало структуры кладёт по нечётному адресу.


Нет. Структура расположена расположена по адресу 0x000083f4. А int поле - по нечетному соответственно. Смотри вложение.
Сейчас посмотрю Ваш вариант.
xelax
Цитата(amw @ Sep 7 2007, 12:18) *
Нет. Структура расположена расположена по адресу 0x000083f4. А int поле - по нечетному соответственно. Смотри вложение.
Сейчас посмотрю Ваш вариант.

видимо зависит от проектной реализации. У меня наоборот начало структуры по нечётному было, а переменная по чётному.
amw
Цитата(xelax @ Sep 7 2007, 11:24) *
видимо зависит от проектной реализации. У меня наоборот начало структуры по нечётному было, а переменная по чётному.

Не понял.

Код
    *pb = q;
    81c0:    e51b2020     ldr    r2, [fp, #-32]
    81c4:    e15b32ba     ldrh    r3, [fp, #-42]
    81c8:    e1c230b0     strh    r3, [r2]
    pstr->b = q;
    81cc:    e51b0018     ldr    r0, [fp, #-24]
    81d0:    e55b102a     ldrb    r1, [fp, #-42]
    81d4:    e3a03000     mov    r3, #0; 0x0
    81d8:    e1a02003     mov    r2, r3
    81dc:    e1a03001     mov    r3, r1
    81e0:    e1823003     orr    r3, r2, r3
    81e4:    e5c03001     strb    r3, [r0, #1]
    81e8:    e55b1029     ldrb    r1, [fp, #-41]
    81ec:    e3a03000     mov    r3, #0; 0x0
    81f0:    e1a02003     mov    r2, r3
    81f4:    e1a03001     mov    r3, r1
    81f8:    e1823003     orr    r3, r2, r3
    81fc:    e5c03002     strb    r3, [r0, #2]

Да, с разименованием работает, а через указатель - нет.
Потому как typedef unsigned short uint16_t - требует расположения по четному адресу.
Puzan
С указателями на поля по-любому не получится. С указателем на структуру и разыменованием работает.
scifi
Если при попытке сделать чтение или запись по неровному адресу процессор генерирует исключение, то можно в обработчике исключения реализовать чтение и запись по неровному адресу. К примеру, Linux так и делает, см. linux/arch/arm/mm/alignement.c.
xelax
Цитата(scifi @ Sep 7 2007, 12:47) *
Если при попытке сделать чтение или запись по неровному адресу процессор генерирует исключение, то можно в обработчике исключения реализовать чтение и запись по неровному адресу. К примеру, Linux так и делает, см. linux/arch/arm/mm/alignement.c.


07.gif Это где такой файл???

Если не тяжело приаттачте сюда плизз.

Цитата
(xelax @ Sep 7 2007, 11:24) *

видимо зависит от проектной реализации. У меня наоборот начало структуры по нечётному было, а переменная по чётному.

Не понял.


имеется в виду я Ваш код не отдельно компилил, а в свой проект вставил.
scifi
Цитата(xelax @ Sep 7 2007, 13:08) *
07.gif Это где такой файл???

Если не тяжело приаттачте сюда плизз.
имеется в виду я Ваш код не отдельно компилил, а в свой проект вставил.

http://www.google.com/search?hl=en&q=l.../mm/alignment.c
xelax
Цитата(scifi @ Sep 7 2007, 12:47) *
Если при попытке сделать чтение или запись по неровному адресу процессор генерирует исключение, то можно в обработчике исключения реализовать чтение и запись по неровному адресу. К примеру, Linux так и делает, см. linux/arch/arm/mm/alignement.c.


Посмотрел я исходник линукса... wacko.gif Видимо я ещё не осознал суть матрицы, так как конвертация thumb инструкций на лету из arm инструкций не поддалась моему разуму. В джедаи не годен smile.gif

А если серьёзно, то такой вопрос возник: в регистрах контроллера памяти я могу посмотреть адрес памяти при доступе к которому возникла ошибка, разрядность и тип этого доступа. Для того чтобы самому завершить запись или чтение в побайтном режиме не хватает для полноты информации адреса куда записать считываемые данные (при ошибки чтения) или адреса откуда записывались данные (при ошибки записи).

Где взять недостающие данные? Есть ли простое решение этой задачки?
Alex03
Цитата(xelax @ Sep 10 2007, 13:09) *
А если серьёзно, то такой вопрос возник: в регистрах контроллера памяти я могу посмотреть адрес памяти при доступе к которому возникла ошибка, разрядность и тип этого доступа.

Эт кто такие данные предоставляет?
Цитата
Для того чтобы самому завершить запись или чтение в побайтном режиме не хватает для полноты информации адреса куда записать считываемые данные (при ошибки чтения) или адреса откуда записывались данные (при ошибки записи).

А это видимо в любом случае регистр. Какой? Кроме как из кода операции видимо никак не узнать.
Цитата
Где взять недостающие данные? Есть ли простое решение этой задачки?

ИМХО простого решения тут видимо нет. Если есть возможность, т.е. не устаканен этот бинарный протокол связи с внешним миром, то можно попереупорядочивать элементы в структурах. Но в ряде случаев это не возможно...


А вообще когдато был топик примерно на эту тему, точно не помню, но по моему вывод был такой:
Ядро ARM - это одно, а контроллер памяти это другое. Простой контроллер памяти генерит исключение, более продвинутый разбивает одно обращение к памяти на несколько.
Вплоть до того что один и тотже пример на чипах разных производителей на ARM7 ядре давал разные результаты.
xelax
Цитата(Alex03 @ Sep 10 2007, 11:34) *
Эт кто такие данные предоставляет?

А это видимо в любом случае регистр. Какой? Кроме как из кода операции видимо никак не узнать.


Регистр статуса контроллера памяти Название регистра: MC_ASR
Регистр адреса аварийной ситуации Название регистра: MC_AASR
для at91sam7 см. либо user manual, либо
http://www.gaw.ru/html.cgi/txt/doc/micros/..._sam7s/19_3.htm

Очень хотелось бы избежать анализа кода инструкций, очень уж это по-линуксовски сложно.
Gemm
Подскажите, пожалуйста, как делать выравненные структуры в IAR? Например, хочу, чтобы следующая структура была длиной 12 байт, чтоб два первых shorta лежали с интервалом в 4 байта. Пробовал использовать #pragma pack(4) - не помогает....

Код
struct {
    unsigned short A;
    unsigned short B;
    unsigned long C;
} s_abc;
Alex03
Цитата(Gemm @ Sep 11 2007, 16:39) *
Подскажите, пожалуйста, как делать выравненные структуры в IAR? Например, хочу, чтобы следующая структура была длиной 12 байт, чтоб два первых shorta лежали с интервалом в 4 байта. Пробовал использовать #pragma pack(4) - не помогает....

Код
struct {
    unsigned short A;
    unsigned short B;
    unsigned long C;
} s_abc;

Про IAR не скажу, но есть ли в вашем случае смысл использовать short вместо int/long?
scifi
Цитата(Gemm @ Sep 11 2007, 14:39) *
Подскажите, пожалуйста, как делать выравненные структуры в IAR? Например, хочу, чтобы следующая структура была длиной 12 байт, чтоб два первых shorta лежали с интервалом в 4 байта. Пробовал использовать #pragma pack(4) - не помогает....

Код
struct {
    unsigned short A;
    unsigned short B;
    unsigned long C;
} s_abc;

Для этого делается заполнение:
Код
struct {
    unsigned short A;
    unsigned short padding1;
    unsigned short B;
    unsigned short padding2;
    unsigned long C;
} s_abc;

Или при помощи безымянных битовых полей (совсем красиво):
Код
struct {
    unsigned short A;
    unsigned short : 16;
    unsigned short B;
    unsigned short : 16;
    unsigned long C;
} s_abc;
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.