【问题标题】:write a byte at address in .data segment in RISC-V assembly在 RISC-V 程序集中的 .data 段中的地址处写入一个字节
【发布时间】:2018-09-24 16:29:39
【问题描述】:

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

【问题讨论】:

  • 使用支持伪指令的汇编程序,并将地址num 的高位部分加载到暂存寄存器中。或者自己做。请记住,sw 机器指令只有 12 个位移位。 RISC V manual confusion: instruction format VS immediate format
  • 感谢回复,我正在使用汇编器riscv64-unknown-elf-as,我该如何使用这个汇编器?谢谢
  • 查看编译器输出以了解存储到全局的函数以了解如何使用luigodbolt.org 已为 RISC-V 发出叮当声。
  • 确切地说,是在您组装程序时出现错误,而不是“当程序到达 sw 时”。错误消息由 GNU as 发出。

标签: assembly riscv illegal-instruction


【解决方案1】:

作为一般经验法则,您编写到汇编器中的程序集是它自己的编程语言,恰好看起来很像 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。它远未完成,但我们很乐意帮助您指出问题或提供更多内容。

【讨论】:

  • 如何通过用 0 填充引导扇区来完成等效的 x86。 times 508-($-$$) db 0
  • sw a0, %lo(num)(a0) 应该是sw a0, %lo(num)(t0),对吧?
【解决方案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)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-12
    相关资源
    最近更新 更多