c - 有副作用的内联汇编

标签 c assembly arm clang inline-assembly

我想使用带有 clang 3.4 的 ARMv7 的内联汇编,以便编写访问 CPU 控制寄存器的低级代码。作为测试,我编写了一个程序,它从寄存器中读取数据,有条件地修改一些位,然后写回新值。

但是,当我查看生成的机器代码时,整个比特摆弄已经被优化掉了。显然我没有使用正确的 asm 约束来告诉 clang 写入寄存器的结果取决于正在写入的内容。 (我只使用了一个简单的“volatile”修饰符)。

我应该如何编写内联 asm 代码以便 clang 生成正确的 asm?这是代码test.c

typedef unsigned int uint32_t;

// code that reads and writes the ID_PFR1 register

uint32_t read_ID_PFR1() {
  uint32_t a;
  asm volatile ("mrc     p15, 0, %0, c0, c1, 1" : : "r"(a) : );
  return a;
}

void write_ID_PFR1(uint32_t a) {
  asm volatile ("mcr     p15, 0, %0, c0, c1, 1" :"=r"(a) :  :  );
}

// regular c code that modifies the register

uint32_t foo(uint32_t b) {
  uint32_t a;
  a = read_ID_PFR1();
  write_ID_PFR1(b);
  return a+b;
}

void bit_fiddle() {
  uint32_t a;
  a = read_ID_PFR1();
  if ((a & 0x3) == 1) {
    a |= 1<<2;
  }
  a |= 1<<3;
  write_ID_PFR1(a);
}

我用

编译过
clang-3.4 -target armv7a-none-eabi test.c -o test -O3

这是生成的机器码

$ arm-linux-gnueabi-objdump -S test

test:     file format elf32-littlearm


Disassembly of section .text:

00000000 <read_ID_PFR1>:
   0:   ee100f31    mrc 15, 0, r0, cr0, cr1, {1}
   4:   e12fff1e    bx  lr

00000008 <write_ID_PFR1>:
   8:   ee000f31    mcr 15, 0, r0, cr0, cr1, {1}
   c:   e12fff1e    bx  lr

00000010 <foo>:
  10:   ee100f31    mrc 15, 0, r0, cr0, cr1, {1}
  14:   ee000f31    mcr 15, 0, r0, cr0, cr1, {1}
  18:   e12fff1e    bx  lr

0000001c <bit_fiddle>:
  1c:   ee100f31    mrc 15, 0, r0, cr0, cr1, {1}
  20:   ee000f31    mcr 15, 0, r0, cr0, cr1, {1}
  24:   e12fff1e    bx  lr

正如您在 <bit_fiddle> 中所见,mrc 之间没有任何内容。和 mcr指示。还可以看看 foo加起来失败 a+b在生成的机器代码中。

最佳答案

你很接近。 "=" 表示操作数是只写的:

While using constraints, for more precise control over the effects of constraints, GCC provides us with constraint modifiers. Mostly used constraint modifiers are

"=" : Means that this operand is write-only for this instruction; the previous value is discarded and replaced by output data. "&" : Means that this operand is an earlyclobber operand, which is modified before the instruction is finished using the input operands. Therefore, this operand may not lie in a register that is used as an input operand or as part of any memory address. An input operand can be tied to an earlyclobber operand if its only use as an input occurs before the early result is written.

输入和输出由分隔的列表中的顺序决定:

  asm ( assembler template 
       : output operands                  /* optional */
       : input operands                   /* optional */
       : list of clobbered registers      /* optional */
       );
  1. 阅读 gcc inline assembly HOWTO .
  2. Copy content of C variable into a register (GCC)

关于c - 有副作用的内联汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21485862/

相关文章:

c - 将指向 void* 的指针传递给 pthread_join 的目的是什么?

c - Return 语句不会在 c 中执行

c++ - mov bl 在汇编中做了什么

arm - HAL 库中的延迟 (HAL_Delay())

linux - 如何 self dlopen一个可执行二进制文件

c - 使用指针求数组之和

c - 从不兼容的指针类型传递 arg 1 of `combine_string'

assembly - 在不使用相关性的情况下直接在 ASM 中调用/跳转(x86)

c - 为什么编译器会在编译的汇编代码中生成额外的 sqrts

c - 变量声明为从未完成的类型