edubart/riscvm

GitHub: edubart/riscvm

一个极简的 RV64I 解释器,可在沙箱中运行 GCC 编译的 C 程序,实现类似脚本语言的灵活部署与隔离执行。

Stars: 69 | Forks: 5

使用 Nelua 编写的微型 RISC-V 虚拟机(因此也包含 C)。 这是一个最小且简单的 RISC-V ISA 模拟器,实现了 RV64I 指令集的一个子集。 仅实现了运行最小用户态虚拟机所需的指令。 该模拟器允许运行经 GCC 编译为 RISC-V 的 C 文件,在一个最小的沙箱虚拟机中运行。 该虚拟机能够通过系统调用调用宿主机的函数。 本项目受 [libriscv](https://github.com/fwsGonzo/libriscv) 启发。 ## 有趣之处在哪里? 这是一个关于如何在沙箱虚拟机中解释执行 C 程序的最小示例。人们可以利用这个概念,在任何安装了该模拟器的系统上运行由 GCC 编译的程序,或者将 C 应用程序隔离在独立的环境中运行,又或者实现应用程序运行时的热重载(这通常由脚本语言完成)。 ## 运行示例 使用 Nelua 运行示例: ``` nelua -r riscvm.nelua examples/fib.bin nelua -r riscvm.nelua examples/ack.bin nelua -r riscvm.nelua examples/sieve.bin ``` 这些示例是从相应的 C 文件编译成 RV64I 二进制文件的。 如果你没有安装 Nelua,也可以: ``` gcc -O2 -o riscvm riscvm.c ./riscvm examples/fib.bin ``` ## 编译示例 所有示例都已经编译为 RV64I,但如果你想编辑或运行一个新的示例, 可以使用例如 `make EXAMPLE=fib.c` 命令将 `fib.c` 编译为 `fib.bin`, 这需要 RISC-V elf 工chain。 ## 它是如何工作的? 0. 示例使用独立式(freestanding)C 代码编写, 沙箱环境之外的功能(例如打印到终端) 是通过 `lib/syscalls.h` 中的系统调用实现的, 而最小化的 libc 则在 `lib/tinyc.c` 中实现。 1. C 示例被编译为 RISC-V elf 二进制文件, 使用 `lib/start.s` 来正确初始化虚拟机状态, 并通过 `lib/link.ld` 的特殊链接规则来调整指令地址。 2. RISC-V 字节码从编译好的 elf 二进制文件中提取出来,生成字节码二进制文件。 3. 字节码二进制文件通过 `riscvm` 加载并运行, 解释执行 RV64I 指令。 4. 在解释执行过程中,虚拟机可能会 通过系统调用调用宿主机。 5. 一旦调用 `exit` 系统调用或发生任何错误,应用程序就会停止。 ## 实现细节 这是通过阅读 [RISC-V 规范](https://riscv.org/technical/specifications/) 实现的 ## 基准测试 在同一个系统中,使用 Lua 5.4、riscvm 和原生代码运行等效代码进行了一些示例测试, 实验表明解释执行的代码比原生代码慢 10~20 倍: | example | lua 5.4 | riscvm | x86_64 | |---------|----------|--------|--------| | ack | 1070ms | 1022ms | 47ms | | sieve | 1077ms | 716ms | 64ms | 注意:此虚拟机不做任何类型的 JIT,且实现非常简单, 还有很大的优化空间。 ## 未来改进 这些扩展尚未实现,但会很有用: * M 扩展 - 乘法和除法 * F 扩展 - 单精度浮点 * D 扩展 - 双精度浮点 此外,更多 C 函数(如 malloc/free/memcpy)也可以作为系统调用实现。
标签:API接口, DNS 反向解析, ELF, GCC, ISA, Nelua, RISC-V, RV64I, 仿真器, 动态执行, 后端技术, 安全沙箱, 客户端加密, 嵌入式, 底层开发, 指令集架构, 沙箱, 热重载, 生成式AI安全, 程序隔离, 系统编程, 脚本语言替代, 虚拟机, 解释器, 轻量级虚拟机