реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Проблема в gcc 4.1.0 (и более ранних), дурит компилятор
makc
сообщение Apr 1 2007, 21:35
Сообщение #1


Гуру
******

Группа: Админы
Сообщений: 3 621
Регистрация: 18-10-04
Из: Москва
Пользователь №: 904



При разработке проекта с использованием пакета компиляторов gnuarm.org в составе которого идет arm-elf-gcc версии 4.1.0 (с версией 3.4.3 наблюдается подобное поведение) обнаружилась проблема: компилятор генерирует неверный код, который приводит к неверным результатам.

Тестовая программа проста:
Код
#include <string.h>

#define FPGA_BASE    0x81000000

static inline void fpga_write( unsigned short address, unsigned short data )
{
    *((volatile unsigned short*)(FPGA_BASE+address)) = data;
    asm volatile( "nop" ); /* Slow down IO */
}

int f()
{
    unsigned int    counter;
    unsigned short*    buf = (unsigned short*)((void*)&counter);

    memcpy( buf, "test", 4 );
    counter++;
    fpga_write( 0x6A, buf[0] );
    fpga_write( 0x6A, buf[1] );

    return 0;
}


По логике работы программы, счетчик сначала должен инкрементироваться, а только потом быть записан пословно в заданное место. Однако если посмотреть на листинг функции:
Код
    str lr,[sp,#-4]!  
    sub sp,sp,#4      
    mov r0,sp          
    ldr r1,.L3        
    mov r2,#4          
    bl memcpy          
    ldr r3,[sp,#0]        ; загружается значение counter
    ldrh r1,[sp,#0]        ; загружается младшее слово counter
    add r3,r3,#1          ; инкремент счетчика
    mov r2,#-2130706432
    str r3,[sp,#0]        ; сохранение инкрементированного счетчика в памяти
    strh r1,[r2,#106]    ; Ошибка! Младшее слово счетчика в r1 не было инкременировано!
    nop                
    ldrh r3,[sp,#2]      ; загружается старшее слово счетчика, здесь все верно
    strh r3,[r2,#106]; и его значение записывается в память.
    nop                
    mov r0,#0          
    add sp,sp,#4      
    ldmfd sp!,{pc}


Итого - получается, что старшее слово счетчика будет взято после инкремента, а его младшее слово - до инкремента.

Вопрос - кто-нибудь сталкивался с подобной проблемой?

PS: Исходный код и Makefile в приложении.
Прикрепленные файлы
Прикрепленный файл  gcc_incr_error_test.zip ( 583 байт ) Кол-во скачиваний: 25
 


--------------------
BR, Makc
В недуге рождены, вскормлены тленом, подлежим распаду. (с) У.Фолкнер.
Go to the top of the page
 
+Quote Post
Alex03
сообщение Apr 2 2007, 08:17
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034



Цитата(makc @ Apr 2 2007, 00:35) *
При разработке проекта с использованием пакета компиляторов gnuarm.org в составе которого идет arm-elf-gcc версии 4.1.0 (с версией 3.4.3 наблюдается подобное поведение) обнаружилась проблема: компилятор генерирует неверный код, который приводит к неверным результатам.
...
Вопрос - кто-нибудь сталкивался с подобной проблемой?


Если всё так, то печально. angry.gif
Ключи оптимизации какие?
С третьей стороны, и компиллер то обвинять не во чтом, он ж оптимизирует работу с памятью, переупорядочивает инструкции и т.д. А о том что указатель указывает на переменную он знать не обязан, хотя мог бы и "догадаться" smile.gif .
Видимо решать такие проблемы надо более другим С-кодом. Начиная с volatile...
Go to the top of the page
 
+Quote Post
scifi
сообщение Apr 2 2007, 09:02
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Это явление называется aliasing:

http://en.wikipedia.org/wiki/Aliasing_(computing)

В стандарте C99 сказано, что то, что Вы делаете в своей программе, делать нельзя. Этот запрет введён для того, чтобы компилятор мог оптимизировать код, не боясь его испортить.
Поищите в гугле по терминам gcc, variable, pointer, alias. Может быть найдёте ключи компилятора, которые уберут эту проблему. Но это приведёт к снижению эффективности оптимизации. А лучше переделайти код, чтобы избавиться от этого самого aliasing.
Go to the top of the page
 
+Quote Post
makc
сообщение Apr 2 2007, 09:24
Сообщение #4


Гуру
******

Группа: Админы
Сообщений: 3 621
Регистрация: 18-10-04
Из: Москва
Пользователь №: 904



Цитата(Alex03 @ Apr 2 2007, 09:17) *
Если всё так, то печально. angry.gif
Ключи оптимизации какие?


Оптимизация по размеру (-Os). С другими ключами оптимизации такой проблемы не наблюдается.

Цитата
С третьей стороны, и компиллер то обвинять не во чтом, он ж оптимизирует работу с памятью, переупорядочивает инструкции и т.д. А о том что указатель указывает на переменную он знать не обязан, хотя мог бы и "догадаться" smile.gif .
Видимо решать такие проблемы надо более другим С-кодом. Начиная с volatile...


volatile тут не поможет. scifi - прав, здесь нарушаются правила создания alias'ов, что противоречит стандарту. Этот кусок кода был выдран не из моей части проекта, но проблема мне показалась интересной и я решил написать про нее.

Итог - нужно быть внимательнее. smile.gif
А компилятор - молодец: если убрать преобразование к (void*), то он начинает честно предупреждать о возможных проблемах. smile.gif


--------------------
BR, Makc
В недуге рождены, вскормлены тленом, подлежим распаду. (с) У.Фолкнер.
Go to the top of the page
 
+Quote Post
Harbour
сообщение Apr 2 2007, 10:08
Сообщение #5


Местами Гуру
*****

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



При -Os не включается -fstrict-aliasing, (см. man gcc), он включается при -O(>=2) При оптимизации -Wstrict-aliasing помогает находить такие косяки. Если человек точно знает чего его прога делает, то тогда можно задать опцию -fno-strict-aliasing - например linux ядро на последних версиях gcc только с этой опцией и собирается, так как логика alias optimization у gcc весьма туповата, хоть и соответствует стандарту.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd June 2025 - 22:30
Рейтинг@Mail.ru


Страница сгенерированна за 0.02167 секунд с 7
ELECTRONIX ©2004-2016