learn-tech/专栏/计算机基础实战课/13小试牛刀:跑通RISC-V平台的HelloWorld程序.md
2024-10-16 10:18:29 +08:00

13 KiB
Raw Blame History

                        因收到Google相关通知网站将会择期关闭。相关通知内容
                        
                        
                        13 小试牛刀跑通RISC-V平台的Hello World程序
                        你好我是LMOS。

在上一课中我们一起约定了主环境安装了编译工具和依赖库构建了交叉编译RISC-V工具链。

今天我们继续构建RISC-V版的模拟器QEMU代码你可以从这里下载让它成为“定制款”更匹配我们的学习需要。为此我们需要设置好主环境的环境变量安装好VSCode及其插件这样才能实现编辑、编译、运行、调试RISC-V程序的一体化、自动化。

话不多说,我们开始吧。

RISC-V运行平台

有了上节课成功构建好的交叉编译器有很多同学可能按捺不住急着想写一个简单的Hello World程序来测试一下刚刚构建的交叉编译器。

恕我直言这时你写出来的Hello World程序虽然会无警告、无错误的编译成功但是只要你一运行铁定会出错。

这是为什么呢因为你忘记了交叉编译器生成的是RISC-V平台的可执行程序这样的程序自然无法在你的宿主机x86平台上运行它只能在RISC-V平台上运行。

摸着自己的荷包你可能陷入了沉思难道我还要买一台RISC-V平台的计算机这样成本可太高了不划算。

贫穷让人学会变通为了节约成本我们希望能用软件模拟RISC-V平台。嘿这当然可以而且前辈们早已给我们写好了这样的软件它就是QEMU。

揭秘QEMU

什么是QEMUQEMU是一个仿真器或者说是模拟器软件与市面上BOCHS类似由软件来实现模拟。

QEMU就像计算机界的“孙悟空”变化多端能模拟出多种类型的CPU比如IA32、AMD64、ARM、MIPS、PPC、SPARC、RISC-V等。QUEM通过动态二进制转换来模拟CPU。除了CPU它还支持模拟各种IO设备并提供一系列的硬件模型。这使得QEMU能模拟出完整的硬件平台使得QEMU能运行各种操作系统如Windows和Linux。

你可以把QEMU当做一个“双面间谍”因为在它上面运行的操作系统也许还认为自己在和硬件直接打交道其实是同QEMU模拟出来的硬件打交道QEMU再将这些指令翻译给真正硬件进行操作。通过这种模式QEMU运行的操作系统就能和宿主机上的硬盘、网卡、CPU、CD-ROM、音频设备、USB设备等进行交互了。

由于QEMU的以上这些特点导致QEMU在宿主平台上可以模拟出其它不同于宿主平台的硬件体系这是QEMU的优点。

不过由于是用了软件来实现的模拟所以性能很差这也是QEMU的缺点。正因为这个缺点后来就出现了 QEMU和KVM结合使用的解决方案。

KVM基于硬件辅助的虚拟化技术主要负责比较繁琐的CPU和内存虚拟化而QEMU则负责 I/O设备的模拟两者合作各自发挥自身的优势成就了强强联合的典范。

回归主题关于QEMU现阶段你最需要记住的就是它有两种主要工作模式系统模式和用户模式。

在系统工作模式下QEMU能模拟整个计算机系统包括CPU及其他IO设备。它能运行和调试不同平台开发的操作系统也能在宿主机上虚拟不同数量、不同平台的虚拟电脑。而在用户工作模式QEMU能建立一个普通进程运行那些由不同体系处理器编译的应用程序比如后面我们要动手编写的RISC-V版的Hello World程序。

构建我们的“定制款”QEMU

说了这么多其实是想让你更加了解QEMU。

下面我们来办正事儿——构建适合我们的QEMU如果我们不是有特殊要求——模拟RISC-V平台且带调试功能的QEMU用不着亲自动手去构建只需要一条安装指令就完事了。

构建QEMU用四步就能搞定首先下载QEMU源代码接着配置QEMU功能选项然后编译QEMU最后安装QEMU。

我们需要从QEMU官网上下载稳定版本的QEMU源代码。如果你和我一样觉得在浏览器上点来点去非常麻烦也可以在切换到RISCV_TOOLS目录的终端下输入如下指令

