2016-07-21 5 views
0

Существует некоторая проблема с встроенным ассемблером, который я не мог понять.рычаг; inline asm; использовать регистр царапин;

У меня есть функция с встроенным ассемблером. Внутри блока ASM мне нужно использовать некоторый регистр нуля для изменения некоторого системного значения.

void setHW(uint32_t val) { 
    asm volatile (
     mrc 15, 0, r0, ... 
     orr r0, r0, %0 
     mcr 15, 0, r0, ... 
     : :"r"(val) :"r0" 
    ); 
} 

На самом деле функция встроена в компилятор, и все в порядке, код все еще работает хорошо.

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

void setHW(uint32_t val) { 
    uint32_t reg; 
    asm volatile (
     mrc 15, 0, %[reg], ... 
     orr %[reg], %[reg], %0 
     mcr 15, 0, %[reg], ... 
     :[reg]"=r"(reg) :"r"(val) : 
    ); 
} 

Теперь компилятор выбрать регистр сам по себе, но на самом деле коррумпирован значение setHW функции вызывающего абонента. В дизассемблере это выглядит как

 add r2, r4, r5  ; caller part, r2 contain some intermedia result 
     mrc 15, 0, r2, ... ; inlined setHW(), r2 is choosen as scratch reg 
     orr r2, r2, r0 
     mcr 15, 0, r2, ... 
     ; caller continue 

Как вы могли видеть r2 повреждены, и все просто развалятся.

Как определить регистр царапин, чтобы этого избежать?

+1

Когда вы добавили '[reg]', val перестали быть '% 0' и стали'% 1'. –

+0

@DavidWohlferd, да спасибо. BTW '[reg]" = r "(reg)' все еще работает неправильно. В некоторых случаях компилятор использует один и тот же регистр для 'val' и' reg', поэтому я получаю 'mrc r3 ...; orr r3, r3, r3; mcr r3 ...; '. '[reg]" + r "(reg)' фактически исправить проблему, но теперь компилятор показывает, что ошибка '' reg 'используется uninitialized ... ', и необходимо присвоить значение дампа' reg', и появится дополнительная инструкция. Не может быть исправлено? – user3124812

+0

Я знаю, что вы уже решили это, но в первом блоке кода я считаю, что проблема, с которой вы сталкиваетесь, заключается в том, что согласно соглашению о вызове ARM EABI первый аргумент функции будет находиться в 'r0', так что код, вероятно, скроет 'uint32_t val' с помощью' mrc 15, 0, r0, ... '. Опять же, обратно в ARM EABI, 'r4-8, r10, r11' считаются« переменными регистрами », поэтому я думаю, что если бы вы использовали один из них, вы бы были хороши. – rjp

ответ

3

Как о чем-то вроде этого:

void setHW(uint32_t val) { 
    uint32_t reg; 
    asm volatile (
     mrc 15, 0, %[reg], ... 
     orr %[reg], %[reg], %[val] 
     mcr 15, 0, %[reg], ... 
     :[reg]"=&r"(reg) :[val] "r"(val) : 
    ); 
} 

Обратите внимание на =&r зафиксировать раннюю проблему затирать (см https://gcc.gnu.org/onlinedocs/gcc/Modifiers.html для описания &).

+0

это! Спасибо, Дэвид – user3124812