Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Q: знатокам arm-вского ассемблера
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
abcdefg
есть команда STR R1, [R0, #0x0]
при R1 = 0x00000000, R0 = 0x400002B5
пишет нули по адресу 0x400002B4 !!!

Есть ли выравнивание по адресу записи?! Если это так, то надо аккуратно работать в keil'e с void-скими указателями sad.gif
DASM
Цитата(abcdefg @ Aug 5 2006, 20:54) *
есть команда STR R1, [R0, #0x0]
при R1 = 0x00000000, R0 = 0x400002B5
пишет нули по адресу 0x400002B4 !!!

Есть ли выравнивание по адресу записи?! Если это так, то надо аккуратно работать в keil'e с void-скими указателями sad.gif

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 тут не причем - архитектура однако
zltigo
Цитата(DASM @ Aug 5 2006, 20:33) *
И Keil тут не причем - архитектура однако

С архитектурными ограниченими дело ясное. Но если Keil вдруг сваял такой ассеблерный код из вполне внятного "C", то он "причем" :-(.
DASM
Цитата(zltigo @ Aug 5 2006, 21:48) *
Цитата(DASM @ Aug 5 2006, 20:33) *

И Keil тут не причем - архитектура однако

С архитектурными ограниченими дело ясное. Но если Keil вдруг сваял такой ассеблерный код из вполне внятного "C", то он "причем" :-(.

гм.. ну так если Keil - у предложили указатель на void - то как бы чего он выравнивать то будет.... то есть смотря как этот указатель инициализировали.. а томже товарищ присвоил указателю адресу байтового массива, а переда его в функцию где int * хочетца ... голова что-то плохо с утра варит, но что-то в этом роде
Rst7
Цитата(abcdefg @ Aug 5 2006, 19:54) *
есть команда STR R1, [R0, #0x0]
при R1 = 0x00000000, R0 = 0x400002B5
пишет нули по адресу 0x400002B4 !!!

Есть ли выравнивание по адресу записи?! Если это так, то надо аккуратно работать в keil'e с void-скими указателями sad.gif


А что вас так испугало? Читаем описание инструкции 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 такое не прокатит, дата аборт сразу...
zltigo
Цитата(Rst7 @ Aug 6 2006, 13:58) *
А что вас так испугало?

Очевидно получение неожиданного и без всяких предупреждений результата на ARM платформе (в отличие , например, от x86 платформы на которой обращение по невыровненному адресу хоть и медленнее, но корректно выполнится). И необходимость держать такой "нюанс" в голове программиста.
Rst7
Цитата(zltigo @ Aug 6 2006, 14:26) *
Цитата(Rst7 @ Aug 6 2006, 13:58) *

А что вас так испугало?

Очевидно получение неожиданного и без всяких предупреждений результата на ARM платформе (в отличие , например, от x86 платформы на которой обращение по невыровненному адресу хоть и медленнее, но корректно выполнится). И необходимость держать такой "нюанс" в голове программиста.


Ну как сказать - неожиданный, на 68000 - аналогично, правда там exception и при записи происходит (а вот начиная с 030 - уже работает невыровненный доступ), PPC - тоже отказывается работать с невыровненными данными, да пожалуй все RISC такие; из классики - PDP11 - тоже самое, IBM360/370 - тоже, вот VAX - не помню. Так что x86 реально в меньшенстве...
zltigo
Цитата(Rst7 @ Aug 6 2006, 14:53) *
Так что x86 реально в меньшенстве...

Но не по привычности/распространенности. Да ведет себя 'правильнее' в данной ситуации.
Давить? :-)))
Rst7
Цитата
Давить? :-)))

Что??? Куда???

Да и это вам привычней, а нам нет wink.gif
abcdefg
Цитата(DASM @ Aug 5 2006, 22:18) *
гм.. ну так если Keil - у предложили указатель на void - то как бы чего он выравнивать то будет.... то есть смотря как этот указатель инициализировали.. а томже товарищ присвоил указателю адресу байтового массива, а переда его в функцию где int * хочетца ... голова что-то плохо с утра варит, но что-то в этом роде