wget https://download.qemu.org/qemu-6.2.0.tar.xz #下载源码包 tar xvJf qemu-6.2.0.tar.xz #解压源码包

这里跑完第一条指令以后下载下来的是压缩的QEMU源码包。所以在下载完成后你要用第二条指令来解压。

由于[上节课]我们构建RISC-V工具链时已经统一安装了构建QEMU所需要的相关依赖库所以这里就不用安装相关依赖库了。

解压成功后我们就要开始配置QEMU的功能了。同样为了不污染源代码目录我们可以先在qemu-6.2.0目录下建立一个build目录然后切换到build目录下进行配置输入如下指令

mkdir build #建立build目录 cd build #切换到build目录下 ../configure --prefix=/opt/riscv/qemu --enable-sdl --enable-tools --enable-debug --target-list=riscv32-softmmu,riscv64-softmmu,riscv32-linux-user,riscv64-linux-user #配置QEMU

上述配置选项中prefix表示QEMU的安装目录我们一起约定为“/opt/riscv/qemu”目录enable-sdl表示QEMU使用sdl图形库 enable-tools表示生成QEMU工具集enable-debug表示打开QEMU调试功能。

最重要的是 target-list 这个选项它表示生成QEMU支持的模拟目标机器。不同选项所支持的平台不同我们的选择如下表所示

如果你什么都不选的话它会默认生成QEMU支持的所有平台。按前面我们讲的操作配置配置成功后build目录下会生成后面截图里展示的文件和目录。

配置好功能选项之后下一步就是编译QEMU了。只要配置成功了编译这事儿就非常简单了我们只要输入如下指令然后交给计算机编译就好了。别忘了等待期间泡杯茶不知道你会不会像我一样哼起那首歌“世上有没有人安静的等待你一直不愿回神……”

sudo make -j8

最后就是安装QEMU经过漫长等待以后我们终于迎来编译的成功。这时你还需要输入如下指令进行安装。

sudo make install

这里说明一下QEMU不像RISC-V工具链那样会在编译结束后自动安装它需要手动安装。

我们在终端中切换到“/opt/riscv/qemu/bin”目录下执行如下指令

qemu-riscv32 -version && qemu-riscv64 -version && qemu-system-riscv32 -version && qemu-system-riscv64 -version

上述指令会输出qemu-riscv32、qemu-riscv64、qemu-system-riscv32、qemu-system-riscv64的版本信息以证明能运行RISC-V平台可执行程序的QEMU构建成功。你可以对照一下后面的截图。

到这里RISC-V平台的编译环境和执行环境已经构建完成并且能生成和执行32位或者64位的RISC-V平台的可执行程序无论是RISC-V平台的应用程序还是RISC-V平台的操作系统。

处理环境变量

不知道你发现了没有我们运行QEMU和RISC-V工具链相关的程序都要切换到/opt/riscv/xxxx/bin目录中才可以运行而不是像Linux中的其它程序可以直接在终端中直接运行。

革命还未成功我们还得努力。这是因为我们没有将QEMU和RISC-V工具链的安装目录加入到Linux的环境变量中。

接下来我们就开始处理环境变量,修改环境的方法有好几种。这里我为你演示比较常用的一种,那就是在当前用户目录下的“.bashrc”文件中加入相关的指令。

这里说的“当前用户的目录”就是在终端中执行”cd ~” 指令。怎么操作呢?我们切换到当前用户目录下,来执行这个指令。然后,在文件尾部加上两行信息就行了。具体指令如下所示:

cd ~ #切换到当前用户目录下 vim ./.bashrc #打开.bashrc文件进行编辑

#在.bashrc文件末尾加入如下信息 export PATH=/opt/riscv/gcc/bin:$PATH export PATH=/opt/riscv/qemu/bin:$PATH

上述操作完成以后,你会看到下图所示的结果:-

随后我们按下键盘上ESC键接着输入”:wq”以便保存并退出Vim。这样操作后你会发现环境变量并没有生效。

这里还差最后一步,我们在终端中输入如下指令,让环境变量生效:

source ./.bashrc

现在你在任何目录之下输入QEMU和RISC-V工具链相关的程序命令它们就都可以正常运行了。

