|
Q: знатокам arm-вского ассемблера |
|
|
|
Aug 5 2006, 16:54
|
Местный
  
Группа: Свой
Сообщений: 201
Регистрация: 23-01-06
Из: Msk
Пользователь №: 13 490

|
есть команда STR R1, [R0, #0x0] при R1 = 0x00000000, R0 = 0x400002B5 пишет нули по адресу 0x400002B4 !!! Есть ли выравнивание по адресу записи?! Если это так, то надо аккуратно работать в keil'e с void-скими указателями
|
|
|
|
|
Aug 5 2006, 17:33
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
Цитата(abcdefg @ Aug 5 2006, 20:54)  есть команда STR R1, [R0, #0x0] при R1 = 0x00000000, R0 = 0x400002B5 пишет нули по адресу 0x400002B4 !!! Есть ли выравнивание по адресу записи?! Если это так, то надо аккуратно работать в keil'e с void-скими указателями  Data can be 8-bit bytes, 16-bit halfwords, or 32 bit doubles. Words MUST BE ALLIGNED to 4-byte boundaries, halfwords must be aligned to 2-byte boundaries И Keil тут не причем - архитектура однако
Сообщение отредактировал DASM - Aug 5 2006, 17:34
|
|
|
|
|
Aug 6 2006, 10:58
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(abcdefg @ Aug 5 2006, 19:54)  есть команда STR R1, [R0, #0x0] при R1 = 0x00000000, R0 = 0x400002B5 пишет нули по адресу 0x400002B4 !!! Есть ли выравнивание по адресу записи?! Если это так, то надо аккуратно работать в keil'e с void-скими указателями  А что вас так испугало? Читаем описание инструкции STR и видим там (документ ARM DDI 0100E стр. A4-89): Цитата Non word-aligned addresses STR instructions ignore the least significant two bits of address. So if these bits are not 0b00, the effects of STR are not precisely opposite to those of LDR. Так что для STR два младших бита игнорируются. А для LDR такое не прокатит, дата аборт сразу...
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Aug 6 2006, 11:53
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(zltigo @ Aug 6 2006, 14:26)  Цитата(Rst7 @ Aug 6 2006, 13:58)  А что вас так испугало?
Очевидно получение неожиданного и без всяких предупреждений результата на ARM платформе (в отличие , например, от x86 платформы на которой обращение по невыровненному адресу хоть и медленнее, но корректно выполнится). И необходимость держать такой "нюанс" в голове программиста. Ну как сказать - неожиданный, на 68000 - аналогично, правда там exception и при записи происходит (а вот начиная с 030 - уже работает невыровненный доступ), PPC - тоже отказывается работать с невыровненными данными, да пожалуй все RISC такие; из классики - PDP11 - тоже самое, IBM360/370 - тоже, вот VAX - не помню. Так что x86 реально в меньшенстве...
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Aug 6 2006, 18:00
|
Местный
  
Группа: Свой
Сообщений: 201
Регистрация: 23-01-06
Из: Msk
Пользователь №: 13 490

|
Цитата(DASM @ Aug 5 2006, 22:18)  гм.. ну так если Keil - у предложили указатель на void - то как бы чего он выравнивать то будет.... то есть смотря как этот указатель инициализировали.. а томже товарищ присвоил указателю адресу байтового массива, а переда его в функцию где int * хочетца ... голова что-то плохо с утра варит, но что-то в этом роде Была определена переменная типа: struct { byte field1; word field2; dword field3; } Var; Судя по всему, сама переменная выравнена по адресу, а вот поле field3 нет. В функцию передается адрес поля field3, который как раз и невыранен, из-за чего происходит глюк! Как с этим бороться, даже не знаю
|
|
|
|
|
Aug 7 2006, 03:22
|

Знающий
   
Группа: Свой
Сообщений: 877
Регистрация: 26-01-05
Из: Екатеринбург
Пользователь №: 2 206

|
Цитата(abcdefg @ Aug 7 2006, 00:00)  Цитата(DASM @ Aug 5 2006, 22:18)  гм.. ну так если Keil - у предложили указатель на void - то как бы чего он выравнивать то будет.... то есть смотря как этот указатель инициализировали.. а томже товарищ присвоил указателю адресу байтового массива, а переда его в функцию где int * хочетца ... голова что-то плохо с утра варит, но что-то в этом роде
Была определена переменная типа: struct { byte field1; word field2; dword field3; } Var; Судя по всему, сама переменная выравнена по адресу, а вот поле field3 нет. В функцию передается адрес поля field3, который как раз и невыранен, из-за чего происходит глюк! Как с этим бороться, даже не знаю  Не должно такого быть, или приведите весь код, включая преобразования типов при обращении к структуре. Такое ощущение, что вы предварительно накладываете структуру на байтовый буфер, типичная ошибка.
--------------------
Пасу котов...
|
|
|
|
|
Aug 7 2006, 07:52
|
Местный
  
Группа: Свой
Сообщений: 201
Регистрация: 23-01-06
Из: Msk
Пользователь №: 13 490

|
Цитата(Andy Mozzhevilov @ Aug 7 2006, 07:22)  Не должно такого быть, или приведите весь код, включая преобразования типов при обращении к структуре. Такое ощущение, что вы предварительно накладываете структуру на байтовый буфер, типичная ошибка. Простейший пример: struct { byte field1; word field2; dword field3; } test_str; dword *ptr1= &(test_str.field3); test_str.field1 = 0x11; // ok test_str.field2 = 0x2233; // ok test_str.field3 = 0x44556677; // ok *ptr1 = 0x00000000; // bug, тут происходит запись в "выравненный адрес"
|
|
|
|
|
Aug 7 2006, 10:00
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Harbour @ Aug 7 2006, 12:36)  что-то видать намучено в linker script с align опцией Linker тут практически ни причем, поскольку оперирует линковкой сегментов. Ну а компилятор - в данном контексте имел возможность отругаться и не выдавать из пакованной структуры смещенный адрес dword. Никаких передач через void * или преобразования типов нет, все явно указано - мог, как минимум, предупредить.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Aug 7 2006, 11:14
|

Местами Гуру
    
Группа: Validating
Сообщений: 1 103
Регистрация: 5-12-04
Пользователь №: 1 323

|
Цитата(zltigo @ Aug 7 2006, 13:00)  Цитата(Harbour @ Aug 7 2006, 12:36)  что-то видать намучено в linker script с align опцией
Linker тут практически ни причем, поскольку оперирует линковкой сегментов. Задав неверную опцию выравнивания для data секции можно тоже получить данный эффект - правда нужно умудриться написать при этом работоспособный код. Цитата Ну а компилятор - в данном контексте имел возможность отругаться и не выдавать из пакованной структуры смещенный адрес dword. Никаких передач через void * или преобразования типов нет, все явно указано - мог, как минимум, предупредить. Где-то стоит опция по умолчанию паковать все структуры. Код небрежный - отсюда и результат. Автору нужно прочитать "веревку" Аллена, однозначно.
|
|
|
|
|
Aug 7 2006, 11:55
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Harbour @ Aug 7 2006, 14:40)  а в случае packed располагает структуру так что field3 находится по выровненному адресу. Ну это достаточно похоже на случайность, к истине можно приблизится если попробовать запихнуть два dword разделив их byte (естественно packed) и повторив фокус с обеими. P.S. GCC я не ругал :-) z.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Aug 7 2006, 13:33
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата Код небрежный - отсюда и результат. Автору нужно прочитать "веревку" Аллена, однозначно. Не.. этот совет здесь не годится. Причинно-следственная связь другая. ;> Сказать: - "всегда грамотно оформляйте структуры, потому что иначе, используя Keil, можете получить data abort" это неравносильно тому что пишут в книгах: - "оформляйте структуры грамотно для повышения пр-ти и сокращения объема, за счет естественного выравнивания". Понятно, что в идеале эту структуру нужно полностью перевернуть, однако (пока что неподтвержденный) факт неверного выравнивания компилятором остается. И спасибо автору ветки за то, что он его словил.
|
|
|
|
|
Aug 7 2006, 13:46
|
Местный
  
