riscv - 如何编译 C 代码以获得最小 RISC-V 汇编程序的裸机框架?

标签 riscv

我有以下简单的 C 代码:

   void main(){
    int A = 333;
    int B=244;
    int sum;
    sum = A + B;  
}

当我编译这个
$riscv64-unknown-elf-gcc code.c -o code.o

如果我想查看我使用的汇编代码
$riscv64-unknown-elf-objdump -d code.o 

但是当我探索汇编代码时,我发现这会生成很多代码,我认为这些代码是为了支持代理内核(我是 riscv 的新手)。但是,我不希望这段代码支持代理内核,因为这个想法是在 FPGA 中只实现这个简单的 C 代码。

我读到 riscv 提供了三种类型的编译:裸机模式、newlib 代理内核和 riscv Linux。根据之前的研究,我应该做的那种编译是裸机模式。这是因为我想要一个不支持操作系统或内核代理的最小程序集。不需要作为系统调用的汇编函数。

但是,我还没有找到,因为我可以编译 C 代码以获得最小 riscv 汇编程序的骨架。如何在裸机模式下编译上面的 C 代码或获得最小 riscv 汇编代码的骨架?

最佳答案

警告:这个答案在最新的 RISC-V Privileged Spec v1.9 中有些过时,其中包括删除 tohost控制/状态寄存器 (CSR),它是非标准主机目标接口(interface) (HTIF) 的一部分,现已被删除。当前(截至 2016 年 9 月)riscv-tests而是执行内存映射存储到 tohost内存位置,在联机环境中由 front-end server 监控.

如果你 真的真的需要/想要运行 RISC-V 代码裸机,那么这里是这样做的说明。你会丢失一堆有用的东西,比如 riscv-pk(代理内核)提供的 printf 或 FP-trap 软件仿真。

首先要做的事情 - Spike 在 0x200 启动。由于 Spike 是黄金 ISA 模拟器模型,您的内核也应该在 0x200 启动。

( 咳嗽 ,截至 2015 年 7 月 13 日,riscv-tools 的“master”分支( https://github.com/riscv/riscv-tools )正在使用旧的 pre-v1.7 特权 ISA,因此从 0x2000 开始。这篇文章将假设您使用的是 v1.7+,这可能需要使用 riscv-tools 的“new_privileged_isa”分支)。

所以当你反汇编你的裸机程序时,最好
从 0x200 开始!!!如果你想在代理内核之上运行它,它
最好从 0x10000 开始(如果是 Linux,它会更大……)。

现在,如果你想运行裸机,你就强制自己写下
处理器启动代码。呸。但是,让我们赌上这一点,假装那不是
必要的。

(你也可以查看 riscv-tests/env/p,对于“虚拟机”
物理寻址机器的描述。你会发现链接描述文件
您需要和一些 macros.h 来描述一些初始设置代码。或更好
然而,在 riscv-tests/benchmarks/common.crt.S)。

无论如何,有了上述(令人困惑的)知识,让我们抛开一切
离开并从头开始我们自己...

hello.s:
 .align 6
 .globl _start
 _start:
 # screw boot code, we're going minimalist
 # mtohost is the CSR in machine mode
 csrw mtohost, 1;
 1:
 j 1b

和链接.ld:
 OUTPUT_ARCH( "riscv" )
 ENTRY( _start )
 SECTIONS
 {
 /* text: test code section */
 . = 0x200;
 .text :
 {
 *(.text)
 }
 /* data: Initialized data segment */
 .data :
 {
 *(.data)
 }
 /* End of uninitalized data segement */
 _end = .;
 }

现在编译这个…

riscv64-unknown-elf-gcc -nostdlib -nostartfiles -Tlink.ld -o hello hello.s

这编译为(riscv64-unknown-elf-objdump -d hello):
 hello: file format elf64-littleriscv

 Disassembly of section .text:

 0000000000000200 <_start>:
 200: 7810d073 csrwi tohost,1
 204: 0000006f j 204 <_start+0x4>

并运行它:
spike hello

这是一件美丽的事情。

链接脚本将我们的代码放置在 0x200。斯派克将从
0x200,然后将 #1 写入控制/状态寄存器
“tohost”,它告诉 Spike “停止运行”。然后我们旋转一个地址
(1: j 1b) 直到前端服务器收到消息并杀死我们。

如果您能弄清楚如何
告诉编译器自己将 <_start> 移动到 0x200。

对于其他示例,您可以仔细阅读以下存储库:

riscv-tests 存储库包含非常少的 RISC-V ISA 测试
(https://github.com/riscv/riscv-tests)。

这个 Makefile 有编译器选项:
https://github.com/riscv/riscv-tests/blob/master/isa/Makefile

许多“虚拟机”描述宏和链接器脚本可以
可以在 riscv-tests/env (https://github.com/riscv/riscv-test-env) 中找到。

您可以在 (riscv-tests/isa/rv64ui-p-simple.dump) 上查看“最简单”的测试。

您可以查看riscv-tests/benchmarks/common用于运行裸机的启动和支持代码。

关于riscv - 如何编译 C 代码以获得最小 RISC-V 汇编程序的裸机框架?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31390127/

相关文章:

factorial - 如何在RISC-V中实现阶乘函数

assembly - %pcrel_hi 和 %pcrel_lo 实际上做了什么?

riscv - 在 VCD 中显示 Chisel 信号

assembly - 为什么 RISC-V S-B 和 U-J 指令类型以这种方式编码?

cpu - 为什么不推荐使用或过时分支延迟槽?

riscv - Rocket-chip指令跟踪列

multithreading - 是否可以在 riscv 中的两个锁上构建原子 "release-and-acquire"操作?

operating-system - 为什么xv6-riscv中没有GDT?

gcc - 支持矢量的 RISC-V 工具链

linux-kernel - RISC-V 中的地址指定