安装VSCode

有了QEMU和RISC-V工具链相关的程序命令我们虽然可以编译调试和执行RISC-V平台的程序了但是必须在终端中输入多条指令才能完成相关的工作。

这对于很多同学来说肯定觉得很陌生特别是在图形化盛行的今天我们更期待能有个轻量级的IDE。

这里我们约定使用VSCode它安装起来也很简单。在 VSCode官网上下载deb包下载后双击deb安装或者切换到刚才下载VSCode目录的终端中输入如下指令就行了。

sudo apt-get install -f *.deb

安装好后在你的桌面会出现VSCode图标双击打开后的页面如下所示

不过有了VSCode我们目前只能写代码还不能编译和调试代码所以需要给VSCode安装C/C++扩展。我们只需打开VSCode按下ctrl+shift+x就能打开VSCode的扩展页面在搜索框中输入C/C++就可以安装了,如下所示:

至此我们的VSCode及其需要的扩展组件就安装完成了。

下一步,我们还需要在你的代码目录下建立一个.vscode文件夹并在文件里写上两个配置文件。这两个配置文件我已经帮你写好了如下所示。

在.vscode文件夹中有个tasks.json文件它主要负责完成用RISC-V编译器编译代码的功能还有用QEMU运行可执行文件的功能。

我们先说说这里的编译工作是怎么完成的。具体就是通过调用make读取代码目录中的Makefile脚本在这个脚本中会调用riscv64-unknown-elf-gcc完成编译。等编译成功后才会调用QEMU来接手由它运行编译好的可执行程序。代码注释已经写得很清楚了你可以停下来仔细看看。

不过tasks.json文件虽然解决了编译与运行的问题但是它也是被其它文件调用的。被谁调用呢那就是我们的调试配置文件launch.json文件它用于启动调试器GDB只不过这里启动的不是宿主平台上的GDB而RISC-V工具链中的GDB。其内容如下所示

当我们写好代码后按下F5键后VSCode就会执行launch.json文件的调试操作了。这里调试器和要调试的可执行程序已经制定好了。不过由于preLaunchTask的指定开始执行调试命令之前VSCode会首先执行tasks.json文件中的操作即编译和运行。

运行Hello World

下面我们一起来写下那个著名的程序——Hello World写好后在main函数所在的行前打上一个断点按下F5键就会看到如下界面。

如果不出意外,哈哈,放心,按我提供给你的步骤,也出不了意外,你一定会看到以上界面。

我们重点来观察红色方框中的信息可以查看代码变量值、CPU的寄存器值、函数的调用栈、断点信息、源代码以及程序执行后在VSCode内嵌终端中输出的信息。有了这些信息我们就能清楚地看到一个程序运行过程的状态和结果。

走到这里我们的定制款QEMU以及VSCode就搭好了可以去图形化编辑、编译、运行和调试RISC-V平台的可执行程序了。

重点回顾

好了我们的RISC-V平台的Hello World也是我们在宿主机上开发的第一个非宿主机的程序现在已经成功运行这说明我们之前的工作完成得很完美今天的课程不知不觉也接近了尾声。

下面来回顾一下,这节课我们都做了些什么。

首先我们构建了能运行RISC-V可执行程序的QEMU模拟器这使得我们不必购买RISC-V平台的机器就能在宿主机上运行RISC-V可执行程序。这不但大大方便了我们的开发工作而且节约了成本。

然后我们处理了环境变量方便我们在任何目录下都可以随意使用RISC-V工具链中的命令和QEMU相关的命令。

最后我们安装了VSCode还在其中安装C/C++扩展并对其进行了相应的配置。以后我们在VSCode图形环境下编写代码、编译代码和调试代码就能一气呵成了。

这节课的要点我整理了导图,供你参考。

恭喜你坚持到这里通过两节课的内容我们拿下了开发环境这一关这对我们后续课程中的实验相当重要。下一模块讲解和调试RISC-V汇编指令的时候你会进一步体会到环境搭建好的便利先好好休息一下咱们下节课见。

思考题

处理环境变量后为什么要执行source ./.bashrc才会生效

欢迎你在留言区提问或者晒晒你的实验记录。如果觉得有收获,也推荐你把这节课分享给你的朋友。