Jump to content
Форум по продукции MOXA

Recommended Posts

Здравствуйте,

Столкнулся с такой вот проблемой при разработке программы для IA-261. Используется самый последный toolchain с сайта моксы. Привожу простенький код:

 

int len = 10;

uint16_t ar[len];

uint16_t *ptr16;

uint32_t *ptr32;

for(int i=0;i<len;i++) ar=i;

 

for(int i=0;i<(len-1);i++){

ptr16 = &ar;

ptr32 = (uint32_t*)&ar;

printf("ar[%d] = %d, ptr16 = %p, ptr32 = %p, *ptr16 = %d, *ptr32 = %d\n", i, ar, ptr16, ptr32, *ptr16, *ptr32);

}

 

Компилирую под Linux Debian в родном gcc (x86), после запуска получаю вот распечатку, здесь видно что все ОК!

ar[0] = 0, ptr16 = 0xbfa975bc, ptr32 = 0xbfa975bc, *ptr16 = 0, *ptr32 = 65536

ar[1] = 1, ptr16 = 0xbfa975be, ptr32 = 0xbfa975be, *ptr16 = 1, *ptr32 = 131073

ar[2] = 2, ptr16 = 0xbfa975c0, ptr32 = 0xbfa975c0, *ptr16 = 2, *ptr32 = 196610

ar[3] = 3, ptr16 = 0xbfa975c2, ptr32 = 0xbfa975c2, *ptr16 = 3, *ptr32 = 262147

ar[4] = 4, ptr16 = 0xbfa975c4, ptr32 = 0xbfa975c4, *ptr16 = 4, *ptr32 = 327684

ar[5] = 5, ptr16 = 0xbfa975c6, ptr32 = 0xbfa975c6, *ptr16 = 5, *ptr32 = 393221

ar[6] = 6, ptr16 = 0xbfa975c8, ptr32 = 0xbfa975c8, *ptr16 = 6, *ptr32 = 458758

ar[7] = 7, ptr16 = 0xbfa975ca, ptr32 = 0xbfa975ca, *ptr16 = 7, *ptr32 = 524295

ar[8] = 8, ptr16 = 0xbfa975cc, ptr32 = 0xbfa975cc, *ptr16 = 8, *ptr32 = 589832

 

 

Тот же самый код, скомпилированный под arm-linux-gcc и запущенный в IA-261 выдает такие вот чудеса:

ar[0] = 0, ptr16 = 0xbed54c8c, ptr32 = 0xbed54c8c, *ptr16 = 0, *ptr32 = 65536

ar[1] = 1, ptr16 = 0xbed54c8e, ptr32 = 0xbed54c8e, *ptr16 = 1, *ptr32 = 1

ar[2] = 2, ptr16 = 0xbed54c90, ptr32 = 0xbed54c90, *ptr16 = 2, *ptr32 = 196610

ar[3] = 3, ptr16 = 0xbed54c92, ptr32 = 0xbed54c92, *ptr16 = 3, *ptr32 = 131075

ar[4] = 4, ptr16 = 0xbed54c94, ptr32 = 0xbed54c94, *ptr16 = 4, *ptr32 = 327684

ar[5] = 5, ptr16 = 0xbed54c96, ptr32 = 0xbed54c96, *ptr16 = 5, *ptr32 = 262149

ar[6] = 6, ptr16 = 0xbed54c98, ptr32 = 0xbed54c98, *ptr16 = 6, *ptr32 = 458758

ar[7] = 7, ptr16 = 0xbed54c9a, ptr32 = 0xbed54c9a, *ptr16 = 7, *ptr32 = 393223

ar[8] = 8, ptr16 = 0xbed54c9c, ptr32 = 0xbed54c9c, *ptr16 = 8, *ptr32 = 589832

 

Т.е. каждый второй результат *ptr32 неверный. Как решить эту ситуацию, с учетом того, что потребуется далее конвертить еще во float, double.

Link to comment

Проблема с выравниванием.

