2

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
15
  • What happens if you put a fake dependency on the inline. On the first asm block do this "msr cpsr_c, r12\n\t" :"=m"(b): : "r12", "cc", "memory"); and then on the second one "msr cpsr_c, r12" :"+m"(c):: "r12", "cc", "memory"); .The compiler is free to relocate the asm blocks even if they are volatile (even moving them relative to other C statements) if it doesn't see dependencies. Commented Nov 3, 2017 at 3:52
  • Compiler retain the sequence of statements given in the source code If i put a fake dependency on the inline. Commented Nov 3, 2017 at 4:02
  • You put those exact dependencies that I gave (changes to both inline assembly) and the order didn't change. You sure? Commented Nov 3, 2017 at 4:10
  • Can you show us a minimal complete verifiable example. Not just a code snippet that demonstrates the issue. Commented Nov 3, 2017 at 4:12
  • 2
    Something I missed the first time in your question You say that b and c can be modified by an interrupt handler. Given that the mul instruction in your outputted assembly is working on registers - did you forget to mark b and c with the volatile keyword like volatile int b,c; ? If they aren't marked volatile then the compiler won't know they can be modified asynchronously and will retain them in registers if the optimizer can do that. Commented Nov 3, 2017 at 5:27

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.