(GNU内联汇编)如何使用未分配的寄存器或复制到C变量?

时间:2012-05-09 02:12:29

标签: c gnu inline-assembly

我正在使用基于GNU的工具链编写内联汇编语句,并且内联汇编中有三条指令用于更新系统寄存器的单个位。步骤将是:

  1. 将(读取)系统寄存器移动到通用寄存器
  2. '与'来自C代码
  3. 的变量值
  4. 移动(写入)回系统寄存器只读
  5. 在我正在使用的指令集中的

    ,内联汇编语法是这样的:

    unsigned int OV_TMP = 0xffefffff;
    asm volatile ( "mfsr %0, $PSW\n\t"
                   "and %0, %0, %1\n\t"
                   "mtsr %0, $PSW"
                   :  : "r"(OV_TMP) : );
    

    %1是我想将OV_TMP的值转发到的寄存器。

    %0对我来说是个问题,我的问题是: 如果内部使用了一个寄存器并且没有从C代码中分配或复制到C变量,如何编写内联汇编代码?

1 个答案:

答案 0 :(得分:1)

这里要考虑的是,从编译器的角度来看,内联汇编指定了寄存器,即使您以后不再使用它。也就是说,你产生的相当于:

register unsigned int OV_TMP = 0xffefffff, scratch;

scratch = magic() & OV_TMP;
more_magic(scratch);
/* and then don't re-use scratch for anything from here on */

由于volatile,无法移动或组合魔术和/或more_magic步骤,因此编译器不能简单地删除已写入但未使用的寄存器。

mfsrmtsr看起来像powerpc指令,我可能会在C代码中执行and步骤(参见脚注);但以下应该通常有效:

unsigned int OV_TMP = 0xffefffff, scratch;
asm volatile("mfsr %0, $PSW\n\t"
             "and %0, %0, %1\n\t"
             "mtsr %0, $PSW"
             : "=&r"(scratch) : "r"(OV_TMP));

这里“=& r”约束表示在读取输入操作数(%0)之前写入输出操作数(%1)。

<小时/> 脚注:据我所知(这不是很远,我只做了一点ppc汇编),没有必要让mfsrmtsr指令保持特定的距离,不像其他处理器上的某些锁步序列。如果是这样,我会写更多这样的东西:

static inline unsigned int read_psw() {
    unsigned int result;
    asm volatile("mfsr %0, $PSW" : "=r"(result));
    return result;
}
static inline void write_psw(unsigned int value) {
    asm volatile("mtsr %0, $PSW" :: "r"(value));
}
#define PSW_FE0 0x00100000 /* this looks like it's FE0 anyway */
...
    write_psw(read_psw() & ~PSW_FE0); /* some appropriate comment here */