2

我正在设计自己的 RISC-V CPU,并且已经能够实现一些指令代码。

我已经安装了 GCC 编译器的 RV32I 版本,所以我现在可以使用汇编器了riscv32-unknown-elf-as

我试图用一条指令组装一个程序:

# simple.asm
add x5,x6,x7

我用汇编器编译它,然后用这个命令运行 objdump:

riscv32-unknown-elf-as simple.asm -o simple
riscv32-unknown-elf-objdump -D simple

这将打印出以下内容:

new:     file format elf32-littleriscv


Disassembly of section .text:

00000000 <.text>:
   0:   007302b3                add     t0,t1,t2

Disassembly of section .riscv.attributes:

00000000 <.riscv.attributes>:
   0:   2d41                    jal     0x690
   2:   0000                    unimp
   4:   7200                    flw     fs0,32(a2)
   6:   7369                    lui     t1,0xffffa
   8:   01007663                bgeu    zero,a6,0x14
   c:   00000023                sb      zero,0(zero) # 0x0
  10:   7205                    lui     tp,0xfffe1
  12:   3376                    fld     ft6,376(sp)
  14:   6932                    flw     fs2,12(sp)
  16:   7032                    flw     ft0,44(sp)
  18:   5f30                    lw      a2,120(a4)
  1a:   326d                    jal     0xfffff9c4
  1c:   3070                    fld     fa2,224(s0)
  1e:   615f 7032 5f30          0x5f307032615f
  24:   3266                    fld     ft4,120(sp)
  26:   3070                    fld     fa2,224(s0)
  28:   645f 7032 0030          0x307032645f

我的问题是:

  1. 这里发生了什么?我以为我会有一个简单的单行十六进制,但还有很多事情要做。
  2. 如何指示我的处理器开始读取某个内存地址的指令?看起来 objdump 也不知道指令将从哪里开始。

需要明确的是,此时我将处理器视为裸机。我想象我将在处理器中硬编码指令从内存地址 X 开始,数据在内存地址 Y 可用,堆栈在内存地址 Z 可用。这是正确的吗?或者这是错误的方法?

4

2 回答 2

5

处理器如何知道从哪个地址开始获取指令?

实际的 CPU 本身将具有一些硬连线地址,它会在复位/上电时从中获取。通常系统会在该物理地址处设计有 ROM 或闪存。(该 ROM 可能具有 ELF 程序加载器的早期引导代码,它将尊重 ELF 入口点元数据以从 ROM 设置 ELF 内核映像,或者您可以在开始时将平面二进制文件与正确的代码链接二进制。)

这里发生了什么?我以为我会有一个简单的单行十六进制,但还有很多事情要做。

objdump -D会反汇编所有 ELF 部分,而不仅仅是 .text。如您所见, .text 部分中只有一条指令,如果您使用 objdump -d 这就是您所看到的。(我通常使用objdump -drwC,虽然-w没有换行可能与 RISC-V 无关,这与 x86 不同,其中单个 insn 可能很长。)

是否可以将我上面编译的文件原样传递给我的处理器?

不是你可能想的那样。另请注意,您为输出选择了错误的文件名。as 生成一个目标文件(通常是 .o),而不是可执行文件。您可以链接ld到一个平面二进制文件,或者链接和objcopy其中的.text部分。

(理论上,您可以将整个 ELF 可执行文件甚至目标文件放入 ROM 中,这样该.text部分恰好从 CPU 获取的位置开始,但不会查看元数据字节。因此,ELF 中的 ELF 入口点地址元数据可执行文件将无关紧要。)

.oa和可执行文件之间的区别:a.o仅具有重定位元数据供链接器填充实际地址,绝对用于la伪指令,或相对于auipc多个.o文件,其中一个文件从另一个文件引用一个符号。(否则可以在组装时计算相对位移,而不是留给链接时。)

因此,如果您的代码使用任何标签作为内存地址,则需要链接器在代码中填写这些重定位条目。然后你可以objcopy从链接的 ELF 可执行文件中取出一些部分。或者使用链接器脚本来设置平面二进制文件的布局。

对于只有add、 nola或任何内容的简单情况,没有重定位条目,因此 中的文本部分.o与链接的可执行文件中的相同。

同样棘手的objcopy是静态数据,例如.data.bss部分。如果您将该.text部分复制到平面二进制文件中,则任何地方都不会有数据。(但在 ROM 中,您需要一个启动函数,将静态初始化程序从 ROM 复制到 RAM for .data,并将.bss空间归零。如果您想将 asm 源代码编写为具有.data非零值的正常部分,您'希望您的构建脚本计算出要复制的大小,以便您的启动功能可以使用它,而不必手动执行所有这些操作。)

于 2021-11-04T05:21:39.723 回答
4

@PeterCordes 的回答让我走上了正确的道路。我终于想出了如何生成我可以使用的原始内存转储文件。

步骤如下:

  1. 修改了程序集文件以具有一个.textand.data部分和一个_start标签。我的simple.asm文件现在如下所示:

    .globl _start
    
    .text
    _start:
      add x5,x6,x7
    
    .data
    L1: .word 27
    
  2. 使用以下命令将其组装.asm到文件中:.o

    riscv32-unknown-elf-as simple.asm -o simple.o
    
  3. 为特定处理器创建链接描述文件。我关注了这个惊人的视频,它介绍了从头开始创建链接器脚本的过程。现在,我只需要.text.data部分。所以我的链接器脚本(mycpu.ld)如下所示:

    OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
    ENTRY(_start)
    
    MEMORY
    {
      DATA (rwx) : ORIGIN = 0x0, LENGTH = 0x80
      INST (rx) : ORIGIN = 0x80, LENGTH = 0x80
    }
    
    SECTIONS
    {
      .data :
      {
        *(.data)
      }> DATA
    
      .text :
      {
        *(.text)
      }> INST
    }
    
    
  4. riscv32-unknown-elf-gcc生成使用自动调用的 ELF 文件riscv32-unknown-elf-ld

    riscv32-unknown-elf-gcc -nostdlib -T mycpu.ld -o simple.elf simple.o
    
  5. .elf从我将用来填充内存内容的文件中创建一个原始二进制或十六进制文件。

    riscv32-unknown-elf-objcopy -O binary simple.elf simple.hex
    

Finalsimple.hex包含以下内容(使用hexyl):

┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ 1b 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │•0000000┊00000000│
│00000010│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │00000000┊00000000│
│00000020│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │00000000┊00000000│
│00000030│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │00000000┊00000000│
│00000040│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │00000000┊00000000│
│00000050│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │00000000┊00000000│
│00000060│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │00000000┊00000000│
│00000070│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │00000000┊00000000│
│00000080│ b3 02 73 00             ┊                         │וs0    ┊        │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘

b3027300的十六进制值在哪里add x5,x6,x7

就是这样!非常感谢@PeterCordes 的帮助!:)

于 2021-11-09T09:14:57.153 回答