C 代码中的内联汇编语句和用于 ARM Cortex 架构的扩展 ASM [英] Inline assembly statements in C code and extended ASM for ARM Cortex architectures

查看:30
本文介绍了C 代码中的内联汇编语句和用于 ARM Cortex 架构的扩展 ASM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 ARM Compiler 5 为 Cortex A 微处理器编译以下两段代码:

I am trying to compile the following two pieces of code with ARM Compiler 5 for a Cortex A microprocessor:

第 1 部分:

static inline void cp15_write_sctlr(uint32_t value)
{
    asm("mcr p15, 0, %0, c1, c0, 0" :: "r"(value));
}

static inline uint32_t cp15_read_actlr(void)
{
    uint32_t actlr;
    asm("mrc p15, 0, %0, c1, c0, 1" : "=r"(actlr));
    return actlr;
}

第 2 部分:

static inline void dmb(void)
{
    asm("dmb" ::: "memory");
}

static inline void dsb(void)
{
    asm("dsb" ::: "memory");
}

static inline void isb(void)
{
    asm("isb" ::: "memory");
}

在这两种情况下,我都会遇到编译错误.见下文,作为例子.

In both cases I get compile errors. See below, as an example.

line 64: Error:  #18: expected a ")"
    asm("dsb" ::: "memory");

是否是编译器版本(ARM编译器5)不支持Extended Asm导致的错误?

Are the error caused by the compiler version (ARM compiler 5), which does not support Extended Asm?

如果我按如下方式重新编写第 1 部分中的代码,则不会出现任何错误.以下代码是否与第 1 部分中的代码等效?

If I re-write the code in Part 1 as follows, I do not get any error. Is the following code equivalent to that in Part 1?

static inline void cp15_write_sctlr(uint32_t value)
{
    __asm
    {
        MCR p15, 0, value, c1, c0, 0
    }
}

static inline uint32_t cp15_read_actlr(void)
{
    uint32_t actlr;
    __asm
    {
        MRC p15, 0, actlr, c1, c0, 1
    }
    return actlr;
}

如果编译器不支持扩展的 Asm,我如何重写第 2 部分中的代码?我有以下想法,但我不确定是否相同.

How could I rewrite the code in Part 2, if the compiler does not support extended Asm? I have in mind the following, but I am not sure it is the same.

static inline void dmb(void)
{
    __schedule_barrier();
    __asm("dmb");
    __schedule_barrier();
}

static inline void dsb(void)
{
    __schedule_barrier();
    __asm("dsb");
    __schedule_barrier();
}

static inline void isb(void)
{
    __schedule_barrier();
    __asm("isb");
    __schedule_barrier();
}

任何帮助将不胜感激.

推荐答案

是否是编译器版本(ARM编译器5)不支持Extended Asm导致的错误?

Are the error caused by the compiler version (ARM compiler 5), which does not support Extended Asm?

那是 GNU C 内联扩展 Asm 语法,所以是的,不支持它的编译器显然会出错.

That's GNU C inline Extend Asm syntax, so yes obviously a compiler that doesn't support it will error.

2016 年 GCC 的变化(PR24414) 给非空的基本 Asm 语句一个隐含的"memory" 破坏,以及让它们在像 x86 这样的目标上隐式破坏 "cc" 扩展 asm 可以做到这一点.因此,如果您的 GCC 版本足够新,我猜您可以能够在这里安全地使用 Basic Asm,假设未记录的 GCC 行为继续存在于未来的 GCC 版本中,以帮助编写不当或旧的代码工作它可能是预期的方式.(假设这在 Keil 中实际上也是安全的,那里也有隐式内存屏障).我不知道它变成了什么 GCC 版本

