При разработке проекта с использованием пакета компиляторов 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 в приложении.