Группа: Свой
Сообщений: 201
Регистрация: 23-01-06
Из: Msk
Пользователь №: 13 490

|
Цитата(defunct @ Aug 7 2006, 14:19)  Цитата(zltigo @ Aug 7 2006, 13:00)  Никаких передач через void * или преобразования типов нет, все явно указано - мог, как минимум, предупредить.
Видимо и предупредил. Тема интересная. Вечером попробую повторить описанный глюк. abcdefg какую версию keil'a Вы использовали? Keil соответсвенно последний (mdk302a, компилятор 2.54a). Void'ский указатель, упомянутый в самом начале, оказался не причем (т.к. думал, что проблема из-за преобразования в void* )
|
|
|
|
|
Aug 7 2006, 21:20
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Для тестов использовал приведенный выше пример Сишного кода. Цитата U32 *ptr1= &(test_str.field3);
test_str.field1 = 0x11; // ok test_str.field2 = 0x2233; // ok test_str.field3 = 0x44556677; // ok
*ptr1 = 0x00000000; // bug, тут происходит запись в "выравненный адрес" для неупакованной структуры: Код struct { U8 field1; U16 field2; U32 field3; } test_str; Был сгенерирован следующий код: Код 28: U32 *ptr1= &(test_str.field3); 29: 0x00000176 4910 LDR R1,[PC,#0x0040] 0x00000178 4A10 LDR R2,[PC,#0x0040] 30: test_str.field1 = 0x11; // ok 0x0000017A 2011 MOV R0,#0x11 0x0000017C 7008 STRB R0,[R1,#0x00] 31: test_str.field2 = 0x2233; // ok 0x0000017E 4810 LDR R0,[PC,#0x0040] 0x00000180 8048 STRH R0,[R1,#0x02] 32: test_str.field3 = 0x44556677; // ok 33: 0x00000182 4810 LDR R0,[PC,#0x0040] 0x00000184 6048 STR R0,[R1,#0x04] 34: *ptr1 = 0x00000000; // bug, тут происходит запись в "выравненный адрес" 0x00000186 2100 MOV R1,#0x00 0x00000188 1C10 ADD R0,R2,#0 0x0000018A 6001 STR R1,[R0,#0x00] Как видно из листинга Keil дополнил стуктуру padding байтом по адресу test_str+1. И код получился вполне грамотным. А вот для упакованной структуры.... Код struct { U8 field1; U16 field2; U32 field3; } __packed test_str;
0x00000176 4815 LDR R0,[PC,#0x0054] 0x00000178 4B15 LDR R3,[PC,#0x0054] 30: test_str.field1 = 0x11; // ok 0x0000017A 2111 MOV R1,#0x11 0x0000017C 7001 STRB R1,[R0,#0x00] 31: test_str.field2 = 0x2233; // ok 0x0000017E 4915 LDR R1,[PC,#0x0054] 0x00000180 4815 LDR R0,[PC,#0x0054] 0x00000182 7001 STRB R1,[R0,#0x00] 0x00000184 0A09 LSR R1,R1,#8 0x00000186 7041 STRB R1,[R0,#0x01] 32: test_str.field3 = 0x44556677; // ok 33: 0x00000188 4914 LDR R1,[PC,#0x0050] 0x0000018A 4811 LDR R0,[PC,#0x0044] 0x0000018C 7001 STRB R1,[R0,#0x00] 0x0000018E 0A09 LSR R1,R1,#8 0x00000190 7041 STRB R1,[R0,#0x01] 0x00000192 0A09 LSR R1,R1,#8 0x00000194 7081 STRB R1,[R0,#0x02] 0x00000196 0A09 LSR R1,R1,#8 0x00000198 70C1 STRB R1,[R0,#0x03] 34: *ptr1 = 0x00000000; // bug, тут происходит запись в "выравненный адрес" 0x0000019A 2100 MOV R1,#0x00 0x0000019C 1C18 ADD R0,R3,#0 0x0000019E 6001 STR R1,[R0,#0x00] // <-- Тут R0 = 493 Как следствие затираются первые два поля структуры (field1, field2) и младший байт третьего поля, хотя результатом последней строки Сишного кода должно было быть обнуление field3. При чтении значения по указателю *ptr был сделан хитрый трюк: Код 35: X = *ptr1; 0x000001A0 1C18 ADD R0,R3,#0 0x000001A2 6800 LDR R0,[R0,#0x00] 0x000001A4 6088 STR R0,[R1,#0x08] Т.о. причитался сохраненный ранее 0.. Вот так дела.. Никакого Warining'a либо ошибки при компиляции выдано не было. Так что проблема с компилятором действительно имеет место быть! Проверял на keil 3.23, CA 2.32, 2.40, 2.41, 2.42... Автору ветки большое спасибо еще раз.
Сообщение отредактировал defunct - Aug 7 2006, 21:22
|
|
|
|
|
Aug 8 2006, 01:20
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Фактически была некорректной эта команда: Код U32 *ptr1= &(test_str.field3); У меня ИАР на неё заругался (выдал Warning). А когда структура в стеке, то вообще отказался компилить и выдал Error.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Aug 10 2006, 11:53
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Нашёл у себя в ИАР то ли баг, то ли я тупой? Напишу в этой же ветке, так как проблема почти один в один. Такой вот код меня удивляет: Код char *ptr = getAddr(); float val = *(float *)ptr; Я почему-то надеялся, что преобразуя байтовый указатель в любой другой он наследует его байтовое выравнивание (фактически отсутствие выравнивания) и компилер должен корректно считывать любые типы. Но что-то случилось... Короче, кто из нас двоих тупой?
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Aug 10 2006, 14:32
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 4-08-05
Из: г. Саратов
Пользователь №: 7 351

|
Цитата(GetSmart @ Aug 10 2006, 17:30)  Ну допустим. Тогда как проще (и желательно красивее) всего прочитать число допустим float с байтового адреса? Как выриант: Код float val; char *ptr = getAddr(); memcpy(&val, ptr, sizeof(val)); Не сказать, что проще и красивее, но это универсальная конструкция, которая будет работать независимо от архитектуры контроллера и особенностей компилятора.
|
|
|
|
|
Aug 10 2006, 15:14
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(GetSmart @ Aug 10 2006, 16:30)  Ну допустим. Тогда как проще (и желательно красивее) всего прочитать число допустим float с байтового адреса? На ум пришло такое: Код float val; #pragma pack (push,1) typedef struct { float data; }packed_float_t; #pragma pack(pop) float = ((packed_float_t *)getAddr())->data; float = (*(packed_float_t *)getAddr()).data; но не проверял. Если попробуешь, сообщи результат.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 11 2006, 08:16
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(GetSmart @ Aug 11 2006, 05:03)  Сергей Борщ Именно так я извратился ещё вчера. (в смысле float = ((packed_float_t *)getAddr())->data;) Говорят, "у дураков мысли сходятся" :-) Однако продолжение почему-то забывают: "но у умных - чаще!" Цитата Странно ещё то, что компилятор даже warning не выдал когда скомпилил мой приведённый отрывок. Мало того, неправильно его скомпилил, так ещё я подумал что он достаточно умный чтоб не ошибиться. На мой взгляд это какая-то недоработка. Вроде у Страуструпа читал, что если уж используешь явное преобразование указателей - сам смотри. Ведь в зависимости от контекста этот код может быть как абсолютно правильным (если этот char * в прошлой жизни был float *) и тогда предупреждения компилятора будут мешать или неправильным как в твоем случае. Видимо, придется просто запомнить, что в подобных случаях могут быть грабли.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|