0

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

4

2 回答 2

5

作为一般经验法则,您写入汇编器的程序集是它自己的编程语言,恰好看起来有点像 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

您可以通过使用上面的 C 代码编译生成此程序集-mcmodel=medlow -mexplicit-relocs -O3。GCC 手册定义了控制代码生成的其他 RISC-V 后端特定选项。

如果您对更多细节感兴趣,我们在 GitHub 上提供了汇编程序员手册:https ://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md 。它远未完成,但我们很乐意帮助您指出问题或提供更多内容。

于 2018-10-04T17:57:40.347 回答
2

store-word ( 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)。

于 2020-02-15T12:00:06.133 回答