diff --git a/articles/20230929-elf2flt-elf2flt-build-1.md b/articles/20230929-elf2flt-elf2flt-build-1.md new file mode 100644 index 0000000000000000000000000000000000000000..62d62dbfa35dde155aab596298c002f950c2f91b --- /dev/null +++ b/articles/20230929-elf2flt-elf2flt-build-1.md @@ -0,0 +1,180 @@ +> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [spaces codeblock codeinline pangu autocorrect]
+> Author: Odysseus <320873791@qq.com>
+> Date: 2023/09/19
+> Revisor: walimis <>
+> Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
+> Proposal: [为 ELF2FLT 完善独立编译与安装支持](https://gitee.com/tinylab/riscv-linux/issues/I79PO2)
+> Sponsor: PLCT Lab, ISCAS + +# elf2flt 篇三 使用 + +## 前言 + +在本机安装完 elf2flt 后,我们就可以使用它构建 bFLT 程序,并放到 no-MMU 的 Linux 系统中运行。 + +我们首先需要一个 no-MMU RISC-V 的系统,这里我们使用 Buildroot 构建的 QEMU 镜像来进行测试。 + +## 准备 + +准备工作主要是 Buildroot 的构建。首先我们进入 cloud-lab 里面的 RISC-V 64 位实验环境。 + +```bash +$ tools/docker/run riscv-lab +``` + +等待片刻,我们就可以进入到 RISC-V 64 位的实验环境了。理论上本机并不需要 RISC-V 64 位的环境,有交叉编译工具链即可,真正需要 RISC-V 64 位的是无 MMU 的目标环境。 + +而后,我们在 RISC-V-lab 里面安装 Buildroot。首先我们把 Buildroot 仓库克隆下来,进入到 Buildroot 目录: + +```sh +$ cd /home/ubuntu +$ git clone git://git.buildroot.net/buildroot +$ cd buildroot +``` + +进入后,我们可能需要先安装 CMake。如果本机是 RISC-V 64 位环境且没有安装 CMake(例如我们的 riscv-lab 环境),Buildroot 会自己构建一份,此时会出现与 libatomic 库有关的错误。 + +```sh +$ sudo apt-get update +$ sudo apt-get install cmake # riscv-lab needed +``` + +然后我们开始配置 Buildroot。由于我们是在 QEMU 上运行的 RISC-V 64 位 no-MMU 系统,因此采用 `qemu_riscv64_nommu_virt_defconfig` 配置: + +```sh +$ make qemu_riscv64_nommu_virt_defconfig +``` + +最后开始构建: + +```sh +$ make +``` + +构建完成后,生成的镜像在 `/home/ubuntu/buildroot/output/images` 下面。我们看一下这个目录下有什么: + +```sh +$ cd /home/ubuntu/buildroot/output/images +$ ls +Image rootfs.ext2 rootfs.tar start-qemu.sh +``` + +这里的 `Image` 是系统镜像,`rootfs.ext2` 是磁盘镜像,`start-qemu.sh` 是系统镜像在 QEMU 上运行的启动脚本。由于下文需要将我们自己的 bFLT 文件拷贝到磁盘镜像下,我们先将其挂载: + +```sh +$ sudo mkdir /mnt/buildroot-nommu +$ sudo mount rootfs.ext2 /mnt/buildroot-nommu +``` + +然后我们启动镜像: + +```sh +$ ./start-qemu.sh + +[ 0.000000] Linux version 6.1.44 (ubuntu@riscv-lab) (riscv64-buildroot-linux-uclibc-gcc.br_real (Buildroot -gbdab4577-dirty) 12.3.0, GNU ld (GNU Binutils) 2.40) #1 SMP Tue Sep 26 00:35:20 CST 2023 +[ 0.000000] random: crng init done +[ 0.000000] Machine model: riscv-virtio,qemu +[ 0.000000] Forcing kernel command line to: root=/dev/vda rw earlycon=uart8250,mmio,0x10000000,115200n8 console=ttyS0 +... +[ 2.438788] Run /sbin/init as init process +Seeding 256 bits and crediting +Saving 256 bits of creditable seed for next boot + +Welcome to Buildroot +buildroot login: root +Jan 1 00:00:10 login[34]: root login on 'console' +~ # +``` + +至此,Buildroot 的准备工作已经完成。 + +## 使用 + +elf2flt 的使用实际上非常简单,只要安装完成,它就已经整合到我们的交叉编译工具链里面。 + +bFLT 程序的构建过程是将源程序编译成 ELF,再将其与同为 ELF 格式的运行时库(例如 uClibc)进行静态链接,因此,理论上只要是 libc,无论其是 glibc、uClibc 还是 musl libc,都可以通过此种方式链接到 bFLT 程序里。这里以 uClibc 为例,讲解如何用整合进 elf2flt 的工具链编译一个可以运行的 bFLT 文件。 + +首先,我们以一个简单的程序作为例子(`hello.c`): + +```c +#include +int main() { + int num = 0; + printf("enter your number here:\n"); + scanf("%d", &num); + printf("hello world from number %d!\n", num); + return 0; +} +``` + +接下来我们编译源程序。理论上在 Buildroot 外部编译的 uClibc 也能使用,但是为省却麻烦,我们直接使用 Buildroot 编译好的 uClibc 库进行编译: + +```sh +$ gcc -o hello-b-gcc hello.c -nostdinc -nostdlib \ +-I/usr/bin/../lib/gcc/riscv64-linux-gnu/11/include \ +-I/usr/bin/../lib/gcc/riscv64-linux-gnu/11/include-fixed \ +-I/home/ubuntu/buildroot/output/host/riscv64-buildroot-linux-uclibc/sysroot/usr/include \ +/home/ubuntu/buildroot/output/build/uclibc-1.0.44/lib/crt1.o \ +/usr/lib/gcc/riscv64-linux-gnu/11/crti.o \ +/usr/lib/gcc/riscv64-linux-gnu/11/crtbeginT.o \ +-L/usr/lib/gcc/riscv64-linux-gnu/11 \ +-L/usr/lib/gcc \ +-L/home/ubuntu/buildroot/output/build/uclibc-1.0.44/lib \ +-Wl,--build-id=none -Wl,-elf2flt=-r --static -lc -lgcc \ +/usr/lib/gcc/riscv64-linux-gnu/11/crtend.o \ +/usr/lib/gcc/riscv64-linux-gnu/11/crtn.o +``` + +注意到这里的链接过程所使用的库有两个来源:gcc 和 uClibc。很显然,来自 gcc 的库使用本机的也可以。 + +生成可执行文件后,我们使用 flthdr 查看它的 header: + +```sh +$ flthdr ./hello-b-gcc +./hello-b-gcc + Magic: bFLT + Rev: 4 + Build Date: Fri Sep 29 08:20:22 2023 + Entry: 0x44 + Data Start: 0x99a0 + Data End: 0xb2d8 + BSS End: 0xd420 + Stack Size: 0x1000 + Reloc Start: 0xb2d8 + Reloc Count: 0x1f + Flags: 0x3 ( Load-to-Ram Has-PIC-GOT ) +``` + +可以看到,编译过程没有问题,这个可执行文件确实是 bFLT 格式。 + +然后我们把构建好的源程序放到挂载好的磁盘镜像中: + +```sh +$ sudo cp ./hello-b-gcc /mnt/buildroot-nommu/root +``` + +最后我们运行 Linux 系统镜像,并在上面运行我们的 bFLT 程序: + +```sh +$ cd /home/ubuntu/buildroot/output/images/ +$ ./start-qemu.sh + +~ # ls +hello-b-gcc +~ # ./hello-b-gcc +enter your number here: +114514 +hello world from number 114514! +``` + +## 总结 + +本篇文章主要内容为 elf2flt 工具的使用,由于其能够整合进已有的交叉工具链中,故使用起来比较方便,但是需要注意编译时使用的 libc 库和头文件。 + +## 参考资料 + +- [https://gitee.com/tinylab/elf2flt][001] +- [https://buildroot.org/downloads/manual/manual.html][002] + +[001]: https://gitee.com/tinylab/elf2flt +[002]: https://buildroot.org/downloads/manual/manual.html