简体   繁体   English

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

[英]write a byte at address in .data segment in RISC-V assembly

I am writing a RISC-V assembly program that need to store a word (saved into a register) into a .data segment:我正在编写一个 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

But when the program reaches sw a1, num I get the error "illegal operands `sw a1,num'".但是当程序到达sw a1, num我得到错误“非法操作数 `sw a1,num'”。 How can I store datas into a memory location inside .data segment?如何将数据存储到 .data 段内的内存位置? could you give me some hints?你能给我一些提示吗?

As a general rule of thumb, the assembly that you write into the assembler is its own programming language that just happens to look quite a bit like what's in the RISC-V ISA manual.作为一般经验法则,您编写到汇编器中的程序集是它自己的编程语言,恰好看起来很像 RISC-V ISA 手册中的内容。 RISC-V is a pretty simple ISA, so for most instructions there's actually no difference between the syntax of the ISA manual and the syntax accepted by the assembler. RISC-V 是一个非常简单的 ISA,因此对于大多数指令,ISA 手册的语法和汇编程序接受的语法实际上没有区别。 The place this starts to break down is when referencing symbols, because while you can fill out the immediate directly in your assembly code you probably want to rely on the linker to do so because you won't know the actual symbol address until link time (and it's likely to change as you modify your program).这开始崩溃的地方是引用符号时,因为虽然您可以直接在汇编代码中填写立即数,但您可能希望依靠链接器来这样做,因为在链接时间之前您不会知道实际的符号地址(它可能会随着您修改程序而改变)。

In order to enable the linker to fill out symbol addresses in your code, you need to emit relocations from the assembler so the linker can later fill these out.为了使链接器能够在您的代码中填写符号地址,您需要从汇编器发出重定位,以便链接器稍后可以填写这些地址。 I have a whole blog post on how this works at SiFive's blog, but we just refreshed the website and I can't figure out how to find it :).我在 SiFive 的博客上有一整篇关于这是如何工作的博客文章,但我们刚刚刷新了网站,我不知道如何找到它:)。

In this case you're essentially trying to write assembly that implements the following C code在这种情况下,您实际上是在尝试编写实现以下 C 代码的程序集

int num = 97;
void func(int val) { num = val; }

You've got all the data stuff correct in your original answer, so the only thing to worry about here is how to emit the correct instructions.您已经在原始答案中获得了正确的所有数据内容,因此这里唯一需要担心的是如何发出正确的指令。 You have a few options as to how to emit these.关于如何发出这些,您有几种选择。 One option is to explicitly write each instruction and relocation into your source code, which would look like this一种选择是将每条指令和重定位显式写入您的源代码中,如下所示

func:
    lui t0, %hi(num)
    sw  a0, %lo(num)(a0)
    ret

You can generate this assembly from my C code above by compiling with -mcmodel=medlow -mexplicit-relocs -O3 .您可以通过使用-mcmodel=medlow -mexplicit-relocs -O3进行编译,从我上面的 C 代码生成此程序集。 The GCC manual defines the other RISC-V backend specific options that control code generation. GCC 手册定义了控制代码生成的其他 RISC-V 后端特定选项。

If you're interested in more details, we have an assembly programmer's manual availiable on GitHub: https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md .如果您对更多详细信息感兴趣,我们在 GitHub 上提供了汇编程序员手册: https : //github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md It's far from complete, but we'd love to have help either pointing out issues or providing more content.它还远未完成,但我们很乐意帮助您指出问题或提供更多内容。

The syntax of the store-word ( sw ) instruction is存储字( sw ) 指令的语法是

sw rs2, offset(rs1)

where offset is a 12 bit immediate operand.其中 offset 是一个 12 位立即数操作数。

When you write sw a1, num you get an syntax error and the assembler fails with:当您编写sw a1, num您会收到语法错误,并且汇编程序会失败:

foo.s: : Assembler messages:
foo.s::13: Error: illegal operands `sw a1,num'

Perhaps the simplest way to solve this is to use the load-address ( la ) pseudo-instruction:也许解决这个问题的最简单方法是使用load-address ( la ) 伪指令:

li a1, 100
la t0, num
sw a1, 0(t0)

Since the la instruction completely loads the address into a register we have to use 0 as offset.由于la指令将地址完全加载到寄存器中,因此我们必须使用0作为偏移量。

The la pseudo-instruction expands to program-counter (PC) relative addressing, ie check with objdump : 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)

Alternatively, you can use absolute addressing:或者,您可以使用绝对寻址:

li a1, 100
lui t0, %hi(num)
sw a1, %lo(num)(t0)

Note that the %hi() and %lo() assembler macros split a 32 bit address into its high 20 bits and low 12 bits parts (ie %hi(num) + sign_ext(%lo(num)) = num ).请注意, %hi()%lo()汇编程序宏将 32 位地址拆分为其高 20 位和低 12 位部分(即%hi(num) + sign_ext(%lo(num)) = num )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM