我是内联汇编的新手,所以我需要你的帮助,以确保我正确使用它。我需要在用Risc-v工具链编译的C代码中添加汇编代码。请考虑以下代码:
int bar = 0xFF00;
int main(){
volatile int result;
int k;
k = funct();
int* ptr;
ptr = &bar;
asm volatile (".insn r 0x33, 0, 0, a4, a5, a3":
"=m"(*ptr), "=r"(result):
[a5] "m"(*ptr), [a3] "r"(k) :
);
}
...
我想做的是bar = bar+k
。实际上,我想改变bar
所在的内存位置的内容。但是我写的代码得到bar
的地址并把它加到k
。有人知道是什么问题吗?
不幸的是,您误解了语法。
在汇编字符串中,您可以使用%0
,%1
引用参数,其中数字是传递给asm
指令的第n个参数。或者,您可以使用符号名,%[myname]
,它以[myname]"r"(k)
的形式引用参数。请注意,符号名与使用数字相同,名称本身没有任何含义。在您的示例中,您可能会得到这样的印象:您正在强制代码使用特定的处理器寄存器。(如果您确实需要使用,可以使用另一种语法。)
例如,如果你这样写:
int bar = 0xFF00;
int main(){
volatile int result;
int k;
k = funct();
int* ptr;
ptr = &bar;
asm volatile (".insn r 0x33, 0, 0, %[res], %[res], %[ptr]":
[res]"+r"(result) : [ptr]"r"(ptr));
}
IAR编译器将发出以下命令:可以看到,a0
被赋值为result
变量(使用符号名res
),a1
被赋值为变量ptr
(这里,符号名与变量名相同)。
000014 0001'2503 lw a0, 0x0(sp)
000018 0000'05B7 lui a1, %hi(bar)
00001C 0005'8593 addi a1, a1, %lo(bar)
000020 00B5'0533 .insn r 0x33, 0, 0, a0, a0, a1
000024 00A1'2023 sw a0, 0x0(sp)
你可以在《IAR C/c++开发指南编译和链接risc - v&c》一章《汇编语言接口》中阅读更多关于IAR内联汇编语法的内容。本书以PDF格式提供,您可以从IAR嵌入式工作台中访问。
根据您的问题中提供的代码片段,我使用IAR C/c++编译器为RISC-V尝试了以下代码:
int funct();
int funct() { return 0xA5; } // stub
int bar = 0xFF00;
int main() {
int k = funct();
int* ptr = &bar;
asm volatile (".insn r 0x33, 0, 0, %[res], %[ptr], %[k]"
: [res]"=r"(*ptr)
: [ptr]"r"(*ptr), [k]"r"(k));
}
在这种情况下,.insn
指令将生成add r,r,r
,它实际上是*ptr = *ptr + k
。
在这个答案的早期版本中,假设需要明确使用哪个寄存器。为此,使用显式寄存器选择器,因为IAR编译器只是允许这样做(例如,"a3"
,="a3"
,"a4"
,"a5"
等)。在这一点上,正如@PeterCordes在评论中指出的那样,GCC提供了一组不同的约束,需要不同的解决方案。但是,如果不需要显式说明寄存器,最好让编译器决定可以直接使用哪些寄存器。它通常会带来更少的开销。