问题
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 explain why"memory" Clobber don't works?
note:
source code.it may fail.
#include <stdio.h>
int main()
{
int a = mul(20, 10);
printf("%d a\n", a);
return 0;
};
int mul(int b, int c)
{
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");
return c;
}
~
this is safe.
#include <stdio.h>
int main()
{
int a = mul(20, 10);
printf("%d a\n", a);
return 0;
};
int mul(int b, int c)
{
asm volatile("mrs r12, cpsr\n\t"
"orr r12, r12, #0xC0\n\t"
"msr cpsr_c, r12\n\t" : "=X" (b) :: "r12", "cc");
c *= b; /* This is safe. */
asm volatile("mrs r12, cpsr\n"
"bic r12, r12, #0xC0\n"
"msr cpsr_c, r12" :: "X" (c) : "r12", "cc");
return c;
}
compile and disassemble command:
lumotuwe@ubuntu:~/test_nfc$ arm-linux-gcc -O2 inline_asm.c
lumotuwe@ubuntu:~/test_nfc$ arm-linux-objdump -d a.out
回答1:
Contrary to the question, the variables a
, b
and c
can not be modified by an interrupt as they are local variables and there is no pointer to them.
If a pointer to the variables is stored in a global variable which an interrupt handler could use access the variable, the "memory"
clobber will ensure access to variables is not moved past the asm
statement.
Either volatile
or a "memory"
is required, ther is no need to do both.
来源:https://stackoverflow.com/questions/47088010/gcc-inline-assembler-memory-clobber-dont-prevent-from-re-arrange-the-code-in