我正在编写一个RISC-V汇编程序,该程序需要将一个字(保存到寄存器中)存储到.data段中:
.section .rodata
msg:
.string "Hello World\n"
.section .data
num:
.word 97
.section .text
.global _start
_start:
li a1, 100
sw a1, num
loop:
j loop
但是当程序到达sw a1, num
时,出现错误“非法操作数'sw a1,num'”。
如何将数据存储到.data段内的存储位置?你能给我一些提示吗?
答案 0 :(得分:2)
作为一般的经验法则,您编写到汇编程序中的汇编程序是其自己的编程语言,看起来恰好类似于RISC-V ISA手册中的程序语言。 RISC-V是一个非常简单的ISA,因此对于大多数指令而言,ISA手册的语法与汇编器接受的语法之间实际上没有区别。它开始出现问题的地方是在引用符号时,因为您可以直接在汇编代码中填写立即数,但您可能希望依靠链接程序来这样做,因为直到链接时间,您才知道实际的符号地址(并且在您修改程序时可能会发生变化。
为了使链接器能够在代码中填写符号地址,您需要从汇编程序中发出重定位,以便链接器以后可以填写这些地址。我在SiFive的博客上有一整篇博客文章,介绍了它如何工作,但是我们只是刷新了网站,却不知道如何找到它:)。
在这种情况下,您实际上是在尝试编写实现以下C代码的程序集
int num = 97;
void func(int val) { num = val; }
您的原始答案中的所有数据内容都是正确的,因此这里唯一需要担心的是如何发出正确的指令。关于如何发出这些信号,您有一些选择。一种选择是显式地将每条指令和重定位写到您的源代码中,就像这样
func:
lui t0, %hi(num)
sw a0, %lo(num)(a0)
ret
您可以使用-mcmodel=medlow -mexplicit-relocs -O3
进行编译,从上面的C代码生成此程序集。 GCC手册定义了其他控制代码生成的RISC-V后端特定选项。
如果您想了解更多详细信息,请在GitHub上找到汇编程序员手册:https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md。它远未完成,但是我们很乐意为您指出问题或提供更多内容提供帮助。
答案 1 :(得分:1)
存储字(sw
)指令的语法为
sw rs2, offset(rs1)
其中offset是12位立即数。
在编写sw a1, num
时,您会遇到语法错误,汇编器将失败并显示以下信息:
foo.s: : Assembler messages:
foo.s::13: Error: illegal operands `sw a1,num'
也许最简单的解决方法是使用 load-address (la
)伪指令:
li a1, 100
la t0, num
sw a1, 0(t0)
由于la
指令已将地址完全加载到寄存器中,因此我们必须使用0
作为偏移量。
la
伪指令扩展为程序计数器(PC)相对寻址,即,使用objdump
进行检查:
00000000000100b0 <_start>:
100b0: 06400593 addi a1,zero,100
100b4: 00001297 auipc t0,0x1
100b8: 01028293 addi t0,t0,16 # 110c4 <__DATA_BEGIN__>
100bc: 00b2a023 sw a1,0(t0)
或者,您可以使用绝对寻址:
li a1, 100
lui t0, %hi(num)
sw a1, %lo(num)(t0)
请注意,%hi()
和%lo()
汇编器宏将32位地址分为其高20位和低12位部分(即%hi(num) + sign_ext(%lo(num)) = num
)。