C语言 RISC-V内联汇编



我是内联汇编的新手,所以我需要你的帮助,以确保我正确使用它。我需要在用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提供了一组不同的约束,需要不同的解决方案。但是,如果不需要显式说明寄存器,最好让编译器决定可以直接使用哪些寄存器。它通常会带来更少的开销。

最新更新