2015-03-24 3 views
0

При компиляции этого кодаARM Cortex M4 (крохотный 3.1) инлайн сборочные

void FastRead() 
{ 
    register uint32_t cnt = 1000, sample; 
    register uint8_t *dst = data; 
    asm volatile(
    "loop1:" 
     "ldr  %[sample], [%[src]]\n\t" 
     "strb %[sample], [%[dst], #1]!\n\t" 
     "subs %[cnt],1 \n\t"     
     "bne  loop1\n\t" 
     : [cnt] "+r" (cnt), [dst] "+r" (dst), [sample] "=r" (sample) 
     : [src] "r" (&CORE_PIN16_PINREG) 
    ); 
} 

Назначение регистров производит этот код, после того, как 'компиляции'

000004dc <_Z8FastReadv>: 
    4dc: f44f 737a mov.w r3, #1000 ; 0x3e8 
    4e0: 4a03  ldr r2, [pc, #12] ; (4f0 <loop1+0xc>) 
    4e2: 4904  ldr r1, [pc, #16] ; (4f4 <loop1+0x10>) 

000004e4 <loop1>: 
    4e4: 6809  ldr r1, [r1, #0] ;   <-- ?!?!?!?!?!? 
    4e6: f802 1f01 strb.w r1, [r2, #1]! 
    4ea: 3b01  subs r3, #1 
    4ec: d1fa  bne.n 4e4 <loop1> 
    4ee: 4770  bx lr 
    4f0: 1fff8820 .word 0x1fff8820 
    4f4: 400ff050 .word 0x400ff050 

я указал SRC, чтобы быть для чтения -одно зарегистрировать, но не означает, что компилятору разрешено перезаписывать его, не так ли? быстрое обходное решение делает каждую переменную read/writeable (+ r).

Но что вызывает это, это ошибка, или кто-нибудь может объяснить мне, почему это происходит?

Edit: извините забыл упомянуть, это нам на Linux с помощью компилятора GCC (арм-NONE-EABI-г ++ обе версии 4.7.2 и 4.8.4)

+0

Кроме того, в списке clobber требуются «память» и «cc», иначе complier предположит, что они не изменились. –

+0

Вы правы, это сложно, поскольку это можно легко забыть (как и я), большую часть времени он отлично работает без этих строк, но да, вы правы. Это может привести к очень сложному обнаружению ошибок, если компилятор становится слишком умным. – user3310744

ответ

1

Это не ошибка в компиляторе. Модель компилятора для входов/выходов операции ассемблерном является то, что они выполнены так:

  1. входы чтения
  2. сделать операцию
  3. выходы записи

Поэтому компилятор разрешается присвойте любое выходное значение тем же регистрам, что и входное значение.

Если у вас есть последовательность инструкций в инструкции asm, например, в вашем примере, некоторые выходы записываются до чтения некоторых входов. Ответ можно найти в документации для встроенных ограничений asm по адресу https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended-Asm.

Часть вам нужно решить эту проблему:

Используйте «&» модификатор ограничения (см Модификаторы) на всех выходных операндов, которые не должны перекрывать вход. В противном случае GCC может выделять выходной операнд в том же регистре, что и несвязанный входной операнд, в предположении, что код ассемблера потребляет свои входы до создания выходов. Это предположение может быть ложным, если код ассемблера фактически состоит из нескольких команд.

Если вы измените выходные ограничения на:

: [cnt] "+&r" (cnt), [dst] "+&r" (dst), [sample] "=&r" (sample) 

тогда вы решить эту проблему.

+0

Если я правильно понимаю, на практике вы всегда должны добавлять &, поскольку вы не знаете, когда вход будет перезаписан выходом. Единственное исключение - для инструкций по сборке отдельных строк, где «компилятор» предоставляет возможность повторного использования регистров. – user3310744

+0

Вы должны использовать &, когда ваша последовательность команд написана до того, как будет прочитан какой-либо ввод. Вы знаете, когда вывод будет записан - он находится прямо в инструкциях по сборке в вашей инструкции asm. –

Смежные вопросы