Там, где неверный результат, адрес ptr32 не кратен четырем.

Обходится по разному. Например, можно копировать из нужного адреса в переменную

нужного типа через memcpy:

memcpy(&uint32_var, &ar, sizeof(uint32_var));

memcpy(&double_var, &ar, sizeof(double_var));

 

или извращаться с union'ами.

Не так элегантно, не так эффективно, зато 100% работает.

Я пока не понял происхождение этого эффекта - это особенность arm процессора или компилятора.

Link to comment

Проблема с выравниванием.

Там, где неверный результат, адрес ptr32 не кратен четырем.

Обходится по разному. Например, можно копировать из нужного адреса в переменную

нужного типа через memcpy:

memcpy(&uint32_var, &ar, sizeof(uint32_var));

memcpy(&double_var, &ar, sizeof(double_var));

 

или извращаться с union'ами.

Не так элегантно, не так эффективно, зато 100% работает.

Я пока не понял происхождение этого эффекта - это особенность arm процессора или компилятора.

 

Спасибо, я примерно так и поступил. Думаю что это относится и к другим контроллерам MOXA, где используется подобный Toolchain.

Link to comment
Спасибо, я примерно так и поступил. Думаю что это относится и к другим контроллерам MOXA, где используется подобный Toolchain.

 

Именно так, поскольку кроме W406-LX я пока ничего не "трогал". И на нем аналогичная особенность. Интересно, а под windows CE будет аналогично?

Link to comment

Это особенность процессора ARM. При попытке чтения 32-битного слова, не выровненного по адресу, кратному 4, вы получаете результат, отличающийся от ожидаемого. Процессор читает слово, выровненное по адресу, кратному 4, но потом "перекручивает" его разряды так, что запрошенный адрес оказывается в младших разрядах регистра.

 

В вашем случае мы имеем следующую последовательность байтов (первый байт последовательности имеет адрес, кратный 4):

 

0x00 0x00 0x01 0x00 0x02 0x00 0x03 0x00

 

Если прочитать первые 4 байта как половину слова и как целое 32-битное слово, результат будет идентичным на обоих платформах: 0x0000 == 0 и 0x00010000 == 65536 соответственно.

 

А теперь читаем невыровненные данные. Платформа x86 пофигистически относится к нарушению выравнивания. Данные читаются с запрошенных адресов. Операция выполняется медленнее, но обычно никто не обращает на это внимание. Читается последовательность байтов 0x01 0x00 0x02 0x00, и в регистре оказывается 0x20001 == 131073

 

Платформа ARM показывает свой нрав. Она читает _выровненную_ последовательность байтов, включающую запрошенный адрес: 0x00 0x00 0x01 0x00 (т.е. то же число, что и при чтении предыдущего выровненного значения - 0x00010000). После этого искомый адрес выводится в младший разряд слова с помощью процесса, аналогичного операции rotate: 0x00010000 => 0x00000001 == 1).

 

Более иллюстративен пример, когда вы пытаетесь читать на ARMе невыровненное слово, начинающееся с тройки. По той же схеме получаем:

Исходные байты: 0x02 0x00 0x03 0x00

Прочитали число: 0x00030002

Перекрутили: 0x00020003 == 131075 - то, что у вас получилось

 

Мораль: выражения типа вашего "ptr32 = (uint32_t*)&ar;" с последующим dereference не зря объявлены undefined behavior. Если вам реально нужно производить такие манипуляции с данными, ваш код должен учитывать особенности вашей платформы (т.е. особенности ARM). Операционная система тут значения не имеет.

 

IMHO, оптимальное решение в вашем случае - хранить все данные выровненными по требованию платформы. Если же речь идет о "плотно упакованном" бинарном протоколе обмена, имеет смысл использовать совет lysenkov'а.

Link to comment
Это особенность процессора ARM...

 

Спасибо!

 

2Администрация: кнопка "Нравится" не работает. Предлагаю починить или убрать...

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...