|
Выравнивание в gcc, Обращение по нечётным адресам |
|
|
|
Sep 7 2007, 06:21
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Есть задача перенести код с avr на arm (компилятор gcc). Люди, которые писали программу на avr активно использовали атрибут packed для структур, затем передавали данные структуры по сериальному интерфейсу. При переходе на arm вот с чем столкнулся. Компилятор с дериктивой packed честно пакует данные без выравнивания, а далее при попытки записать и прочитать 16, 32 - разрядные переменные, запакованные по нечётным адресам вызывает переходя ядра arm в abort mode. Есть ли какая возможность обойти данную особенность архитектуры с помощью компилятора. Например деректива какая-нибудь. Что бы он например при обращении по нечётным адресам, делал вычитывание побайтно, а затем собирал из них short или long. Вообще кто-нибудь сталкивался с такой проблемой? И как решал её?
|
|
|
|
|
Sep 7 2007, 06:36
|
Участник

Группа: Новичок
Сообщений: 30
Регистрация: 16-12-05
Пользователь №: 12 295

|
Директивами не исправить. Попробуй сделать битовыми полями.
Сообщение отредактировал Puzan - Sep 7 2007, 06:38
|
|
|
|
|
Sep 7 2007, 07:13
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(Puzan @ Sep 7 2007, 10:36)  Директивами не исправить. Попробуй сделать битовыми полями. около ста файлов в проекте, очень не хочется отыскивать структуры и править их руками. Вот нашёл в старых разделах форума Цитата 1. Все memory allocator'ы выделяют "выровненные" блоки памяти. Можешь у себя это проверить выделив два блока памяти размером в байт и посмотреть на адреса соответствующих pointer'ов. 2. Если уж очень надо читать с невыровненного адреса существует специальный модификатор (по крайней мере в EVC++) - __unaligned, например - WORD __unaligned *pwD. Он нормально (только медленнее) читает с любого адреса.
Насчет Keil и прочих - не в курсе, но наверное есть что-то похожее но такой или похожей фичи для gnu-gcc на их сайте найти не могу в упор.
|
|
|
|
|
Sep 7 2007, 07:44
|
Знающий
   
Группа: Свой
Сообщений: 601
Регистрация: 22-09-05
Из: Kharkov
Пользователь №: 8 847

|
Цитата(xelax @ Sep 7 2007, 09:21)  Есть задача перенести код с avr на arm (компилятор gcc). Люди, которые писали программу на avr активно использовали атрибут packed для структур, затем передавали данные структуры по сериальному интерфейсу. При переходе на arm вот с чем столкнулся. Компилятор с дериктивой packed честно пакует данные без выравнивания, а далее при попытки записать и прочитать 16, 32 - разрядные переменные, запакованные по нечётным адресам вызывает переходя ядра arm в abort mode. Есть ли какая возможность обойти данную особенность архитектуры с помощью компилятора. Например деректива какая-нибудь. Что бы он например при обращении по нечётным адресам, делал вычитывание побайтно, а затем собирал из них short или long. Вообще кто-нибудь сталкивался с такой проблемой? И как решал её?  Код 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 со сдвигом. Все в порядке.
--------------------
- А мораль отсюда такова: всякому овощу свое время. Или, хочешь, я это сформулирую попроще: никогда не думай, что ты иная, чем могла бы быть иначе, чем будучи иной в тех случаях, когда иначе нельзя не быть. © Lewis Carroll. Alice's adventures in wonderland.
|
|
|
|
|
Sep 7 2007, 07:53
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Код #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] Отрадно конечно, но всё равно половина присваиваний в коде идёт через разыменование указателей.
Сообщение отредактировал xelax - Sep 7 2007, 08:21
|
|
|
|
|
Sep 7 2007, 08:16
|
Местный
  
Группа: Свой
Сообщений: 201
Регистрация: 23-01-06
Из: Msk
Пользователь №: 13 490

|
Цитата(Puzan @ Sep 7 2007, 10:36)  Директивами не исправить. Попробуй сделать битовыми полями. Наверно имелось ввиду байтовые?! имел похожу проблему в keil'е, пришлось менять на массивы байтов...
|
|
|
|
|
Sep 7 2007, 08:18
|
Знающий
   
Группа: Свой
Сообщений: 601
Регистрация: 22-09-05
Из: Kharkov
Пользователь №: 8 847

