在RISC-V程序集的.data段中的地址处写入一个字节

时间:2018-09-24 16:29:39

标签: assembly riscv illegal-instruction

我正在编写一个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段内的存储位置?你能给我一些提示吗?

2 个答案:

答案 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)。