There is some problem w/ inline assembler I could not understand.
I have a function with inline assembler. Inside the ASM block I need to use some scratch register to modify some system value.
void setHW(uint32_t val) {
asm volatile (
mrc 15, 0, r0, ...
orr r0, r0, %0
mcr 15, 0, r0, ...
: :"r"(val) :"r0"
);
}
Actually function is inlined by compiler and it's alright, code still works well.
The problem appears when I try to replace hardcoded r0 with some stub variable so compiler could choose the best possible register to use. It looks like this
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) :
);
}
Now compiler choose register by itself but actually corrupt the value of setHW caller function.
In disassembler it looks like
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
As you could see r2 is corrupted and everything just fall apart.
How should I define scratch register to avoid this?
[reg], val stopped being%0and became%1. - David Wohlferd[reg]"=r"(reg)still doesn't work properly. In some cases compiler uses the same register forvalandregso I getmrc r3...; orr r3, r3, r3; mcr r3...;.[reg]"+r"(reg)actually fix the problem but now compiler shows error'reg' is used uninitialized...and it's necessary to assign a dump value toregand extra instruction appears. Could it be fixed? - user3124812r0, so that code is likely clobberinguint32_t valwithmrc 15, 0, r0, .... Again, back in the ARM EABI,r4-8,r10,r11are considered "variable registers", so I think if you had used one of those instead, you'd have been good. - rjpr0is chosen compiler will preserve the value fromr0beforeasm volatileand restore it after. - user3124812