|
Цитата А ваш пример действительно работает, так как он начало структуры кладёт по нечётному адресу. Нет. Структура расположена расположена по адресу 0x000083f4. А int поле - по нечетному соответственно. Смотри вложение. Сейчас посмотрю Ваш вариант.
Сообщение отредактировал amw - Sep 7 2007, 08:19
--------------------
- А мораль отсюда такова: всякому овощу свое время. Или, хочешь, я это сформулирую попроще: никогда не думай, что ты иная, чем могла бы быть иначе, чем будучи иной в тех случаях, когда иначе нельзя не быть. © Lewis Carroll. Alice's adventures in wonderland.
|
|
|
|
|
Sep 7 2007, 08:32
|
Знающий
   
Группа: Свой
Сообщений: 601
Регистрация: 22-09-05
Из: Kharkov
Пользователь №: 8 847

|
Цитата(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 - требует расположения по четному адресу.
--------------------
- А мораль отсюда такова: всякому овощу свое время. Или, хочешь, я это сформулирую попроще: никогда не думай, что ты иная, чем могла бы быть иначе, чем будучи иной в тех случаях, когда иначе нельзя не быть. © Lewis Carroll. Alice's adventures in wonderland.
|
|
|
|
|
Sep 7 2007, 08:42
|
Участник

Группа: Новичок
Сообщений: 30
Регистрация: 16-12-05
Пользователь №: 12 295

|
С указателями на поля по-любому не получится. С указателем на структуру и разыменованием работает.
|
|
|
|
|
Sep 7 2007, 09:08
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(scifi @ Sep 7 2007, 12:47)  Если при попытке сделать чтение или запись по неровному адресу процессор генерирует исключение, то можно в обработчике исключения реализовать чтение и запись по неровному адресу. К примеру, Linux так и делает, см. linux/arch/arm/mm/alignement.c.  Это где такой файл??? Если не тяжело приаттачте сюда плизз. Цитата (xelax @ Sep 7 2007, 11:24) *
видимо зависит от проектной реализации. У меня наоборот начало структуры по нечётному было, а переменная по чётному.
Не понял. имеется в виду я Ваш код не отдельно компилил, а в свой проект вставил.
|
|
|
|
|
Sep 10 2007, 07:09
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(scifi @ Sep 7 2007, 12:47)  Если при попытке сделать чтение или запись по неровному адресу процессор генерирует исключение, то можно в обработчике исключения реализовать чтение и запись по неровному адресу. К примеру, Linux так и делает, см. linux/arch/arm/mm/alignement.c. Посмотрел я исходник линукса...  Видимо я ещё не осознал суть матрицы, так как конвертация thumb инструкций на лету из arm инструкций не поддалась моему разуму. В джедаи не годен А если серьёзно, то такой вопрос возник: в регистрах контроллера памяти я могу посмотреть адрес памяти при доступе к которому возникла ошибка, разрядность и тип этого доступа. Для того чтобы самому завершить запись или чтение в побайтном режиме не хватает для полноты информации адреса куда записать считываемые данные (при ошибки чтения) или адреса откуда записывались данные (при ошибки записи). Где взять недостающие данные? Есть ли простое решение этой задачки?
Сообщение отредактировал xelax - Sep 10 2007, 07:10
|
|
|
|
|
Sep 10 2007, 07:34
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
Цитата(xelax @ Sep 10 2007, 13:09)  А если серьёзно, то такой вопрос возник: в регистрах контроллера памяти я могу посмотреть адрес памяти при доступе к которому возникла ошибка, разрядность и тип этого доступа. Эт кто такие данные предоставляет? Цитата Для того чтобы самому завершить запись или чтение в побайтном режиме не хватает для полноты информации адреса куда записать считываемые данные (при ошибки чтения) или адреса откуда записывались данные (при ошибки записи). А это видимо в любом случае регистр. Какой? Кроме как из кода операции видимо никак не узнать. Цитата Где взять недостающие данные? Есть ли простое решение этой задачки? ИМХО простого решения тут видимо нет. Если есть возможность, т.е. не устаканен этот бинарный протокол связи с внешним миром, то можно попереупорядочивать элементы в структурах. Но в ряде случаев это не возможно... А вообще когдато был топик примерно на эту тему, точно не помню, но по моему вывод был такой: Ядро ARM - это одно, а контроллер памяти это другое. Простой контроллер памяти генерит исключение, более продвинутый разбивает одно обращение к памяти на несколько. Вплоть до того что один и тотже пример на чипах разных производителей на ARM7 ядре давал разные результаты.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|