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

Adr*_*ian 12 riscv

我有以下简单的C代码:

   void main(){
    int A = 333;
    int B=244;
    int sum;
    sum = A + B;  
}
Run Code Online (Sandbox Code Playgroud)

当我用它编译时

$riscv64-unknown-elf-gcc code.c -o code.o
Run Code Online (Sandbox Code Playgroud)

如果我想看到我使用的汇编代码

$riscv64-unknown-elf-objdump -d code.o 
Run Code Online (Sandbox Code Playgroud)

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

我读到riscv提供了三种类型的编译:裸机模式,newlib代理内核和riscv Linux.根据以前的研究,我应该做的编译是裸机模式.这是因为我希望在不支持操作系统或内核代理的情况下进行最小程序集.不需要作为系统调用的汇编函数.

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

Chr*_*ris 14

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


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

第一件事 - Spike在0x200处启动.由于Spike是黄金ISA模拟器模型,您的核心也应该在0x200启动.

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

因此,当您拆卸裸机程序时,最好从0x200开始!如果你想在代理内核之上运行它,最好从0x10000开始(如果是Linux,那就更大了......).

现在,如果你想运行裸机,你就会强迫自己编写处理器启动代码.呸.但是,让我们对此表示不满,并假装没有必要.

(您还可以查看riscv-tests/env/p,了解物理寻址机器的"虚拟机"描述.您将找到所需的链接描述文件和一些宏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
Run Code Online (Sandbox Code Playgroud)

和link.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 = .;
 }
Run Code Online (Sandbox Code Playgroud)

现在编译这个......

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>
Run Code Online (Sandbox Code Playgroud)

并运行它:

spike hello
Run Code Online (Sandbox Code Playgroud)

这是一件美丽的事情.

链接脚本将我们的代码放在0x200.Spike将从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启动和支持运行裸机的代码.


use*_*418 5

gcc将“额外”代码放在这里,是任何程序所需的东西。代理内核被设计为运行这些东西所需的最少支持。一旦您的处理器正常工作,我建议在pk之上而不是裸机上运行。

同时,如果您要看简单的汇编,我建议跳过使用'-c'的链接阶段:

riscv64-unknown-elf-gcc code.c -c -o code.o
riscv64-unknown-elf-objdump -d code.o
Run Code Online (Sandbox Code Playgroud)

对于没有pk或linux的运行代码的示例,我将看riscv-tests