工作__asm__ __volatile ___(“”:::“记忆”)

时间:2013-02-19 05:40:18

标签: c gcc arm embedded-linux volatile

基本上__asm__ __volatile__ ()对ARM架构的"memory"有什么作用以及它的意义是什么?

4 个答案:

答案 0 :(得分:62)

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

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

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

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

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

问题是编译器(在这种情况下为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

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;
}

因此,您可以按照自己的意愿获得指令序列:

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

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

答案 1 :(得分:17)

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

__asm__是允许汇编语言语句嵌入在C代码中的gcc扩展 - 这里使用它的属性是能够指定阻止编译器执行某些类型的优化的副作用(在这种情况下可能最终生成错误的代码。)

需要

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

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

答案 2 :(得分:9)

这里解释的意思是:

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

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

答案 3 :(得分:-3)

{
  "title": "comparision_jmeter_jenkins",
  "type": "line",
  "params": {
    "shareYAxis": true,
    "addTooltip": true,
    "addLegend": true,
    "showCircles": true,
    "smoothLines": false,
    "interpolate": "linear",
    "scale": "linear",
    "drawLinesBetweenPoints": true,
    "radiusRatio": 9,
    "times": [],
    "addTimeMarker": false,
    "defaultYExtents": false,
    "setYExtents": false,
    "yAxis": {}
  },
  "aggs": [
    {
      "id": "1",
      "type": "count",
      "schema": "metric",
      "params": {}
    },
    {
      "id": "2",
      "type": "date_histogram",
      "schema": "segment",
      "params": {
        "field": "timestamp",
        "interval": "auto",
        "customInterval": "2h",
        "min_doc_count": 1,
        "extended_bounds": {}
      }
    },
    {
      "id": "3",
      "type": "date_range",
      "schema": "group",
      "params": {
        "field": "timestamp",
        "ranges": [
          {
            "from": "now-5d/d+6h",
            "to": "now-5d/d+7h"
          },
          {
            "from": "now-2d/d+10h",
            "to": "now-2d/d+11h"
          }
        ]
      }
    }
  ],
  "listeners": {}
}