assembly RISC-V GCC编译器错误编译ASM代码

hgqdbh6s  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(162)

我正在编写一个嵌入式C程序来测试我在FPGA板上开发的硬件IP。我在使用RISC-V GCC ASM语法时发现了这个奇怪的问题。
这是我在C程序中编写的代码。write_targetbase_addr都声明为volatile uint32_t。

// write_target = 0x1F9
asm volatile ( 
  "li   %0, 0x1F9\n"
  : "=r"(write_target)
);

// base_addr = 0x1040_6000
asm volatile (
  "lui %0, %1"
  : "=r" (base_addr)
  : "i" (66566)
);

// base_addr = 0x1040_6000 + 0x0
asm volatile ( 
  "addi   %0, %1, %2\n"
  : "=r"(base_addr)
  : "r"(base_addr), "i"(0)
);

// mem[base_addr] = write_target
asm volatile ( 
  "sh   %0, 0(%1)\n"
  : "=r"(write_target)
  : "r"(base_addr)
);

当我查看编译后的转储文件时,我看到它已被编译为以下内容:

800031e6:   1f900793            li  a5,505        // a5 = 0x1F9 = d'505
800031ea:   f6f42423            sw  a5,-152(s0)   // mem[s0-152] = 505
800031ee:   104067b7            lui a5,0x10406    // a5 = 0x10406 = d'66566
800031f2:   f6f42623            sw  a5,-148(s0)   // mem[s0-148] = 0x10406
800031f6:   f6c42783            lw  a5,-148(s0)   // a5 = mem[s0-148]
800031fa:   00078793            mv  a5,a5         // a5 = a5
800031fe:   f6f42623            sw  a5,-148(s0)   // mem[s0-148] = 0x10406
80003202:   f6c42783            lw  a5,-148(s0)   // a5 = mem[s0-148]
80003206:   00f79023            sh  a5,0(a5) # 10406000 <_tbss_end+0x10406000>
                                                  // mem[a5] = a5

我不明白为何会出现这种情况。我不太熟悉RISC-V GCC交叉编译器的内部工作原理,所以我不知道我做错了什么。我反复检查了语法,据我所知,它是正确的。我正在运行-O3优化标志。
我真的很感激你们所有人的指导。
谢谢你,谢谢
更新:我正在使用riscv-gnu-toolchain Git repo中的Newlib gcc编译器。
我遇到的问题是,我想将write_target的值存储到base_addr中。但编译后的代码似乎将base_addr存储到base_addr中。

oewdyzsn

oewdyzsn1#

问题似乎是你在这个汇编指令上使用了一个输出约束:

// mem[base_addr] = write_target
asm volatile ( 
  "sh   %0, 0(%1)\n"
  : "=r"(write_target)
  : "r"(base_addr)
);

这就是为什么GCC从不将write_target传递给语句的原因。为了匹配您的风格,它需要两个寄存器输入约束,分别为write_targetbase_addr
使用一个没有任何输入/输出约束的asm块,以及在汇编程序中使用的硬寄存器的clobbers可能更容易。如果将\n嵌入到字符串中,则可以在一个asm语句中嵌入多行。(惯例是使用\n\t,以匹配编译器生成的指令缩进。

相关问题