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

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

问题描述

我正在尝试使用 ARM编译器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");

错误是由不支持扩展Asm的编译器版本(ARM编译器5)引起的吗?

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

任何帮助将不胜感激.

推荐答案

错误是由不支持扩展Asm的编译器版本(ARM编译器5)引起的吗?

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

那是GNU C内联Extend 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语句提供了一个隐式内存" 破坏器,以及在诸如x86的目标上使它们隐式破坏"cc" ,Extended 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确实 not 对于Basic asm有一个隐式的mem破坏器,但是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 检测到错误的编译器,并忽略其阻塞的 :::内存" 部分,假设它会将asm语句视为具有内存破坏者.或检测 __ GNUC __ __ GNUC_MINOR __ 版本等,并使用它来检测任何声称与支持扩展asm的C的GNU方言兼容的编译器.

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.

绝不能在GNU C中的函数内部使用基本Asm ,即使对于诸如 dsb 之类的不读取或写入寄存器的指令,也没有保证顺序的书面保证.wrt.编译器生成的内存访问. 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不能做任何事情,而对于Extended则不能做任何事情.(几乎根本无法使用Basic安全地进行任何操作:您无法安全地触摸寄存器甚至是内存中的全局var(请参阅

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.)

因此,依赖于具有隐式内存" 破坏器的未记录的Basic Asm行为非常麻烦.隐式的mem破坏器GCC更改没有充分的理由(除了可能使旧的和/或不良的代码更有可能正确运行);在GNU C中,扩展asm以使其显式总是更好.

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是否为 atomic_thread_fence(memory_order_seq_cst)支持 stdatomic.h 来发出"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天全站免登陆