mdnaif Posted October 7, 2013 Share Posted October 7, 2013 Здравствуйте, Столкнулся с такой вот проблемой при разработке программы для 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
lysenkov Posted October 7, 2013 Share Posted October 7, 2013 Проблема с выравниванием. Там, где неверный результат, адрес ptr32 не кратен четырем. Обходится по разному. Например, можно копировать из нужного адреса в переменную нужного типа через memcpy: memcpy(&uint32_var, &ar, sizeof(uint32_var)); memcpy(&double_var, &ar, sizeof(double_var)); или извращаться с union'ами. Не так элегантно, не так эффективно, зато 100% работает. Я пока не понял происхождение этого эффекта - это особенность arm процессора или компилятора. Link to comment
mdnaif Posted October 8, 2013 Author Share Posted October 8, 2013 Проблема с выравниванием. Там, где неверный результат, адрес ptr32 не кратен четырем. Обходится по разному. Например, можно копировать из нужного адреса в переменную нужного типа через memcpy: memcpy(&uint32_var, &ar, sizeof(uint32_var)); memcpy(&double_var, &ar, sizeof(double_var)); или извращаться с union'ами. Не так элегантно, не так эффективно, зато 100% работает. Я пока не понял происхождение этого эффекта - это особенность arm процессора или компилятора. Спасибо, я примерно так и поступил. Думаю что это относится и к другим контроллерам MOXA, где используется подобный Toolchain. Link to comment
lysenkov Posted October 8, 2013 Share Posted October 8, 2013 Спасибо, я примерно так и поступил. Думаю что это относится и к другим контроллерам MOXA, где используется подобный Toolchain. Именно так, поскольку кроме W406-LX я пока ничего не "трогал". И на нем аналогичная особенность. Интересно, а под windows CE будет аналогично? Link to comment
MuadDib Posted October 9, 2013 Share Posted October 9, 2013 Это особенность процессора 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
lysenkov Posted October 9, 2013 Share Posted October 9, 2013 Это особенность процессора ARM... Спасибо! 2Администрация: кнопка "Нравится" не работает. Предлагаю починить или убрать... Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now