首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >裸金属RISC-V CPU -处理器如何知道从哪个地址开始获取指令?

裸金属RISC-V CPU -处理器如何知道从哪个地址开始获取指令?
EN

Stack Overflow用户
提问于 2021-11-04 03:53:04
回答 2查看 937关注 0票数 3

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

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

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

代码语言:javascript
运行
复制
# simple.asm
add x5,x6,x7

我用汇编程序编译它,然后使用以下命令运行objdump:

代码语言:javascript
运行
复制
riscv32-unknown-elf-as simple.asm -o simple
riscv32-unknown-elf-objdump -D simple

这将打印出以下内容:

代码语言:javascript
运行
复制
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可用。这是正确的吗?还是这是错误的做法?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-11-04 05:21:39

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

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

这里发生什么事情?我以为我会有一个简单的巫术,但有更多的事情。

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

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

不像你想的那样。还请注意,您为输出选择了错误的文件名。生成对象文件(通常是.o),而不是可执行文件。您可以将ld链接到一个平面二进制文件中,也可以将.text部分链接到其中。

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

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

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

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

使用objcopy也很难理解静态数据,例如.data.bss部分。如果只将.text部分复制到平面二进制文件中,那么任何地方都不会有数据。(但是在ROM中,您需要一个启动函数,将静态初始化器从ROM复制到.data的内存中,并对.bss空间进行0。如果您想要编写asm源代码,使其具有一个具有非零值的正常外观的.data部分,那么您的构建脚本就需要计算出要复制的大小,这样您的启动函数就可以使用它,而不必手动完成所有这些操作。)

票数 5
EN

Stack Overflow用户

发布于 2021-11-09 09:14:57

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

这些步骤如下:

  1. 修改程序集文件,使其具有.text.data部分和_start标签。我的simple.asm文件现在看起来如下: .globl _start .text _start: add x5,x6,x7 .data L1:.word 27
  2. 使用以下命令将.asm组装成一个.o文件: riscv32 32-未知-精灵-为simple.asm -o simple.o
  3. 为特定处理器创建链接器脚本。我遵循了这个神奇的视频,它从头到尾都在创建链接器脚本。现在,我只需要.text.data部分。因此,我的链接器脚本(mycpu.ld)如下所示: OUTPUT_FORMAT(“elf32 32-littleriscv”、“elf32 32-littleriscv”、“elf32 32-littleriscv”)条目(_start)内存{ DATA (rwx):开头= 0x0,长度= 0x80 INST (rx):开头= 0x80 }节{ .data:{ *(.data) }> DATA .text:{ *(.text) }> INST }
  4. 使用riscv32-unknown-elf-gcc生成ELF文件,该文件自动调用riscv32-unknown-elf-ld: riscv32 32-未知-精灵-gcc -nostdlib -T mycpu.ld -o simple.elf simple.o
  5. .elf文件中创建一个原始二进制或十六进制文件,我将使用该文件填充内存的内容。 riscv32 32-未知-elf-objcopy -O二进制simple.elf simple.hex

最终的simple.hex包含以下内容(使用hexyl):

代码语言:javascript
运行
复制
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│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    ┊        │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘

其中b3027300add x5,x6,x7的十六进制值。

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

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69834360

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档