【发布时间】:2014-01-31 17:05:36
【问题描述】:
我想使用带有 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 加在一起。
【问题讨论】:
-
尝试用
clang-3.4 -target armv7a-none-eabi test.c -o test -O0编译 -
我只是混淆了“r”和“=r”约束吗?应该反过来吗?
标签: c assembly arm clang inline-assembly