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

时间:2015-07-13 17:51:04

标签: 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汇编代码的骨架?

3 个答案:

答案 0 :(得分:13)

警告:自最新的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(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

和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 = .;
 }

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

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

这编译为(riscv64-unknown-elf-objdump -d你好):

 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)直到前端服务器收到消息并杀死我们。

如果你能弄明白如何,可能会抛弃链接器脚本 告诉编译器移动&lt; _start&gt;单独到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启动和支持运行裸机的代码。

答案 1 :(得分:5)

&#34;额外&#34;代码由gcc放在那里,是任何程序所需的东西。代理内核旨在成为运行此类内容所需的最低限度的支持。一旦你的处理器工作,我会建议在pk而不是裸机上运行。

与此同时,如果您想查看简单的装配,我建议您使用&#39; -c&#39;来跳过链接阶段:

riscv64-unknown-elf-gcc code.c -c -o code.o
riscv64-unknown-elf-objdump -d code.o

有关运行不带pk或linux的代码的示例,我会查看riscv-tests

答案 2 :(得分:0)

我很惊讶没有人提到gcc -S,尽管有很多样板,但它跳过了汇编和链接并输出了汇编代码,但只是四处浏览可能很方便。