GCC Inline Assembler "memory" Clobber don't prevent from re-arrange the code in ARM .

David Brown david@westcontrol.com
Fri Nov 3 09:34:00 GMT 2017


On 03/11/17 04:11, stephen lu wrote:
> I read article about GCC Inline Assembler
> (http://www.ethernut.de/en/documents/arm-inline-asm.html).
> 
> In this article,  "memory" Clobber forces the compiler to store all
> cached values before and reload them after executing the assembler
> instructions. And it must retain the sequence.
> 
> this is the example.
> The following code intends to multiply c with b, of which one or both
> may be modified by an interrupt routine. Disabling interrupts before
> accessing the variables and re-enable them afterwards looks like a
> good idea.
> 
> 
> This may fail. Because the optimizer may decide to do the
> multiplication first and then execute both inline assembler
> instructions or vice versa.  :
> asm volatile("mrs r12, cpsr\n\t"
>     "orr r12, r12, #0xC0\n\t"
>     "msr cpsr_c, r12\n\t" ::: "r12", "cc");
> c *= b; /* This may fail. */
> asm volatile("mrs r12, cpsr\n"
>     "bic r12, r12, #0xC0\n"
>     "msr cpsr_c, r12" ::: "r12", "cc");
> 
> 
> This is safe by adding "memory" Clobber .
> asm volatile("mrs r12, cpsr\n\t"
>     "orr r12, r12, #0xC0\n\t"
>     "msr cpsr_c, r12\n\t" :: : "r12", "cc", "memory");
> c *= b; /* This is safe. */
> asm volatile("mrs r12, cpsr\n"
>     "bic r12, r12, #0xC0\n"
>     "msr cpsr_c, r12" ::: "r12", "cc", "memory");
> 
> 
> But I disassemble code by objdump -d .  "memory" Clobber  don't works,
> the code is to do execute both inline assembler instructions, and then
> do the multiplication.
> 
> mrs     ip, CPSR
> orr     ip, ip, #192    ; 0xc0
> msr     CPSR_c, ip
> mrs     ip, CPSR
> bic     ip, ip, #192    ; 0xc0
> msr     CPSR_c, ip
> mul     r0, r1, r0
> mov     pc, lr
> 
> 
> Can anyone help me?

Yes - read the next paragraph in the webpage you referenced.  It tells
you how to add dummy dependencies to the assembly lines to force the
ordering.  A memory clobber will only force ordering if the variables
involved ("b" and "c" in this case) are in memory.  That is implied in
the example on the page, since they "may be modified by an interrupt
routine" - but it will not be the case if you just declared them locally
in a function.  The version giving the dependencies on "b" and "c"
explicitly is not only more efficient, it is also correct - wherever "b"
and "c" might be located.

The webpage is, IMHO, not a good reference.  It gets a lot of things
wrong - or at least, gives poor examples and poor suggestions.  So be
careful not to copy too much from it.  The example here is fine as an
example of how to enforce ordering using inline assembly - it is /not/ a
good example of how to handle data that can be changed in an interrupt,
and it is not a good example of how to disable interrupts on an ARM.  It
gives the impression that the compiler's optimiser is an enemy to fight
- in fact, it is a partner to work together with.  It gives the
impression that inline assembly is a useful tool for getting optimal
code - it is rare that it is the correct tool for the job.  In most
cases, the compiler will do a better job than you will get from
handwritten assembly (especially if you use a newer version of gcc).

Inline assembly in gcc is like playing with a chainsaw.  It can be fun,
and it is the ideal tool for some jobs - but it can be dangerous, and
you should be sure it makes sense before you fire it up.





More information about the Gcc-help mailing list