A GCC change in 2016 (PR24414) gave non-empty Basic Asm statements an implicit "memory" clobber, as well as making them implicitly clobber "cc" on targets like x86 where Extended asm does that. So if your GCC version is new enough, you I guess could be able to safely use Basic Asm here, assuming that undocumented GCC behaviour continues to be present in future GCC versions to help badly written or old code work the way it was probably intended. (Assuming that's actually also safe in Keil, with an implicit memory barrier there, too). I don't know what GCC versions this made it into

(用于在 asm 语句中存储和重新加载全局变量的试金石将告诉您这在任何给定 GCC 版本上的行为如何.如果您看到寄存器值被用于 asm("" :::);(显式扩展没有内存破坏)但不适用于 asm("#comment");(非空 Basic),这意味着非空 Basic asm 语句具有内隐记忆撞,否则你所期望的相同的优化与扩展,这的 Godbolt编译器浏览器链接节目GCC 6.4确实没有对于 Basic asm 有一个隐式的内存破坏,但是 GCC7.1 有.

(A litmus test for storing and reloading a global across an asm statement will tell you how this behaves on any given GCC version. If you see the register value being reused for asm("" ::: ); (Extended with explicitly no memory clobber) but not for asm("# comment"); (non-empty Basic), that implies non-empty Basic asm statements have an implicit memory clobber. Otherwise you'd expect the same optimization as with Extended. This Godbolt compiler explorer link shows GCC 6.4 does not have an implicit mem clobber for Basic asm, but GCC7.1 does.

或者更好的是,您可以使用 CPP 宏来#if 检测错误的编译器并省略它阻塞的 :::memory" 部分,假设它将 asm 语句视为具有内存破坏.或者检测 __GNUC____GNUC_MINOR__ 版本等,并使用它来检测任何声称与支持扩展 asm 的 GNU 方言 C 版本兼容的编译器.

Or better, you could use CPP macros to #if detect the bad compiler and omit the ::: "memory" part that it chokes on, on the assumption that it treats the asm statement as having a memory clobber. Or detect __GNUC__ and __GNUC_MINOR__ version, etc. and use that to detect any compiler that claims compatibility with a version of the GNU dialect of C that supports Extended asm.

Basic Asm 永远不应该在 GNU C 的函数内部使用,即使对于像 dsb 这样不读取或写入寄存器的指令,因为没有记录的顺序保证写的编译器生成的内存访问.https://gcc.gnu.org/wiki/ConvertBasicAsmToExtended.通常,您应该只将它用于 __attribute__((naked)) 函数的主体,或在全局范围内使用.

Basic Asm should never be used inside functions in GNU C, even for instructions like dsb that don't read or write registers, because there's no documented guarantee of ordering wrt. compiler-generated memory accesses. https://gcc.gnu.org/wiki/ConvertBasicAsmToExtended. Normally you should only ever use it for the body of a __attribute__((naked)) function, or at global scope.

Basic asm 没有好处;内联 asm 是你永远不应该随便使用的东西,并且你不能用 Basic 做任何你不能在非裸函数中使用 Extended 显式做的事情.(实际上,您实际上根本无法使用 Basic 安全地做任何事情:您无法安全地触摸内存中的寄存器甚至全局变量(请参阅 这个,并且不能保证订购任何东西.)

There's no upside to Basic asm; inline asm is something you should never ever use casually, and there's nothing you can do with Basic you can't do explicitly with Extended inside a non-naked function. (And almost nothing you actually can do safely with Basic at all: you can't safely touch registers or even global vars in memory (see this, and it's not guaranteed to be ordered wrt. anything.)

因此,依赖具有隐式 memory" 破坏的未记录的基本 Asm 行为非常糟糕.隐含的 mem clobber GCC 更改没有充分的理由(除了可能使旧的和/或错误的代码更有可能正常工作);扩展 asm 以使其明确在 GNU C 中总是更好.

So it sucks a lot to depend on undocumented Basic Asm behaviour of having an implicit "memory" clobber. There was no good reason for that implicit mem clobber GCC change (except for maybe making old and/or bad code more likely to happen to work right); Extended asm to make that explicit is always better in GNU C.

Keil 是否支持 stdatomic.hatomic_thread_fence(memory_order_seq_cst) 发出dmb"?不能用周围的代码重新排序?(不过对 dsb 和 isb 没有帮助).

Does Keil support stdatomic.h for atomic_thread_fence(memory_order_seq_cst) to emit a "dmb" that can't be reordered with surrounding code? (Doesn't help for dsb and isb, though).

这篇关于C 代码中的内联汇编语句和用于 ARM Cortex 架构的扩展 ASM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