C语言 __asm__ __volatile__ ("" :: : "memory") 的工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14950614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:24:01  来源:igfitidea点击:

Working of __asm__ __volatile__ ("" : : : "memory")

cgccarmembedded-linuxvolatile

提问by vnr1992

What basically __asm__ __volatile__ ()does and what is significance of "memory"for ARM architecture?

ARM 架构的基本__asm__ __volatile__ ()功能和意义是什么"memory"

回答by auselen

asm volatile("" ::: "memory");

creates a compiler level memory barrier forcing optimizer to not re-order memory accesses across the barrier.

创建编译器级别的内存屏障,强制优化器不重新排序跨屏障的内存访问。

For example, if you need to access some address in a specific order (probably because that memory area is actually backed by a different device rather than a memory) you need to be able tell this to the compiler otherwise it may just optimize your steps for the sake of efficiency.

例如,如果您需要以特定顺序访问某个地址(可能是因为该内存区域实际上由不同的设备而不是内存支持),您需要能够将其告知编译器,否则它可能只会优化您的步骤为了效率。

Assume in this scenario you must increment a value in address, read something and increment another value in an adjacent address.

假设在这种情况下,您必须增加地址中的一个值,读取某些内容并增加相邻地址中的另一个值。

int c(int *d, int *e) {
        int r;
        d[0] += 1;
        r = e[0];
        d[1] += 1;
        return r;
}

Problem is compiler (gccin this case) can rearrange your memory access to get better performance if you ask for it (-O). Probably leading to a sequence of instructions like below:

问题是编译器(gcc在这种情况下)可以重新安排您的内存访问以获得更好的性能(如果您要求的话-O)。可能会导致一系列指令,如下所示:

00000000 <c>:
   0:   4603        mov r3, r0
   2:   c805        ldmia   r0, {r0, r2}
   4:   3001        adds    r0, #1
   6:   3201        adds    r2, #1
   8:   6018        str r0, [r3, #0]
   a:   6808        ldr r0, [r1, #0]
   c:   605a        str r2, [r3, #4]
   e:   4770        bx  lr

Above values for d[0]and d[1]are loaded at the same time. Lets assume this is something you want to avoid then you need to tell compiler not to reorder memory accesses and that is to use asm volatile("" ::: "memory").

对于上面的值d[0],并d[1]在同一时间被加载。让我们假设这是你想要避免的事情,然后你需要告诉编译器不要重新排序内存访问,那就是使用asm volatile("" ::: "memory").

int c(int *d, int *e) {
        int r;
        d[0] += 1;
        r = e[0];
        asm volatile("" ::: "memory");
        d[1] += 1;
        return r;
}

So you'll get your instruction sequence as you want it to be:

所以你会得到你想要的指令序列:

00000000 <c>:
   0:   6802        ldr r2, [r0, #0]
   2:   4603        mov r3, r0
   4:   3201        adds    r2, #1
   6:   6002        str r2, [r0, #0]
   8:   6808        ldr r0, [r1, #0]
   a:   685a        ldr r2, [r3, #4]
   c:   3201        adds    r2, #1
   e:   605a        str r2, [r3, #4]
  10:   4770        bx  lr
  12:   bf00        nop

It should be noted that this is only compile time memory barrier to avoid compiler to reorder memory accesses, as it puts no extra hardware level instructions to flush memories or wait for load or stores to be completed. CPUs can still reorder memory accesses if they have the architectural capabilities and memory addresses are on normaltype instead of strongly orderedor device(ref).

应该注意的是,这只是编译时内存屏障,以避免编译器重新排序内存访问,因为它没有放置额外的硬件级指令来刷新内存或等待加载或存储完成。如果 CPU 具有架构功能并且内存地址在normal类型上而不是strongly orderedor device( ref),则它们仍然可以重新排序内存访问。

回答by unixsmurf

This sequence is a compiler memory access scheduling barrier, as noted in the article referenced by Udo. This one is GCC specific - other compilers have other ways of describing them, some of them with more explicit (and less esoteric) statements.

这个序列是一个编译器内存访问调度屏障,如 Udo 引用的文章中所述。这是特定于 GCC 的 - 其他编译器有其他方式来描述它们,其中一些具有更明确(且不太深奥)的语句。

__asm__is a gcc extension of permitting assembly language statements to be entered nested within your C code - used here for its property of being able to specify side effects that prevent the compiler from performing certain types of optimisations (which in this case might end up generating incorrect code).

__asm__是一个 gcc 扩展,允许在您的 C 代码中嵌套输入汇编语言语句 - 此处使用它的属性是能够指定防止编译器执行某些类型的优化的副作用(在这种情况下最终可能会生成不正确的代码)。

__volatile__is required to ensure that the asmstatement itself is not reordered with any other volatile accesses any (a guarantee in the C language).

__volatile__需要确保asm语句本身不会与任何其他易失性访问 any 重新排序(C 语言中的保证)。

memoryis an instruction to GCC that (sort of) says that the inline asm sequence has side effects on global memory, and hence not just effects on local variables need to be taken into account.

memory是 GCC 的一条指令,它(某种程度上)说内联 asm 序列对全局内存有副作用,因此不仅需要考虑对局部变量的影响。

回答by Udo Klein

The meaning is explained here:

含义解释如下:

http://en.wikipedia.org/wiki/Memory_ordering

http://en.wikipedia.org/wiki/Memory_ordering

Basically it implies that the assembly code will be executed where you expect it. It tells the compiler to not reorder instructions around it. That is what is coded before this piece of code will be executed before and what is coded after will be executed after.

基本上它意味着汇编代码将在您期望的地方执行。它告诉编译器不要对它周围的指令重新排序。这就是在这段代码之前编码的内容将在之前执行,之后编码的内容将在之后执行。

回答by leesagacious

static inline unsigned long arch_local_irq_save(void)
{
    unsigned long flags;

    asm volatile(
        "   mrs %0, cpsr    @ arch_local_irq_save\n"
        "   cpsid   i"      //disabled irq
        : "=r" (flags) : : "memory", "cc");
return flags;
}