Была определена переменная типа:
struct {
byte field1;
word field2;
dword field3;
} Var;
Судя по всему, сама переменная выравнена по адресу, а вот поле field3 нет. В функцию передается адрес поля field3, который как раз и невыранен, из-за чего происходит глюк!
Как с этим бороться, даже не знаю sad.gif
goodwin
А вообще-то это зависит от конкретного компилятора - как правило в них имеется прагма для выравнивания элементов структур.
Но в этом случае могут быть нестыковки допустим при передаче структуры по последовательному порту в другое устройство (используя указатель).
Я в MSP так уже натыкался... С тех пор не злю медведя - лучше добавить еще byte в структуру, или на худой конец поместить byte последним.

Действительно, с 86 таких проблем нет - установил выравнивание по границе 1 байт и все...
Andy Mozzhevilov
Цитата(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, который как раз и невыранен, из-за чего происходит глюк!
Как с этим бороться, даже не знаю sad.gif


Не должно такого быть, или приведите весь код, включая преобразования типов при обращении к структуре.
Такое ощущение, что вы предварительно накладываете структуру на байтовый буфер, типичная ошибка.
abcdefg
Цитата(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, тут происходит запись в "выравненный адрес"
Harbour
что-то видать намучено в linker script с align опцией - начало структур выравнивается по двойному слову (align 4), т.е. в test_str в середине компилер делает gap. К упакованным структурам применяется более медленная побайтовая адресация.
zltigo
Цитата(Harbour @ Aug 7 2006, 12:36) *
что-то видать намучено в linker script с align опцией

Linker тут практически ни причем, поскольку оперирует линковкой сегментов.
Ну а компилятор - в данном контексте имел возможность отругаться и не выдавать из пакованной структуры смещенный адрес dword. Никаких передач через void * или преобразования типов нет, все явно указано - мог, как минимум, предупредить.
defunct
Цитата(zltigo @ Aug 7 2006, 13:00) *
Никаких передач через void * или преобразования типов нет, все явно указано - мог, как минимум, предупредить.

Видимо и предупредил. Тема интересная. Вечером попробую повторить описанный глюк.
abcdefg какую версию keil'a Вы использовали?
Harbour
Цитата(zltigo @ Aug 7 2006, 13:00) *
Цитата(Harbour @ Aug 7 2006, 12:36) *

что-то видать намучено в linker script с align опцией

Linker тут практически ни причем, поскольку оперирует линковкой сегментов.


Задав неверную опцию выравнивания для data секции можно тоже получить данный эффект - правда нужно умудриться написать при этом работоспособный код.

Цитата
Ну а компилятор - в данном контексте имел возможность отругаться и не выдавать из пакованной структуры смещенный адрес dword. Никаких передач через void * или преобразования типов нет, все явно указано - мог, как минимум, предупредить.


Где-то стоит опция по умолчанию паковать все структуры. Код небрежный - отсюда и результат. Автору нужно прочитать "веревку" Аллена, однозначно.
Harbour
Проверил на arm-elf-gcc 4.1.1 - в любом случае (packed/non-packed struct) генерит корректный с точки зрения архитектуры код - в случае non-packed он вставляет gap, а в случае packed располагает структуру так что field3 находится по выровненному адресу. Вот те и gcc, который все ругают wink.gif
zltigo
Цитата(Harbour @ Aug 7 2006, 14:40) *
а в случае packed располагает структуру так что field3 находится по выровненному адресу.

Ну это достаточно похоже на случайность, к истине можно приблизится если попробовать запихнуть два dword разделив их byte (естественно packed) и повторив фокус с обеими.


P.S.
GCC я не ругал :-)
z.
defunct
Цитата
Код небрежный - отсюда и результат. Автору нужно прочитать "веревку" Аллена, однозначно.

Не.. этот совет здесь не годится.
Причинно-следственная связь другая. ;>
Сказать:
- "всегда грамотно оформляйте структуры, потому что иначе, используя Keil, можете получить data abort"
это неравносильно тому что пишут в книгах:
- "оформляйте структуры грамотно для повышения пр-ти и сокращения объема, за счет естественного выравнивания".

Понятно, что в идеале эту структуру нужно полностью перевернуть, однако (пока что неподтвержденный) факт неверного выравнивания компилятором остается. И спасибо автору ветки за то, что он его словил.
abcdefg
Цитата(defunct @ Aug 7 2006, 14:19) *
Цитата(zltigo @ Aug 7 2006, 13:00) *

Никаких передач через void * или преобразования типов нет, все явно указано - мог, как минимум, предупредить.

Видимо и предупредил. Тема интересная. Вечером попробую повторить описанный глюк.
abcdefg какую версию keil'a Вы использовали?


Keil соответсвенно последний (mdk302a, компилятор 2.54a).
Void'ский указатель, упомянутый в самом начале, оказался не причем (т.к. думал, что проблема из-за преобразования в void* )
defunct
Для тестов использовал приведенный выше пример Сишного кода.

Цитата
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...
Автору ветки большое спасибо еще раз.
goodwin
Вот и я о том. Лучше перебдеть, чем недобдеть - расставить все ручками в структуре и добавить байтик при необходимости...
GetSmart
Фактически была некорректной эта команда:
Код
U32 *ptr1= &(test_str.field3);
У меня ИАР на неё заругался (выдал Warning). А когда структура в стеке, то вообще отказался компилить и выдал Error.
defunct
Отправил bug report в Keil, сказали пофиксят..
GetSmart
Нашёл у себя в ИАР то ли баг, то ли я тупой?
Напишу в этой же ветке, так как проблема почти один в один.
Такой вот код меня удивляет:
Код
char *ptr = getAddr();
float val = *(float *)ptr;
Я почему-то надеялся, что преобразуя байтовый указатель в любой другой он наследует его байтовое выравнивание (фактически отсутствие выравнивания) и компилер должен корректно считывать любые типы. Но что-то случилось...
Короче, кто из нас двоих тупой?
GetSmart
Или может я ошибаюсь? Может выравнивание прикрепляется только к создаваемым новым типам, например к структурам и юнионам?
Сергей Борщ
Цитата(GetSmart @ Aug 10 2006, 15:18) *
Или может я ошибаюсь? Может выравнивание прикрепляется только к создаваемым новым типам, например к структурам и юнионам?
Точнее к полям структуры. Т.е. если через указатель на эту упакованную структуру будешь обращаться к ее полям, то обращение будет побайтовым. А корректность указателей на поля упакованной структуры никто не обещал. Та кчто ошибаешься.
GetSmart
Ну допустим. Тогда как проще (и желательно красивее) всего прочитать число допустим float с байтового адреса?
ek74
Цитата(GetSmart @ Aug 10 2006, 17:30) *
Ну допустим. Тогда как проще (и желательно красивее) всего прочитать число допустим float с байтового адреса?


Как выриант:
Код
float val;
char *ptr = getAddr();
memcpy(&val, ptr, sizeof(val));


Не сказать, что проще и красивее, но это универсальная конструкция, которая будет работать независимо от архитектуры контроллера и особенностей компилятора.
Сергей Борщ
Цитата(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;

но не проверял. Если попробуешь, сообщи результат.
GetSmart
Сергей Борщ
Именно так я извратился ещё вчера. (в смысле float = ((packed_float_t *)getAddr())->data;)
Но скомпиленный код получился ужасный. Хотя корректный.

Через memcpy тоже вобщем нормально. Точнее не хуже этого.

Странно ещё то, что компилятор даже warning не выдал когда скомпилил мой приведённый отрывок. Мало того, неправильно его скомпилил, так ещё я подумал что он достаточно умный чтоб не ошибиться. На мой взгляд это какая-то недоработка.
Rst7
Ну есть еще злой способ:
Код
float getfloat(char *p)
{
#pragma pack(1)
union
{
  float x;
  struct
  {
    char c1;
    char c2;
    char c3;
    char c4;
  };
};
#pragma pack()
c1=*p++;
c2=*p++;
c3=*p++;
c4=*p;
return(x);
}

В иаре точно стрельнет, в остальных - скорее всего надо именовать юнион и структуру, что не меняет идеи wink.gif
Сергей Борщ
Цитата(GetSmart @ Aug 11 2006, 05:03) *
Сергей Борщ
Именно так я извратился ещё вчера. (в смысле float = ((packed_float_t *)getAddr())->data;)
Говорят, "у дураков мысли сходятся" :-) Однако продолжение почему-то забывают: "но у умных - чаще!"
Цитата
Странно ещё то, что компилятор даже warning не выдал когда скомпилил мой приведённый отрывок. Мало того, неправильно его скомпилил, так ещё я подумал что он достаточно умный чтоб не ошибиться. На мой взгляд это какая-то недоработка.
Вроде у Страуструпа читал, что если уж используешь явное преобразование указателей - сам смотри. Ведь в зависимости от контекста этот код может быть как абсолютно правильным (если этот char * в прошлой жизни был float *) и тогда предупреждения компилятора будут мешать или неправильным как в твоем случае. Видимо, придется просто запомнить, что в подобных случаях могут быть грабли.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.